mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
"github.com/warmbly/warmbly/internal/api/middleware"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
)
|
|
|
|
// GetContact returns the hydrated contact 360 payload. Used by the
|
|
// slide-over on open to render the Overview / engagement-summary tab
|
|
// in a single round-trip. Organization is optional — when the caller
|
|
// has none selected we still return core + engagement, just without
|
|
// org-scoped suppression / complaint counts.
|
|
func (h *Handler) GetContact(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrAuth)
|
|
return
|
|
}
|
|
contactID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrUuid)
|
|
return
|
|
}
|
|
|
|
orgID := middleware.GetOrganizationID(c)
|
|
|
|
detail, xerr := h.ContactService.GetDetail(c.Request.Context(), userID, orgID, contactID)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, detail)
|
|
}
|
|
|
|
// ListContactEmails returns one row per email we sent (or tried to
|
|
// send) to the contact. Cursor pagination keyed on the task ID.
|
|
func (h *Handler) ListContactEmails(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrAuth)
|
|
return
|
|
}
|
|
contactID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrUuid)
|
|
return
|
|
}
|
|
|
|
limit := 50
|
|
if l, err := strconv.Atoi(c.Query("limit")); err == nil && l > 0 && l <= 200 {
|
|
limit = l
|
|
}
|
|
|
|
// The cursor for sent-email pagination is the (created_at, task_id)
|
|
// pair from the last row of the previous page. Both must be present
|
|
// or we skip the cursor and start fresh.
|
|
var beforeAt *time.Time
|
|
var beforeID *uuid.UUID
|
|
if v := c.Query("before_at"); v != "" {
|
|
if t, perr := time.Parse(time.RFC3339Nano, v); perr == nil {
|
|
beforeAt = &t
|
|
}
|
|
}
|
|
if v := c.Query("before_id"); v != "" {
|
|
if id, perr := uuid.Parse(v); perr == nil {
|
|
beforeID = &id
|
|
}
|
|
}
|
|
|
|
res, xerr := h.ContactService.ListSentEmails(c.Request.Context(), userID, contactID, limit, beforeAt, beforeID)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, res)
|
|
}
|
|
|
|
// ListContactTimeline returns the merged activity feed for a contact.
|
|
// Suppression / deliverability / reply / note events are org-scoped
|
|
// and require a selected organization; we 400 if there isn't one to
|
|
// avoid silently returning a misleadingly thin feed.
|
|
func (h *Handler) ListContactTimeline(c *gin.Context) {
|
|
userID, err := middleware.GetUserUUID(c)
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrAuth)
|
|
return
|
|
}
|
|
contactID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.Handle(c, errx.ErrUuid)
|
|
return
|
|
}
|
|
|
|
orgID := middleware.GetOrganizationID(c)
|
|
if orgID == nil {
|
|
errx.Handle(c, errx.New(errx.BadRequest, "no organization selected"))
|
|
return
|
|
}
|
|
|
|
limit := 50
|
|
if l, err := strconv.Atoi(c.Query("limit")); err == nil && l > 0 && l <= 200 {
|
|
limit = l
|
|
}
|
|
|
|
var before *time.Time
|
|
if v := c.Query("before"); v != "" {
|
|
if t, perr := time.Parse(time.RFC3339Nano, v); perr == nil {
|
|
before = &t
|
|
}
|
|
}
|
|
|
|
res, xerr := h.ContactService.ListTimeline(c.Request.Context(), userID, orgID, contactID, limit, before)
|
|
if xerr != nil {
|
|
errx.Handle(c, xerr)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, res)
|
|
}
|