kekkek
This commit is contained in:
parent
2aa1739b3f
commit
13151f6fe5
@ -423,3 +423,59 @@ func DeleteUser(db *gorm.DB) http.HandlerFunc {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,25 @@ type MonthlyConsumption struct {
|
||||
Month string `gorm:"type:char(7);index;not null"` // Format YYYY-MM
|
||||
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 {
|
||||
MessagingProduct string `json:"messaging_product"` // always "whatsapp"
|
||||
@ -76,6 +95,7 @@ type WhatsappMessage struct {
|
||||
Contacts []Contact `json:"contacts,omitempty"`
|
||||
Interactive *Interactive `json:"interactive,omitempty"`
|
||||
Reaction *Reaction `json:"reaction,omitempty"`
|
||||
Template *Template `json:"template,omitempty"` // ✅ Ajoute ce champ
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
@ -376,3 +396,45 @@ func BuildMessageFromPayload(payload map[string]interface{}) (interface{}, error
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ func RoutesProtected(r *mux.Router, db *gorm.DB) {
|
||||
r.HandleFunc("/admin/user/new", renders.AdminUserCreate()).Methods("GET")
|
||||
r.HandleFunc("/dashboard", renders.Dashboard(db))
|
||||
r.HandleFunc("/test/send", renders.TestMessagesPages)
|
||||
r.HandleFunc("/api/message/send", handlers.HandleTemplateTest(db)).Methods("POST")
|
||||
|
||||
|
||||
|
||||
|
||||
52
frontend/templates/test-send.pages.tmpl
Normal file
52
frontend/templates/test-send.pages.tmpl
Normal 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 }}
|
||||
Loading…
Reference in New Issue
Block a user