fix/status-review-sync-20260409 #1

Merged
long merged 65 commits from fix/status-review-sync-20260409 into main 2026-04-18 15:05:51 +00:00
12 changed files with 891 additions and 3 deletions
Showing only changes of commit 0564bfd9ad - Show all commits

View File

@@ -30,6 +30,17 @@ func NewAuthHandler(authService *service.AuthService) *AuthHandler {
return &AuthHandler{authService: authService}
}
// Register 用户注册
// @Summary 用户注册
// @Description 用户注册新账号,支持用户名+密码或手机号注册
// @Tags 认证
// @Accept json
// @Produce json
// @Param request body service.RegisterRequest true "注册请求"
// @Success 201 {object} Response{data=service.UserInfo} "注册成功"
// @Failure 400 {object} Response{code=int,message=string} "请求参数错误"
// @Failure 409 {object} Response{code=int,message=string} "用户已存在"
// @Router /api/v1/auth/register [post]
func (h *AuthHandler) Register(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required"`
@@ -65,6 +76,18 @@ func (h *AuthHandler) Register(c *gin.Context) {
})
}
// Login 用户登录
// @Summary 用户登录
// @Description 用户使用账号密码登录,支持多种认证方式(用户名/邮箱/手机号)
// @Tags 认证
// @Accept json
// @Produce json
// @Param request body service.LoginRequest true "登录请求"
// @Success 200 {object} Response{data=service.LoginResponse} "登录成功"
// @Failure 400 {object} Response{code=int,message=string} "请求参数错误"
// @Failure 401 {object} Response{code=int,message=string} "认证失败"
// @Failure 429 {object} Response{code=int,message=string} "登录尝试过多"
// @Router /api/v1/auth/login [post]
func (h *AuthHandler) Login(c *gin.Context) {
var req struct {
Account string `json:"account"`
@@ -109,6 +132,16 @@ func (h *AuthHandler) Login(c *gin.Context) {
})
}
// Logout 用户登出
// @Summary 用户登出
// @Description 使当前 access_token 和 refresh_token 失效
// @Tags 认证
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.LogoutRequest false "登出请求token可从header获取"
// @Success 200 {object} Response{code=int,message=string} "登出成功"
// @Router /api/v1/auth/logout [post]
func (h *AuthHandler) Logout(c *gin.Context) {
var req struct {
AccessToken string `json:"access_token"`
@@ -136,6 +169,17 @@ func (h *AuthHandler) Logout(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "logged out"})
}
// RefreshToken 刷新访问令牌
// @Summary 刷新访问令牌
// @Description 使用 refresh_token 获取新的 access_token
// @Tags 认证
// @Accept json
// @Produce json
// @Param request body RefreshTokenRequest true "刷新令牌请求"
// @Success 200 {object} Response{data=service.LoginResponse} "刷新成功"
// @Failure 400 {object} Response{code=int,message=string} "请求参数错误"
// @Failure 401 {object} Response{code=int,message=string} "refresh_token无效或已过期"
// @Router /api/v1/auth/refresh-token [post]
func (h *AuthHandler) RefreshToken(c *gin.Context) {
var req struct {
RefreshToken string `json:"refresh_token" binding:"required"`
@@ -159,6 +203,15 @@ func (h *AuthHandler) RefreshToken(c *gin.Context) {
})
}
// GetUserInfo 获取当前用户信息
// @Summary 获取当前用户信息
// @Description 获取已登录用户的详细信息
// @Tags 认证
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=service.UserInfo} "用户信息"
// @Failure 401 {object} Response{code=int,message=string} "未认证"
// @Router /api/v1/auth/userinfo [get]
func (h *AuthHandler) GetUserInfo(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -179,6 +232,13 @@ func (h *AuthHandler) GetUserInfo(c *gin.Context) {
})
}
// GetCSRFToken 获取CSRF令牌
// @Summary 获取CSRF令牌
// @Description 由于系统使用JWT Bearer Token认证不存在CSRF风险返回空token
// @Tags 认证
// @Produce json
// @Success 200 {object} map "CSRF token为空"
// @Router /api/v1/auth/csrf-token [get]
func (h *AuthHandler) GetCSRFToken(c *gin.Context) {
// 系统使用 JWT Bearer Token 认证Bearer Token 不会被浏览器自动携带(非 cookie
// 因此不存在传统意义上的 CSRF 风险,此端点返回空 token 作为兼容响应
@@ -188,6 +248,13 @@ func (h *AuthHandler) GetCSRFToken(c *gin.Context) {
})
}
// GetAuthCapabilities 获取认证能力
// @Summary 获取系统认证能力
// @Description 返回系统支持的认证方式和配置如是否需要邮件激活、是否支持OAuth等
// @Tags 认证
// @Produce json
// @Success 200 {object} Response{data=service.AuthCapabilities} "认证能力配置"
// @Router /api/v1/auth/capabilities [get]
func (h *AuthHandler) GetAuthCapabilities(c *gin.Context) {
ctx := c.Request.Context()
caps := h.authService.GetAuthCapabilities(ctx)
@@ -198,23 +265,65 @@ func (h *AuthHandler) GetAuthCapabilities(c *gin.Context) {
})
}
// OAuthLogin OAuth登录初始化
// @Summary OAuth登录初始化
// @Description 发起OAuth登录流程当前未配置
// @Tags OAuth
// @Produce json
// @Param provider path string true "OAuth提供商如 github, google"
// @Success 200 {object} Response "OAuth未配置"
// @Router /api/v1/auth/oauth/{provider} [get]
func (h *AuthHandler) OAuthLogin(c *gin.Context) {
provider := c.Param("provider")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "OAuth not configured", "data": gin.H{"provider": provider}})
}
// OAuthCallback OAuth回调
// @Summary OAuth回调处理
// @Description 处理OAuth provider回调当前未配置
// @Tags OAuth
// @Produce json
// @Param provider path string true "OAuth提供商"
// @Success 200 {object} Response "OAuth未配置"
// @Router /api/v1/auth/oauth/{provider}/callback [get]
func (h *AuthHandler) OAuthCallback(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "OAuth not configured"})
}
// OAuthExchange OAuth令牌交换
// @Summary OAuth令牌交换
// @Description 使用OAuth code交换access_token当前未配置
// @Tags OAuth
// @Accept json
// @Produce json
// @Param provider path string true "OAuth提供商"
// @Success 200 {object} Response "OAuth未配置"
// @Router /api/v1/auth/oauth/{provider}/exchange [post]
func (h *AuthHandler) OAuthExchange(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "OAuth not configured"})
}
// GetEnabledOAuthProviders 获取已启用的OAuth提供商
// @Summary 获取OAuth提供商列表
// @Description 返回系统已配置并启用的OAuth提供商列表
// @Tags OAuth
// @Produce json
// @Success 200 {object} Response{data=map} "提供商列表"
// @Router /api/v1/auth/oauth/providers [get]
func (h *AuthHandler) GetEnabledOAuthProviders(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": gin.H{"providers": []string{}}})
}
// ActivateEmail 激活邮箱
// @Summary 激活用户邮箱
// @Description 使用邮箱激活token激活用户账号
// @Tags 邮箱认证
// @Produce json
// @Param token query string true "激活token"
// @Success 200 {object} Response "激活成功"
// @Failure 400 {object} Response "token缺失"
// @Failure 401 {object} Response "token无效或已过期"
// @Router /api/v1/auth/activate-email [post]
func (h *AuthHandler) ActivateEmail(c *gin.Context) {
token := c.Query("token")
if token == "" {
@@ -228,6 +337,16 @@ func (h *AuthHandler) ActivateEmail(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "email activated successfully"})
}
// ResendActivationEmail 重发激活邮件
// @Summary 重发激活邮件
// @Description 重新发送账号激活邮件(防枚举:无论邮箱是否注册都返回成功)
// @Tags 邮箱认证
// @Accept json
// @Produce json
// @Param request body ResendActivationRequest true "邮箱地址"
// @Success 200 {object} Response "激活邮件已发送(如果邮箱已注册)"
// @Failure 400 {object} Response "邮箱格式错误"
// @Router /api/v1/auth/resend-activation-email [post]
func (h *AuthHandler) ResendActivationEmail(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required,email"`
@@ -244,6 +363,16 @@ func (h *AuthHandler) ResendActivationEmail(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "activation email sent if address is registered"})
}
// SendEmailCode 发送邮箱验证码
// @Summary 发送邮箱验证码
// @Description 发送邮箱登录验证码(防枚举:无论邮箱是否注册都返回成功)
// @Tags 邮箱认证
// @Accept json
// @Produce json
// @Param request body SendEmailCodeRequest true "邮箱地址"
// @Success 200 {object} Response "验证码已发送"
// @Failure 400 {object} Response "邮箱格式错误"
// @Router /api/v1/auth/send-email-code [post]
func (h *AuthHandler) SendEmailCode(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required,email"`
@@ -261,6 +390,17 @@ func (h *AuthHandler) SendEmailCode(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "验证码已发送"})
}
// LoginByEmailCode 使用邮箱验证码登录
// @Summary 邮箱验证码登录
// @Description 使用邮箱和验证码完成登录
// @Tags 邮箱认证
// @Accept json
// @Produce json
// @Param request body LoginByEmailCodeRequest true "登录请求"
// @Success 200 {object} Response{data=service.LoginResponse} "登录成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "验证码错误或已过期"
// @Router /api/v1/auth/login-by-email-code [post]
func (h *AuthHandler) LoginByEmailCode(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required,email"`
@@ -307,6 +447,19 @@ func (h *AuthHandler) LoginByEmailCode(c *gin.Context) {
})
}
// BootstrapAdmin 引导初始化管理员
// @Summary 引导初始化管理员账号
// @Description 在系统未配置管理员时创建第一个管理员账号需要BOOTSTRAP_SECRET
// @Tags 系统初始化
// @Accept json
// @Produce json
// @Security BootstrapSecret
// @Param X-Bootstrap-Secret header string true "引导密钥"
// @Param request body BootstrapAdminRequest true "管理员信息"
// @Success 201 {object} Response{data=service.UserInfo} "管理员创建成功"
// @Failure 401 {object} Response "引导密钥无效"
// @Failure 403 {object} Response "引导初始化未授权"
// @Router /api/v1/auth/bootstrap-admin [post]
func (h *AuthHandler) BootstrapAdmin(c *gin.Context) {
// P0 修复BootstrapAdmin 端点需要 bootstrap secret 验证
bootstrapSecret := os.Getenv("BOOTSTRAP_SECRET")
@@ -358,38 +511,110 @@ func (h *AuthHandler) BootstrapAdmin(c *gin.Context) {
})
}
// SendEmailBindCode 发送邮箱绑定验证码
// @Summary 发送邮箱绑定验证码
// @Description 发送验证码到邮箱以绑定邮箱(当前未配置)
// @Tags 邮箱绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/email/bind/send [post]
func (h *AuthHandler) SendEmailBindCode(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "email bind not configured"})
}
// BindEmail 绑定邮箱
// @Summary 绑定邮箱
// @Description 使用邮箱验证码绑定账号(当前未配置)
// @Tags 邮箱绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/email/bind [post]
func (h *AuthHandler) BindEmail(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "email bind not configured"})
}
// UnbindEmail 解绑邮箱
// @Summary 解绑邮箱
// @Description 解绑账号关联的邮箱(当前未配置)
// @Tags 邮箱绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/email/unbind [post]
func (h *AuthHandler) UnbindEmail(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "email unbind not configured"})
}
// SendPhoneBindCode 发送手机绑定验证码
// @Summary 发送手机绑定验证码
// @Description 发送验证码到手机以绑定手机号(当前未配置)
// @Tags 手机绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/phone/bind/send [post]
func (h *AuthHandler) SendPhoneBindCode(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "phone bind not configured"})
}
// BindPhone 绑定手机号
// @Summary 绑定手机号
// @Description 使用手机验证码绑定账号(当前未配置)
// @Tags 手机绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/phone/bind [post]
func (h *AuthHandler) BindPhone(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "phone bind not configured"})
}
// UnbindPhone 解绑手机号
// @Summary 解绑手机号
// @Description 解绑账号关联的手机号(当前未配置)
// @Tags 手机绑定
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/phone/unbind [post]
func (h *AuthHandler) UnbindPhone(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "phone unbind not configured"})
}
// GetSocialAccounts 获取社交账号列表
// @Summary 获取已绑定的社交账号列表
// @Description 获取当前用户绑定的第三方社交账号列表
// @Tags 社交账号
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response "社交账号列表"
// @Router /api/v1/auth/social-accounts [get]
func (h *AuthHandler) GetSocialAccounts(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": gin.H{"accounts": []interface{}{}}})
}
// BindSocialAccount 绑定社交账号
// @Summary 绑定社交账号
// @Description 绑定第三方社交账号到当前用户(当前未配置)
// @Tags 社交账号
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/social/bind [post]
func (h *AuthHandler) BindSocialAccount(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "social binding not configured"})
}
// UnbindSocialAccount 解绑社交账号
// @Summary 解绑社交账号
// @Description 解绑当前用户关联的第三方社交账号(当前未配置)
// @Tags 社交账号
// @Accept json
// @Produce json
// @Success 200 {object} Response "功能未配置"
// @Router /api/v1/auth/social/unbind [post]
func (h *AuthHandler) UnbindSocialAccount(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "social unbinding not configured"})
}

