mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-18 16:01:18 +00:00
113 lines
3.0 KiB
Go
113 lines
3.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
func (h *Handler) CreateSequence(c *gin.Context) {
|
|
userID := middleware.GetUserID(c)
|
|
|
|
id := c.Param("id")
|
|
|
|
resp, err := h.SequenceService.Create(c.Request.Context(), userID, id)
|
|
if err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
|
|
h.auditOrg(c, models.AuditActionCreate, models.AuditEntitySequence, &resp.ID, nil, map[string]string{"campaign_id": id})
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *Handler) GetSequences(c *gin.Context) {
|
|
userID := middleware.GetUserID(c)
|
|
|
|
id := c.Param("id")
|
|
|
|
resp, err := h.SequenceService.Get(c.Request.Context(), userID, id)
|
|
if err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
func (h *Handler) UpdateSequence(c *gin.Context) {
|
|
userID := middleware.GetUserID(c)
|
|
|
|
id := c.Param("id")
|
|
sequenceID := c.Param("sid")
|
|
|
|
var data models.UpdateSequence
|
|
|
|
if err := c.ShouldBindJSON(&data); err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
|
|
resp, err := h.SequenceService.Update(c.Request.Context(), userID, id, sequenceID, &data)
|
|
if err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
|
|
h.auditOrg(c, models.AuditActionUpdate, models.AuditEntitySequence, &resp.ID, nil, map[string]string{"campaign_id": id})
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
// PatchSequenceLayout persists only the canvas coordinates of a campaign's
|
|
// steps so a teammate's arrangement "sticks" across visits. Like the automation
|
|
// layout endpoint it is written continuously as steps are dragged (the live
|
|
// cursor/drag stream is the realtime half), so it is deliberately NOT audited
|
|
// and does not bump updated_at: a reposition is cosmetic and must not spam the
|
|
// audit log or read as a content change. Retries are naturally safe (positions
|
|
// are last-write-wins), so no Idempotency-Key is required.
|
|
func (h *Handler) PatchSequenceLayout(c *gin.Context) {
|
|
userID := middleware.GetUserID(c)
|
|
id := c.Param("id")
|
|
|
|
var data models.SequenceLayout
|
|
if err := c.ShouldBindJSON(&data); err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
if len(data.Positions) > 1000 {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "too many positions"))
|
|
return
|
|
}
|
|
if err := h.SequenceService.UpdateLayout(c.Request.Context(), userID, id, data.Positions); err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"ok": true})
|
|
}
|
|
|
|
func (h *Handler) DeleteSequence(c *gin.Context) {
|
|
userID := middleware.GetUserID(c)
|
|
|
|
id := c.Param("id")
|
|
sequenceID := c.Param("sid")
|
|
|
|
if err := h.SequenceService.Delete(c.Request.Context(), userID, id, sequenceID); err != nil {
|
|
errx.Handle(c, err)
|
|
return
|
|
}
|
|
|
|
if sid, perr := uuid.Parse(sequenceID); perr == nil {
|
|
h.auditOrg(c, models.AuditActionDelete, models.AuditEntitySequence, &sid, nil, map[string]string{"campaign_id": id})
|
|
} else {
|
|
h.auditOrg(c, models.AuditActionDelete, models.AuditEntitySequence, nil, nil, map[string]string{"campaign_id": id})
|
|
}
|
|
|
|
c.Status(http.StatusOK)
|
|
}
|