mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-03 16:02:02 +00:00
180 lines
4.7 KiB
Go
180 lines
4.7 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.InvalidBody(err))
|
|
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) {
|
|
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
|
|
}
|
|
rows, xerr := h.OrganizationService.ListLimitRequestsForOrg(c.Request.Context(), orgID, session.UserID)
|
|
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
|
|
}
|
|
offset, ok := offsetCursor(c)
|
|
if !ok {
|
|
return
|
|
}
|
|
search.Offset = offset
|
|
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)
|
|
}
|