feat(routes): expand account parity coverage

This commit is contained in:
2026-06-04 20:44:20 +08:00
parent 14fa51d0b6
commit 14e784c51d
7 changed files with 253 additions and 20 deletions
@@ -151,4 +151,72 @@ func (h *InboxMemberHandler) UpdateMultiple(c *gin.Context) {
"members": members,
"meta": gin.H{"count": len(members)},
})
}
}
// ShowAccountScoped retrieves all agents assigned to an inbox using Chatwoot's account-level route.
// GET /api/v1/accounts/:account_id/inbox_members/:inbox_id
func (h *InboxMemberHandler) ShowAccountScoped(c *gin.Context) {
inboxID, err := parseUintParam(c, "inbox_id")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid inbox id"})
return
}
members, svcErr := h.svc.ListByInbox(c.Request.Context(), inboxID)
if svcErr != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "failed to list inbox members"})
return
}
c.JSON(http.StatusOK, gin.H{"members": members, "meta": gin.H{"count": len(members)}})
}
// CreateAccountScoped adds or replaces inbox members using Chatwoot's account-level create route.
// POST /api/v1/accounts/:account_id/inbox_members
func (h *InboxMemberHandler) CreateAccountScoped(c *gin.Context) {
h.updateAccountScoped(c)
}
// UpdateAccountScoped replaces all members of an inbox using Chatwoot's account-level update route.
// PATCH /api/v1/accounts/:account_id/inbox_members
func (h *InboxMemberHandler) UpdateAccountScoped(c *gin.Context) {
h.updateAccountScoped(c)
}
func (h *InboxMemberHandler) updateAccountScoped(c *gin.Context) {
var req service.UpdateMultipleRequest
if bindErr := c.ShouldBindJSON(&req); bindErr != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": bindErr.Error()})
return
}
members, svcErr := h.svc.UpdateMultiple(c.Request.Context(), req)
if svcErr != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "failed to update members"})
return
}
c.JSON(http.StatusOK, gin.H{"members": members, "meta": gin.H{"count": len(members)}})
}
// DestroyAccountScoped removes selected users from an inbox using Chatwoot's account-level route.
// DELETE /api/v1/accounts/:account_id/inbox_members
func (h *InboxMemberHandler) DestroyAccountScoped(c *gin.Context) {
var req struct {
InboxID uint `json:"inbox_id" binding:"required"`
UserIDs []uint `json:"user_ids" binding:"required"`
}
if bindErr := c.ShouldBindJSON(&req); bindErr != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": bindErr.Error()})
return
}
for _, userID := range req.UserIDs {
if svcErr := h.svc.RemoveMember(c.Request.Context(), req.InboxID, userID); svcErr != nil {
c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "failed to remove member"})
return
}
}
c.Status(http.StatusOK)
}
@@ -57,7 +57,7 @@ func (h *NotificationHandler) Get(c *gin.Context) {
response.AbortWithStatusError(c, http.StatusServiceUnavailable, response.ErrInternal, "Notification service not available")
return
}
notificationID, err := parseUintParam(c, "notification_id")
notificationID, err := parseUintAnyParam(c, "notification_id", "id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid notification id")
return
@@ -76,7 +76,7 @@ func (h *NotificationHandler) Get(c *gin.Context) {
// PUT /api/v1/accounts/:account_id/notifications/:id
// Reference: Chatwoot update — @notification.update(read_at: DateTime.now.utc); render json: @notification
func (h *NotificationHandler) Update(c *gin.Context) {
notificationID, err := parseUintParam(c, "notification_id")
notificationID, err := parseUintAnyParam(c, "notification_id", "id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid notification id")
return
@@ -134,7 +134,7 @@ func (h *NotificationHandler) UnreadCount(c *gin.Context) {
// POST /api/v1/accounts/:account_id/notifications/:id/snooze
// Reference: Chatwoot snooze — update(snoozed_until: ..., meta: ...)
func (h *NotificationHandler) Snooze(c *gin.Context) {
notificationID, err := parseUintParam(c, "notification_id")
notificationID, err := parseUintAnyParam(c, "notification_id", "id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid notification id")
return
@@ -170,7 +170,7 @@ func (h *NotificationHandler) Snooze(c *gin.Context) {
// POST /api/v1/accounts/:account_id/notifications/:id/unread
// Reference: Chatwoot unread — @notification.update(read_at: nil); render json: @notification
func (h *NotificationHandler) Unread(c *gin.Context) {
notificationID, err := parseUintParam(c, "notification_id")
notificationID, err := parseUintAnyParam(c, "notification_id", "id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid notification id")
return
@@ -192,7 +192,7 @@ func (h *NotificationHandler) Unread(c *gin.Context) {
// DELETE /api/v1/accounts/:account_id/notifications/:id
// Reference: Chatwoot destroy — @notification.destroy; head :ok
func (h *NotificationHandler) Destroy(c *gin.Context) {
notificationID, err := parseUintParam(c, "notification_id")
notificationID, err := parseUintAnyParam(c, "notification_id", "id")
if err != nil {
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid notification id")
return
@@ -225,4 +225,4 @@ func (h *NotificationHandler) DestroyAll(c *gin.Context) {
}
c.Status(http.StatusOK)
}
}