Files
uPortal/internal/web/profile.go
T

164 lines
4.4 KiB
Go
Raw Normal View History

2026-10-15 23:25:46 +03:00
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)
}