diff --git a/backend/handlers/main.go b/backend/handlers/main.go index 4bfe5f8..727529d 100644 --- a/backend/handlers/main.go +++ b/backend/handlers/main.go @@ -534,5 +534,25 @@ func HandleTemplateTest(db *gorm.DB) http.HandlerFunc { json.NewEncoder(w).Encode(respBody) } } +func AdminUserDelete(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := mux.Vars(r)["id"] + + var user models.User + if err := db.First(&user, id).Error; err != nil { + http.Error(w, "Utilisateur introuvable", http.StatusNotFound) + return + } + + if err := db.Delete(&user).Error; err != nil { + http.Error(w, "Erreur suppression", http.StatusInternalServerError) + return + } + + // On retourne du HTML vide car on swap "outerHTML" + w.WriteHeader(http.StatusOK) + w.Write([]byte("")) + } +} diff --git a/backend/renders/renders.go b/backend/renders/renders.go index f05b35a..be5d2c8 100644 --- a/backend/renders/renders.go +++ b/backend/renders/renders.go @@ -6,8 +6,9 @@ import ( "strconv" "text/template" "time" - + "github.com/google/uuid" "github.com/gorilla/mux" + "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) @@ -55,14 +56,107 @@ func AdminUserEdit(db *gorm.DB) http.HandlerFunc { renderPartial(w, "admin_user_edit", data) } } -func AdminUserCreate() http.HandlerFunc { +func AdminUserCreate(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - data := map[string]interface{}{ - "User": models.User{}, + if err := r.ParseForm(); err != nil { + http.Error(w, "Formulaire invalide", http.StatusBadRequest) + return } + + email := r.FormValue("email") + password := r.FormValue("password") + role := models.UserRole(r.FormValue("role")) + + hashed, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + if err != nil { + http.Error(w, "Erreur hash", http.StatusInternalServerError) + return + } + + ssoid := "sso_" + uuid.New().String() + user := models.User{ + Email: email, + Password: string(hashed), + Role: role, + IsActive: true, + SSOID: ssoid, + } + + if err := db.Create(&user).Error; err != nil { + http.Error(w, "Erreur enregistrement", http.StatusInternalServerError) + return + } + + w.Header().Set("HX-Trigger", `{"userCreated":"Utilisateur créé avec succès"}`) + w.Header().Set("HX-Remove", "true") // cache le form + renderPartial(w, "admin_user_row", map[string]interface{}{"User": user}) + } +} + +func AdminUserCreateForm() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + renderPartial(w, "admin_user_create", nil) + } +} + +func AdminUserEditForm(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := mux.Vars(r)["id"] + + var user models.User + if err := db.First(&user, id).Error; err != nil { + http.Error(w, "Utilisateur introuvable", http.StatusNotFound) + return + } + + data := map[string]interface{}{ + "User": user, + } + renderPartial(w, "admin_user_edit", data) } } +func AdminUserUpdate(db *gorm.DB) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + idStr := mux.Vars(r)["id"] + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "ID invalide", http.StatusBadRequest) + return + } + + if err := r.ParseForm(); err != nil { + http.Error(w, "Formulaire invalide", http.StatusBadRequest) + return + } + + var user models.User + if err := db.First(&user, id).Error; err != nil { + http.Error(w, "Utilisateur introuvable", http.StatusNotFound) + return + } + + // Mise à jour des champs + user.Email = r.FormValue("email") + user.Role = models.UserRole(r.FormValue("role")) + user.IsActive = r.FormValue("is_active") == "on" + + if err := db.Save(&user).Error; err != nil { + http.Error(w, "Erreur mise à jour", http.StatusInternalServerError) + return + } + + // Réafficher la ligne utilisateur mise à jour + data := map[string]interface{}{ + "User": user, + } + renderPartial(w, "admin_user_row", data) + } +} + + + + func AdminConversationPage(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { idStr := mux.Vars(r)["id"] diff --git a/backend/routes/routes.go b/backend/routes/routes.go index 016adc6..860ae17 100644 --- a/backend/routes/routes.go +++ b/backend/routes/routes.go @@ -35,8 +35,11 @@ func RoutesProtected(r *mux.Router, db *gorm.DB) { r.HandleFunc("/admin/user/{id}/conversations", renders.AdminConversationPage(db)) r.HandleFunc("/api/user/{id}/conversations", renders.AdminConversationRows(db)) r.HandleFunc("/admin/user/{id}/edit", renders.AdminUserEdit(db)).Methods("GET") - r.HandleFunc("/admin/user/new", renders.AdminUserCreate()).Methods("GET") r.HandleFunc("/admin/user", renders.AdminUserList(db)) + r.HandleFunc("/api/user/delete/{id}", handlers.AdminUserDelete(db)).Methods("DELETE") + r.HandleFunc("/api/user/update/{id}", renders.AdminUserUpdate(db)).Methods("POST") + r.HandleFunc("/api/user/create", renders.AdminUserCreate(db)).Methods("POST") + r.HandleFunc("/admin/user/create-form", renders.AdminUserCreateForm()).Methods("GET") r.HandleFunc("/dashboard", renders.Dashboard(db)) r.HandleFunc("/test/send", renders.TestMessagesPages) diff --git a/frontend/templates/admin_user_create.pages.tmpl b/frontend/templates/admin_user_create.pages.tmpl new file mode 100644 index 0000000..e338488 --- /dev/null +++ b/frontend/templates/admin_user_create.pages.tmpl @@ -0,0 +1,40 @@ +{{ define "admin_user_create.pages.tmpl" }} +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+{{ end }} diff --git a/frontend/templates/admin_user_edit.pages.tmpl b/frontend/templates/admin_user_edit.pages.tmpl index a04bede..c974d32 100644 --- a/frontend/templates/admin_user_edit.pages.tmpl +++ b/frontend/templates/admin_user_edit.pages.tmpl @@ -46,7 +46,7 @@
- +
diff --git a/frontend/templates/admin_users.pages.tmpl b/frontend/templates/admin_users.pages.tmpl index 698a71f..5ac9773 100644 --- a/frontend/templates/admin_users.pages.tmpl +++ b/frontend/templates/admin_users.pages.tmpl @@ -1,13 +1,25 @@ {{ define "admin_users.pages.tmpl" }} -

Gestion des utilisateurs

{{ template "head" . }} - +

Gestion des utilisateurs

+ + +
+ + +
+ +
+ + +
+ + @@ -26,14 +38,40 @@ {{ end }}
{{ .Role }} {{ if .IsActive }}✅{{ else }}❌{{ end }} - - + +
+
+ + + {{ end }} diff --git a/frontend/templates/sidebar.pages.tmpl b/frontend/templates/sidebar.pages.tmpl index 1f13b08..85d9bd6 100644 --- a/frontend/templates/sidebar.pages.tmpl +++ b/frontend/templates/sidebar.pages.tmpl @@ -5,7 +5,7 @@
  • 🏠 Dashboard
  • {{ if eq .User.Role "ADMIN" }} -
  • 👤 Utilisateurs
  • +
  • 👤 Utilisateurs
  • 📤 Test envoi
  • 📤 Test envoi template
  • diff --git a/go.mod b/go.mod index 9aa9f7b..269ab46 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( require ( github.com/golang-jwt/jwt/v5 v5.2.2 + github.com/google/uuid v1.6.0 github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/stretchr/testify v1.10.0 diff --git a/go.sum b/go.sum index d83d72d..6ea6f23 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=