Manage user account

This commit is contained in:
William Bouzourène 2025-01-05 14:44:05 +01:00
parent e2d2697907
commit ee9a453f63
Signed by: bouzoure
SSH key fingerprint: SHA256:19MbXpLua4rUtk8tunMesD8KUKb91LXLHg8E/qTooww
4 changed files with 297 additions and 0 deletions

139
controllers/account.go Normal file
View file

@ -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,
})
}

View file

@ -115,6 +115,12 @@ func main() {
app.Get("/totp/verify", controllers.TotpVerifyPage) app.Get("/totp/verify", controllers.TotpVerifyPage)
app.Post("/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 // Admin: Sections
app.Get("/admin/sections", controllers.Sections) app.Get("/admin/sections", controllers.Sections)
app.Get("/admin/sections/:id<int;min(0)>", controllers.SectionShow) app.Get("/admin/sections/:id<int;min(0)>", controllers.SectionShow)

109
views/account_manage.html Normal file
View file

@ -0,0 +1,109 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Accueil</a></li>
<li class="breadcrumb-item active">Gérer mon compte utilisateur</li>
</ol>
</nav>
<hr>
</div>
{% if Errors %}
<div class="alert alert-danger">
<ul class="m-0">
{% for Error in Errors %}
<li>{{ Error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<form id="user" method="post">
<div class="mb-3">
<label for="name" class="form-label">
Nom complet
</label>
<input
id="name"
class="form-control"
type="text"
name="name"
required
value="{{ User.Name }}"
>
</div>
<div class="mb-3">
<label for="email" class="form-label">
Email
</label>
<input
id="email"
class="form-control"
type="email"
name="email"
required
value="{{ User.Email }}"
>
</div>
<div class="mb-3">
<label for="password" class="form-label">
Mot de passe
</label>
<input
id="password"
class="form-control"
type="password"
name="password"
>
<div class="form-text">
Laisser vide pour ne pas changer
</div>
</div>
<div class="mb-3">
<label for="password" class="form-label">
Confirmer le mot de passe
</label>
<input
id="password-verify"
class="form-control"
type="password"
name="password-verify"
>
</div>
<div class="mt-4">
<button class="btn btn-primary" type="submit">
<i class="me-1 bi-floppy"></i>
Enregistrer
</button>
</div>
</form>
</div>
{% endblock %}
{% block javascript %}
<script>
$(document).ready(function() {
$("#password").on("input", function() {
var enable = false;
if ($(this).val().length > 0) {
enable = true;
}
$("#password-verify").prop("disabled", !enable);
$("#password-verify").prop("required", enable);
});
$("#password").trigger("input");
});
</script>
{% endblock %}

43
views/account_totp.html Normal file
View file

@ -0,0 +1,43 @@
{% extends "layouts/main.html" %}
{% block main %}
<div class="container mt-4">
<div class="mb-4">
<nav>
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Accueil</a></li>
<li class="breadcrumb-item active">Gérer multifacteur (TOTP)</li>
</ol>
</nav>
<hr>
</div>
<form id="user" method="post">
<div class="mb-3">
<input
type="checkbox"
class="form-check-input me-2"
id="reset_totp"
name="reset_totp"
required
>
<label for="reset_totp" class="form-label">
Réinitialiser le double facteur (TOTP)
</label>
<div class="form-text">
Si la case est cochée, vous devrez effectuer
un nouvel enrollement TOTP.
</div>
</div>
<div class="mt-4">
<button class="btn btn-primary" type="submit">
<i class="me-1 bi-floppy"></i>
Enregistrer
</button>
</div>
</form>
</div>
{% endblock %}