This commit is contained in:
cangui 2025-05-09 11:23:54 +02:00
parent 2aa1739b3f
commit 13151f6fe5
4 changed files with 172 additions and 1 deletions

View File

@ -422,4 +422,60 @@ func DeleteUser(db *gorm.DB) http.HandlerFunc {
} }
w.WriteHeader(http.StatusNoContent) w.WriteHeader(http.StatusNoContent)
} }
} }
func HandleTemplateTest(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, "Non authentifié", http.StatusUnauthorized)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, "Form invalide", http.StatusBadRequest)
return
}
to := r.FormValue("to")
templateName := r.FormValue("template_name")
lang := r.FormValue("language")
var params []string
for i := 1; i <= 5; i++ {
val := r.FormValue(fmt.Sprintf("param%d", i))
if val != "" {
params = append(params, val)
}
}
var user models.User
if err := db.Where("sso_id = ?", ssoid).First(&user).Error; err != nil || user.ID == 0 {
http.Error(w, "Utilisateur introuvable", http.StatusUnauthorized)
return
}
message := models.NewTemplateMessage(to, templateName, lang, params)
jsonBody, _ := json.MarshalIndent(message, "", " ")
apiURL := fmt.Sprintf("https://graph.facebook.com/v22.0/%s/messages", user.WhatsappPhoneNumberID)
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBody))
if err != nil {
http.Error(w, "Requête WhatsApp échouée", http.StatusInternalServerError)
return
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+user.WhatsappToken)
resp, err := http.DefaultClient.Do(req)
if err != nil {
http.Error(w, "Échec de l'appel API WhatsApp", http.StatusBadGateway)
return
}
defer resp.Body.Close()
io.Copy(w, resp.Body)
}
}

View File

@ -59,6 +59,25 @@ type MonthlyConsumption struct {
Month string `gorm:"type:char(7);index;not null"` // Format YYYY-MM Month string `gorm:"type:char(7);index;not null"` // Format YYYY-MM
TotalUsed uint `gorm:"not null"` // Crédits utilisés ce mois TotalUsed uint `gorm:"not null"` // Crédits utilisés ce mois
} }
type Template struct {
Name string `json:"name"`
Language TemplateLanguage `json:"language"`
Components []TemplateComponent `json:"components"`
}
type TemplateLanguage struct {
Code string `json:"code"`
}
type TemplateComponent struct {
Type string `json:"type"`
Parameters []TemplateParameter `json:"parameters"`
}
type TemplateParameter struct {
Type string `json:"type"`
Text string `json:"text"`
}
type WhatsappMessage struct { type WhatsappMessage struct {
MessagingProduct string `json:"messaging_product"` // always "whatsapp" MessagingProduct string `json:"messaging_product"` // always "whatsapp"
@ -76,6 +95,7 @@ type WhatsappMessage struct {
Contacts []Contact `json:"contacts,omitempty"` Contacts []Contact `json:"contacts,omitempty"`
Interactive *Interactive `json:"interactive,omitempty"` Interactive *Interactive `json:"interactive,omitempty"`
Reaction *Reaction `json:"reaction,omitempty"` Reaction *Reaction `json:"reaction,omitempty"`
Template *Template `json:"template,omitempty"` // ✅ Ajoute ce champ
} }
type Address struct { type Address struct {
@ -376,3 +396,45 @@ func BuildMessageFromPayload(payload map[string]interface{}) (interface{}, error
return nil, fmt.Errorf("failed to build message") return nil, fmt.Errorf("failed to build message")
} }
func NewTemplateMessage(to, name, lang string, params []string) WhatsappMessage {
paramList := make([]TemplateParameter, len(params))
for i, p := range params {
paramList[i] = TemplateParameter{
Type: "text",
Text: p,
}
}
return WhatsappMessage{
MessagingProduct: "whatsapp",
To: to,
Type: "template",
Template: &Template{
Name: name,
Language: TemplateLanguage{Code: lang},
Components: []TemplateComponent{
{
Type: "body",
Parameters: paramList,
},
},
},
}
}
// Enregistre une erreur de statut dans la table Conversation
func SaveMessageStatusError(db *gorm.DB, userID uint, recipient, msgID, status, errorMsg string) error {
conv := Conversation{
UserID: userID,
From: "system",
To: recipient,
MessageID: msgID,
Type: "status",
Content: errorMsg,
Direction: "outbound",
Status: status,
CreatedAt: time.Now(),
}
return db.Create(&conv).Error
}

View File

@ -38,6 +38,7 @@ func RoutesProtected(r *mux.Router, db *gorm.DB) {
r.HandleFunc("/admin/user/new", renders.AdminUserCreate()).Methods("GET") r.HandleFunc("/admin/user/new", renders.AdminUserCreate()).Methods("GET")
r.HandleFunc("/dashboard", renders.Dashboard(db)) r.HandleFunc("/dashboard", renders.Dashboard(db))
r.HandleFunc("/test/send", renders.TestMessagesPages) r.HandleFunc("/test/send", renders.TestMessagesPages)
r.HandleFunc("/api/message/send", handlers.HandleTemplateTest(db)).Methods("POST")

View File

@ -0,0 +1,52 @@
{{ define "test-send.pages.tmpl" }}
{{ template "head" . }}
<body>
<section class="section">
<div class="container">
<h1 class="title">📤 Test envoi de message WhatsApp - Template</h1>
<form hx-post="/api/message/send" hx-trigger="submit" hx-target="#template-result" hx-swap="innerHTML">
<div class="field">
<label class="label">Numéro WhatsApp</label>
<div class="control">
<input class="input" name="to" placeholder="ex: 33612345678" required>
</div>
</div>
<div class="field">
<label class="label">Nom du template</label>
<div class="control">
<input class="input" name="template_name" value="rappel_demande_info" required>
</div>
</div>
<div class="field">
<label class="label">Langue</label>
<div class="control">
<input class="input" name="language" value="fr" required>
</div>
</div>
<div class="field">
<label class="label">Paramètre 1</label>
<div class="control">
<input class="input" name="param1" value="Jean">
</div>
</div>
<div class="field">
<label class="label">Paramètre 2 (optionnel)</label>
<div class="control">
<input class="input" name="param2">
</div>
</div>
<button class="button is-link" type="submit">Envoyer le template</button>
</form>
<div id="template-result" class="mt-4"></div>
</div>
</section>
</body>
{{ end }}