package v1 import ( "errors" "net/http" "github.com/gin-gonic/gin" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/service" "github.com/gochat/gochat/pkg/response" ) // SlackIntegrationHandler handles Slack integration endpoints. // Reference: Chatwoot Integrations::SlackController type SlackIntegrationHandler struct { svc *service.SlackIntegrationService } // NewSlackIntegrationHandler creates a new SlackIntegrationHandler. func NewSlackIntegrationHandler(svc *service.SlackIntegrationService) *SlackIntegrationHandler { return &SlackIntegrationHandler{svc: svc} } // Create creates a Slack integration for an account. // POST /api/v1/accounts/:account_id/integrations/slack func (h *SlackIntegrationHandler) Create(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } var req service.CreateSlackRequest if err := c.ShouldBind(&req); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error()) return } hook, svcErr := h.svc.Create(c.Request.Context(), accountID, req) if svcErr != nil { handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, h.slackAppPayload(c, accountID, []model.IntegrationHook{*hook})) } // Update updates a Slack integration for an account. // PATCH /api/v1/accounts/:account_id/integrations/slack func (h *SlackIntegrationHandler) Update(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } var req service.UpdateSlackRequest if err := c.ShouldBind(&req); err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, err.Error()) return } hook, svcErr := h.svc.Update(c.Request.Context(), accountID, req) if svcErr != nil { if errors.Is(svcErr, service.ErrSlackInvalidChannel) { c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "Invalid slack channel. Please try again"}) return } handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, h.slackAppPayload(c, accountID, []model.IntegrationHook{*hook})) } // Delete removes a Slack integration for an account. // DELETE /api/v1/accounts/:account_id/integrations/slack func (h *SlackIntegrationHandler) Delete(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } if svcErr := h.svc.Delete(c.Request.Context(), accountID); svcErr != nil { handleServiceError(c, svcErr) return } c.Status(http.StatusOK) } // ListAllChannels lists available Slack channels. // GET /api/v1/accounts/:account_id/integrations/slack/list_all_channels func (h *SlackIntegrationHandler) ListAllChannels(c *gin.Context) { accountID, err := parseUintParam(c, "account_id") if err != nil { response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrBadRequest, "invalid account_id") return } channels, svcErr := h.svc.ListAllChannels(c.Request.Context(), accountID) if svcErr != nil { handleServiceError(c, svcErr) return } c.JSON(http.StatusOK, channels) } // RegisterSlackIntegrationRoutes registers Slack integration routes. func RegisterSlackIntegrationRoutes(g *gin.RouterGroup, h *SlackIntegrationHandler) { g.POST("/slack", h.Create) g.PATCH("/slack", h.Update) g.PUT("/slack", h.Update) g.DELETE("/slack", h.Delete) slack := g.Group("/slack") { slack.POST("/", h.Create) slack.PATCH("/", h.Update) slack.PUT("/", h.Update) slack.DELETE("/", h.Delete) slack.GET("/list_all_channels", h.ListAllChannels) } } func (h *SlackIntegrationHandler) slackAppPayload(c *gin.Context, accountID uint, fallback []model.IntegrationHook) gin.H { hooks, err := h.svc.ListHooks(c.Request.Context(), accountID) if err != nil || len(hooks) == 0 { hooks = fallback } serializedHooks := make([]gin.H, 0, len(hooks)) for _, hook := range hooks { serializedHooks = append(serializedHooks, serializeIntegrationHook(hook)) } return gin.H{ "id": "slack", "name": "Slack", "description": "Connect Slack channels for real-time notifications", "short_description": "Connect Slack channels for real-time notifications", "enabled": len(serializedHooks) > 0, "hooks": serializedHooks, "hook_type": integrationAppHookType("slack"), "allow_multiple_hooks": integrationAppAllowsMultipleHooks("slack"), "settings_form_schema": integrationAppSettingsFormSchema("slack"), "visible_properties": integrationAppVisibleProperties("slack"), } }