fix(routes): align whatsapp call ids

This commit is contained in:
2026-06-07 13:04:27 +08:00
parent 5062acec61
commit 7ea4bf9362
7 changed files with 53 additions and 51 deletions
+7 -5
View File
@@ -49,16 +49,16 @@ Hermes task landing checklist:
## Current Baseline
- Current tracking checkpoint: 2026-06-07 P3.100 dashboard app route parameter parity, prepared as `fix(routes): align dashboard app ids`.
- Latest implementation checkpoint: this checkpoint, prepared as `fix(routes): align dashboard app ids`.
- Latest documentation/tooling checkpoint: this tracker update records exact Chatwoot `dashboard_apps/:id` route-parameter parity and regenerated route artifacts.
- Current tracking checkpoint: 2026-06-07 P3.101 WhatsApp call route parameter parity, prepared as `fix(routes): align whatsapp call ids`.
- Latest implementation checkpoint: this checkpoint, prepared as `fix(routes): align whatsapp call ids`.
- Latest documentation/tooling checkpoint: this tracker update records exact Chatwoot `whatsapp_calls/:id` account-route parameter parity, the Gin wildcard-name limit for remaining AgentCapacity nested parameter-compatible rows, and regenerated route artifacts.
- Plan landing status: complete for the current known Hermes plans and user-confirmed scope. Future work should update this file directly instead of opening a parallel tracker.
- Worktree status at this implementation checkpoint: dashboard app member routes now register the same `:id` path parameter used by Chatwoot `resources :dashboard_apps`, while the handler still accepts the legacy local `:dashboard_app_id` name for focused tests and extension routes. Route parity artifacts are regenerated and the tracked frontend-critical audit improves to 425 exact routes. This retains P3.99 conversation destroy async parity, P3.98 conversation transcript delivery parity, P3.97 conversation typing event parity, and prior checkpoints. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
- Worktree status at this implementation checkpoint: account-level WhatsApp call routes now register the same `:id` path parameter used by Chatwoot `routes.rb:237-242`, while the handler still accepts legacy local `:call_id` mounts. AgentCapacity nested handlers also accept Chatwoot `:agent_capacity_policy_id`/`:id` params if mounted in isolation, but the main Gin router keeps `/:id/...` plus `:user_id`/`:limit_id` because Gin rejects sibling wildcard-name changes below the existing policy `/:id` member route. Route parity artifacts are regenerated and the tracked frontend-critical audit improves to 430 exact routes. This retains P3.100 dashboard app route-parameter parity, P3.99 conversation destroy async parity, P3.98 conversation transcript delivery parity, P3.97 conversation typing event parity, and prior checkpoints. Live API/browser/enterprise smoke still needs the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack.
- Next executable implementation checkpoint: continue Phase 2/3 drift audit for the next reused-frontend mismatch, or run B12 live smoke when the full PostgreSQL/Redis/Meilisearch/GoChat/Vite/Chrome stack is available. Re-run Phase 6 placeholder audit after future route/smoke changes.
- `go test ./...` passes when run outside the restricted socket sandbox for the latest implementation baseline; the latest docs/tooling checkpoint verified `scripts/parity_frontend_smoke.sh --check` with workspace-local temp/cache dirs after `/tmp` was full.
- Route dump succeeds with `967` registered routes after dashboard app route-parameter tracking.
- Route parity artifacts now exist under `docs/parity/` and are generated by `cmd/route_parity`.
- Tracked frontend-critical route audit covers 439 Chatwoot routes: 425 exact, 0 method-compatible, 14 parameter-compatible, 0 missing. The 14 parameter-compatible routes are Gin-internal parameter-name differences for nested AgentCapacityPolicy users/inbox limits, WhatsApp call `:id` route names, plus the public article `.md`/`.png` suffixes served through the same external article route dispatcher.
- Tracked frontend-critical route audit covers 439 Chatwoot routes: 430 exact, 0 method-compatible, 9 parameter-compatible, 0 missing. The 9 parameter-compatible routes are Gin-internal parameter-name differences for nested AgentCapacityPolicy users/inbox limits plus the public article `.md`/`.png` suffixes served through the same external article route dispatcher.
- `/api/v1/widget` stubs are burned down and public inbox/contact/conversation/message core flows are backed by real handlers.
- Handler test stability fixes are committed into the baseline before feature parity work continues.
- `.codegraph/` is generated indexing output and is not part of tracked product code.
@@ -156,6 +156,7 @@ This table is the shortest authoritative handoff view. If an older lower section
| Priority | Workstream | Current state | Next checkpoint | Commit close rule |
| --- | --- | --- | --- | --- |
| 0 | P3.101 WhatsApp call route parameter parity | Implemented for reused WhatsApp call controls: account-level show/accept/reject/terminate/upload-recording routes now register Chatwoot's `:id` parameter name from `routes.rb:237-242`, while the handler still accepts legacy `:call_id` mounts. Route parity improves from `425 exact / 14 parameter-compatible` to `430 exact / 9 parameter-compatible` with no missing critical routes. AgentCapacity nested route names stay parameter-compatible in the main Gin router because Gin cannot register `/:id` policy members and `/:agent_capacity_policy_id` nested siblings under the same prefix without a wildcard conflict; the nested handlers now tolerate both parameter-name families. | Keep in Review; reopen from B12 WhatsApp calling smoke or fresh reference evidence for route/action payload drift beyond the inspected enterprise controller/frontend call API contract. | Focused WhatsAppCallHandler, AgentCapacityHandler, and router tests passed; route dump/parity artifacts regenerated; full `go test ./...` passed outside the restricted socket sandbox after retrying the known `internal/worker` SQLite in-memory flake; `git diff --check` passed. |
| 0 | P3.100 dashboard app route parameter parity | Implemented for reused dashboard app settings routes: GoChat now registers standard dashboard app member routes with Chatwoot's `:id` parameter name for `show/update/destroy`, keeps `PATCH` and `PUT`, and preserves legacy handler compatibility for local focused tests and widget extension routes. Route parity improves from `421 exact / 18 parameter-compatible` to `425 exact / 14 parameter-compatible` with no missing critical routes. | Keep in Review; reopen from B12 dashboard app settings smoke or fresh reference evidence for serializer/request-permit drift beyond the inspected controller/Jbuilder/frontend store contract. | Focused DashboardAppHandler and router tests passed; route dump/parity artifacts regenerated; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. |
| 0 | P3.99 conversation destroy async parity | Implemented for reused conversation delete actions: `DELETE /conversations/:conversation_id` now returns empty `200 OK` like Chatwoot and queues a low-priority durable `conversation:delete_object` job when workers are configured. The job performs the existing soft delete, dispatches `conversation.deleted`, and removes the search index entry; no-worker construction keeps synchronous focused-test behavior. | Keep in Review; reopen from B12 conversation delete smoke or fresh reference evidence for enterprise `DeleteObjectJob#process_post_deletion_tasks`, exact Pundit destroy permission drift, or heavy-association purge behavior beyond conversation objects. | Focused ConversationService delete/job tests and ConversationHandler delete response tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change. |
| 0 | P3.98 conversation transcript delivery parity | Implemented for reused conversation transcript and automation transcript actions: `POST /conversations/:conversation_id/transcript` now checks Chatwoot-style email transcript availability, enforces configured daily email limits, delivers through the SMTP transcript boundary, increments account outbound-email counters, and scopes transcript content to public incoming/outgoing chat messages. Automation `send_email_transcript` no-ops when disabled and stops recipient fan-out at the rate limit before sync delivery or durable enqueue. | Keep in Review; reopen from B12 transcript smoke or fresh reference evidence for exact Redis TTL behavior, cloud-only global default limit handling, mailer template HTML body drift, or provider-specific SMTP availability checks beyond the inspected mailer gate. | Focused ConversationService, ConversationHandler, ActionService, and Account model transcript tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. `accounts.limits` migration is included; no route artifacts change. |
@@ -2782,3 +2783,4 @@ Verification milestone gates:
- 2026-06-07: P3.98 conversation transcript checkpoint prepared as `feat(conversations): align transcript delivery`; audited Chatwoot `ConversationsController#transcript`, `AccountEmailRateLimitable`, `ConversationReplyMailer#conversation_transcript`, `Message.chat`, `MessageFilterHelpers#conversation_transcriptable?`, and automation `ActionService#send_email_transcript`. GoChat account conversation transcript now honors email transcript availability, configured email limits, raw `402`/empty `429` response shapes, SMTP transcript delivery, outbound-email count increments, and public incoming/outgoing chat-message scoping; automation `send_email_transcript` no-ops when disabled and stops recipient fan-out at the rate limit before sync delivery or durable enqueue. Focused Account model, ConversationService, ConversationHandler, and ActionService transcript tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change.
- 2026-06-07: P3.99 conversation destroy checkpoint prepared as `feat(conversations): align destroy job`; audited Chatwoot `ConversationsController#destroy`, `DeleteObjectJob`, and reused dashboard `ConversationApi.delete` / `deleteConversation` action. GoChat account conversation delete now returns empty `200 OK` instead of local `204`, queues a low-priority durable `conversation:delete_object` job when WorkerPool is configured, and the worker performs the existing soft delete, `conversation.deleted` dispatch, and search-index deletion; no-worker construction keeps synchronous deletion for focused tests/local callers. Focused ConversationService delete/job tests and ConversationHandler delete tests passed; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed. No route artifacts change.
- 2026-06-07: P3.100 dashboard app route-parameter checkpoint prepared as `fix(routes): align dashboard app ids`; audited Chatwoot `routes.rb:130`, `DashboardAppsController`, dashboard app Jbuilder views, and reused dashboard `dashboardApps.js` API/store calls. GoChat now registers dashboard app member CRUD routes with Chatwoot's `:id` parameter name, keeps `PATCH` and `PUT`, and preserves legacy local `:dashboard_app_id` parsing for focused tests and GoChat-only widget extensions. Focused DashboardAppHandler and router tests passed; route dump/parity regenerated to `TOTAL: 967` and `425 exact, 0 method-compatible, 14 parameter-compatible, 0 missing out of 439`; full `go test ./...` passed outside the restricted socket sandbox; `git diff --check` passed.
- 2026-06-07: P3.101 WhatsApp call route-parameter checkpoint prepared as `fix(routes): align whatsapp call ids`; audited Chatwoot `routes.rb:237-242` and the reused account WhatsApp call route family. GoChat now registers account-level WhatsApp call show/action routes with Chatwoot's `:id` parameter name, preserves legacy `:call_id` handler compatibility, and makes AgentCapacity nested handlers accept both Chatwoot `:agent_capacity_policy_id`/`:id` and local Gin-compatible `:id`/`:user_id`/`:limit_id` parameter names. The main router keeps AgentCapacity nested route names parameter-compatible because Gin rejects wildcard-name changes below the existing policy `/:id` member route. Focused WhatsAppCallHandler, AgentCapacityHandler, and router tests passed; route dump/parity regenerated to `TOTAL: 967` and `430 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 439`; full `go test ./...` passed outside the restricted socket sandbox after retrying the known `internal/worker` SQLite in-memory flake; `git diff --check` passed.
+5 -5
View File
@@ -390,7 +390,7 @@ GET /api/v1/accounts/:account_id/users
GET /api/v1/accounts/:account_id/web_widgets/offline_messages
GET /api/v1/accounts/:account_id/webhooks
GET /api/v1/accounts/:account_id/webhooks/:webhook_id
GET /api/v1/accounts/:account_id/whatsapp_calls/:call_id
GET /api/v1/accounts/:account_id/whatsapp_calls/:id
GET /api/v1/accounts/all
GET /api/v1/auth/confirm_email
GET /api/v1/auth/mfa/status
@@ -782,10 +782,10 @@ POST /api/v1/accounts/:account_id/upload
POST /api/v1/accounts/:account_id/users
POST /api/v1/accounts/:account_id/webhooks
POST /api/v1/accounts/:account_id/whatsapp/authorization
POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/accept
POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/reject
POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/terminate
POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/upload_recording
POST /api/v1/accounts/:account_id/whatsapp_calls/:id/accept
POST /api/v1/accounts/:account_id/whatsapp_calls/:id/reject
POST /api/v1/accounts/:account_id/whatsapp_calls/:id/terminate
POST /api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording
POST /api/v1/accounts/:account_id/whatsapp_calls/initiate
POST /api/v1/auth/login
POST /api/v1/auth/login/mfa
+6 -6
View File
@@ -7,7 +7,7 @@ Generated from:
This report covers tracked frontend-critical Chatwoot routes from `reference/chatwoot/config/routes.rb`, including API v1 account routes, Captain/Copilot, assignment policies, widget/public APIs, and API v2 reports. Ruby is not installed in the workspace, so Chatwoot routes are sourced from static route declarations instead of `bin/rails routes`.
Summary: 425 exact, 0 method-compatible, 14 parameter-compatible, 0 missing out of 439 tracked critical routes.
Summary: 430 exact, 0 method-compatible, 9 parameter-compatible, 0 missing out of 439 tracked critical routes.
## Missing Critical Routes
@@ -32,16 +32,11 @@ These routes exist with equivalent method and path shape but different parameter
| DELETE | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/inbox_limits/:id` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits/:limit_id` | `api/v1/accounts/agent_capacity_policies/inbox_limits#destroy` | `routes.rb:126` | parameter-compatible |
| DELETE | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/users/:id` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/users/:user_id` | `api/v1/accounts/agent_capacity_policies/users#destroy` | `routes.rb:125` | parameter-compatible |
| GET | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/users` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/users` | `api/v1/accounts/agent_capacity_policies/users#index` | `routes.rb:125` | parameter-compatible |
| GET | `/api/v1/accounts/:account_id/whatsapp_calls/:id` | `/api/v1/accounts/:account_id/whatsapp_calls/:call_id` | `api/v1/accounts/whatsapp_calls#show` | `routes.rb:237` | parameter-compatible |
| GET | `/hc/:slug/articles/:article_slug.md` | `/hc/:slug/articles/:article_slug` | `public/api/v1/portals/articles#show_markdown` | `routes.rb:599` | parameter-compatible |
| GET | `/hc/:slug/articles/:article_slug.png` | `/hc/:slug/articles/:article_slug` | `public/api/v1/portals/articles#tracking_pixel` | `routes.rb:598` | parameter-compatible |
| PATCH | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/inbox_limits/:id` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits/:limit_id` | `api/v1/accounts/agent_capacity_policies/inbox_limits#update` | `routes.rb:126` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/inbox_limits` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits` | `api/v1/accounts/agent_capacity_policies/inbox_limits#create` | `routes.rb:126` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/users` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/users` | `api/v1/accounts/agent_capacity_policies/users#create` | `routes.rb:125` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/accept` | `/api/v1/accounts/:account_id/whatsapp_calls/:call_id/accept` | `api/v1/accounts/whatsapp_calls#accept` | `routes.rb:239` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/reject` | `/api/v1/accounts/:account_id/whatsapp_calls/:call_id/reject` | `api/v1/accounts/whatsapp_calls#reject` | `routes.rb:240` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/terminate` | `/api/v1/accounts/:account_id/whatsapp_calls/:call_id/terminate` | `api/v1/accounts/whatsapp_calls#terminate` | `routes.rb:241` | parameter-compatible |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording` | `/api/v1/accounts/:account_id/whatsapp_calls/:call_id/upload_recording` | `api/v1/accounts/whatsapp_calls#upload_recording` | `routes.rb:242` | parameter-compatible |
| PUT | `/api/v1/accounts/:account_id/agent_capacity_policies/:agent_capacity_policy_id/inbox_limits/:id` | `/api/v1/accounts/:account_id/agent_capacity_policies/:id/inbox_limits/:limit_id` | `api/v1/accounts/agent_capacity_policies/inbox_limits#update` | `routes.rb:126` | parameter-compatible |
## Exact Critical Routes
@@ -215,6 +210,7 @@ These routes exist with equivalent method and path shape but different parameter
| GET | `/api/v1/accounts/:account_id/teams/:team_id` | `/api/v1/accounts/:account_id/teams/:team_id` | `api/v1/accounts/teams#show` | `routes.rb:296` | exact |
| GET | `/api/v1/accounts/:account_id/teams/:team_id/team_members/` | `/api/v1/accounts/:account_id/teams/:team_id/team_members/` | `api/v1/accounts/teams/team_members#index` | `routes.rb:297` | exact |
| GET | `/api/v1/accounts/:account_id/webhooks` | `/api/v1/accounts/:account_id/webhooks` | `api/v1/accounts/webhooks#index` | `routes.rb:342` | exact |
| GET | `/api/v1/accounts/:account_id/whatsapp_calls/:id` | `/api/v1/accounts/:account_id/whatsapp_calls/:id` | `api/v1/accounts/whatsapp_calls#show` | `routes.rb:237` | exact |
| GET | `/api/v1/profile` | `/api/v1/profile` | `api/v1/profiles#show` | `routes.rb:421` | exact |
| GET | `/api/v1/profile/mfa` | `/api/v1/profile/mfa` | `api/v1/profile/mfa#show` | `routes.rb:433` | exact |
| GET | `/api/v1/widget/campaigns` | `/api/v1/widget/campaigns` | `api/v1/widget/campaigns#index` | `routes.rb:445` | exact |
@@ -397,6 +393,10 @@ These routes exist with equivalent method and path shape but different parameter
| POST | `/api/v1/accounts/:account_id/update_active_at` | `/api/v1/accounts/:account_id/update_active_at` | `api/v1/accounts#update_active_at` | `routes.rb:49` | exact |
| POST | `/api/v1/accounts/:account_id/webhooks` | `/api/v1/accounts/:account_id/webhooks` | `api/v1/accounts/webhooks#create` | `routes.rb:342` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp/authorization` | `/api/v1/accounts/:account_id/whatsapp/authorization` | `api/v1/accounts/whatsapp/authorizations#create` | `routes.rb:339` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/accept` | `/api/v1/accounts/:account_id/whatsapp_calls/:id/accept` | `api/v1/accounts/whatsapp_calls#accept` | `routes.rb:239` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/reject` | `/api/v1/accounts/:account_id/whatsapp_calls/:id/reject` | `api/v1/accounts/whatsapp_calls#reject` | `routes.rb:240` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/terminate` | `/api/v1/accounts/:account_id/whatsapp_calls/:id/terminate` | `api/v1/accounts/whatsapp_calls#terminate` | `routes.rb:241` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording` | `/api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording` | `api/v1/accounts/whatsapp_calls#upload_recording` | `routes.rb:242` | exact |
| POST | `/api/v1/accounts/:account_id/whatsapp_calls/initiate` | `/api/v1/accounts/:account_id/whatsapp_calls/initiate` | `api/v1/accounts/whatsapp_calls#initiate` | `routes.rb:245` | exact |
| POST | `/api/v1/notification_subscriptions` | `/api/v1/notification_subscriptions` | `api/v1/notification_subscriptions#create` | `routes.rb:440` | exact |
| POST | `/api/v1/profile/auto_offline` | `/api/v1/profile/auto_offline` | `api/v1/profiles#auto_offline` | `routes.rb:425` | exact |
@@ -186,8 +186,8 @@ func (h *AgentCapacityHandler) CreateInboxLimit(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
@@ -217,13 +217,13 @@ func (h *AgentCapacityHandler) UpdateInboxLimit(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
limitID, err := parseUintParam(c, "limit_id")
if err != nil {
limitID, err := parseUintAnyParam(c, "limit_id", "id")
if err != nil || limitID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid limit id")
return
}
@@ -253,13 +253,13 @@ func (h *AgentCapacityHandler) DeleteInboxLimit(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
limitID, err := parseUintParam(c, "limit_id")
if err != nil {
limitID, err := parseUintAnyParam(c, "limit_id", "id")
if err != nil || limitID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid limit id")
return
}
@@ -283,8 +283,8 @@ func (h *AgentCapacityHandler) ListUsers(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
@@ -306,8 +306,8 @@ func (h *AgentCapacityHandler) CreateUser(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
@@ -340,13 +340,13 @@ func (h *AgentCapacityHandler) DeleteUser(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, "account not identified")
return
}
policyID, err := parseUintParam(c, "id")
if err != nil {
policyID, err := parseUintAnyParam(c, "agent_capacity_policy_id", "id")
if err != nil || policyID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid id")
return
}
userID, err := parseUintParam(c, "user_id")
if err != nil {
userID, err := parseUintAnyParam(c, "user_id", "id")
if err != nil || userID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid user id")
return
}
@@ -25,7 +25,7 @@ func NewWhatsAppCallHandler(svc *service.WhatsAppCallService) *WhatsAppCallHandl
}
// Show returns a Chatwoot WhatsApp call payload.
// GET /api/v1/accounts/:account_id/whatsapp_calls/:call_id
// GET /api/v1/accounts/:account_id/whatsapp_calls/:id
func (h *WhatsAppCallHandler) Show(c *gin.Context) {
accountID, callID, ok := h.parseAccountCallParams(c)
if !ok {
@@ -72,7 +72,7 @@ func (h *WhatsAppCallHandler) Initiate(c *gin.Context) {
}
// Accept forwards an SDP answer to Meta and returns the updated call payload.
// POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/accept
// POST /api/v1/accounts/:account_id/whatsapp_calls/:id/accept
func (h *WhatsAppCallHandler) Accept(c *gin.Context) {
accountID, callID, ok := h.parseAccountCallParams(c)
if !ok {
@@ -91,7 +91,7 @@ func (h *WhatsAppCallHandler) Accept(c *gin.Context) {
}
// Reject rejects a ringing WhatsApp call.
// POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/reject
// POST /api/v1/accounts/:account_id/whatsapp_calls/:id/reject
func (h *WhatsAppCallHandler) Reject(c *gin.Context) {
accountID, callID, ok := h.parseAccountCallParams(c)
if !ok {
@@ -106,7 +106,7 @@ func (h *WhatsAppCallHandler) Reject(c *gin.Context) {
}
// Terminate terminates an active or ringing WhatsApp call.
// POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/terminate
// POST /api/v1/accounts/:account_id/whatsapp_calls/:id/terminate
func (h *WhatsAppCallHandler) Terminate(c *gin.Context) {
accountID, callID, ok := h.parseAccountCallParams(c)
if !ok {
@@ -121,7 +121,7 @@ func (h *WhatsAppCallHandler) Terminate(c *gin.Context) {
}
// UploadRecording attaches an audio recording to the linked voice_call message.
// POST /api/v1/accounts/:account_id/whatsapp_calls/:call_id/upload_recording
// POST /api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording
func (h *WhatsAppCallHandler) UploadRecording(c *gin.Context) {
accountID, callID, ok := h.parseAccountCallParams(c)
if !ok {
@@ -146,8 +146,8 @@ func (h *WhatsAppCallHandler) parseAccountCallParams(c *gin.Context) (uint, uint
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account id")
return 0, 0, false
}
callID, err := parseUintParam(c, "call_id")
if err != nil {
callID, err := parseUintAnyParam(c, "call_id", "id")
if err != nil || callID == 0 {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid call id")
return 0, 0, false
}
@@ -70,12 +70,12 @@ func setupWhatsAppCallHandlerTest(t *testing.T) (*gin.Engine, *gorm.DB, *model.A
c.Set("user_id", uint(7))
c.Next()
})
router.GET("/api/v1/accounts/:account_id/whatsapp_calls/:call_id", handler.Show)
router.GET("/api/v1/accounts/:account_id/whatsapp_calls/:id", handler.Show)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/initiate", handler.Initiate)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:call_id/accept", handler.Accept)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:call_id/reject", handler.Reject)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:call_id/terminate", handler.Terminate)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:call_id/upload_recording", handler.UploadRecording)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:id/accept", handler.Accept)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:id/reject", handler.Reject)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:id/terminate", handler.Terminate)
router.POST("/api/v1/accounts/:account_id/whatsapp_calls/:id/upload_recording", handler.UploadRecording)
return router, db, account, conversation
}
+5 -5
View File
@@ -687,12 +687,12 @@ func registerV1Routes(g *gin.RouterGroup, h *Handlers) {
accounts.POST("/:account_id/bulk_actions", h.BulkAction.Create)
// Account WhatsApp calls (ref: Chatwoot enterprise whatsapp_calls_controller.rb)
accounts.GET("/:account_id/whatsapp_calls/:call_id", h.WhatsAppCall.Show)
accounts.GET("/:account_id/whatsapp_calls/:id", h.WhatsAppCall.Show)
accounts.POST("/:account_id/whatsapp_calls/initiate", h.WhatsAppCall.Initiate)
accounts.POST("/:account_id/whatsapp_calls/:call_id/accept", h.WhatsAppCall.Accept)
accounts.POST("/:account_id/whatsapp_calls/:call_id/reject", h.WhatsAppCall.Reject)
accounts.POST("/:account_id/whatsapp_calls/:call_id/terminate", h.WhatsAppCall.Terminate)
accounts.POST("/:account_id/whatsapp_calls/:call_id/upload_recording", h.WhatsAppCall.UploadRecording)
accounts.POST("/:account_id/whatsapp_calls/:id/accept", h.WhatsAppCall.Accept)
accounts.POST("/:account_id/whatsapp_calls/:id/reject", h.WhatsAppCall.Reject)
accounts.POST("/:account_id/whatsapp_calls/:id/terminate", h.WhatsAppCall.Terminate)
accounts.POST("/:account_id/whatsapp_calls/:id/upload_recording", h.WhatsAppCall.UploadRecording)
// Account members (ref: Chatwoot namespace :account_users)
accounts.GET("/:account_id/users", h.Account.ListUsers)