(ctx context.Context, in *updateWebhookInput)
| 380 | } |
| 381 | |
| 382 | func (s *Server) handleUpdateWebhook(ctx context.Context, in *updateWebhookInput) (*webhookOutput, error) { |
| 383 | user, err := s.requireAccountUser(ctx) |
| 384 | if err != nil { |
| 385 | return nil, err |
| 386 | } |
| 387 | req := in.Body |
| 388 | // A webhook with no events or no URL is a broken state — reject the |
| 389 | // clearing patch (DELETE the webhook to remove it). |
| 390 | if req.Events != nil && len(*req.Events) == 0 { |
| 391 | return nil, NewError(http.StatusBadRequest, "invalid_request", "events must not be empty (DELETE the webhook to remove it)") |
| 392 | } |
| 393 | if req.URL != nil && *req.URL == "" { |
| 394 | return nil, NewError(http.StatusBadRequest, "invalid_request", "url must not be empty") |
| 395 | } |
| 396 | // Validate the effective post-patch state against the create-time rules. |
| 397 | current, err := s.deps.GetWebhook(ctx, in.ID, user.ID) |
| 398 | if err != nil || current == nil { |
| 399 | return nil, NewError(http.StatusNotFound, "not_found", "webhook not found") |
| 400 | } |
| 401 | effURL := current.URL |
| 402 | if req.URL != nil { |
| 403 | effURL = *req.URL |
| 404 | } |
| 405 | effEvents := current.Events |
| 406 | if req.Events != nil { |
| 407 | effEvents = *req.Events |
| 408 | } |
| 409 | effFilters := WebhookFiltersView{AgentIDs: current.Filters.AgentIDs, ConversationIDs: current.Filters.ConversationIDs, Labels: current.Filters.Labels} |
| 410 | if req.Filters != nil { |
| 411 | effFilters = *req.Filters |
| 412 | } |
| 413 | effDesc := current.Description |
| 414 | if req.Description != nil { |
| 415 | effDesc = *req.Description |
| 416 | } |
| 417 | if env := s.validateWebhookFields(ctx, user.ID, effURL, effEvents, effFilters, effDesc); env != nil { |
| 418 | return nil, env |
| 419 | } |
| 420 | var idFilters *identity.WebhookFilters |
| 421 | if req.Filters != nil { |
| 422 | idFilters = &identity.WebhookFilters{AgentIDs: req.Filters.AgentIDs, ConversationIDs: req.Filters.ConversationIDs, Labels: req.Filters.Labels} |
| 423 | } |
| 424 | wh, err := s.deps.UpdateWebhook(ctx, in.ID, user.ID, identity.WebhookUpdate{ |
| 425 | URL: req.URL, Events: req.Events, Filters: idFilters, Description: req.Description, Enabled: req.Enabled, |
| 426 | }) |
| 427 | if err != nil { |
| 428 | switch { |
| 429 | case errors.Is(err, identity.ErrWebhookNotFound): |
| 430 | return nil, NewError(http.StatusNotFound, "not_found", "webhook not found") |
| 431 | case errors.Is(err, identity.ErrWebhookCooldown): |
| 432 | return nil, NewError(http.StatusConflict, "webhook_cooldown", err.Error()) |
| 433 | default: |
| 434 | return nil, NewError(http.StatusInternalServerError, "internal_error", "failed to update webhook") |
| 435 | } |
| 436 | } |
| 437 | return &webhookOutput{Body: webhookView(wh)}, nil |
| 438 | } |
| 439 |
nothing calls this directly
no test coverage detected