423 lines
9.4 KiB
Go
423 lines
9.4 KiB
Go
/**
|
||
* 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"
|
||
"gorm.io/gorm"
|
||
)
|
||
|
||
/**
|
||
* 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, "获取成功")
|
||
}
|
||
|
||
/**
|
||
* CreateChatGroupHandler
|
||
* 功能:创建群聊
|
||
* 路径:POST /api/groups
|
||
*/
|
||
func CreateChatGroupHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
|
||
var req struct {
|
||
Name string `json:"name" binding:"required"`
|
||
Avatar string `json:"avatar"`
|
||
MemberIDs []string `json:"member_ids" binding:"required"`
|
||
AdminIDs []string `json:"admin_ids"`
|
||
}
|
||
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
creatorID := userID.(string)
|
||
members := req.MemberIDs
|
||
|
||
// 确保创建者在成员列表中
|
||
found := false
|
||
for _, id := range members {
|
||
if id == creatorID {
|
||
found = true
|
||
break
|
||
}
|
||
}
|
||
if !found {
|
||
members = append(members, creatorID)
|
||
}
|
||
|
||
room, err := service.RoomSvc.CreateGroupRoom(creatorID, members, req.Name, req.Avatar, req.AdminIDs)
|
||
if err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.SuccessWithData(c, room, "创建群聊成功")
|
||
}
|
||
|
||
/**
|
||
* GetGroupInfoHandler
|
||
* 功能:获取群聊基础信息及成员数量
|
||
* 路径:GET /api/groups/:room_id
|
||
*/
|
||
func GetGroupInfoHandler(c *gin.Context) {
|
||
roomID := c.Param("room_id")
|
||
|
||
room, err := service.RoomSvc.GetRoom(roomID)
|
||
if err != nil {
|
||
if err == gorm.ErrRecordNotFound {
|
||
utils.NotFound(c, "群聊不存在")
|
||
return
|
||
}
|
||
utils.InternalError(c, "查询失败")
|
||
return
|
||
}
|
||
|
||
members, err := service.RoomSvc.ListGroupMembers(roomID)
|
||
if err != nil {
|
||
utils.InternalError(c, "查询成员失败")
|
||
return
|
||
}
|
||
|
||
// 统计管理员ID
|
||
adminIDs := make([]string, 0)
|
||
for _, m := range members {
|
||
if m.Role == 1 {
|
||
adminIDs = append(adminIDs, m.UserID)
|
||
}
|
||
}
|
||
|
||
utils.SuccessWithData(c, gin.H{
|
||
"room": room,
|
||
"member_count": len(members),
|
||
"admin_ids": adminIDs,
|
||
"owner_id": room.OwnerID,
|
||
}, "获取成功")
|
||
}
|
||
|
||
/**
|
||
* ListGroupMembersHandler
|
||
* 功能:获取群成员列表
|
||
* 路径:GET /api/groups/:room_id/members
|
||
*/
|
||
func ListGroupMembersHandler(c *gin.Context) {
|
||
roomID := c.Param("room_id")
|
||
|
||
members, err := service.RoomSvc.ListGroupMembers(roomID)
|
||
if err != nil {
|
||
utils.InternalError(c, "查询失败")
|
||
return
|
||
}
|
||
|
||
utils.SuccessWithData(c, members, "获取成功")
|
||
}
|
||
|
||
/**
|
||
* AddGroupMembersHandler
|
||
* 功能:邀请/拉人入群
|
||
* 路径:POST /api/groups/:room_id/members
|
||
*/
|
||
func AddGroupMembersHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
|
||
var req struct {
|
||
MemberIDs []string `json:"member_ids" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
if err := service.RoomSvc.AddGroupMembers(roomID, userID.(string), req.MemberIDs); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "添加成员成功")
|
||
}
|
||
|
||
/**
|
||
* RemoveGroupMemberHandler
|
||
* 功能:移除群成员或退群
|
||
* 路径:POST /api/groups/:room_id/members/:user_id/remove
|
||
*/
|
||
func RemoveGroupMemberHandler(c *gin.Context) {
|
||
operatorID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
memberID := c.Param("user_id")
|
||
|
||
// 自己移除自己 = 退群
|
||
if operatorID.(string) == memberID {
|
||
if err := service.RoomSvc.QuitGroup(roomID, memberID); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
utils.Success(c, "已退出群聊")
|
||
return
|
||
}
|
||
|
||
// 否则为管理员/群主踢人
|
||
if err := service.RoomSvc.RemoveGroupMember(roomID, operatorID.(string), memberID); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "已移除成员")
|
||
}
|
||
|
||
/**
|
||
* UpdateGroupInfoHandler
|
||
* 功能:修改群名称/头像
|
||
* 路径:POST /api/groups/:room_id/update
|
||
*/
|
||
func UpdateGroupInfoHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
|
||
var req struct {
|
||
Name string `json:"name"`
|
||
Avatar string `json:"avatar"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
// 仅群主或管理员可修改群信息
|
||
ok, err := service.RoomSvc.IsGroupAdminOrOwner(roomID, userID.(string))
|
||
if err != nil {
|
||
utils.InternalError(c, "权限校验失败")
|
||
return
|
||
}
|
||
if !ok {
|
||
utils.Forbidden(c, "无权限修改群信息")
|
||
return
|
||
}
|
||
|
||
updates := make(map[string]interface{})
|
||
if req.Name != "" {
|
||
updates["room_name"] = req.Name
|
||
}
|
||
if req.Avatar != "" {
|
||
updates["room_avatar"] = req.Avatar
|
||
}
|
||
|
||
if len(updates) == 0 {
|
||
utils.BadRequest(c, "没有可更新的字段")
|
||
return
|
||
}
|
||
|
||
// 更新群基础信息
|
||
if err := service.RoomSvc.DB.Model(&model.ChatRoom{}).
|
||
Where("room_id = ?", roomID).
|
||
Updates(updates).Error; err != nil {
|
||
utils.InternalError(c, "更新失败")
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "更新成功")
|
||
}
|
||
|
||
/**
|
||
* ChangeMemberRoleHandler
|
||
* 功能:调整成员角色
|
||
* 路径:POST /api/groups/:room_id/members/:user_id/role
|
||
*/
|
||
func ChangeMemberRoleHandler(c *gin.Context) {
|
||
operatorID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
memberID := c.Param("user_id")
|
||
|
||
var req struct {
|
||
Role int8 `json:"role" binding:"required"`
|
||
}
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
utils.BadRequest(c, "参数错误: "+err.Error())
|
||
return
|
||
}
|
||
|
||
if err := service.RoomSvc.ChangeMemberRole(roomID, operatorID.(string), memberID, req.Role); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "角色已更新")
|
||
}
|
||
|
||
/**
|
||
* QuitGroupHandler
|
||
* 功能:群成员主动退出群聊
|
||
* 路径:POST /api/groups/:room_id/quit
|
||
*/
|
||
func QuitGroupHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
|
||
// 校验用户是否为该群的成员
|
||
members, err := service.RoomSvc.ListGroupMembers(roomID)
|
||
if err != nil {
|
||
utils.InternalError(c, "查询成员失败")
|
||
return
|
||
}
|
||
|
||
isMember := false
|
||
for _, m := range members {
|
||
if m.UserID == userID.(string) {
|
||
isMember = true
|
||
break
|
||
}
|
||
}
|
||
|
||
if !isMember {
|
||
utils.BadRequest(c, "您不是该群的成员")
|
||
return
|
||
}
|
||
|
||
// 调用服务层退出群聊
|
||
if err := service.RoomSvc.QuitGroup(roomID, userID.(string)); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "已退出群聊")
|
||
}
|
||
|
||
/**
|
||
* DissolveGroupHandler
|
||
* 功能:群主解散群聊
|
||
* 路径:POST /api/groups/:room_id/dissolve
|
||
*/
|
||
func DissolveGroupHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
roomID := c.Param("room_id")
|
||
|
||
// 调用服务层解散群聊
|
||
if err := service.RoomSvc.DissolveGroup(roomID, userID.(string)); err != nil {
|
||
utils.BadRequest(c, err.Error())
|
||
return
|
||
}
|
||
|
||
utils.Success(c, "群聊已解散")
|
||
}
|
||
|
||
/**
|
||
* GetGroupNotificationsHandler
|
||
* 功能:获取群通知列表
|
||
* 路径:GET /api/group-notifications
|
||
*/
|
||
func GetGroupNotificationsHandler(c *gin.Context) {
|
||
userID, _ := c.Get("user_id")
|
||
|
||
// 分页参数
|
||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||
isReadStr := c.Query("is_read")
|
||
|
||
if page < 1 {
|
||
page = 1
|
||
}
|
||
if pageSize < 1 || pageSize > 100 {
|
||
pageSize = 20
|
||
}
|
||
|
||
// 构建查询条件
|
||
query := service.ChatSvc.DB.Model(&model.ChatMessage{}).
|
||
Where("message_type = ?", model.MessageTypeGroupNotif).
|
||
Where("room_id IN (SELECT room_id FROM room_members WHERE user_id = ?)", userID)
|
||
|
||
// 可选:按已读状态过滤
|
||
if isReadStr == "true" || isReadStr == "false" {
|
||
// 注意:chat_messages 表可能没有 is_read 字段,这里先不实现
|
||
// 如果需要,可以在 extra 字段中存储或使用其他方式
|
||
}
|
||
|
||
// 获取总数
|
||
var total int64
|
||
query.Count(&total)
|
||
|
||
// 分页查询
|
||
offset := (page - 1) * pageSize
|
||
var messages []model.ChatMessage
|
||
if err := query.Order("created_at desc").
|
||
Offset(offset).
|
||
Limit(pageSize).
|
||
Find(&messages).Error; err != nil {
|
||
utils.InternalError(c, "查询失败")
|
||
return
|
||
}
|
||
|
||
// 确保返回空数组而不是null
|
||
if messages == nil {
|
||
messages = []model.ChatMessage{}
|
||
}
|
||
|
||
utils.SuccessWithData(c, gin.H{
|
||
"data": messages,
|
||
"total": total,
|
||
"page": page,
|
||
"page_size": pageSize,
|
||
}, "获取成功")
|
||
}
|