package httpapi import ( "net/http" "github.com/gin-gonic/gin" "productier/apps/backend/internal/store" ) func (s *Server) registerCRMRoutes(group *gin.RouterGroup) { // Contacts group.GET("/contacts", func(c *gin.Context) { workspaceSlug := c.Query("workspaceSlug") if _, ok := s.requireWorkspaceMember(c, workspaceSlug); !ok { return } c.JSON(http.StatusOK, gin.H{"data": s.store.ListContacts(workspaceSlug)}) }) group.GET("/contacts/:contactId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } c.JSON(http.StatusOK, gin.H{"data": contact}) }) group.POST("/contacts", func(c *gin.Context) { var input store.CreateContactInput if err := c.ShouldBindJSON(&input); err != nil { s.writeStatusError(c, http.StatusBadRequest, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, input.WorkspaceSlug); !ok { return } contact := s.store.CreateContact(input) c.JSON(http.StatusCreated, gin.H{"data": contact}) }) group.PATCH("/contacts/:contactId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } var input store.UpdateContactInput if err := c.ShouldBindJSON(&input); err != nil { s.writeStatusError(c, http.StatusBadRequest, err.Error()) return } updated, err := s.store.UpdateContact(c.Param("contactId"), input) if err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"data": updated}) }) group.DELETE("/contacts/:contactId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } if err := s.store.DeleteContact(c.Param("contactId")); err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }) // Companies group.GET("/companies", func(c *gin.Context) { workspaceSlug := c.Query("workspaceSlug") if _, ok := s.requireWorkspaceMember(c, workspaceSlug); !ok { return } c.JSON(http.StatusOK, gin.H{"data": s.store.ListCompanies(workspaceSlug)}) }) group.GET("/companies/:companyId", func(c *gin.Context) { company, err := s.store.GetCompanyByID(c.Param("companyId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, company.WorkspaceSlug); !ok { return } c.JSON(http.StatusOK, gin.H{"data": company}) }) group.POST("/companies", func(c *gin.Context) { var input store.CreateCompanyInput if err := c.ShouldBindJSON(&input); err != nil { s.writeStatusError(c, http.StatusBadRequest, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, input.WorkspaceSlug); !ok { return } company := s.store.CreateCompany(input) c.JSON(http.StatusCreated, gin.H{"data": company}) }) group.PATCH("/companies/:companyId", func(c *gin.Context) { company, err := s.store.GetCompanyByID(c.Param("companyId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, company.WorkspaceSlug); !ok { return } var input store.UpdateCompanyInput if err := c.ShouldBindJSON(&input); err != nil { s.writeStatusError(c, http.StatusBadRequest, err.Error()) return } updated, err := s.store.UpdateCompany(c.Param("companyId"), input) if err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"data": updated}) }) group.DELETE("/companies/:companyId", func(c *gin.Context) { company, err := s.store.GetCompanyByID(c.Param("companyId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, company.WorkspaceSlug); !ok { return } if err := s.store.DeleteCompany(c.Param("companyId")); err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }) // Contact-Task linking group.POST("/contacts/:contactId/tasks/:taskId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } if err := s.store.LinkContactToTask(c.Param("contactId"), c.Param("taskId")); err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }) group.DELETE("/contacts/:contactId/tasks/:taskId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } if err := s.store.UnlinkContactFromTask(c.Param("contactId"), c.Param("taskId")); err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }) // Contact-Event linking group.POST("/contacts/:contactId/events/:eventId", func(c *gin.Context) { contact, err := s.store.GetContactByID(c.Param("contactId")) if err != nil { s.writeStatusError(c, http.StatusNotFound, err.Error()) return } if _, ok := s.requireWorkspaceMember(c, contact.WorkspaceSlug); !ok { return } if err := s.store.LinkContactToEvent(c.Param("contactId"), c.Param("eventId")); err != nil { s.writeStatusError(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"ok": true}) }) }