164 lines
4.4 KiB
Go
164 lines
4.4 KiB
Go
package web
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"strconv"
|
||
|
|
|
||
|
|
"uPortal/internal/auth"
|
||
|
|
"uPortal/internal/user"
|
||
|
|
)
|
||
|
|
|
||
|
|
// HandleProfile shows the current user's own profile.
|
||
|
|
func (s *WebService) HandleProfile(w http.ResponseWriter, r *http.Request) {
|
||
|
|
data, ok := s.basicViewData(w, r, "Profile")
|
||
|
|
if !ok {
|
||
|
|
http.Redirect(w, r, "/signin", http.StatusSeeOther)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
full, err := s.users.GetUserById(r.Context(), data.User.Id)
|
||
|
|
if err != nil {
|
||
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
data.User = full
|
||
|
|
|
||
|
|
s.render(w, r, "profile/view.html", data)
|
||
|
|
}
|
||
|
|
|
||
|
|
// HandleProfileEdit renders the edit form on GET and applies changes on POST.
|
||
|
|
func (s *WebService) HandleProfileEdit(w http.ResponseWriter, r *http.Request) {
|
||
|
|
data, ok := s.basicViewData(w, r, "Edit Profile")
|
||
|
|
if !ok {
|
||
|
|
http.Redirect(w, r, "/signin", http.StatusSeeOther)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
switch r.Method {
|
||
|
|
case http.MethodGet:
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
|
||
|
|
case http.MethodPost:
|
||
|
|
if err := r.ParseMultipartForm(32 << 20); err != nil {
|
||
|
|
data.Error = "Could not parse form"
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err := auth.ValidateCsrf(r, CsrfCookieName, CsrfFieldName); err != nil {
|
||
|
|
data.Error = "Invalid form, please try again"
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
// Display name: UpdateUser writes the displayname column via the user row.
|
||
|
|
displayName := r.FormValue("display_name")
|
||
|
|
if displayName != "" {
|
||
|
|
data.User.DisplayName = &displayName
|
||
|
|
if err := s.users.UpdateUser(r.Context(), data.User); err != nil {
|
||
|
|
data.Error = "Could not save display name"
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Avatar: upload a JPG/PNG <= 256x256 (validated by the user package).
|
||
|
|
if _, _, err := r.FormFile("avatar"); err == nil {
|
||
|
|
bytes, _, err := user.ExtractUploadedImageBytes(r, "avatar")
|
||
|
|
if err != nil {
|
||
|
|
data.Error = "Invalid avatar image: " + err.Error()
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err := s.users.CreateAvatar(r.Context(), data.User.Id, bytes); err != nil {
|
||
|
|
data.Error = "Could not save avatar"
|
||
|
|
s.render(w, r, "profile/edit.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
http.Redirect(w, r, "/profile", http.StatusSeeOther)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// HandleProfilePassword renders the password change form on GET and
|
||
|
|
// applies the new password on POST.
|
||
|
|
func (s *WebService) HandleProfilePassword(w http.ResponseWriter, r *http.Request) {
|
||
|
|
data, ok := s.basicViewData(w, r, "Change Password")
|
||
|
|
if !ok {
|
||
|
|
http.Redirect(w, r, "/signin", http.StatusSeeOther)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
switch r.Method {
|
||
|
|
case http.MethodGet:
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
|
||
|
|
case http.MethodPost:
|
||
|
|
if err := r.ParseForm(); err != nil {
|
||
|
|
data.Error = "Could not parse form"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err := auth.ValidateCsrf(r, CsrfCookieName, CsrfFieldName); err != nil {
|
||
|
|
data.Error = "Invalid form token"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
oldPassword := r.FormValue("old_password")
|
||
|
|
newPassword := r.FormValue("new_password")
|
||
|
|
confirmPassword := r.FormValue("confirm_password")
|
||
|
|
|
||
|
|
if !auth.CheckPasswordHash(oldPassword, data.User.Password) {
|
||
|
|
data.Error = "Current password is incorrect"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(newPassword) < 6 {
|
||
|
|
data.Error = "New password must be at least 6 characters"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
if newPassword != confirmPassword {
|
||
|
|
data.Error = "New passwords do not match"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
hashedPassword, err := auth.HashPassword(newPassword)
|
||
|
|
if err != nil {
|
||
|
|
data.Error = "Could not hash password"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
data.User.Password = hashedPassword
|
||
|
|
if err := s.users.UpdateUser(r.Context(), data.User); err != nil {
|
||
|
|
data.Error = "Could not update password"
|
||
|
|
s.render(w, r, "profile/password.html", data)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
http.Redirect(w, r, "/profile", http.StatusSeeOther)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// HandleAvatar serves a stored avatar image by user id.
|
||
|
|
func (s *WebService) HandleAvatar(w http.ResponseWriter, r *http.Request) {
|
||
|
|
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
|
||
|
|
if err != nil {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
data, err := s.users.GetAvatar(r.Context(), id)
|
||
|
|
if err != nil || len(data) == 0 {
|
||
|
|
http.NotFound(w, r)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
w.Header().Set("Content-Type", http.DetectContentType(data))
|
||
|
|
w.Write(data)
|
||
|
|
}
|