120 lines
2.8 KiB
Go
120 lines
2.8 KiB
Go
package controllers
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"gorm.io/gorm"
|
|
|
|
"server/internal/models"
|
|
)
|
|
|
|
type AdminController struct{}
|
|
|
|
func NewAdminController() *AdminController {
|
|
return &AdminController{}
|
|
}
|
|
|
|
// Typescript: interface
|
|
type ListUsersRequest struct {
|
|
Page int `json:"page" validate:"omitempty,min=1"`
|
|
PageSize int `json:"pageSize" validate:"omitempty,min=1,max=100"`
|
|
}
|
|
|
|
// Typescript: interface
|
|
type BlockUserRequest struct {
|
|
Action string `json:"action" validate:"required,oneof=block unblock"`
|
|
}
|
|
|
|
// ListUsers returns a paginated list of users (requires admin permissions).
|
|
func (ac *AdminController) ListUsers(c fiber.Ctx) error {
|
|
var req ListUsersRequest
|
|
if err := c.Bind().Body(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
|
}
|
|
if err := validateStruct(&req); err != nil {
|
|
return err
|
|
}
|
|
if req.Page <= 0 {
|
|
req.Page = 1
|
|
}
|
|
if req.PageSize <= 0 || req.PageSize > 100 {
|
|
req.PageSize = 20
|
|
}
|
|
|
|
db, err := dbFromCtx(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var list []models.User
|
|
offset := (req.Page - 1) * req.PageSize
|
|
if err := db.Preload("Details").Preload("Preferences").
|
|
Limit(req.PageSize).
|
|
Offset(offset).
|
|
Find(&list).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to load users")
|
|
}
|
|
|
|
// Map to short representation
|
|
short := make([]models.UserShort, 0, len(list))
|
|
for i := range list {
|
|
short = append(short, models.ToUserShort(&list[i]))
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": fiber.Map{
|
|
"page": req.Page,
|
|
"pageSize": req.PageSize,
|
|
"items": short,
|
|
},
|
|
"error": nil,
|
|
})
|
|
}
|
|
|
|
// BlockUser blocks or unblocks a user account by UUID.
|
|
func (ac *AdminController) BlockUser(c fiber.Ctx) error {
|
|
var req BlockUserRequest
|
|
if err := c.Bind().Body(&req); err != nil {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
|
}
|
|
if err := validateStruct(&req); err != nil {
|
|
return err
|
|
}
|
|
|
|
db, err := dbFromCtx(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
uuid := c.Params("uuid")
|
|
if uuid == "" {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid user uuid")
|
|
}
|
|
|
|
var user models.User
|
|
if err := db.Preload("Details").Preload("Preferences").Where("uuid = ?", uuid).First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return fiber.NewError(fiber.StatusNotFound, "user not found")
|
|
}
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
|
|
}
|
|
|
|
switch req.Action {
|
|
case "block":
|
|
user.Status = models.UserStatusDisabled
|
|
case "unblock":
|
|
user.Status = models.UserStatusActive
|
|
default:
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid action")
|
|
}
|
|
user.UpdatedAt = time.Now().UTC()
|
|
|
|
if err := db.Save(&user).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to update user status")
|
|
}
|
|
|
|
return c.JSON(success(models.ToUserShort(&user)))
|
|
}
|