117 lines
2.8 KiB
Go
117 lines
2.8 KiB
Go
package admin
|
|
|
|
import (
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"gorm.io/gorm"
|
|
|
|
"server/internal/db"
|
|
"server/internal/responses"
|
|
users "server/internal/user"
|
|
"server/internal/validation"
|
|
)
|
|
|
|
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 := validation.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 := db.DBFromCtx(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var list []users.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")
|
|
}
|
|
|
|
return c.JSON(fiber.Map{
|
|
"data": fiber.Map{
|
|
"page": req.Page,
|
|
"pageSize": req.PageSize,
|
|
"items": list,
|
|
},
|
|
"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 := validation.ValidateStruct(&req); err != nil {
|
|
return err
|
|
}
|
|
|
|
db, err := db.DBFromCtx(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
uuid := c.Params("uuid")
|
|
if uuid == "" {
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid user uuid")
|
|
}
|
|
|
|
var u users.User
|
|
if err := db.Preload("Details").Preload("Preferences").Where("uuid = ?", uuid).First(&u).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":
|
|
u.Status = users.UserStatusDisabled
|
|
case "unblock":
|
|
u.Status = users.UserStatusActive
|
|
default:
|
|
return fiber.NewError(fiber.StatusBadRequest, "invalid action")
|
|
}
|
|
u.UpdatedAt = time.Now().UTC()
|
|
|
|
if err := db.Save(&u).Error; err != nil {
|
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to update user status")
|
|
}
|
|
|
|
return c.JSON(responses.Success(u))
|
|
}
|