mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 00:01:14 +00:00
bc435747ea
Add richer backend models, handlers, services, and repository queries for admin campaigns, discounts, outreach, organizations, limit requests, and provisioning surfaces.
170 lines
4.5 KiB
Go
170 lines
4.5 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"
|
|
)
|
|
|
|
// User-facing endpoints under /v1/organizations/:orgId/limit-requests.
|
|
|
|
// SubmitLimitIncreaseRequest is POST /v1/organizations/:orgId/limit-requests.
|
|
func (h *Handler) SubmitLimitIncreaseRequest(c *gin.Context) {
|
|
session := middleware.GetSession(c)
|
|
if session == nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
orgID, err := uuid.Parse(c.Param("orgId"))
|
|
if err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID"))
|
|
return
|
|
}
|
|
var req models.CreateLimitIncreaseRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request body"))
|
|
return
|
|
}
|
|
lr, xerr := h.OrganizationService.SubmitLimitIncreaseRequest(c.Request.Context(), orgID, session.UserID, &req)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, lr)
|
|
}
|
|
|
|
// ListOrgLimitRequests is GET /v1/organizations/:orgId/limit-requests.
|
|
func (h *Handler) ListOrgLimitRequests(c *gin.Context) {
|
|
orgID, err := uuid.Parse(c.Param("orgId"))
|
|
if err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID"))
|
|
return
|
|
}
|
|
rows, xerr := h.OrganizationService.ListLimitRequestsForOrg(c.Request.Context(), orgID)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"data": rows})
|
|
}
|
|
|
|
// CancelLimitRequest is DELETE /v1/limit-requests/:id (submitter only).
|
|
func (h *Handler) CancelLimitRequest(c *gin.Context) {
|
|
session := middleware.GetSession(c)
|
|
if session == nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
id, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
|
|
return
|
|
}
|
|
if xerr := h.OrganizationService.CancelLimitRequest(c.Request.Context(), id, session.UserID); xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.Status(http.StatusNoContent)
|
|
}
|
|
|
|
// Admin-facing endpoints under /admin/limit-requests.
|
|
|
|
// AdminListLimitRequests is GET /admin/limit-requests with the shared faceted
|
|
// query params; returns the standard {data, pagination} envelope.
|
|
func (h *Handler) AdminListLimitRequests(c *gin.Context) {
|
|
var search models.AdminLimitRequestSearch
|
|
if err := c.ShouldBindQuery(&search); err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid query parameters"))
|
|
return
|
|
}
|
|
result, xerr := h.OrganizationService.AdminListLimitRequests(c.Request.Context(), &search)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, result)
|
|
}
|
|
|
|
// AdminApproveLimitRequest is POST /admin/limit-requests/:id/approve.
|
|
func (h *Handler) AdminApproveLimitRequest(c *gin.Context) {
|
|
adminID := middleware.GetAdminUserID(c)
|
|
if adminID == nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
id, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
|
|
return
|
|
}
|
|
var body models.ReviewLimitRequestBody
|
|
_ = c.ShouldBindJSON(&body) // notes are optional
|
|
|
|
lr, xerr := h.OrganizationService.ApproveLimitRequest(c.Request.Context(), id, *adminID, body.Notes)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.AdminService.LogAdminAction(
|
|
c.Request.Context(),
|
|
*adminID,
|
|
"approve_limit_request",
|
|
"limit_request",
|
|
&id,
|
|
map[string]any{
|
|
"field": lr.Field,
|
|
"requested": lr.Requested,
|
|
"notes": body.Notes,
|
|
},
|
|
c.ClientIP(),
|
|
c.Request.UserAgent(),
|
|
)
|
|
c.JSON(http.StatusOK, lr)
|
|
}
|
|
|
|
// AdminRejectLimitRequest is POST /admin/limit-requests/:id/reject.
|
|
func (h *Handler) AdminRejectLimitRequest(c *gin.Context) {
|
|
adminID := middleware.GetAdminUserID(c)
|
|
if adminID == nil {
|
|
errx.JSON(c, errx.ErrUnauthorized)
|
|
return
|
|
}
|
|
id, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "invalid request ID"))
|
|
return
|
|
}
|
|
var body models.ReviewLimitRequestBody
|
|
if err := c.ShouldBindJSON(&body); err != nil || body.Notes == "" {
|
|
errx.JSON(c, errx.New(errx.BadRequest, "review notes are required when rejecting"))
|
|
return
|
|
}
|
|
|
|
lr, xerr := h.OrganizationService.RejectLimitRequest(c.Request.Context(), id, *adminID, body.Notes)
|
|
if xerr != nil {
|
|
errx.JSON(c, xerr)
|
|
return
|
|
}
|
|
|
|
h.AdminService.LogAdminAction(
|
|
c.Request.Context(),
|
|
*adminID,
|
|
"reject_limit_request",
|
|
"limit_request",
|
|
&id,
|
|
map[string]any{
|
|
"field": lr.Field,
|
|
"requested": lr.Requested,
|
|
"notes": body.Notes,
|
|
},
|
|
c.ClientIP(),
|
|
c.Request.UserAgent(),
|
|
)
|
|
c.JSON(http.StatusOK, lr)
|
|
}
|