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 getNewPositiveHandler(w http.ResponseWriter, r *http.Request) {
36 data := map[string]interface{}{"Negative": false}
37 xt.ExecuteTemplate(w, "new.tmpl", data)
38}
39
40func getNewNegativeHandler(w http.ResponseWriter, r *http.Request) {
41 data := map[string]interface{}{"Negative": true}
42 xt.ExecuteTemplate(w, "new.tmpl", data)
43}
44
45func postNewHandler(w http.ResponseWriter, r *http.Request) {
46 negative := r.FormValue("negative") == "on"
47 name := r.FormValue("name")
48
49 if !checkHabitName(name) {
50 http.Error(w, "Bad habit name.", http.StatusBadRequest)
51 }
52
53 var days uint
54 if !negative {
55 res, err := strconv.ParseUint(r.FormValue("days"), 10, 64)
56 if err != nil {
57 http.Error(w, "Bad days value.", http.StatusBadRequest)
58 return
59 }
60 days = uint(res)
61 }
62
63 user, ok := getLoggedUser(r)
64 if !ok {
65 http.Error(w, "Could not get logged user", http.StatusInternalServerError)
66 }
67
68 db.Create(&Habit{
69 UserID: user.ID,
70 Name: name,
71 Days: days,
72 Negative: negative,
73 })
74
75 http.Redirect(w, r, "/habits", http.StatusFound)
76}
77
78func getRegisterHandler(w http.ResponseWriter, r *http.Request) {
79 xt.ExecuteTemplate(w, "auth-register.tmpl", nil)
80}
81
82func getLoginHandler(w http.ResponseWriter, r *http.Request) {
83 _, err := readSessionCookie(r)
84 if err != nil {
85 xt.ExecuteTemplate(w, "auth-login.tmpl", nil)
86 return
87 }
88
89 http.Redirect(w, r, "/habits", http.StatusFound)
90}
91
92func getResetPasswordHandler(w http.ResponseWriter, r *http.Request) {
93 xt.ExecuteTemplate(w, "auth-reset_password.tmpl", nil)
94}
95
96func postRegisterHandler(w http.ResponseWriter, r *http.Request) {
97 if !registrationEnabled {
98 http.Error(w, "Registration is currently disabled.", http.StatusForbidden)
99 return
100 }
101
102 username, err := sanitizeUsername(r.FormValue("username"))
103 if err != nil {
104 http.Error(w, "Invalid username.", http.StatusBadRequest)
105 return
106 }
107
108 email, err := sanitizeEmail(r.FormValue("email"))
109 if err != nil {
110 http.Error(w, "Invalid email.", http.StatusBadRequest)
111 return
112 }
113
114 _, err = getUserByName(username, 0)
115 if err == nil {
116 http.Error(w, "This username is already registered.", http.StatusConflict)
117 return
118 }
119
120 hashedPassword, salt, err := g.HashPassword(r.FormValue("password"))
121 if err != nil {
122 http.Error(w, "Invalid password.", http.StatusBadRequest)
123 return
124 }
125
126 user := User{
127 Username: username,
128 Email: email,
129 PasswordHash: hashedPassword,
130 Salt: salt,
131 }
132
133 db.Create(&user)
134 if user.ID == 0 {
135 http.Error(w, "This email is already registered.", http.StatusConflict)
136 return
137 }
138
139 login(w, user.ID, false)
140 http.Redirect(w, r, "/login", http.StatusFound)
141}
142
143func postLoginHandler(w http.ResponseWriter, r *http.Request) {
144 username := r.FormValue("username")
145 password := r.FormValue("password")
146 remember := r.FormValue("remember")
147
148 user, err := getUserByName(username, 0)
149
150 if err != nil || !g.CheckPassword(password, user.Salt, user.PasswordHash) {
151 http.Error(w, "Invalid credentials", http.StatusUnauthorized)
152 return
153 }
154
155 login(w, user.ID, remember == "on")
156 http.Redirect(w, r, "/login", http.StatusFound)
157}
158
159func logoutHandler(w http.ResponseWriter, r *http.Request) {
160 http.SetCookie(w, g.GenerateEmptyCookie())
161 http.Redirect(w, r, "/login", http.StatusFound)
162}
163
164func postResetPasswordHandler(w http.ResponseWriter, r *http.Request) {
165 emailInput := r.FormValue("email")
166
167 var user User
168 db.Where("email = ?", emailInput).First(&user)
169
170 if user.ID == 0 {
171 http.Redirect(w, r, "/login", http.StatusFound)
172 return
173 }
174
175 resetToken, err := g.GenerateRandomToken(32)
176 if err != nil {
177 http.Error(w, "Could not generate reset token.", http.StatusInternalServerError)
178 return
179 }
180
181 ks.Set("reset:"+resetToken, user.ID, time.Hour)
182 sendResetEmail(user.Email, resetToken)
183
184 http.Redirect(w, r, "/login", http.StatusFound)
185
186}
187
188func getResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) {
189 token := r.URL.Query().Get("token")
190 _, err := ks.Get("reset:" + token)
191 if err != nil {
192 http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized)
193 return
194 }
195
196 xt.ExecuteTemplate(w, "auth-new_password.tmpl", nil)
197}
198
199func postResetPasswordConfirmHandler(w http.ResponseWriter, r *http.Request) {
200 token := r.URL.Query().Get("token")
201 userID, err := ks.Get("reset:" + token)
202 if err != nil {
203 http.Error(w, "Token is invalid or expired.", http.StatusUnauthorized)
204 return
205 }
206
207 var user User
208 db.First(&user, *userID)
209
210 password := r.FormValue("password")
211
212 hashedPassword, salt, err := g.HashPassword(password)
213 if err != nil {
214 http.Error(w, "Invalid password.", http.StatusBadRequest)
215 return
216 }
217
218 user.PasswordHash = hashedPassword
219 user.Salt = salt
220 db.Save(&user)
221 ks.Delete(token)
222
223 http.Redirect(w, r, "/login", http.StatusFound)
224}