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" ) // AdminListOrganizations returns the paginated admin org listing. func (h *Handler) AdminListOrganizations(c *gin.Context) { var search models.AdminOrgSearch if err := c.ShouldBindQuery(&search); err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid query parameters")) return } result, xerr := h.OrganizationService.SearchOrganizationsForAdmin(c.Request.Context(), &search) if xerr != nil { errx.JSON(c, xerr) return } c.JSON(http.StatusOK, result) } // AdminGetOrganization returns the detail payload for a single org. func (h *Handler) AdminGetOrganization(c *gin.Context) { orgID, err := uuid.Parse(c.Param("id")) if err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID")) return } detail, xerr := h.OrganizationService.GetOrganizationAdminDetail(c.Request.Context(), orgID) if xerr != nil { errx.JSON(c, xerr) return } c.JSON(http.StatusOK, detail) } // AdminGetOrganizationMembers returns the members of an org with users. func (h *Handler) AdminGetOrganizationMembers(c *gin.Context) { orgID, err := uuid.Parse(c.Param("id")) if err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID")) return } members, xerr := h.OrganizationService.GetOrganizationMembersForAdmin(c.Request.Context(), orgID) if xerr != nil { errx.JSON(c, xerr) return } c.JSON(http.StatusOK, &models.AdminOrgMembersResult{Data: members}) } // AdminGetOrgOverrides returns the override row for an org, or 200 with // null when no admin has touched it yet. Read access requires only // view_organizations. func (h *Handler) AdminGetOrgOverrides(c *gin.Context) { orgID, err := uuid.Parse(c.Param("id")) if err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID")) return } o, xerr := h.OrganizationService.GetLimitOverrides(c.Request.Context(), orgID) if xerr != nil { errx.JSON(c, xerr) return } c.JSON(http.StatusOK, o) } // AdminUpdateOrgOverrides upserts the override row. Audit row captures // only the request body (which is the diff the admin asked for) plus // the org id, not the post-write state — that's already on the // override row's granted_by/granted_at/updated_at. func (h *Handler) AdminUpdateOrgOverrides(c *gin.Context) { adminID := middleware.GetAdminUserID(c) if adminID == nil { errx.JSON(c, errx.ErrUnauthorized) return } orgID, err := uuid.Parse(c.Param("id")) if err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID")) return } var req models.UpdateOrgOverridesRequest if err := c.ShouldBindJSON(&req); err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid request body")) return } if !anyOverrideFieldSet(&req) { errx.JSON(c, errx.New(errx.BadRequest, "no override fields provided")) return } o, xerr := h.OrganizationService.SetLimitOverrides(c.Request.Context(), orgID, &req, *adminID) if xerr != nil { errx.JSON(c, xerr) return } h.AdminService.LogAdminAction( c.Request.Context(), *adminID, "set_org_limit_overrides", "organization", &orgID, overrideAuditDetails(&req), c.ClientIP(), c.Request.UserAgent(), ) c.JSON(http.StatusOK, o) } func anyOverrideFieldSet(req *models.UpdateOrgOverridesRequest) bool { return req.MaxCampaigns != nil || req.MaxActiveCampaigns != nil || req.MaxTeamMembers != nil || req.MaxEmailAccounts != nil || req.MaxContacts != nil || req.DailyCampaignLimit != nil || req.Notes != nil } func overrideAuditDetails(req *models.UpdateOrgOverridesRequest) map[string]any { d := map[string]any{} if req.MaxCampaigns != nil { d["max_campaigns"] = *req.MaxCampaigns } if req.MaxActiveCampaigns != nil { d["max_active_campaigns"] = *req.MaxActiveCampaigns } if req.MaxTeamMembers != nil { d["max_team_members"] = *req.MaxTeamMembers } if req.MaxEmailAccounts != nil { d["max_email_accounts"] = *req.MaxEmailAccounts } if req.MaxContacts != nil { d["max_contacts"] = *req.MaxContacts } if req.DailyCampaignLimit != nil { d["daily_campaign_limit"] = *req.DailyCampaignLimit } if req.Notes != nil { d["notes"] = *req.Notes } return d }