package service import ( "bytes" "context" "encoding/json" "net/http" "time" "github.com/calendarapi/internal/models" "github.com/calendarapi/internal/repository" "github.com/calendarapi/internal/utils" "github.com/google/uuid" ) type TaskWebhookService struct { queries *repository.Queries } func NewTaskWebhookService(queries *repository.Queries) *TaskWebhookService { return &TaskWebhookService{queries: queries} } func (s *TaskWebhookService) Deliver(ctx context.Context, ownerID uuid.UUID, event string, task *models.Task) { webhooks, err := s.queries.ListTaskWebhooksByOwner(ctx, utils.ToPgUUID(ownerID)) if err != nil { return } payload := map[string]interface{}{ "event": event, "task": task, "timestamp": time.Now().UTC().Format(time.RFC3339), } body, _ := json.Marshal(payload) for _, wh := range webhooks { if !s.webhookSubscribedTo(wh.Events, event) { continue } secret := "" if wh.Secret.Valid { secret = wh.Secret.String } go s.postWebhook(wh.Url, body, []byte(secret)) } } func (s *TaskWebhookService) webhookSubscribedTo(eventsJSON []byte, event string) bool { var events []string if err := json.Unmarshal(eventsJSON, &events); err != nil { return false } for _, e := range events { if e == event { return true } } return false } func (s *TaskWebhookService) postWebhook(url string, body []byte, secret []byte) { req, err := http.NewRequest("POST", url, bytes.NewReader(body)) if err != nil { return } req.Header.Set("Content-Type", "application/json") if len(secret) > 0 { req.Header.Set("X-Webhook-Signature", string(secret)) } client := &http.Client{Timeout: 10 * time.Second} _, _ = client.Do(req) }