src/app/handlers.go (view raw)
1package app
2
3import (
4 "net/http"
5 "strconv"
6 "time"
7)
8
9func getIndexHandler(w http.ResponseWriter, r *http.Request) {
10 xt.ExecuteTemplate(w, "index.tmpl", nil)
11}
12
13func getHabitsHandler(w http.ResponseWriter, r *http.Request) {
14 user, ok := getLoggedUser(r)
15 if !ok {
16 http.Error(w, "Could not find user in context.", http.StatusInternalServerError)
17 return
18 }
19
20 positive, negative, err := getAllHabits(user.ID)
21 if err != nil {
22 http.Error(w, "Could not get user habits.", http.StatusInternalServerError)
23 return
24 }
25
26 data := map[string]interface{}{
27 "User": user,
28 "Positive": positive,
29 "Negative": negative,
30 }
31
32 xt.ExecuteTemplate(w, "habits.tmpl", data)
33}
34
35func getHabitsIDHandler(w http.ResponseWriter, r *http.Request) {
36 habit, err := getHabitHelper(w, r)
37 if err != nil {
38 return
39 }
40
41 xt.ExecuteTemplate(w, "habits-id.tmpl", habit)
42}
43
44func getNewPositiveHandler(w http.ResponseWriter, r *http.Request) {
45 data := map[string]interface{}{"Negative": false}
46 xt.ExecuteTemplate(w, "new.tmpl", data)
47}
48
49func getNewNegativeHandler(w http.ResponseWriter, r *http.Request) {
50 data := map[string]interface{}{"Negative": true}
51 xt.ExecuteTemplate(w, "new.tmpl", data)
52}
53
54func postNewHandler(w http.ResponseWriter, r *http.Request) {
55 negative := r.FormValue("negative") == "on"
56 name := r.FormValue("name")
57
58 if !checkHabitName(name) {
59 http.Error(w, "Bad habit name.", http.StatusBadRequest)
60 }
61
62 var days uint
63 if !negative {
64 res, err := strconv.ParseUint(r.FormValue("days"), 10, 64)
65 if err != nil {
66 http.Error(w, "Bad days value.", http.StatusBadRequest)
67 return
68 }
69 days = uint(res)
70 }
71
72 user, ok := getLoggedUser(r)
73 if !ok {
74 http.Error(w, "Could not get logged user", http.StatusInternalServerError)
75 }
76
77 db.Create(&Habit{
78 UserID: user.ID,
79 Name: name,
80 Days: days,
81 Negative: negative,
82 })
83
84 http.Redirect(w, r, "/habits", http.StatusFound)
85}
86
87func postAckIDHandler(w http.ResponseWriter, r *http.Request) {
88 habit, err := getHabitHelper(w, r)
89 if err != nil {
90 return
91 }
92
93 if habit.LastAck != nil {
94 if time.Since(*habit.LastAck) < 6*time.Hour {
95 http.Redirect(w, r, "/habits", http.StatusFound) // TODO: redirect to an error page instead
96 return
97 }
98 }
99
100 db.Create(Ack{HabitID: habit.ID})
101
102 now := time.Now()
103 habit.LastAck = &now
104 db.Save(&habit)
105
106 http.Redirect(w, r, "/habits", http.StatusFound)
107}
108
109func getRegisterHandler(w http.ResponseWriter, r *http.Request) {
110 xt.ExecuteTemplate(w, "auth-register.tmpl", nil)
111}
112
113func getLoginHandler(w http.ResponseWriter, r *http.Request) {
114 _, err := readSessionCookie(r)
115 if err != nil {
116 xt.ExecuteTemplate(w, "auth-login.tmpl", nil)
117 return
118 }
119
120 http.Redirect(w, r, "/habits", http.StatusFound)
121}
122
123func getResetPasswordHandler(w http.ResponseWriter, r *http.Request) {
124 xt.ExecuteTemplate(w, "auth-reset_password.tmpl", nil)
125}
126
127func postRegisterHandler(w http.ResponseWriter, r *http.Request) {
128 if !registrationEnabled {
129 http.Error(w, "Registration is currently disabled.", http.StatusForbidden)
130 return
131 }
132
133 username, err := sanitizeUsername(r.FormValue("username"))
134 if err != nil {
135 http.Error(w, "Invalid username.", http.StatusBadRequest)
136 return
137 }
138
139 email, err := sanitizeEmail(r.FormValue("email"))
140 if err != nil {
141 http.Error(w, "Invalid email.", http.StatusBadRequest)
142 return
143 }
144
145 _, err = getUserByName(username, 0)
146 if err == nil {
147 http.Error(w, "This username is already registered.", http.StatusConflict)
148 return
149 }
150
151 hashedPassword, salt, err := g.HashPassword(r.FormValue("password"))
152 if err != nil {
153 http.Error(w, "Invalid password.", http.StatusBadRequest)
154 return
155 }
156
157 user := User{
158 Username: username,
159 Email: email,
160 PasswordHash: hashedPassword,
161 Salt: salt,
162 }
163
164 db.Create(&user)
165 if user.ID == 0 {
166 http.Error(w, "This email is already registered.", http.StatusConflict)
167 return
168 }
169
170 login(w, user.ID, false)
171 http.Redirect(w, r, "/login", http.StatusFound)
172}
173
174func postLoginHandler(w http.ResponseWriter, r *http.Request) {
175 username := r.FormValue("username")
176 password := r.FormValue("password")
177 remember := r.FormValue("remember")
178
179 user, err := getUserByName(username, 0)
180
181 if err != nil || !g.CheckPassword(password, user.Salt, user.PasswordHash) {
182 http.Error(w, "Invalid credentials", http.StatusUnauthorized)
183 return
184 }
185
186 login(w, user.ID, remember == "on")
187 http.Redirect(w, r, "/login", http.StatusFound)
188}
189
190func logoutHandler(w http.ResponseWriter, r *http.Request) {
191 http.SetCookie(w, g.GenerateEmptyCookie())
192 http.Redirect(w, r, "/login", http.StatusFound)
193}
194
195func postResetPasswordHandler(w http.ResponseWriter, r *http.Request) {
196 emailInput := r.FormValue("email")
197
198 var user User
199 db.Where("email = ?", emailInput).First(&user)
200
201 if user.ID == 0 {
202 http.Redirect(w, r, "/login", http.StatusFound)
203 return
204 }
205
206 resetToken, err := g.GenerateRandomToken(32)
207 if err != nil {
208 http.Error(w, "Could not generate reset token.", http.StatusInternalServerError)
209 return
210 }
211
212 ks.Set("reset:"+resetToken, user.ID, time.Hour)
213 sendResetEmail(user.Email, resetToken)
214
215 http.Redirect(w, r, "/login", http.StatusFound)
216
217}
218
219func getResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) {
220 token := r.URL.Query().Get("token")
221 _, err := ks.Get("reset:" + token)
222 if err != nil {
223 http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized)
224 return
225 }
226
227 xt.ExecuteTemplate(w, "auth-new_password.tmpl", nil)
228}
229
230func postResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) {
231 token := r.URL.Query().Get("token")
232 userID, err := ks.Get("reset:" + token)
233 if err != nil {
234 http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized)
235 return
236 }
237
238 var user User
239 db.First(&user, *userID)
240
241 password := r.FormValue("password")
242
243 hashedPassword, salt, err := g.HashPassword(password)
244 if err != nil {
245 http.Error(w, "Invalid password.", http.StatusBadRequest)
246 return
247 }
248
249 user.PasswordHash = hashedPassword
250 user.Salt = salt
251 db.Save(&user)
252 ks.Delete(token)
253
254 http.Redirect(w, r, "/login", http.StatusFound)
255}