ultisuite-backend/internal/api/mail/service_webhooks.go
R3D347HR4Y 1b9a3394e2 Implement rule simulation and webhook enhancements
- Added a new endpoint for simulating rules based on sample messages, allowing users to test rule conditions and actions.
- Enhanced webhook management with versioning, preview capabilities, and improved validation for webhook requests.
- Updated service interfaces to support new functionalities, including max retries for webhooks and signing secrets.
- Implemented observability metrics for webhook retries and dead-letter tracking, improving error handling and monitoring.
- Enhanced unit tests to cover new simulation and webhook features, ensuring robust functionality and validation.
2026-05-22 17:53:51 +02:00

71 lines
1.9 KiB
Go

package mail
import (
"context"
"encoding/json"
"errors"
"github.com/jackc/pgx/v5"
"github.com/ultisuite/ulti-backend/internal/mail/webhooks"
)
func (s *Service) UpdateWebhook(ctx context.Context, externalID, webhookID string, req *updateWebhookRequest, method string, maxRetries int) error {
headersJSON, _ := json.Marshal(req.Headers)
tx, err := s.db.Begin(ctx)
if err != nil {
return err
}
defer tx.Rollback(ctx)
var version int
err = tx.QueryRow(ctx, `
UPDATE webhook_templates
SET
name = $1,
url = $2,
method = $3,
headers = $4,
body_template = $5,
signing_secret = $6,
max_retries = $7,
version = version + 1,
updated_at = NOW()
WHERE id = $8
AND user_id = (SELECT id FROM users WHERE external_id = $9)
RETURNING version
`, req.Name, req.URL, method, headersJSON, req.BodyTemplate, req.SigningSecret, maxRetries, webhookID, externalID).Scan(&version)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ErrNotFound
}
return err
}
if _, err := tx.Exec(ctx, `
INSERT INTO webhook_template_versions (template_id, version, method, headers, body_template)
VALUES ($1, $2, $3, $4, $5)
`, webhookID, version, method, headersJSON, req.BodyTemplate); err != nil {
return err
}
return tx.Commit(ctx)
}
func (s *Service) PreviewWebhookTemplate(_ context.Context, _ string, req *previewWebhookRequest) (map[string]any, error) {
msgCtx := &webhooks.MessageContext{
SenderName: req.Message.SenderName,
SenderEmail: req.Message.SenderEmail,
Subject: req.Message.Subject,
BodyText: req.Message.BodyText,
BodyHTML: req.Message.BodyHTML,
Date: req.Message.Date,
Recipients: req.Message.Recipients,
HasAttachment: req.Message.HasAttachment,
MessageID: req.Message.MessageID,
}
return map[string]any{
"payload": webhooks.RenderBodyTemplate(req.BodyTemplate, msgCtx),
}, nil
}