View File

@@ -32,7 +32,21 @@ func generateSecureToken(length int) string {
return hex.EncodeToString(bytes)[:length]
}
// UploadAvatar handles avatar file upload
// UploadAvatar 上传用户头像
// @Summary 上传用户头像
// @Description 上传并更新用户头像(仅本人或管理员)
// @Tags 用户头像
// @Accept multipart/form-data
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param avatar formData file true "头像文件最大5MB支持jpg/jpeg/png/gif/webp"
// @Success 200 {object} Response{data=AvatarResponse} "上传成功"
// @Failure 400 {object} Response "文件无效或大小超限"
// @Failure 401 {object} Response "未认证"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id}/avatar [post]
func (h *AvatarHandler) UploadAvatar(c *gin.Context) {
userIDStr := c.Param("id")
userID, err := strconv.ParseInt(userIDStr, 10, 64)

View File

@@ -18,6 +18,13 @@ func NewCaptchaHandler(captchaService *service.CaptchaService) *CaptchaHandler {
return &CaptchaHandler{captchaService: captchaService}
}
// GenerateCaptcha 生成验证码
// @Summary 生成验证码
// @Description 生成图形验证码
// @Tags 验证码
// @Produce json
// @Success 200 {object} Response{data=CaptchaResponse} "验证码信息"
// @Router /api/v1/captcha/generate [get]
func (h *CaptchaHandler) GenerateCaptcha(c *gin.Context) {
result, err := h.captchaService.Generate(c.Request.Context())
if err != nil {
@@ -35,10 +42,28 @@ func (h *CaptchaHandler) GenerateCaptcha(c *gin.Context) {
})
}
// GetCaptchaImage 获取验证码图片
// @Summary 获取验证码图片
// @Description 根据captcha_id获取验证码图片当前未实现
// @Tags 验证码
// @Produce json
// @Param captcha_id query string false "验证码ID"
// @Success 200 {object} Response "验证码图片"
// @Router /api/v1/captcha/image [get]
func (h *CaptchaHandler) GetCaptchaImage(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success"})
}
// VerifyCaptcha 验证验证码
// @Summary 验证验证码
// @Description 验证用户输入的验证码是否正确
// @Tags 验证码
// @Accept json
// @Produce json
// @Param request body VerifyCaptchaRequest true "验证码信息"
// @Success 200 {object} Response{data=VerifyResponse} "验证成功"
// @Failure 400 {object} Response "验证码无效"
// @Router /api/v1/captcha/verify [post]
func (h *CaptchaHandler) VerifyCaptcha(c *gin.Context) {
var req struct {
CaptchaID string `json:"captcha_id" binding:"required"`

View File

@@ -20,6 +20,17 @@ func NewCustomFieldHandler(customFieldService *service.CustomFieldService) *Cust
}
// CreateField 创建自定义字段
// @Summary 创建自定义字段
// @Description 创建新的自定义字段定义(仅管理员)
// @Tags 自定义字段
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateFieldRequest true "字段定义"
// @Success 201 {object} Response{data=domain.CustomField} "创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/fields [post]
func (h *CustomFieldHandler) CreateField(c *gin.Context) {
var req service.CreateFieldRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -41,6 +52,19 @@ func (h *CustomFieldHandler) CreateField(c *gin.Context) {
}
// UpdateField 更新自定义字段
// @Summary 更新自定义字段
// @Description 更新自定义字段定义(仅管理员)
// @Tags 自定义字段
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "字段ID"
// @Param request body service.UpdateFieldRequest true "更新信息"
// @Success 200 {object} Response{data=domain.CustomField} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "字段不存在"
// @Router /api/v1/fields/{id} [put]
func (h *CustomFieldHandler) UpdateField(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -68,6 +92,16 @@ func (h *CustomFieldHandler) UpdateField(c *gin.Context) {
}
// DeleteField 删除自定义字段
// @Summary 删除自定义字段
// @Description 删除自定义字段定义(仅管理员)
// @Tags 自定义字段
// @Produce json
// @Security BearerAuth
// @Param id path int true "字段ID"
// @Success 200 {object} Response "删除成功"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "字段不存在"
// @Router /api/v1/fields/{id} [delete]
func (h *CustomFieldHandler) DeleteField(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -87,6 +121,15 @@ func (h *CustomFieldHandler) DeleteField(c *gin.Context) {
}
// GetField 获取自定义字段
// @Summary 获取自定义字段详情
// @Description 根据ID获取自定义字段定义
// @Tags 自定义字段
// @Produce json
// @Security BearerAuth
// @Param id path int true "字段ID"
// @Success 200 {object} Response{data=domain.CustomField} "字段信息"
// @Failure 404 {object} Response "字段不存在"
// @Router /api/v1/fields/{id} [get]
func (h *CustomFieldHandler) GetField(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -108,6 +151,13 @@ func (h *CustomFieldHandler) GetField(c *gin.Context) {
}
// ListFields 获取所有自定义字段
// @Summary 获取自定义字段列表
// @Description 获取所有自定义字段定义列表
// @Tags 自定义字段
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.CustomField} "字段列表"
// @Router /api/v1/fields [get]
func (h *CustomFieldHandler) ListFields(c *gin.Context) {
fields, err := h.customFieldService.ListFields(c.Request.Context())
if err != nil {
@@ -123,6 +173,17 @@ func (h *CustomFieldHandler) ListFields(c *gin.Context) {
}
// SetUserFieldValues 设置用户自定义字段值
// @Summary 设置用户自定义字段值
// @Description 设置当前用户的自定义字段值
// @Tags 自定义字段
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body SetUserFieldValuesRequest true "字段值"
// @Success 200 {object} Response "设置成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/users/me/fields [put]
func (h *CustomFieldHandler) SetUserFieldValues(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -151,6 +212,14 @@ func (h *CustomFieldHandler) SetUserFieldValues(c *gin.Context) {
}
// GetUserFieldValues 获取用户自定义字段值
// @Summary 获取用户自定义字段值
// @Description 获取当前用户的自定义字段值
// @Tags 自定义字段
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=map} "字段值"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/users/me/fields [get]
func (h *CustomFieldHandler) GetUserFieldValues(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {

View File

@@ -22,6 +22,17 @@ func NewDeviceHandler(deviceService *service.DeviceService) *DeviceHandler {
return &DeviceHandler{deviceService: deviceService}
}
// CreateDevice 创建设备
// @Summary 创建设备记录
// @Description 当前用户创建设备记录
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateDeviceRequest true "设备信息"
// @Success 201 {object} Response{data=domain.Device} "设备创建成功"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices [post]
func (h *DeviceHandler) CreateDevice(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -48,6 +59,17 @@ func (h *DeviceHandler) CreateDevice(c *gin.Context) {
})
}
// GetMyDevices 获取我的设备列表
// @Summary 获取当前用户的设备列表
// @Description 获取当前用户的所有设备记录
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices [get]
func (h *DeviceHandler) GetMyDevices(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -76,6 +98,16 @@ func (h *DeviceHandler) GetMyDevices(c *gin.Context) {
})
}
// GetDevice 获取设备详情
// @Summary 获取设备详情
// @Description 根据ID获取设备详细信息
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response{data=domain.Device} "设备信息"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [get]
func (h *DeviceHandler) GetDevice(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -96,6 +128,19 @@ func (h *DeviceHandler) GetDevice(c *gin.Context) {
})
}
// UpdateDevice 更新设备
// @Summary 更新设备信息
// @Description 更新设备的基本信息
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body service.UpdateDeviceRequest true "更新信息"
// @Success 200 {object} Response{data=domain.Device} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [put]
func (h *DeviceHandler) UpdateDevice(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -122,6 +167,16 @@ func (h *DeviceHandler) UpdateDevice(c *gin.Context) {
})
}
// DeleteDevice 删除设备
// @Summary 删除设备
// @Description 删除设备记录
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response "删除成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id} [delete]
func (h *DeviceHandler) DeleteDevice(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -140,6 +195,19 @@ func (h *DeviceHandler) DeleteDevice(c *gin.Context) {
})
}
// UpdateDeviceStatus 更新设备状态
// @Summary 更新设备状态
// @Description 更新设备状态active/inactive
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body UpdateDeviceStatusRequest true "状态信息"
// @Success 200 {object} Response "状态更新成功"
// @Failure 400 {object} Response "无效的状态值"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/status [put]
func (h *DeviceHandler) UpdateDeviceStatus(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -178,6 +246,18 @@ func (h *DeviceHandler) UpdateDeviceStatus(c *gin.Context) {
})
}
// GetUserDevices 获取指定用户的设备列表
// @Summary 获取用户设备列表
// @Description 获取指定用户的设备列表(仅本人或管理员)
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/{id}/devices [get]
func (h *DeviceHandler) GetUserDevices(c *gin.Context) {
// IDOR 修复:检查当前用户是否有权限查看指定用户的设备
currentUserID, ok := getUserIDFromContext(c)
@@ -232,7 +312,19 @@ func (h *DeviceHandler) GetUserDevices(c *gin.Context) {
})
}
// GetAllDevices 获取所有设备列表(管理员)
// GetAllDevices 获取所有设备列表
// @Summary 获取所有设备列表
// @Description 获取所有设备列表(仅管理员),支持游标分页和偏移分页
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param cursor query string false "游标分页游标"
// @Param size query int false "每页数量(游标模式)"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=DeviceListResponse} "设备列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/admin/devices [get]
func (h *DeviceHandler) GetAllDevices(c *gin.Context) {
var req service.GetAllDevicesRequest
if err := c.ShouldBindQuery(&req); err != nil {
@@ -280,6 +372,17 @@ type TrustDeviceRequest struct {
}
// TrustDevice 设置设备为信任设备
// @Summary 设置设备为信任设备
// @Description 将指定设备设置为信任设备,在信任期内免二次验证
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Param request body TrustDeviceRequest true "信任配置"
// @Success 200 {object} Response "设置成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/trust [post]
func (h *DeviceHandler) TrustDevice(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -307,7 +410,18 @@ func (h *DeviceHandler) TrustDevice(c *gin.Context) {
})
}
// TrustDeviceByDeviceID 根据设备标识字符串设置设备为信任状态
// TrustDeviceByDeviceID 根据设备标识设置设备为信任状态
// @Summary 根据设备标识设置信任
// @Description 根据设备唯一标识字符串设置设备为信任状态
// @Tags 设备管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param deviceId path string true "设备唯一标识"
// @Param request body TrustDeviceRequest true "信任配置"
// @Success 200 {object} Response "设置成功"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/trust/{deviceId} [post]
func (h *DeviceHandler) TrustDeviceByDeviceID(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -342,6 +456,15 @@ func (h *DeviceHandler) TrustDeviceByDeviceID(c *gin.Context) {
}
// UntrustDevice 取消设备信任状态
// @Summary 取消设备信任
// @Description 取消设备的信任状态
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "设备ID"
// @Success 200 {object} Response "取消成功"
// @Failure 404 {object} Response "设备不存在"
// @Router /api/v1/devices/{id}/trust [delete]
func (h *DeviceHandler) UntrustDevice(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -361,6 +484,14 @@ func (h *DeviceHandler) UntrustDevice(c *gin.Context) {
}
// GetMyTrustedDevices 获取我的信任设备列表
// @Summary 获取信任设备列表
// @Description 获取当前用户的信任设备列表
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Device} "信任设备列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/trusted [get]
func (h *DeviceHandler) GetMyTrustedDevices(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -382,6 +513,16 @@ func (h *DeviceHandler) GetMyTrustedDevices(c *gin.Context) {
}
// LogoutAllOtherDevices 登出所有其他设备
// @Summary 登出其他设备
// @Description 登出当前用户除指定设备外的所有其他设备
// @Tags 设备管理
// @Produce json
// @Security BearerAuth
// @Param X-Device-ID header string true "当前设备ID"
// @Success 200 {object} Response "登出成功"
// @Failure 400 {object} Response "无效的设备ID"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/devices/logout-others [post]
func (h *DeviceHandler) LogoutAllOtherDevices(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {

View File

@@ -24,6 +24,17 @@ func NewLogHandler(loginLogService *service.LoginLogService, operationLogService
}
}
// GetMyLoginLogs 获取我的登录日志
// @Summary 获取登录日志
// @Description 获取当前用户的登录日志
// @Tags 日志
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=LoginLogListResponse} "登录日志列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/users/me/login-logs [get]
func (h *LogHandler) GetMyLoginLogs(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -52,6 +63,17 @@ func (h *LogHandler) GetMyLoginLogs(c *gin.Context) {
})
}
// GetMyOperationLogs 获取我的操作日志
// @Summary 获取操作日志
// @Description 获取当前用户的操作日志
// @Tags 日志
// @Produce json
// @Security BearerAuth
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=OperationLogListResponse} "操作日志列表"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/users/me/operation-logs [get]
func (h *LogHandler) GetMyOperationLogs(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {
@@ -80,6 +102,19 @@ func (h *LogHandler) GetMyOperationLogs(c *gin.Context) {
})
}
// GetLoginLogs 获取登录日志列表
// @Summary 获取登录日志列表
// @Description 获取所有登录日志(仅管理员),支持游标分页和偏移分页
// @Tags 日志
// @Produce json
// @Security BearerAuth
// @Param cursor query string false "游标分页游标"
// @Param size query int false "每页数量(游标模式)"
// @Param page query int false "页码"
// @Param page_size query int false "每页数量"
// @Success 200 {object} Response{data=LoginLogListResponse} "登录日志列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/admin/logs/login [get]
func (h *LogHandler) GetLoginLogs(c *gin.Context) {
var req service.ListLoginLogRequest
if err := c.ShouldBindQuery(&req); err != nil {

View File

@@ -27,6 +27,16 @@ func NewPasswordResetHandlerWithSMS(passwordResetService *service.PasswordResetS
}
}
// ForgotPassword 忘记密码
// @Summary 忘记密码
// @Description 请求密码重置邮件
// @Tags 密码重置
// @Accept json
// @Produce json
// @Param request body ForgotPasswordRequest true "邮箱地址"
// @Success 200 {object} Response "密码重置邮件已发送"
// @Failure 400 {object} Response "请求参数错误"
// @Router /api/v1/auth/password/forgot [post]
func (h *PasswordResetHandler) ForgotPassword(c *gin.Context) {
var req struct {
Email string `json:"email" binding:"required"`

View File

@@ -20,6 +20,18 @@ func NewPermissionHandler(permissionService *service.PermissionService) *Permiss
return &PermissionHandler{permissionService: permissionService}
}
// CreatePermission 创建权限
// @Summary 创建权限
// @Description 创建新的权限定义(仅管理员)
// @Tags 权限管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreatePermissionRequest true "权限信息"
// @Success 201 {object} Response{data=domain.Permission} "创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/permissions [post]
func (h *PermissionHandler) CreatePermission(c *gin.Context) {
var req service.CreatePermissionRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -40,6 +52,14 @@ func (h *PermissionHandler) CreatePermission(c *gin.Context) {
})
}
// ListPermissions 获取权限列表
// @Summary 获取权限列表
// @Description 获取系统权限列表
// @Tags 权限管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Permission} "权限列表"
// @Router /api/v1/permissions [get]
func (h *PermissionHandler) ListPermissions(c *gin.Context) {
var req service.ListPermissionRequest
if err := c.ShouldBindQuery(&req); err != nil {
@@ -60,6 +80,16 @@ func (h *PermissionHandler) ListPermissions(c *gin.Context) {
})
}
// GetPermission 获取权限详情
// @Summary 获取权限详情
// @Description 根据ID获取权限详细信息
// @Tags 权限管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "权限ID"
// @Success 200 {object} Response{data=domain.Permission} "权限信息"
// @Failure 404 {object} Response "权限不存在"
// @Router /api/v1/permissions/{id} [get]
func (h *PermissionHandler) GetPermission(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -80,6 +110,20 @@ func (h *PermissionHandler) GetPermission(c *gin.Context) {
})
}
// UpdatePermission 更新权限
// @Summary 更新权限
// @Description 更新权限信息(仅管理员)
// @Tags 权限管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "权限ID"
// @Param request body service.UpdatePermissionRequest true "更新信息"
// @Success 200 {object} Response{data=domain.Permission} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "权限不存在"
// @Router /api/v1/permissions/{id} [put]
func (h *PermissionHandler) UpdatePermission(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -106,6 +150,17 @@ func (h *PermissionHandler) UpdatePermission(c *gin.Context) {
})
}
// DeletePermission 删除权限
// @Summary 删除权限
// @Description 删除权限定义(仅管理员)
// @Tags 权限管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "权限ID"
// @Success 200 {object} Response "删除成功"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "权限不存在"
// @Router /api/v1/permissions/{id} [delete]
func (h *PermissionHandler) DeletePermission(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -124,6 +179,20 @@ func (h *PermissionHandler) DeletePermission(c *gin.Context) {
})
}
// UpdatePermissionStatus 更新权限状态
// @Summary 更新权限状态
// @Description 更新权限状态enabled/disabled仅管理员
// @Tags 权限管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "权限ID"
// @Param request body UpdatePermissionStatusRequest true "状态信息"
// @Success 200 {object} Response "状态更新成功"
// @Failure 400 {object} Response "无效的状态值"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "权限不存在"
// @Router /api/v1/permissions/{id}/status [put]
func (h *PermissionHandler) UpdatePermissionStatus(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -162,6 +231,14 @@ func (h *PermissionHandler) UpdatePermissionStatus(c *gin.Context) {
})
}
// GetPermissionTree 获取权限树
// @Summary 获取权限树
// @Description 获取系统权限的树形结构
// @Tags 权限管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]domain.Permission} "权限树"
// @Router /api/v1/permissions/tree [get]
func (h *PermissionHandler) GetPermissionTree(c *gin.Context) {
tree, err := h.permissionService.GetPermissionTree(c.Request.Context())
if err != nil {

View File

@@ -20,6 +20,18 @@ func NewRoleHandler(roleService *service.RoleService) *RoleHandler {
return &RoleHandler{roleService: roleService}
}
// CreateRole 创建角色
// @Summary 创建角色
// @Description 创建新角色(仅管理员)
// @Tags 角色管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.CreateRoleRequest true "角色信息"
// @Success 201 {object} Response{data=domain.Role} "角色创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/roles [post]
func (h *RoleHandler) CreateRole(c *gin.Context) {
var req service.CreateRoleRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -40,6 +52,14 @@ func (h *RoleHandler) CreateRole(c *gin.Context) {
})
}
// ListRoles 获取角色列表
// @Summary 获取角色列表
// @Description 获取系统角色列表
// @Tags 角色管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=RoleListResponse} "角色列表"
// @Router /api/v1/roles [get]
func (h *RoleHandler) ListRoles(c *gin.Context) {
var req service.ListRoleRequest
if err := c.ShouldBindQuery(&req); err != nil {
@@ -63,6 +83,16 @@ func (h *RoleHandler) ListRoles(c *gin.Context) {
})
}
// GetRole 获取角色详情
// @Summary 获取角色详情
// @Description 根据ID获取角色详细信息
// @Tags 角色管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Success 200 {object} Response{data=domain.Role} "角色信息"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id} [get]
func (h *RoleHandler) GetRole(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -83,6 +113,20 @@ func (h *RoleHandler) GetRole(c *gin.Context) {
})
}
// UpdateRole 更新角色
// @Summary 更新角色
// @Description 更新角色信息(仅管理员)
// @Tags 角色管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Param request body service.UpdateRoleRequest true "更新信息"
// @Success 200 {object} Response{data=domain.Role} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id} [put]
func (h *RoleHandler) UpdateRole(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -109,6 +153,17 @@ func (h *RoleHandler) UpdateRole(c *gin.Context) {
})
}
// DeleteRole 删除角色
// @Summary 删除角色
// @Description 删除角色(仅管理员)
// @Tags 角色管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Success 200 {object} Response "删除成功"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id} [delete]
func (h *RoleHandler) DeleteRole(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -127,6 +182,20 @@ func (h *RoleHandler) DeleteRole(c *gin.Context) {
})
}
// UpdateRoleStatus 更新角色状态
// @Summary 更新角色状态
// @Description 更新角色状态enabled/disabled仅管理员
// @Tags 角色管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Param request body UpdateRoleStatusRequest true "状态信息"
// @Success 200 {object} Response "状态更新成功"
// @Failure 400 {object} Response "无效的状态值"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id}/status [put]
func (h *RoleHandler) UpdateRoleStatus(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -166,6 +235,16 @@ func (h *RoleHandler) UpdateRoleStatus(c *gin.Context) {
})
}
// GetRolePermissions 获取角色权限
// @Summary 获取角色权限列表
// @Description 获取角色的权限列表
// @Tags 角色管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Success 200 {object} Response{data=[]domain.Permission} "权限列表"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id}/permissions [get]
func (h *RoleHandler) GetRolePermissions(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -186,6 +265,20 @@ func (h *RoleHandler) GetRolePermissions(c *gin.Context) {
})
}
// AssignPermissions 分配角色权限
// @Summary 分配角色权限
// @Description 为角色分配权限(替换现有权限)(仅管理员)
// @Tags 角色管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "角色ID"
// @Param request body AssignPermissionsRequest true "权限ID列表"
// @Success 200 {object} Response "权限分配成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "角色不存在"
// @Router /api/v1/roles/{id}/permissions [post]
func (h *RoleHandler) AssignPermissions(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {

View File

@@ -18,6 +18,16 @@ func NewStatsHandler(statsService *service.StatsService) *StatsHandler {
return &StatsHandler{statsService: statsService}
}
// GetDashboard 获取仪表盘统计
// @Summary 获取仪表盘统计
// @Description 获取系统仪表盘统计数据(仅管理员)
// @Tags 统计
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=service.DashboardStats} "仪表盘数据"
// @Failure 403 {object} Response "无权限"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/admin/stats/dashboard [get]
func (h *StatsHandler) GetDashboard(c *gin.Context) {
stats, err := h.statsService.GetDashboardStats(c.Request.Context())
if err != nil {
@@ -27,6 +37,16 @@ func (h *StatsHandler) GetDashboard(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": stats})
}
// GetUserStats 获取用户统计
// @Summary 获取用户统计
// @Description 获取用户统计数据(仅管理员)
// @Tags 统计
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=service.UserStats} "用户统计数据"
// @Failure 403 {object} Response "无权限"
// @Failure 500 {object} Response "服务器错误"
// @Router /api/v1/admin/stats/users [get]
func (h *StatsHandler) GetUserStats(c *gin.Context) {
stats, err := h.statsService.GetUserStats(c.Request.Context())
if err != nil {

View File

@@ -22,6 +22,15 @@ func NewTOTPHandler(authService *service.AuthService, totpService *service.TOTPS
}
}
// GetTOTPStatus 获取TOTP状态
// @Summary 获取TOTP状态
// @Description 获取当前用户的TOTP两步验证状态
// @Tags 两步验证
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=TOTPStatusResponse} "TOTP状态"
// @Failure 401 {object} Response "未认证"
// @Router /api/v1/auth/totp/status [get]
func (h *TOTPHandler) GetTOTPStatus(c *gin.Context) {
userID, ok := getUserIDFromContext(c)
if !ok {

View File

@@ -21,6 +21,19 @@ func NewUserHandler(userService *service.UserService) *UserHandler {
return &UserHandler{userService: userService}
}
// CreateUser 创建用户
// @Summary 创建用户
// @Description 创建新用户账号(仅管理员)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body CreateUserRequest true "用户信息"
// @Success 201 {object} Response{data=UserResponse} "用户创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 401 {object} Response "未认证"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users [post]
func (h *UserHandler) CreateUser(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required"`
@@ -62,6 +75,18 @@ func (h *UserHandler) CreateUser(c *gin.Context) {
})
}
// ListUsers 获取用户列表
// @Summary 获取用户列表
// @Description 获取用户列表,支持游标分页和偏移分页
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Param cursor query string false "游标分页游标"
// @Param size query int false "每页大小"
// @Param offset query int false "偏移分页偏移量"
// @Param limit query int false "每页大小"
// @Success 200 {object} Response{data=UserListResponse} "用户列表"
// @Router /api/v1/users [get]
func (h *UserHandler) ListUsers(c *gin.Context) {
cursor := c.Query("cursor")
sizeStr := c.DefaultQuery("size", "")
@@ -113,6 +138,16 @@ func (h *UserHandler) ListUsers(c *gin.Context) {
})
}
// GetUser 获取用户详情
// @Summary 获取用户详情
// @Description 根据ID获取用户详细信息
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Success 200 {object} Response{data=UserResponse} "用户信息"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id} [get]
func (h *UserHandler) GetUser(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -129,6 +164,20 @@ func (h *UserHandler) GetUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": toUserResponse(user)})
}
// UpdateUser 更新用户
// @Summary 更新用户信息
// @Description 更新用户的基本信息(仅管理员或本人)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param request body UpdateUserRequest true "更新信息"
// @Success 200 {object} Response{data=UserResponse} "更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id} [put]
func (h *UserHandler) UpdateUser(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -167,6 +216,17 @@ func (h *UserHandler) UpdateUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": toUserResponse(user)})
}
// DeleteUser 删除用户
// @Summary 删除用户
// @Description 删除用户账号(仅管理员)
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Success 200 {object} Response "删除成功"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id} [delete]
func (h *UserHandler) DeleteUser(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -182,6 +242,20 @@ func (h *UserHandler) DeleteUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success"})
}
// UpdatePassword 修改密码
// @Summary 修改用户密码
// @Description 修改用户密码(仅管理员或本人)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param request body UpdatePasswordRequest true "密码信息"
// @Success 200 {object} Response "密码修改成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id}/password [put]
func (h *UserHandler) UpdatePassword(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -207,6 +281,20 @@ func (h *UserHandler) UpdatePassword(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "密码修改成功"})
}
// UpdateUserStatus 更新用户状态
// @Summary 更新用户状态
// @Description 更新用户账号状态active/inactive/locked/disabled仅管理员
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param request body UpdateStatusRequest true "状态信息"
// @Success 200 {object} Response "状态更新成功"
// @Failure 400 {object} Response "无效的状态值"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id}/status [put]
func (h *UserHandler) UpdateUserStatus(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -246,6 +334,17 @@ func (h *UserHandler) UpdateUserStatus(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success"})
}
// GetUserRoles 获取用户角色
// @Summary 获取用户角色列表
// @Description 获取指定用户的角色列表(仅本人或管理员)
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Success 200 {object} Response{data=[]domain.Role} "角色列表"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id}/roles [get]
func (h *UserHandler) GetUserRoles(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -282,6 +381,20 @@ func (h *UserHandler) GetUserRoles(c *gin.Context) {
})
}
// AssignRoles 分配用户角色
// @Summary 分配用户角色
// @Description 为用户分配角色(替换现有角色)(仅管理员)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Param request body AssignRolesRequest true "角色ID列表"
// @Success 200 {object} Response "角色分配成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Failure 404 {object} Response "用户不存在"
// @Router /api/v1/users/{id}/roles [post]
func (h *UserHandler) AssignRoles(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
@@ -306,6 +419,18 @@ func (h *UserHandler) AssignRoles(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "角色分配成功"})
}
// BatchUpdateStatus 批量更新用户状态
// @Summary 批量更新用户状态
// @Description 批量更新多个用户的状态(仅管理员)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.BatchUpdateStatusRequest true "批量更新请求"
// @Success 200 {object} Response "批量更新成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/batch/status [put]
func (h *UserHandler) BatchUpdateStatus(c *gin.Context) {
var req service.BatchUpdateStatusRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -322,6 +447,18 @@ func (h *UserHandler) BatchUpdateStatus(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "更新成功", "data": gin.H{"count": count}})
}
// BatchDelete 批量删除用户
// @Summary 批量删除用户
// @Description 批量删除多个用户(仅管理员)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body service.BatchDeleteRequest true "批量删除请求"
// @Success 200 {object} Response "批量删除成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/batch [delete]
func (h *UserHandler) BatchDelete(c *gin.Context) {
var req service.BatchDeleteRequest
if err := c.ShouldBindJSON(&req); err != nil {
@@ -338,6 +475,15 @@ func (h *UserHandler) BatchDelete(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "删除成功", "data": gin.H{"count": count}})
}
// ListAdmins 获取管理员列表
// @Summary 获取管理员列表
// @Description 获取所有管理员用户列表(仅管理员)
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Success 200 {object} Response{data=[]UserResponse} "管理员列表"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/admins [get]
func (h *UserHandler) ListAdmins(c *gin.Context) {
admins, err := h.userService.ListAdmins(c.Request.Context())
if err != nil {
@@ -353,6 +499,18 @@ func (h *UserHandler) ListAdmins(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "success", "data": adminResponses})
}
// CreateAdmin 创建管理员
// @Summary 创建管理员
// @Description 创建新管理员账号(仅管理员)
// @Tags 用户管理
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body CreateAdminRequest true "管理员信息"
// @Success 201 {object} Response{data=UserResponse} "管理员创建成功"
// @Failure 400 {object} Response "请求参数错误"
// @Failure 403 {object} Response "无权限"
// @Router /api/v1/users/admins [post]
func (h *UserHandler) CreateAdmin(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required"`
@@ -382,6 +540,18 @@ func (h *UserHandler) CreateAdmin(c *gin.Context) {
c.JSON(http.StatusCreated, gin.H{"code": 0, "message": "管理员创建成功", "data": toUserResponse(admin)})
}
// DeleteAdmin 删除管理员
// @Summary 删除管理员
// @Description 删除管理员角色(最后管理员保护、自删保护)(仅管理员)
// @Tags 用户管理
// @Produce json
// @Security BearerAuth
// @Param id path int true "用户ID"
// @Success 200 {object} Response "管理员已移除"
// @Failure 400 {object} Response "无效的用户ID"
// @Failure 403 {object} Response "无权限"
// @Failure 409 {object} Response "无法删除(最后管理员或自删)"
// @Router /api/v1/users/admins/{id} [delete]
func (h *UserHandler) DeleteAdmin(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {