From ee9a453f63ff34f1b4b073e801fbc5f838ab6d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20Bouzour=C3=A8ne?= Date: Sun, 5 Jan 2025 14:44:05 +0100 Subject: [PATCH] Manage user account --- controllers/account.go | 139 ++++++++++++++++++++++++++++++++++++++ main.go | 6 ++ views/account_manage.html | 109 ++++++++++++++++++++++++++++++ views/account_totp.html | 43 ++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 controllers/account.go create mode 100644 views/account_manage.html create mode 100644 views/account_totp.html diff --git a/controllers/account.go b/controllers/account.go new file mode 100644 index 0000000..93273f3 --- /dev/null +++ b/controllers/account.go @@ -0,0 +1,139 @@ +package controllers + +import ( + "git.readonly.ch/bouzoure/popvaud-people/helpers" + "git.readonly.ch/bouzoure/popvaud-people/models" + "github.com/go-playground/validator" + "github.com/gofiber/fiber/v2" +) + +type AccountManageValidation struct { + Email string `validate:"required,min=6,max=100,email"` + Name string `validate:"required,min=2,max=100"` + Password string `validate:"required,min=10,max=100"` + PasswordVerify string `validate:"required,eqfield=Password"` +} + +func AccountManage(c *fiber.Ctx) error { + id, err := helpers.GetSessionUserId(c) + if err != nil { + return err + } + + db, err := helpers.GetDatabase() + if err != nil { + return err + } + + var user models.User + result := db.Find(&user, "id = ?", id) + + if result.Error != nil { + return result.Error + } + + var errors []string + if c.Method() == "POST" { + data := WelcomeValidation{ + Email: c.FormValue("email", user.Email), + Name: c.FormValue("name"), + Password: c.FormValue("password"), + PasswordVerify: c.FormValue("password-verify"), + } + + validate := validator.New() + validErrs := validate.Struct(data) + + if validErrs != nil { + for _, validErr := range validErrs.(validator.ValidationErrors) { + switch validErr.Field() { + case "Email": + errors = append(errors, "L'adresse email doit être valide") + case "Name": + errors = append(errors, "Le nom doit contenir entre 2 et 100 caractères") + case "Password": + if len(data.Password) > 0 { + errors = append(errors, "Le mot de passe doit contenir entre 10 et 100 caractères") + } + case "PasswordVerify": + if len(data.Password) > 0 { + errors = append(errors, "Les mots de passe doivent correspondre") + } + } + } + } + + user.SkipWelcome = true + user.Name = data.Name + user.Email = data.Email + + var usersEmail []models.User + result := db.Find(&usersEmail, "email = ? AND id <> ?", user.Email, user.ID) + if result.Error != nil { + return result.Error + } + + if result.RowsAffected > 0 { + errors = append(errors, "L'adresse email est déjà utilisée par un autre utilisateur") + } + + if len(data.Password) > 0 { + passwordHash, err := helpers.HashPassword(data.Password) + if err != nil { + return err + } + + user.Password = passwordHash + } + + if len(errors) == 0 { + result = db.Save(&user) + if result.Error != nil { + return result.Error + } else { + c.Redirect("/account/manage") + } + } + } + + return c.Render("account_manage", fiber.Map{ + "PageTitle": "Gérer mon compte utilisateur", + "User": user, + "Errors": errors, + }) +} + +func AccountTotp(c *fiber.Ctx) error { + id, err := helpers.GetSessionUserId(c) + if err != nil { + return err + } + + db, err := helpers.GetDatabase() + if err != nil { + return err + } + + var user models.User + result := db.Find(&user, "id = ?", id) + + if result.Error != nil { + return result.Error + } + + if c.Method() == "POST" && c.FormValue("reset_totp") == "on" { + user.TotpSecret.Valid = false + + result = db.Save(&user) + if result.Error != nil { + return result.Error + } else { + c.Redirect("/account/totp") + } + } + + return c.Render("account_totp", fiber.Map{ + "PageTitle": "Gérer multifacteur (TOTP)", + "User": user, + }) +} diff --git a/main.go b/main.go index 4f2c80c..3721c2c 100644 --- a/main.go +++ b/main.go @@ -115,6 +115,12 @@ func main() { app.Get("/totp/verify", controllers.TotpVerifyPage) app.Post("/totp/verify", controllers.TotpVerifyPage) + // Account manage + app.Get("/account/manage", controllers.AccountManage) + app.Post("/account/manage", controllers.AccountManage) + app.Get("/account/totp", controllers.AccountTotp) + app.Post("/account/totp", controllers.AccountTotp) + // Admin: Sections app.Get("/admin/sections", controllers.Sections) app.Get("/admin/sections/:id", controllers.SectionShow) diff --git a/views/account_manage.html b/views/account_manage.html new file mode 100644 index 0000000..14e1f29 --- /dev/null +++ b/views/account_manage.html @@ -0,0 +1,109 @@ +{% extends "layouts/main.html" %} + +{% block main %} +
+
+ +
+
+ + {% if Errors %} +
+
    + {% for Error in Errors %} +
  • {{ Error }}
  • + {% endfor %} +
+
+ {% endif %} + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ Laisser vide pour ne pas changer +
+
+ +
+ + +
+ +
+ +
+
+ +
+{% endblock %} + +{% block javascript %} + +{% endblock %} \ No newline at end of file diff --git a/views/account_totp.html b/views/account_totp.html new file mode 100644 index 0000000..1ec8dc0 --- /dev/null +++ b/views/account_totp.html @@ -0,0 +1,43 @@ +{% extends "layouts/main.html" %} + +{% block main %} +
+
+ +
+
+ +
+ +
+ + +
+ Si la case est cochée, vous devrez effectuer + un nouvel enrollement TOTP. +
+
+ +
+ +
+
+ +
+{% endblock %}