package v1 import ( "encoding/json" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/service" ) // NotificationSubscriptionHandler handles notification subscription API endpoints. // Reference: Chatwoot app/controllers/api/v1/notification_subscriptions_controller.rb // Routes: resource :notification_subscriptions, only: [:create, :destroy] type NotificationSubscriptionHandler struct { svc *service.NotificationSubscriptionService } func NewNotificationSubscriptionHandler(svc *service.NotificationSubscriptionService) *NotificationSubscriptionHandler { return &NotificationSubscriptionHandler{svc: svc} } // Create adds a new notification subscription. // POST /api/v1/notification_subscriptions // Chatwoot: requires identifier, subscription_attributes, subscription_type func (h *NotificationSubscriptionHandler) Create(c *gin.Context) { userID := getUserID(c) if userID == 0 { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) return } var req service.CreateSubscriptionRequest if err := bindJSONWrappedOrRaw(c, "notification_subscription", &req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Validate subscription_attributes based on type if err := service.ValidateSubscriptionAttributes(req.SubscriptionType, req.SubscriptionAttributes); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } sub, err := h.svc.Create(c.Request.Context(), userID, &req) if err != nil { c.JSON(http.StatusUnprocessableEntity, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, notificationSubscriptionPayloadFromModel(sub)) } // Destroy removes a notification subscription. // DELETE /api/v1/notification_subscriptions/:identifier // Chatwoot: finds by identifier and deletes func (h *NotificationSubscriptionHandler) Destroy(c *gin.Context) { userID := getUserID(c) if userID == 0 { c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) return } pushToken := c.Query("push_token") if pushToken == "" { pushToken = c.Param("identifier") } if pushToken == "" { pushToken = c.PostForm("push_token") } if pushToken == "" && c.Request.Body != nil { var body struct { PushToken string `json:"push_token"` } _ = c.ShouldBindJSON(&body) pushToken = body.PushToken } _ = h.svc.Destroy(c.Request.Context(), userID, pushToken) c.Status(http.StatusOK) } type notificationSubscriptionDTO struct { ID uint `json:"id"` Identifier string `json:"identifier"` SubscriptionAttributes json.RawMessage `json:"subscription_attributes"` SubscriptionType string `json:"subscription_type"` UserID uint `json:"user_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } func notificationSubscriptionPayloadFromModel(sub *model.NotificationSubscription) notificationSubscriptionDTO { return notificationSubscriptionDTO{ ID: sub.ID, Identifier: sub.Identifier, SubscriptionAttributes: sub.SubscriptionAttributes, SubscriptionType: sub.SubscriptionType.String(), UserID: sub.UserID, CreatedAt: sub.CreatedAt, UpdatedAt: sub.UpdatedAt, } }