whatapp-go-pvnet/backend/renders/renders.go

497 lines
14 KiB
Go
Raw Normal View History

2025-05-09 08:14:22 +00:00
package renders
import (
"cangui/whatsapp/backend/models"
"net/http"
"strconv"
"text/template"
"time"
2025-05-09 15:28:15 +00:00
"github.com/google/uuid"
2025-05-09 08:14:22 +00:00
"github.com/gorilla/mux"
2025-05-09 15:28:15 +00:00
"golang.org/x/crypto/bcrypt"
2025-05-09 08:14:22 +00:00
"gorm.io/gorm"
)
2025-05-11 16:27:41 +00:00
// les renders permette d afficher les pages html.
2025-05-09 08:14:22 +00:00
2025-05-09 17:04:21 +00:00
func Login(w http.ResponseWriter, r *http.Request){
renderTemplate(w,"login",nil)
2025-05-09 08:14:22 +00:00
}
2025-05-09 17:04:21 +00:00
func JwtTest(w http.ResponseWriter, r *http.Request){
renderTemplate(w,"jwt",nil)
2025-05-09 08:14:22 +00:00
}
2025-05-09 17:04:21 +00:00
func TestMessagesPages(w http.ResponseWriter, r *http.Request){
renderTemplate(w,"test-send",nil)
2025-05-09 09:27:52 +00:00
}
2025-05-09 17:04:21 +00:00
func TestMessagesPages2(w http.ResponseWriter, r *http.Request){
renderTemplate(w,"test",nil)
2025-05-09 08:14:22 +00:00
}
2025-05-11 07:46:08 +00:00
func ApiDocPage(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{}
if val := r.Context().Value("ssoid"); val != nil {
var user models.User
if err := db.Where("sso_id = ?", val.(string)).First(&user).Error; err == nil {
data["User"] = user
}
}
renderTemplate(w, "apidoc", data)
}
}
2025-05-09 15:09:51 +00:00
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,
}
2025-05-11 06:32:43 +00:00
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
}
}
}
2025-05-09 15:09:51 +00:00
2025-05-09 17:04:21 +00:00
renderTemplate(w, "admin_users", data)
2025-05-09 15:09:51 +00:00
}
}
2025-05-09 08:14:22 +00:00
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{}{
2025-05-11 07:06:49 +00:00
"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
}
}
2025-05-09 08:14:22 +00:00
}
2025-05-11 06:55:54 +00:00
2025-05-11 06:32:43 +00:00
renderTemplate(w, "admin_user_edit", data)
2025-05-09 08:14:22 +00:00
}
}
2025-05-09 15:34:32 +00:00
func CreateUserHandler(db *gorm.DB) http.HandlerFunc {
2025-05-09 08:14:22 +00:00
return func(w http.ResponseWriter, r *http.Request) {
2025-05-09 15:28:15 +00:00
if err := r.ParseForm(); err != nil {
http.Error(w, "Formulaire invalide", http.StatusBadRequest)
return
}
email := r.FormValue("email")
password := r.FormValue("password")
2025-05-09 15:34:32 +00:00
role := r.FormValue("role")
monthlyCreditsStr := r.FormValue("monthly_credits")
waToken := r.FormValue("whatsapp_token")
waPhoneID := r.FormValue("whatsapp_phone_number_id")
2025-05-09 15:28:15 +00:00
2025-05-09 15:34:32 +00:00
if email == "" || password == "" {
http.Error(w, "Email et mot de passe requis", http.StatusBadRequest)
return
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
2025-05-09 15:28:15 +00:00
if err != nil {
2025-05-09 15:34:32 +00:00
http.Error(w, "Erreur hash mot de passe", http.StatusInternalServerError)
2025-05-09 15:28:15 +00:00
return
}
2025-05-09 15:34:32 +00:00
monthlyCredits := uint(100)
if monthlyCreditsStr != "" {
if val, err := strconv.Atoi(monthlyCreditsStr); err == nil {
monthlyCredits = uint(val)
}
2025-05-09 15:28:15 +00:00
}
2025-05-09 15:34:32 +00:00
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)
2025-05-09 15:28:15 +00:00
return
}
2025-05-09 15:34:32 +00:00
w.Header().Set("HX-Trigger", "userCreated")
w.WriteHeader(http.StatusOK)
w.Write([]byte("<article class='message is-success'><div class='message-body'>Utilisateur créé avec succès.</div></article>"))
2025-05-09 15:28:15 +00:00
}
}
2025-05-11 06:41:14 +00:00
func AdminUserCreateForm(db *gorm.DB) http.HandlerFunc {
2025-05-09 15:28:15 +00:00
return func(w http.ResponseWriter, r *http.Request) {
2025-05-11 06:41:14 +00:00
data := map[string]interface{}{
2025-05-11 07:15:14 +00:00
"H": "",
2025-05-11 06:41:14 +00:00
}
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 {
2025-05-11 07:03:57 +00:00
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
}
2025-05-11 06:41:14 +00:00
}
}
renderTemplate(w, "admin_user_create", data)
2025-05-09 15:28:15 +00:00
}
}
2025-05-09 17:04:21 +00:00
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})
}
}
2025-05-09 15:28:15 +00:00
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
}
2025-05-09 08:14:22 +00:00
data := map[string]interface{}{
2025-05-09 15:28:15 +00:00
"User": user,
2025-05-09 08:14:22 +00:00
}
2025-05-11 06:32:43 +00:00
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
}
}
}
2025-05-09 15:28:15 +00:00
2025-05-11 06:32:43 +00:00
renderTemplate(w, "admin_user_edit", data)
2025-05-09 08:14:22 +00:00
}
}
2025-05-09 15:28:15 +00:00
func AdminUserUpdate(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
2025-05-09 15:50:18 +00:00
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)
2025-05-09 15:28:15 +00:00
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "Formulaire invalide", http.StatusBadRequest)
return
}
2025-05-09 15:50:18 +00:00
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)
}
2025-05-09 15:28:15 +00:00
}
2025-05-09 15:50:18 +00:00
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)
}
2025-05-09 15:28:15 +00:00
if err := db.Save(&user).Error; err != nil {
2025-05-09 15:50:18 +00:00
http.Error(w, "Erreur lors de la mise à jour", http.StatusInternalServerError)
2025-05-09 15:28:15 +00:00
return
}
2025-05-09 15:50:18 +00:00
w.Header().Set("HX-Trigger", "userUpdated")
w.WriteHeader(http.StatusOK)
w.Write([]byte("<article class='message is-success'><div class='message-body'>Utilisateur mis à jour avec succès.</div></article>"))
2025-05-09 15:28:15 +00:00
}
}
2025-05-09 08:14:22 +00:00
func AdminConversationPage(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
idStr := mux.Vars(r)["id"]
2025-05-09 19:51:38 +00:00
2025-05-09 08:14:22 +00:00
data := map[string]interface{}{
"UserID": idStr,
}
2025-05-11 07:36:01 +00:00
var currentUser models.User
if val := r.Context().Value("ssoid"); val != nil {
ssoid := val.(string)
if err := db.Where("sso_id = ?", ssoid).First(&currentUser).Error; err == nil {
data["User"] = currentUser
2025-05-09 19:51:38 +00:00
}
}
2025-05-11 07:36:01 +00:00
// 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
}
2025-05-09 17:04:21 +00:00
renderTemplate(w, "adminconversations", data)
2025-05-09 08:14:22 +00:00
}
}
2025-05-11 07:36:01 +00:00
2025-05-09 08:14:22 +00:00
func AdminConversationRows(db *gorm.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
2025-05-09 16:12:29 +00:00
// 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(&currentUser).Error; err != nil {
http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized)
return
}
// 3. Récupération des filtres
2025-05-09 08:14:22 +00:00
idStr := mux.Vars(r)["id"]
id, _ := strconv.Atoi(idStr)
typeFilter := r.URL.Query().Get("type")
2025-05-09 16:12:29 +00:00
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{}
}
2025-05-09 08:14:22 +00:00
var convs []models.Conversation
2025-05-09 16:12:29 +00:00
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)
}
2025-05-09 08:14:22 +00:00
if typeFilter != "" {
query = query.Where("type = ?", typeFilter)
}
2025-05-09 16:12:29 +00:00
2025-05-09 08:14:22 +00:00
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
2025-05-11 09:18:01 +00:00
query := db.Order("created_at asc")
if id != 0 {
query = query.Where("user_id = ?", id)
}
if err := query.Find(&convs).Error; err != nil {
http.Error(w, "Erreur lors du chargement des conversations", http.StatusInternalServerError)
return
}
2025-05-09 08:14:22 +00:00
data := map[string]interface{}{
"Conversations": convs,
"UserID": idStr,
}
renderPartial(w, "admin_conversations_thread", data)
}
}
2025-05-11 09:18:01 +00:00
2025-05-09 08:14:22 +00:00
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,
}
2025-05-09 17:04:21 +00:00
renderTemplate(w, "dashboard", data)
2025-05-09 08:14:22 +00:00
}
}
2025-05-11 16:27:41 +00:00
// pour un rendu complet de la page
2025-05-09 17:04:21 +00:00
func renderTemplate(w http.ResponseWriter, templ string, data map[string]interface{}) {
t, err := template.ParseFiles(
2025-05-09 14:57:13 +00:00
"./frontend/templates/head.pages.tmpl",
"./frontend/templates/sidebar.pages.tmpl",
"./frontend/templates/" + templ + ".pages.tmpl",
2025-05-09 17:04:21 +00:00
)
2025-05-09 08:14:22 +00:00
2025-05-09 17:04:21 +00:00
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)
2025-05-09 08:14:22 +00:00
2025-05-09 17:04:21 +00:00
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
2025-05-11 16:27:41 +00:00
// pour un rendu de composent.
2025-05-09 08:14:22 +00:00
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)
}
}