From 5039071ea3ee736446924f688061434fe1e03605 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 31 Jan 2026 13:06:21 -0500 Subject: [PATCH] Add admin-configurable device cap per user - Add max_devices column to users table (default: 10) - Add UpdateUserMaxDevices database query - Add CountUserDevices database query - Add UpdateUserMaxDevices handler with validation (1-100 devices) - Add PUT /api/auth/users/:id/max-devices endpoint (admin only) - Update UserList struct to include max_devices field - Validate user ID format and max_devices range - Return appropriate errors for invalid requests --- internal/handlers/auth.go | 55 ++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 7387cc0..589a9ce 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -473,15 +473,16 @@ func (h *AuthHandler) ListUsers(c echo.Context) error { } type UserList struct { - ID string `json:"id"` - Email string `json:"email"` - Username string `json:"username"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Theme string `json:"theme"` - Role string `json:"role"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` + ID string `json:"id"` + Email string `json:"email"` + Username string `json:"username"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Theme string `json:"theme"` + Role string `json:"role"` + MaxDevices int32 `json:"max_devices"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` } var userList []UserList @@ -855,6 +856,42 @@ func (h *AuthHandler) GetScanSettings(c echo.Context) error { }) } +type UpdateUserMaxDevicesRequest struct { + MaxDevices int32 `json:"max_devices" validate:"required,min=1,max=100"` +} + +// UpdateUserMaxDevices handles PUT /api/auth/users/:id/max-devices (admin only) +func (h *AuthHandler) UpdateUserMaxDevices(c echo.Context) error { + userID := c.Param("id") + if userID == "" { + return c.JSON(http.StatusBadRequest, map[string]string{"error": "user id required"}) + } + + var req UpdateUserMaxDevicesRequest + if err := c.Bind(&req); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid request"}) + } + + if err := c.Validate(&req); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()}) + } + + userUUID, err := uuid.Parse(userID) + if err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{"error": "invalid user id"}) + } + + err = h.db.UpdateUserMaxDevices(c.Request().Context(), database.UpdateUserMaxDevicesParams{ + ID: pgtype.UUID{Bytes: userUUID, Valid: true}, + MaxDevices: pgtype.Int4{Int32: req.MaxDevices, Valid: true}, + }) + if err != nil { + return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()}) + } + + return c.JSON(http.StatusOK, map[string]string{"message": "max devices updated"}) +} + // AdminMiddleware checks if the user has admin role func AdminMiddleware(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error {