Files
geo/server/internal/ops/transport/admin_user_handler.go
T
root 7be0de0614 feat(ops): add tenant admin user management module
Adds /admin-users CRUD on the ops backend, covering listing, plan/role/KOL
toggles, subscription expiry, status flips and password resets, with a
configurable default plan code. The ops console exposes a new top-level
"用户管理" view and reorganises the sidebar so 操作员管理 and 审计日志
move under a "系统设置" group; AccountsView is renamed accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 00:02:46 +08:00

287 lines
7.3 KiB
Go

package transport
import (
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/geo-platform/tenant-api/internal/ops/app"
"github.com/geo-platform/tenant-api/internal/shared/response"
)
type createAdminUserRequest struct {
Phone string `json:"phone" binding:"required"`
Email string `json:"email"`
Name string `json:"name"`
Password string `json:"password" binding:"required"`
PlanCode string `json:"plan_code"`
Role string `json:"role"`
}
type updateAdminUserRequest struct {
Phone string `json:"phone" binding:"required"`
Email string `json:"email"`
Name string `json:"name"`
}
type changeAdminUserPlanRequest struct {
PlanCode string `json:"plan_code" binding:"required"`
}
type updateAdminUserSubscriptionExpiryRequest struct {
EndAt time.Time `json:"end_at" binding:"required"`
}
type changeAdminUserRoleRequest struct {
Role string `json:"role" binding:"required"`
}
type setAdminUserKOLRequest struct {
Enabled bool `json:"enabled"`
DisplayName string `json:"display_name"`
MarketEnabled bool `json:"market_enabled"`
}
func listPlansHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
plans, err := svc.ListPlans(c.Request.Context())
if err != nil {
response.Error(c, err)
return
}
response.Success(c, plans)
}
}
func listRolesHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
response.Success(c, svc.ListRoles())
}
}
func listAdminUsersHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
size, _ := strconv.Atoi(c.DefaultQuery("size", "20"))
result, err := svc.List(c.Request.Context(), app.AdminUserListInput{
Keyword: c.Query("keyword"),
Status: c.Query("status"),
Page: page,
Size: size,
})
if err != nil {
response.Error(c, err)
return
}
response.Success(c, result)
}
}
func createAdminUserHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
var body createAdminUserRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
detail, err := svc.Create(c.Request.Context(), actorFromGin(c), app.CreateAdminUserInput{
Phone: body.Phone,
Email: body.Email,
Name: body.Name,
Password: body.Password,
PlanCode: body.PlanCode,
Role: body.Role,
})
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func getAdminUserHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
detail, err := svc.Get(c.Request.Context(), id)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func updateAdminUserHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body updateAdminUserRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
if err := svc.Update(c.Request.Context(), actorFromGin(c), id, app.UpdateAdminUserInput{
Phone: body.Phone,
Email: body.Email,
Name: body.Name,
}); err != nil {
response.Error(c, err)
return
}
response.Success(c, gin.H{"id": id})
}
}
func changeAdminUserPlanHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body changeAdminUserPlanRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
detail, err := svc.ChangePlan(c.Request.Context(), actorFromGin(c), id, body.PlanCode)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func updateAdminUserSubscriptionExpiryHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body updateAdminUserSubscriptionExpiryRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
detail, err := svc.UpdateSubscriptionExpiry(c.Request.Context(), actorFromGin(c), id, body.EndAt)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func resetAdminUserPlanUsageHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
result, err := svc.ResetCurrentPlanUsage(c.Request.Context(), actorFromGin(c), id)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, result)
}
}
func changeAdminUserRoleHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body changeAdminUserRoleRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
detail, err := svc.ChangeRole(c.Request.Context(), actorFromGin(c), id, body.Role)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func setAdminUserKOLHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body setAdminUserKOLRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
detail, err := svc.SetKOL(c.Request.Context(), actorFromGin(c), id, app.SetAdminUserKOLInput{
Enabled: body.Enabled,
DisplayName: body.DisplayName,
MarketEnabled: body.MarketEnabled,
})
if err != nil {
response.Error(c, err)
return
}
response.Success(c, detail)
}
}
func setAdminUserStatusHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body setStatusRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
if err := svc.SetStatus(c.Request.Context(), actorFromGin(c), id, body.Status); err != nil {
response.Error(c, err)
return
}
response.Success(c, gin.H{"id": id, "status": body.Status})
}
}
func resetAdminUserPasswordHandler(svc *app.AdminUserService) gin.HandlerFunc {
return func(c *gin.Context) {
id, err := parseIDParam(c)
if err != nil {
response.Error(c, err)
return
}
var body resetPasswordRequest
if err := c.ShouldBindJSON(&body); err != nil {
response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error()))
return
}
if err := svc.ResetPassword(c.Request.Context(), actorFromGin(c), id, body.Password); err != nil {
response.Error(c, err)
return
}
response.Success(c, gin.H{"id": id})
}
}