package renders import ( "cangui/whatsapp/backend/models" "net/http" "strconv" "text/template" "time" "github.com/google/uuid" "github.com/gorilla/mux" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) func Login(w http.ResponseWriter, r *http.Request){ renderTemplate(w,"login",nil) } func JwtTest(w http.ResponseWriter, r *http.Request){ renderTemplate(w,"jwt",nil) } func TestMessagesPages(w http.ResponseWriter, r *http.Request){ renderTemplate(w,"test-send",nil) } func TestMessagesPages2(w http.ResponseWriter, r *http.Request){ renderTemplate(w,"test",nil) } func AdminUserList(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var users []models.User if err := db.Find(&users).Error; err != nil { http.Error(w, "Erreur lors du chargement des utilisateurs", http.StatusInternalServerError) return } data := map[string]interface{}{ "Users": users, } if _, exists := data["User"]; !exists { if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err == nil { data["User"] = user } } } renderTemplate(w, "admin_users", data) } } func AdminUserEdit(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id, _ := strconv.Atoi(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{}{ "U": user, } if _, exists := data["User"]; !exists { if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err == nil { data["User"] = user } } } renderTemplate(w, "admin_user_edit", data) } } func CreateUserHandler(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { http.Error(w, "Formulaire invalide", http.StatusBadRequest) return } email := r.FormValue("email") password := r.FormValue("password") role := r.FormValue("role") monthlyCreditsStr := r.FormValue("monthly_credits") waToken := r.FormValue("whatsapp_token") waPhoneID := r.FormValue("whatsapp_phone_number_id") if email == "" || password == "" { http.Error(w, "Email et mot de passe requis", http.StatusBadRequest) return } hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { http.Error(w, "Erreur hash mot de passe", http.StatusInternalServerError) return } monthlyCredits := uint(100) if monthlyCreditsStr != "" { if val, err := strconv.Atoi(monthlyCreditsStr); err == nil { monthlyCredits = uint(val) } } newUser := models.User{ Email: email, Password: string(hashedPassword), Role: models.UserRole(role), SSOID: uuid.New().String(), IsActive: true, MonthlyCredits: monthlyCredits, CurrentMonthCredits: monthlyCredits, WhatsappToken: waToken, WhatsappPhoneNumberID: waPhoneID, } if err := db.Create(&newUser).Error; err != nil { http.Error(w, "Erreur lors de la création", http.StatusInternalServerError) return } w.Header().Set("HX-Trigger", "userCreated") w.WriteHeader(http.StatusOK) w.Write([]byte("
Utilisateur créé avec succès.
")) } } func AdminUserCreateForm(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{ "H": "", } if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err == nil { data["U"] = user } } if _, exists := data["User"]; !exists { if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err == nil { data["User"] = user } } } renderTemplate(w, "admin_user_create", data) } } func AdminUserCreate(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { 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 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, } if _, exists := data["User"]; !exists { if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err == nil { data["User"] = user } } } renderTemplate(w, "admin_user_edit", data) } } func AdminUserUpdate(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 := r.ParseForm(); err != nil { http.Error(w, "Formulaire invalide", http.StatusBadRequest) return } email := r.FormValue("email") password := r.FormValue("password") role := r.FormValue("role") isActive := r.FormValue("is_active") == "on" waToken := r.FormValue("whatsapp_token") waPhoneID := r.FormValue("whatsapp_phone_number_id") monthlyCreditsStr := r.FormValue("monthly_credits") user.Email = email user.Role = models.UserRole(role) user.IsActive = isActive user.WhatsappToken = waToken user.WhatsappPhoneNumberID = waPhoneID if monthlyCreditsStr != "" { if val, err := strconv.Atoi(monthlyCreditsStr); err == nil { user.MonthlyCredits = uint(val) } } if password != "" { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) if err != nil { http.Error(w, "Erreur de hachage du mot de passe", http.StatusInternalServerError) return } user.Password = string(hash) } if err := db.Save(&user).Error; err != nil { http.Error(w, "Erreur lors de la mise à jour", http.StatusInternalServerError) return } w.Header().Set("HX-Trigger", "userUpdated") w.WriteHeader(http.StatusOK) w.Write([]byte("
Utilisateur mis à jour avec succès.
")) } } func AdminConversationPage(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { idStr := mux.Vars(r)["id"] data := map[string]interface{}{ "UserID": idStr, } var currentUser models.User if val := r.Context().Value("ssoid"); val != nil { ssoid := val.(string) if err := db.Where("sso_id = ?", ssoid).First(¤tUser).Error; err == nil { data["User"] = currentUser } } // Si ADMIN → récupérer tous les utilisateurs qui ont des conversations if currentUser.Role == models.ROLE_ADMIN { var clients []models.User db.Raw(` SELECT DISTINCT users.* FROM users JOIN conversations ON users.id = conversations.user_id ORDER BY users.email `).Scan(&clients) data["Clients"] = clients } renderTemplate(w, "adminconversations", data) } } func AdminConversationRows(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // 1. Récupérer SSOID depuis le contexte val := r.Context().Value("ssoid") ssoid, ok := val.(string) if !ok || ssoid == "" { http.Error(w, "Non authentifié", http.StatusUnauthorized) return } // 2. Trouver l'utilisateur var currentUser models.User if err := db.Where("sso_id = ?", ssoid).First(¤tUser).Error; err != nil { http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized) return } // 3. Récupération des filtres idStr := mux.Vars(r)["id"] id, _ := strconv.Atoi(idStr) typeFilter := r.URL.Query().Get("type") dateFilter := r.URL.Query().Get("filter") var fromDate time.Time now := time.Now() switch dateFilter { case "today": fromDate = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) case "week": fromDate = now.AddDate(0, 0, -7) default: fromDate = time.Time{} } var convs []models.Conversation query := db.Model(&models.Conversation{}) // 4. ADMIN → tout ou par utilisateur ciblé if currentUser.Role != models.ROLE_ADMIN { query = query.Where("user_id = ?", currentUser.ID) } else if id > 0 { query = query.Where("user_id = ?", id) } if !fromDate.IsZero() { query = query.Where("created_at >= ?", fromDate) } if typeFilter != "" { query = query.Where("type = ?", typeFilter) } query.Order("created_at desc").Find(&convs) data := map[string]interface{}{ "Conversations": convs, "UserID": idStr, } renderPartial(w, "admin_conversations_rows", data) } } func AdminConversationThread(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { idStr := mux.Vars(r)["id"] id, _ := strconv.Atoi(idStr) var convs []models.Conversation db.Where("user_id = ?", id).Order("created_at asc").Find(&convs) data := map[string]interface{}{ "Conversations": convs, "UserID": idStr, } renderPartial(w, "admin_conversations_thread", data) } } func Dashboard(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { val := r.Context().Value("ssoid") ssoid, ok := val.(string) if !ok || ssoid == "" { http.Error(w, "Utilisateur non authentifié", http.StatusUnauthorized) return } var user models.User if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err != nil { http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized) return } filter := r.URL.Query().Get("filter") var fromDate time.Time now := time.Now() switch filter { case "today": fromDate = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) case "week": fromDate = now.AddDate(0, 0, -7) default: fromDate = time.Time{} // zero time: no filter } var totalUsers int64 var totalCredits uint var totalConversations int64 var conversations []models.Conversation if user.Role == models.ROLE_ADMIN { db.Model(&models.User{}).Count(&totalUsers) db.Model(&models.Consumption{}).Select("SUM(credits_used)").Scan(&totalCredits) db.Model(&models.Conversation{}).Where("created_at >= ?", fromDate).Count(&totalConversations) db.Where("created_at >= ?", fromDate).Order("created_at desc").Limit(10).Find(&conversations) } else { db.Model(&models.User{}).Where("id = ?", user.ID).Count(&totalUsers) db.Model(&models.Consumption{}).Where("user_id = ?", user.ID).Select("SUM(credits_used)").Scan(&totalCredits) db.Model(&models.Conversation{}).Where("user_id = ? AND created_at >= ?", user.ID, fromDate).Count(&totalConversations) db.Where("user_id = ? AND created_at >= ?", user.ID, fromDate).Order("created_at desc").Limit(10).Find(&conversations) } data := map[string]interface{}{ "User": user, "Stats": map[string]interface{}{ "TotalUsers": totalUsers, "TotalCreditsUsed": totalCredits, "TotalConversations": totalConversations, }, "Conversations": conversations, } renderTemplate(w, "dashboard", data) } } func renderTemplate(w http.ResponseWriter, templ string, data map[string]interface{}) { t, err := template.ParseFiles( "./frontend/templates/head.pages.tmpl", "./frontend/templates/sidebar.pages.tmpl", "./frontend/templates/" + templ + ".pages.tmpl", ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } // Exécutez explicitement le template principal err = t.ExecuteTemplate(w, templ+".pages.tmpl", data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func renderPartial(w http.ResponseWriter, templ string, data map[string]interface{}) { t, err := template.ParseFiles("./frontend/templates/" + templ + ".pages.tmpl") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } err = t.Execute(w, data) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }