v2版本
This commit is contained in:
153
internal/api/attachment_handler.go
Normal file
153
internal/api/attachment_handler.go
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:附件管理相关API处理器
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* UploadAttachmentHandler
|
||||
* 功能:上传附件
|
||||
* 路径:POST /api/attachments/upload
|
||||
*/
|
||||
func UploadAttachmentHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
// 获取文件
|
||||
file, err := c.FormFile("file")
|
||||
if err != nil {
|
||||
utils.BadRequest(c, "文件上传失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 获取文件类型
|
||||
fileType := c.PostForm("type")
|
||||
if fileType == "" {
|
||||
// 根据文件扩展名推断类型
|
||||
ext := file.Filename[len(file.Filename)-4:]
|
||||
if ext == ".jpg" || ext == ".png" || ext == ".gif" || ext == "webp" || ext == "jpeg" {
|
||||
fileType = "image"
|
||||
} else {
|
||||
fileType = "video"
|
||||
}
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
if fileType != "image" && fileType != "video" {
|
||||
utils.BadRequest(c, "文件类型必须是image或video")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证文件大小
|
||||
if fileType == "image" && file.Size > model.MaxImageSize {
|
||||
utils.BadRequest(c, "图片大小不能超过10MB")
|
||||
return
|
||||
}
|
||||
if fileType == "video" && file.Size > model.MaxVideoSize {
|
||||
utils.BadRequest(c, "视频大小不能超过500MB")
|
||||
return
|
||||
}
|
||||
|
||||
// 打开文件
|
||||
src, err := file.Open()
|
||||
if err != nil {
|
||||
utils.BadRequest(c, "打开文件失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
// 上传文件
|
||||
attachment, err := service.AttachmentSvc.UploadFile(
|
||||
userID.(string),
|
||||
file.Filename,
|
||||
fileType,
|
||||
file.Size,
|
||||
src,
|
||||
)
|
||||
if err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, attachment, "上传成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetAttachmentHandler
|
||||
* 功能:获取附件信息
|
||||
* 路径:GET /api/attachments/:id
|
||||
*/
|
||||
func GetAttachmentHandler(c *gin.Context) {
|
||||
attachmentID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
attachment, err := service.AttachmentSvc.GetAttachment(uint(attachmentID))
|
||||
if err != nil {
|
||||
utils.NotFound(c, "附件不存在")
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, attachment, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteAttachmentHandler
|
||||
* 功能:删除附件(仅上传者可删除)
|
||||
* 路径:DELETE /api/attachments/:id
|
||||
*/
|
||||
func DeleteAttachmentHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
attachmentID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
if err := service.AttachmentSvc.DeleteAttachment(uint(attachmentID), userID.(string)); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "附件已删除")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetAttachmentsHandler
|
||||
* 功能:获取附件列表
|
||||
* 路径:GET /api/attachments
|
||||
*/
|
||||
func GetAttachmentsHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
fileType := c.Query("type")
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
attachments, total, err := service.AttachmentSvc.GetUserAttachments(userID.(string), fileType, page, pageSize)
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if attachments == nil {
|
||||
attachments = []model.Attachment{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"data": attachments,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"size": pageSize,
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
225
internal/api/auth_handler.go
Normal file
225
internal/api/auth_handler.go
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:认证相关API处理器
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* LoginHandler
|
||||
* 功能:用户登录
|
||||
* 路径:POST /api/login
|
||||
*/
|
||||
func LoginHandler(c *gin.Context) {
|
||||
var req model.LoginReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 获取客户端IP
|
||||
ip := getClientIP(c)
|
||||
|
||||
// 调用认证服务登录
|
||||
user, err := service.AuthSvc.Login(req.Account, req.Password)
|
||||
if err != nil {
|
||||
// 记录登录失败日志
|
||||
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
|
||||
utils.Unauthorized(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 生成Token
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
// 记录登录失败日志
|
||||
service.LoginLogSvc.LogLogin(req.Account, "0", ip, false)
|
||||
utils.InternalError(c, "生成Token失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 清除密码字段
|
||||
user.Password = ""
|
||||
|
||||
// 记录登录成功日志
|
||||
service.LoginLogSvc.LogLogin(req.Account, user.ID, ip, true)
|
||||
|
||||
utils.SuccessWithData(c, model.LoginResponse{
|
||||
Token: token,
|
||||
User: *user,
|
||||
}, "登录成功")
|
||||
}
|
||||
|
||||
// getClientIP 获取客户端IP
|
||||
func getClientIP(c *gin.Context) string {
|
||||
// 优先从X-Forwarded-For获取
|
||||
ip := c.GetHeader("X-Forwarded-For")
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
// 从X-Real-IP获取
|
||||
ip = c.GetHeader("X-Real-IP")
|
||||
if ip != "" {
|
||||
return ip
|
||||
}
|
||||
|
||||
// 从RemoteAddr获取
|
||||
return c.ClientIP()
|
||||
}
|
||||
|
||||
/**
|
||||
* RegisterHandler
|
||||
* 功能:用户注册
|
||||
* 路径:POST /api/register
|
||||
*/
|
||||
func RegisterHandler(c *gin.Context) {
|
||||
var req model.RegisterReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果提供了验证码,验证验证码
|
||||
if req.Code != "" {
|
||||
// 根据邮箱或手机号确定类型
|
||||
codeType := "email"
|
||||
if len(req.Phone) > 0 {
|
||||
codeType = "sms"
|
||||
}
|
||||
target := req.Email
|
||||
if codeType == "sms" {
|
||||
target = req.Phone
|
||||
}
|
||||
|
||||
valid, err := service.AuthSvc.VerifyCode(target, req.Code, codeType)
|
||||
if err != nil || !valid {
|
||||
utils.BadRequest(c, "验证码无效或已过期")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 调用认证服务注册
|
||||
user, err := service.AuthSvc.Register(&req)
|
||||
if err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 生成Token
|
||||
token, err := utils.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
utils.InternalError(c, "生成Token失败")
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, model.RegisterResponse{
|
||||
Token: token,
|
||||
User: *user,
|
||||
}, "注册成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* LogoutHandler
|
||||
* 功能:用户登出(可选,前端清除token)
|
||||
* 路径:POST /api/logout
|
||||
*/
|
||||
func LogoutHandler(c *gin.Context) {
|
||||
// 登出主要是前端清除token,后端可以记录日志或清除session
|
||||
utils.Success(c, "登出成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* CheckTokenHandler
|
||||
* 功能:检查Token有效性
|
||||
* 路径:GET /api/check-token
|
||||
*/
|
||||
func CheckTokenHandler(c *gin.Context) {
|
||||
token := c.GetHeader("Authorization")
|
||||
if token == "" {
|
||||
utils.Unauthorized(c, "缺少Token")
|
||||
return
|
||||
}
|
||||
|
||||
// 移除 "Bearer " 前缀(如果存在)
|
||||
if len(token) > 7 && token[:7] == "Bearer " {
|
||||
token = token[7:]
|
||||
}
|
||||
|
||||
userID, err := utils.ValidateToken(token)
|
||||
if err != nil {
|
||||
utils.Unauthorized(c, "Token无效或已过期")
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"status": "valid",
|
||||
"user_id": userID,
|
||||
}, "Token有效")
|
||||
}
|
||||
|
||||
/**
|
||||
* SendEmailCodeHandler
|
||||
* 功能:发送邮箱验证码
|
||||
* 路径:POST /api/send-email-code
|
||||
*/
|
||||
func SendEmailCodeHandler(c *gin.Context) {
|
||||
var req model.SendCodeReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.Type != "email" {
|
||||
utils.BadRequest(c, "类型必须是email")
|
||||
return
|
||||
}
|
||||
|
||||
code, err := service.AuthSvc.SendEmailCode(req.Target)
|
||||
if err != nil {
|
||||
utils.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 开发环境返回验证码,生产环境不应返回
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"code": code, // 仅开发环境,生产环境应移除
|
||||
}, "验证码已发送")
|
||||
}
|
||||
|
||||
/**
|
||||
* SendSmsCodeHandler
|
||||
* 功能:发送短信验证码
|
||||
* 路径:POST /api/send-sms-code
|
||||
*/
|
||||
func SendSmsCodeHandler(c *gin.Context) {
|
||||
var req model.SendCodeReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if req.Type != "sms" {
|
||||
utils.BadRequest(c, "类型必须是sms")
|
||||
return
|
||||
}
|
||||
|
||||
code, err := service.AuthSvc.SendSmsCode(req.Target)
|
||||
if err != nil {
|
||||
utils.InternalError(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 开发环境返回验证码,生产环境不应返回
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"code": code, // 仅开发环境,生产环境应移除
|
||||
}, "验证码已发送")
|
||||
}
|
||||
|
||||
362
internal/api/contact_handler.go
Normal file
362
internal/api/contact_handler.go
Normal file
@@ -0,0 +1,362 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:联系人管理相关API处理器
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* ContactListHandler
|
||||
* 功能:获取联系人列表(已存在,需改为从数据库查询)
|
||||
* 路径:GET /api/contacts
|
||||
*/
|
||||
func ContactListHandler(c *gin.Context) {
|
||||
// 从Context获取用户ID(由JWT中间件注入)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
// 如果没有认证,返回空列表(兼容旧代码)
|
||||
utils.SuccessWithData(c, []interface{}{}, "获取成功")
|
||||
return
|
||||
}
|
||||
|
||||
contacts, err := service.ContactSvc.GetContactsWithUserInfo(userID.(string))
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if contacts == nil {
|
||||
contacts = []map[string]interface{}{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, contacts, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* SearchUsersHandler
|
||||
* 功能:搜索用户
|
||||
* 路径:GET /api/contacts/search
|
||||
*/
|
||||
func SearchUsersHandler(c *gin.Context) {
|
||||
keyword := c.Query("keyword")
|
||||
if keyword == "" {
|
||||
utils.BadRequest(c, "搜索关键词不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))
|
||||
if limit < 1 || limit > 100 {
|
||||
limit = 20
|
||||
}
|
||||
|
||||
users, err := service.ContactSvc.SearchUsers(keyword, limit)
|
||||
if err != nil {
|
||||
utils.InternalError(c, "搜索失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if users == nil {
|
||||
users = []model.User{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, users, "搜索成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* AddFriendHandler
|
||||
* 功能:添加好友(发送申请)
|
||||
* 路径:POST /api/contacts/add-friend
|
||||
*/
|
||||
func AddFriendHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
var req struct {
|
||||
ToUserID string `json:"to_user_id" binding:"required"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.AddFriend(userID.(string), req.ToUserID, req.Message); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "好友申请已发送")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFriendRequestsHandler
|
||||
* 功能:获取好友申请列表
|
||||
* 路径:GET /api/contacts/friend-requests
|
||||
*/
|
||||
func GetFriendRequestsHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
requests, err := service.ContactSvc.GetFriendRequests(userID.(string))
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if requests == nil {
|
||||
requests = []model.FriendRequest{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, requests, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* AcceptFriendRequestHandler
|
||||
* 功能:接受好友申请
|
||||
* 路径:POST /api/contacts/accept-request
|
||||
*/
|
||||
func AcceptFriendRequestHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
var req struct {
|
||||
RequestID uint `json:"request_id" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.AcceptFriendRequest(req.RequestID, userID.(string)); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "已接受好友申请")
|
||||
}
|
||||
|
||||
/**
|
||||
* RejectFriendRequestHandler
|
||||
* 功能:拒绝好友申请
|
||||
* 路径:POST /api/contacts/reject-request
|
||||
*/
|
||||
func RejectFriendRequestHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
var req struct {
|
||||
RequestID uint `json:"request_id" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.RejectFriendRequest(req.RequestID, userID.(string)); err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "已拒绝好友申请")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetGroupsHandler
|
||||
* 功能:获取分组列表
|
||||
* 路径:GET /api/contacts/groups
|
||||
*/
|
||||
func GetGroupsHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
groups, err := service.ContactSvc.GetGroups(userID.(string))
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if groups == nil {
|
||||
groups = []model.ContactGroup{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, groups, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateGroupHandler
|
||||
* 功能:创建分组
|
||||
* 路径:POST /api/contacts/groups
|
||||
*/
|
||||
func CreateGroupHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
var req struct {
|
||||
GroupName string `json:"group_name" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
group, err := service.ContactSvc.CreateGroup(userID.(string), req.GroupName)
|
||||
if err != nil {
|
||||
utils.BadRequest(c, "创建失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, group, "创建成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateGroupHandler
|
||||
* 功能:更新分组
|
||||
* 路径:PUT /api/contacts/groups/:id
|
||||
*/
|
||||
func UpdateGroupHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
groupID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
var req struct {
|
||||
GroupName string `json:"group_name"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := make(map[string]interface{})
|
||||
if req.GroupName != "" {
|
||||
updates["group_name"] = req.GroupName
|
||||
}
|
||||
if req.SortOrder > 0 {
|
||||
updates["sort_order"] = req.SortOrder
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.UpdateGroup(uint(groupID), userID.(string), updates); err != nil {
|
||||
utils.BadRequest(c, "更新失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "更新成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteGroupHandler
|
||||
* 功能:删除分组
|
||||
* 路径:DELETE /api/contacts/groups/:id
|
||||
*/
|
||||
func DeleteGroupHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
groupID, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
if err := service.ContactSvc.DeleteGroup(uint(groupID), userID.(string)); err != nil {
|
||||
utils.BadRequest(c, "删除失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "删除成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetContactDetailHandler
|
||||
* 功能:获取好友详情
|
||||
* 路径:GET /api/contacts/:id
|
||||
*/
|
||||
func GetContactDetailHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
contactID := c.Param("id")
|
||||
|
||||
contact, err := service.ContactSvc.GetContactDetail(userID.(string), contactID)
|
||||
if err != nil {
|
||||
utils.NotFound(c, "好友不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取联系人用户信息
|
||||
user, err := service.UserSvc.GetUserByID(contactID)
|
||||
if err != nil {
|
||||
utils.NotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"contact": contact,
|
||||
"user": user,
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, result, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateContactHandler
|
||||
* 功能:更新好友信息
|
||||
* 路径:PUT /api/contacts/:id
|
||||
*/
|
||||
func UpdateContactHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
contactID := c.Param("id")
|
||||
|
||||
var req struct {
|
||||
RemarkName string `json:"remark_name"`
|
||||
GroupID uint `json:"group_id"`
|
||||
IsTop *bool `json:"is_top"`
|
||||
IsMuted *bool `json:"is_muted"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
updates := make(map[string]interface{})
|
||||
if req.RemarkName != "" {
|
||||
updates["remark_name"] = req.RemarkName
|
||||
}
|
||||
if req.GroupID > 0 {
|
||||
updates["group_id"] = req.GroupID
|
||||
}
|
||||
if req.IsTop != nil {
|
||||
updates["is_top"] = *req.IsTop
|
||||
}
|
||||
if req.IsMuted != nil {
|
||||
updates["is_muted"] = *req.IsMuted
|
||||
}
|
||||
|
||||
if err := service.ContactSvc.UpdateContact(userID.(string), contactID, updates); err != nil {
|
||||
utils.BadRequest(c, "更新失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "更新成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteContactHandler
|
||||
* 功能:删除好友
|
||||
* 路径:DELETE /api/contacts/:id
|
||||
*/
|
||||
func DeleteContactHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
contactID := c.Param("id")
|
||||
|
||||
if err := service.ContactSvc.DeleteContact(userID.(string), contactID); err != nil {
|
||||
utils.BadRequest(c, "删除失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "已删除好友")
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
"xk-websocket-v2/internal/manager"
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/turnserver"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/spf13/viper"
|
||||
@@ -33,7 +34,7 @@ func SendHandler(c *gin.Context) {
|
||||
var req model.SendMessageReq
|
||||
// 1. 绑定并校验 JSON 参数
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "无效的JSON参数"})
|
||||
utils.BadRequest(c, "无效的JSON参数")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ func SendHandler(c *gin.Context) {
|
||||
service.ChatSvc.HandleUserMessage(mockClient, &req)
|
||||
|
||||
// 6. 返回成功响应
|
||||
c.JSON(http.StatusOK, gin.H{"status": "ok"})
|
||||
utils.Success(c, "消息已发送")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,12 +90,12 @@ func SendToUserHandler(c *gin.Context) {
|
||||
func BindHandler(c *gin.Context) {
|
||||
var req model.BindReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
// 调用服务层进行绑定
|
||||
service.ChatSvc.BindUserByClientID(req.ClientID, req.UserID)
|
||||
c.JSON(http.StatusOK, gin.H{"status": "success"})
|
||||
utils.Success(c, "绑定成功")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,7 +107,7 @@ func CheckUserOnlineHandler(c *gin.Context) {
|
||||
userID := c.Query("user_id")
|
||||
// 调用服务层查询 Redis
|
||||
isOnline := service.ChatSvc.IsUserOnline(userID)
|
||||
c.JSON(http.StatusOK, gin.H{"status": "success", "result": isOnline})
|
||||
utils.SuccessWithData(c, gin.H{"is_online": isOnline}, "查询成功")
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -120,18 +121,52 @@ func CheckUserOnlineHandler(c *gin.Context) {
|
||||
*/
|
||||
func HistoryHandler(c *gin.Context) {
|
||||
roomID := c.Query("room_id")
|
||||
var msgs []model.ChatMessage
|
||||
|
||||
// 简单查询最近 50 条
|
||||
// 生产环境应添加 page, page_size 参数
|
||||
result := service.ChatSvc.DB.Where("room_id = ?", roomID).
|
||||
Order("created_at desc").Limit(50).Find(&msgs)
|
||||
|
||||
if result.Error != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "db error"})
|
||||
if roomID == "" {
|
||||
utils.BadRequest(c, "room_id参数必填")
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"data": msgs})
|
||||
|
||||
// 分页参数
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 50
|
||||
}
|
||||
|
||||
var msgs []model.ChatMessage
|
||||
var total int64
|
||||
|
||||
// 获取总数
|
||||
service.ChatSvc.DB.Model(&model.ChatMessage{}).Where("room_id = ?", roomID).Count(&total)
|
||||
|
||||
// 分页查询
|
||||
offset := (page - 1) * pageSize
|
||||
result := service.ChatSvc.DB.Where("room_id = ?", roomID).
|
||||
Order("created_at desc").
|
||||
Offset(offset).
|
||||
Limit(pageSize).
|
||||
Find(&msgs)
|
||||
|
||||
if result.Error != nil {
|
||||
utils.InternalError(c, "db error")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if msgs == nil {
|
||||
msgs = []model.ChatMessage{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"data": msgs,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"size": pageSize,
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,28 +178,6 @@ func SyncMessagesHandler(c *gin.Context) {
|
||||
HistoryHandler(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* ContactListHandler
|
||||
* 功能:获取联系人列表 (模拟数据)。
|
||||
* 路径:GET /api/contacts
|
||||
* 说明:用于前端展示登录后的好友列表。
|
||||
*/
|
||||
func ContactListHandler(c *gin.Context) {
|
||||
// 模拟 10 个用户数据
|
||||
users := []model.UserContact{
|
||||
{ID: "1001", Name: "张三 (我)", Avatar: "张", Desc: "Golang 专家"},
|
||||
{ID: "1002", Name: "李琦 (妻)", Avatar: "李", Desc: "在线"},
|
||||
{ID: "1003", Name: "王医生", Avatar: "医", Desc: "主任医师"},
|
||||
{ID: "1004", Name: "客服小蜜", Avatar: "客", Desc: "全天在线"},
|
||||
{ID: "1005", Name: "技术支持", Avatar: "技", Desc: "请重启试试"},
|
||||
{ID: "1006", Name: "财务小赵", Avatar: "财", Desc: "报销单请提交"},
|
||||
{ID: "1007", Name: "运维阿强", Avatar: "运", Desc: "服务器维护中"},
|
||||
{ID: "1008", Name: "测试小丽", Avatar: "测", Desc: "Bug 太多了"},
|
||||
{ID: "1009", Name: "HR", Avatar: "人", Desc: "本月考勤异常"},
|
||||
{ID: "1010", Name: "老板", Avatar: "老", Desc: "今晚开会"},
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"data": users})
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// 系统与 WebRTC 接口
|
||||
@@ -176,11 +189,11 @@ func ContactListHandler(c *gin.Context) {
|
||||
* 路径:GET /api/health
|
||||
*/
|
||||
func HealthHandler(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"status": "ok",
|
||||
"node": viper.GetString("app.node_id"),
|
||||
"time": time.Now().Format(time.RFC3339),
|
||||
})
|
||||
}, "服务正常")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,5 +218,5 @@ func ICEHandler(c *gin.Context) {
|
||||
Username: username,
|
||||
Credential: credential,
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"data": []model.ICEServerConfig{cfg}})
|
||||
utils.SuccessWithData(c, []model.ICEServerConfig{cfg}, "获取成功")
|
||||
}
|
||||
|
||||
71
internal/api/room_handler.go
Normal file
71
internal/api/room_handler.go
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:房间管理相关API处理器
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* CreateRoomHandler
|
||||
* 功能:创建房间
|
||||
* 路径:POST /api/rooms
|
||||
*/
|
||||
func CreateRoomHandler(c *gin.Context) {
|
||||
userID, _ := c.Get("user_id")
|
||||
|
||||
var req struct {
|
||||
RoomType string `json:"room_type" binding:"required,oneof=p2p group"`
|
||||
Members []string `json:"members" binding:"required"`
|
||||
RoomName string `json:"room_name"`
|
||||
RoomAvatar string `json:"room_avatar"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
room, err := service.RoomSvc.CreateRoom(req.RoomType, req.Members, userID.(string))
|
||||
if err != nil {
|
||||
utils.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 如果提供了房间名称和头像,更新
|
||||
if req.RoomName != "" || req.RoomAvatar != "" {
|
||||
updates := make(map[string]interface{})
|
||||
if req.RoomName != "" {
|
||||
updates["room_name"] = req.RoomName
|
||||
}
|
||||
if req.RoomAvatar != "" {
|
||||
updates["room_avatar"] = req.RoomAvatar
|
||||
}
|
||||
service.RoomSvc.DB.Model(room).Updates(updates)
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, room, "创建成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetRoomHandler
|
||||
* 功能:获取房间信息
|
||||
* 路径:GET /api/rooms/:id
|
||||
*/
|
||||
func GetRoomHandler(c *gin.Context) {
|
||||
roomID := c.Param("id")
|
||||
|
||||
room, err := service.RoomSvc.GetRoom(roomID)
|
||||
if err != nil {
|
||||
utils.NotFound(c, "房间不存在")
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, room, "获取成功")
|
||||
}
|
||||
|
||||
155
internal/api/user_handler.go
Normal file
155
internal/api/user_handler.go
Normal file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* package api
|
||||
* 作用:用户管理相关API处理器
|
||||
*/
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
"xk-websocket-v2/internal/model"
|
||||
"xk-websocket-v2/internal/service"
|
||||
"xk-websocket-v2/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
/**
|
||||
* GetMyInfoHandler
|
||||
* 功能:获取当前用户信息
|
||||
* 路径:GET /api/user/my-info
|
||||
* 需要:JWT认证
|
||||
*/
|
||||
func GetMyInfoHandler(c *gin.Context) {
|
||||
// 从Context获取用户ID(由JWT中间件注入)
|
||||
userID, exists := c.Get("user_id")
|
||||
if !exists {
|
||||
utils.Unauthorized(c, "未认证")
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.UserSvc.GetUserByID(userID.(string))
|
||||
if err != nil {
|
||||
utils.NotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, user, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* GetUserListHandler
|
||||
* 功能:获取用户列表
|
||||
* 路径:GET /api/user/list
|
||||
*/
|
||||
func GetUserListHandler(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 || pageSize > 100 {
|
||||
pageSize = 20
|
||||
}
|
||||
|
||||
users, total, err := service.UserSvc.GetUserList(page, pageSize)
|
||||
if err != nil {
|
||||
utils.InternalError(c, "查询失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 确保返回空数组而不是null
|
||||
if users == nil {
|
||||
users = []model.User{}
|
||||
}
|
||||
|
||||
utils.SuccessWithData(c, gin.H{
|
||||
"data": users,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"size": pageSize,
|
||||
}, "获取成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateUserHandler
|
||||
* 功能:创建用户(管理员)
|
||||
* 路径:POST /api/user/create
|
||||
*/
|
||||
func CreateUserHandler(c *gin.Context) {
|
||||
var user model.User
|
||||
if err := c.ShouldBindJSON(&user); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 生成用户ID
|
||||
user.ID = generateUserID()
|
||||
|
||||
if err := service.UserSvc.CreateUser(&user); err != nil {
|
||||
utils.BadRequest(c, "创建用户失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = "" // 清除密码
|
||||
utils.SuccessWithData(c, user, "创建成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateUserHandler
|
||||
* 功能:更新用户信息
|
||||
* 路径:POST /api/user/update
|
||||
*/
|
||||
func UpdateUserHandler(c *gin.Context) {
|
||||
var req struct {
|
||||
ID string `json:"id" binding:"required"`
|
||||
Updates map[string]interface{} `json:"updates" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.UserSvc.UpdateUser(req.ID, req.Updates); err != nil {
|
||||
utils.BadRequest(c, "更新失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "更新成功")
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteUserHandler
|
||||
* 功能:删除用户
|
||||
* 路径:POST /api/user/delete
|
||||
*/
|
||||
func DeleteUserHandler(c *gin.Context) {
|
||||
var req struct {
|
||||
ID string `json:"id" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
utils.BadRequest(c, "参数错误")
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.UserSvc.DeleteUser(req.ID); err != nil {
|
||||
utils.BadRequest(c, "删除失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
utils.Success(c, "删除成功")
|
||||
}
|
||||
|
||||
// 辅助函数:生成用户ID
|
||||
func generateUserID() string {
|
||||
// 使用时间戳+随机数生成用户ID
|
||||
timestamp := time.Now().UnixNano()
|
||||
random := rand.Intn(1000000)
|
||||
return fmt.Sprintf("user_%d_%d", timestamp, random)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user