Files
backend/internal/handler/group_handler.go

1802 lines
43 KiB
Go
Raw Permalink Normal View History

package handler
import (
"log"
"strconv"
"github.com/gin-gonic/gin"
"carrot_bbs/internal/dto"
"carrot_bbs/internal/model"
"carrot_bbs/internal/pkg/response"
"carrot_bbs/internal/service"
)
// GroupHandler 群组处理器
type GroupHandler struct {
groupService service.GroupService
userService *service.UserService
}
// NewGroupHandler 创建群组处理器
func NewGroupHandler(groupService service.GroupService, userService *service.UserService) *GroupHandler {
return &GroupHandler{
groupService: groupService,
userService: userService,
}
}
// parseUserID 从上下文获取用户IDUUID格式
func parseUserID(c *gin.Context) string {
return c.GetString("user_id")
}
// parseGroupID 从路径参数获取群组ID
func parseGroupID(c *gin.Context) string {
return c.Param("id")
}
// parseUserIDFromPath 从路径参数获取用户IDUUID格式
func parseUserIDFromPath(c *gin.Context) string {
return c.Param("userId")
}
// parseAnnouncementID 从路径参数获取公告ID
func parseAnnouncementID(c *gin.Context) string {
return c.Param("announcementId")
}
// ==================== 群组管理 ====================
// CreateGroup 创建群组
// POST /api/groups
func (h *GroupHandler) CreateGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var req dto.CreateGroupRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
group, err := h.groupService.CreateGroup(userID, req.Name, req.Description, req.MemberIDs)
if err != nil {
response.InternalServerError(c, err.Error())
return
}
response.Success(c, dto.GroupToResponse(group))
}
// GetGroup 获取群组详情
// GET /api/groups/:id
func (h *GroupHandler) GetGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
group, err := h.groupService.GetGroupByID(groupID)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 实时计算群成员数量
memberCount, _ := h.groupService.GetMemberCount(groupID)
// 创建响应并设置实时计算的member_count
resp := dto.GroupToResponse(group)
resp.MemberCount = memberCount
response.Success(c, resp)
}
// UpdateGroup 更新群组信息
// PUT /api/groups/:id
func (h *GroupHandler) UpdateGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.UpdateGroupRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
updates := make(map[string]interface{})
if req.Name != "" {
updates["name"] = req.Name
}
if req.Description != "" {
updates["description"] = req.Description
}
if req.Avatar != "" {
updates["avatar"] = req.Avatar
}
if err := h.groupService.UpdateGroup(userID, groupID, updates); err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "没有权限修改群组信息")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取更新后的群组信息
group, _ := h.groupService.GetGroupByID(groupID)
response.Success(c, dto.GroupToResponse(group))
}
// DissolveGroup 解散群组
// DELETE /api/groups/:id
func (h *GroupHandler) DissolveGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
if err := h.groupService.DissolveGroup(userID, groupID); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以解散群组")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "群组已解散", nil)
}
// TransferOwner 转让群主
// POST /api/groups/:id/transfer
func (h *GroupHandler) TransferOwner(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.TransferOwnerRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.TransferOwner(userID, groupID, req.NewOwnerID); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以转让群主")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "新群主必须是群成员")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "群主已转让", nil)
}
// GetUserGroups 获取用户的群组列表
// GET /api/groups
func (h *GroupHandler) GetUserGroups(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
groups, total, err := h.groupService.GetUserGroups(userID, page, pageSize)
if err != nil {
response.InternalServerError(c, err.Error())
return
}
response.Paginated(c, dto.GroupsToResponse(groups), total, page, pageSize)
}
// ==================== 成员管理 ====================
// InviteMembers 邀请成员加入群组
// POST /api/groups/:id/members/invite
func (h *GroupHandler) InviteMembers(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.InviteMembersRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.InviteMembers(userID, groupID, req.MemberIDs); err != nil {
if err == service.ErrNotGroupMember {
response.Forbidden(c, "只有群成员可以邀请他人")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrGroupFull {
response.BadRequest(c, "群已满")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "邀请成功", nil)
}
// JoinGroup 加入群组
// POST /api/groups/:id/join
func (h *GroupHandler) JoinGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
if err := h.groupService.JoinGroup(userID, groupID); err != nil {
if err == service.ErrCannotJoin {
response.Forbidden(c, "该群不允许加入")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrAlreadyMember {
response.BadRequest(c, "已经是群成员")
return
}
if err == service.ErrGroupFull {
response.BadRequest(c, "群已满")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "加入成功", nil)
}
// LeaveGroup 退出群组
// POST /api/groups/:id/leave
func (h *GroupHandler) LeaveGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
if err := h.groupService.LeaveGroup(userID, groupID); err != nil {
if err == service.ErrNotGroupMember {
response.BadRequest(c, "不是群成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "已退出群组", nil)
}
// RemoveMember 移除群成员
// DELETE /api/groups/:id/members/:userId
func (h *GroupHandler) RemoveMember(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
targetUserID := parseUserIDFromPath(c)
if targetUserID == "" {
response.BadRequest(c, "invalid user id")
return
}
if err := h.groupService.RemoveMember(userID, groupID, targetUserID); err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以移除成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
if err == service.ErrCannotRemoveOwner {
response.Forbidden(c, "不能移除群主")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "已移除成员", nil)
}
// GetMembers 获取群成员列表
// GET /api/groups/:id/members
func (h *GroupHandler) GetMembers(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50"))
members, total, err := h.groupService.GetMembers(groupID, page, pageSize)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 转换为响应格式,并预加载用户信息
result := make([]*dto.GroupMemberResponse, 0, len(members))
for _, member := range members {
memberResp := dto.GroupMemberToResponse(&member)
// 预加载用户信息
user, _ := h.userService.GetUserByID(c.Request.Context(), member.UserID)
if user != nil {
memberResp.User = dto.ConvertUserToResponse(user)
}
result = append(result, memberResp)
}
response.Paginated(c, result, total, page, pageSize)
}
// ==================== RESTful Action 端点 ====================
// HandleCreateGroup 创建群组
// POST /api/v1/groups/create
func (h *GroupHandler) HandleCreateGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.CreateGroupParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
group, err := h.groupService.CreateGroup(userID, params.Name, params.Description, params.MemberIDs)
if err != nil {
response.InternalServerError(c, err.Error())
return
}
response.Success(c, dto.GroupToResponse(group))
}
// HandleGetUserGroups 获取用户群组列表
// GET /api/v1/groups/list
func (h *GroupHandler) HandleGetUserGroups(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
groups, total, err := h.groupService.GetUserGroups(userID, page, pageSize)
if err != nil {
response.InternalServerError(c, err.Error())
return
}
response.Paginated(c, dto.GroupsToResponse(groups), total, page, pageSize)
}
// HandleGetMyMemberInfo 获取我在群组中的成员信息
// GET /api/v1/groups/get_my_info?group_id=xxx
func (h *GroupHandler) HandleGetMyMemberInfo(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := c.Query("group_id")
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
}
// 获取群组信息
group, err := h.groupService.GetGroupByID(groupID)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取当前用户的成员信息
member, err := h.groupService.GetMember(groupID, userID)
if err != nil {
response.NotFound(c, "不是群成员")
return
}
// 构建响应
memberResp := dto.GroupMemberToResponse(member)
// 预加载用户信息
user, _ := h.userService.GetUserByID(c.Request.Context(), userID)
if user != nil {
memberResp.User = dto.ConvertUserToResponse(user)
}
// 添加群组禁言状态信息
response.Success(c, map[string]interface{}{
"member": memberResp,
"mute_all": group.MuteAll,
"is_muted": member.Muted || group.MuteAll,
"can_speak": !member.Muted && !group.MuteAll,
})
}
// HandleDissolveGroup 解散群组
// POST /api/v1/groups/dissolve
func (h *GroupHandler) HandleDissolveGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.DissolveGroupParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if err := h.groupService.DissolveGroup(userID, params.GroupID); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以解散群组")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "群组已解散", nil)
}
// HandleTransferOwner 转让群主
// POST /api/v1/groups/transfer
func (h *GroupHandler) HandleTransferOwner(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.TransferOwnerParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.NewOwnerID == "" {
response.BadRequest(c, "new_owner_id is required")
return
}
if err := h.groupService.TransferOwner(userID, params.GroupID, params.NewOwnerID); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以转让群主")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "新群主必须是群成员")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "群主已转让", nil)
}
// HandleInviteMembers 邀请成员加入群组
// POST /api/v1/groups/invite_members
func (h *GroupHandler) HandleInviteMembers(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.InviteMembersParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if err := h.groupService.InviteMembers(userID, params.GroupID, params.MemberIDs); err != nil {
if err == service.ErrNotGroupMember {
response.Forbidden(c, "只有群成员可以邀请他人")
return
}
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以邀请他人")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNoEligibleInvitee {
response.BadRequest(c, "暂无可邀请对象(需互相关注且未在群内)")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "邀请请求已处理", nil)
}
// HandleJoinGroup 加入群组
// POST /api/v1/groups/join
func (h *GroupHandler) HandleJoinGroup(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.JoinGroupParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if err := h.groupService.JoinGroup(userID, params.GroupID); err != nil {
if err == service.ErrJoinRequestPending {
response.SuccessWithMessage(c, "申请已提交,等待群主/管理员审批", nil)
return
}
if err == service.ErrCannotJoin {
response.Forbidden(c, "该群不允许加入")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrAlreadyMember {
response.BadRequest(c, "已经是群成员")
return
}
if err == service.ErrGroupFull {
response.BadRequest(c, "群已满")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "加入成功", nil)
}
// HandleSetNickname 设置群内昵称
// POST /api/v1/groups/set_nickname
func (h *GroupHandler) HandleSetNickname(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetNicknameParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if err := h.groupService.SetMemberNickname(userID, params.GroupID, params.Nickname); err != nil {
if err == service.ErrNotGroupMember {
response.BadRequest(c, "不是群成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "昵称已更新", nil)
}
// HandleSetJoinType 设置加群方式
// POST /api/v1/groups/set_join_type
func (h *GroupHandler) HandleSetJoinType(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetJoinTypeParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if err := h.groupService.SetJoinType(userID, params.GroupID, params.JoinType); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置加群方式")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
joinTypeStr := "允许任何人加入"
switch params.JoinType {
case int(model.JoinTypeApproval):
joinTypeStr = "需要审批"
case int(model.JoinTypeForbidden):
joinTypeStr = "不允许加入"
}
response.SuccessWithMessage(c, "加群方式已更新为: "+joinTypeStr, nil)
}
// HandleCreateAnnouncement 创建群公告
// POST /api/v1/groups/create_announcement
func (h *GroupHandler) HandleCreateAnnouncement(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.CreateAnnouncementParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
announcement, err := h.groupService.CreateAnnouncement(userID, params.GroupID, params.Content)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以发布公告")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.Success(c, dto.GroupAnnouncementToResponse(announcement))
}
// HandleGetAnnouncements 获取群公告列表
// GET /api/v1/groups/get_announcements?group_id=xxx
func (h *GroupHandler) HandleGetAnnouncements(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := c.Query("group_id")
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
announcements, total, err := h.groupService.GetAnnouncements(groupID, page, pageSize)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.Paginated(c, dto.GroupAnnouncementsToResponse(announcements), total, page, pageSize)
}
// HandleDeleteAnnouncement 删除群公告
// POST /api/v1/groups/delete_announcement
func (h *GroupHandler) HandleDeleteAnnouncement(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.DeleteAnnouncementParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.AnnouncementID == "" {
response.BadRequest(c, "announcement_id is required")
return
}
if err := h.groupService.DeleteAnnouncement(userID, params.AnnouncementID); err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以删除公告")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "公告已删除", nil)
}
// GetMyMemberInfo 获取当前用户在群组中的成员信息
// GET /api/groups/:id/me
func (h *GroupHandler) GetMyMemberInfo(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
// 获取群组信息
group, err := h.groupService.GetGroupByID(groupID)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取当前用户的成员信息
member, err := h.groupService.GetMember(groupID, userID)
if err != nil {
response.NotFound(c, "不是群成员")
return
}
// 构建响应
memberResp := dto.GroupMemberToResponse(member)
// 预加载用户信息
user, _ := h.userService.GetUserByID(c.Request.Context(), userID)
if user != nil {
memberResp.User = dto.ConvertUserToResponse(user)
}
// 添加群组禁言状态信息
response.Success(c, map[string]interface{}{
"member": memberResp,
"mute_all": group.MuteAll,
"is_muted": member.Muted || group.MuteAll,
"can_speak": !member.Muted && !group.MuteAll,
})
}
// SetMemberRole 设置成员角色
// PUT /api/groups/:id/members/:userId/role
func (h *GroupHandler) SetMemberRole(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
targetUserID := parseUserIDFromPath(c)
if targetUserID == "" {
response.BadRequest(c, "invalid user id")
return
}
var req dto.SetRoleRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.SetMemberRole(userID, groupID, targetUserID, req.Role); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置成员角色")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "角色已更新", nil)
}
// SetNickname 设置群内昵称
// PUT /api/groups/:id/nickname
func (h *GroupHandler) SetNickname(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.SetNicknameRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.SetMemberNickname(userID, groupID, req.Nickname); err != nil {
if err == service.ErrNotGroupMember {
response.BadRequest(c, "不是群成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "昵称已更新", nil)
}
// MuteMember 禁言/解禁成员
// PUT /api/groups/:id/members/:userId/mute
func (h *GroupHandler) MuteMember(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
targetUserID := parseUserIDFromPath(c)
if targetUserID == "" {
response.BadRequest(c, "invalid user id")
return
}
var req dto.MuteMemberRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.MuteMember(userID, groupID, targetUserID, req.Muted); err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以禁言成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
if err == service.ErrCannotMuteOwner {
response.Forbidden(c, "不能禁言群主")
return
}
response.InternalServerError(c, err.Error())
return
}
if req.Muted {
response.SuccessWithMessage(c, "已禁言该成员", nil)
} else {
response.SuccessWithMessage(c, "已解除禁言", nil)
}
}
// ==================== 群设置 ====================
// SetMuteAll 设置全员禁言
// PUT /api/groups/:id/mute-all
func (h *GroupHandler) SetMuteAll(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.SetMuteAllRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.SetMuteAll(userID, groupID, req.MuteAll); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置全员禁言")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
if req.MuteAll {
response.SuccessWithMessage(c, "已开启全员禁言", nil)
} else {
response.SuccessWithMessage(c, "已关闭全员禁言", nil)
}
}
// SetJoinType 设置加群方式
// PUT /api/groups/:id/join-type
func (h *GroupHandler) SetJoinType(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.SetJoinTypeRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
if err := h.groupService.SetJoinType(userID, groupID, req.JoinType); err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置加群方式")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
joinTypeStr := "允许任何人加入"
switch req.JoinType {
case int(model.JoinTypeApproval):
joinTypeStr = "需要审批"
case int(model.JoinTypeForbidden):
joinTypeStr = "不允许加入"
}
response.SuccessWithMessage(c, "加群方式已更新为: "+joinTypeStr, nil)
}
// ==================== 群公告 ====================
// CreateAnnouncement 创建群公告
// POST /api/groups/:id/announcements
func (h *GroupHandler) CreateAnnouncement(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
var req dto.CreateAnnouncementRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, err.Error())
return
}
announcement, err := h.groupService.CreateAnnouncement(userID, groupID, req.Content)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以发布公告")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.Success(c, dto.GroupAnnouncementToResponse(announcement))
}
// GetAnnouncements 获取群公告列表
// GET /api/groups/:id/announcements
func (h *GroupHandler) GetAnnouncements(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
announcements, total, err := h.groupService.GetAnnouncements(groupID, page, pageSize)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.Paginated(c, dto.GroupAnnouncementsToResponse(announcements), total, page, pageSize)
}
// DeleteAnnouncement 删除群公告
// DELETE /api/groups/:id/announcements/:announcementId
func (h *GroupHandler) DeleteAnnouncement(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := parseGroupID(c)
if groupID == "" {
response.BadRequest(c, "invalid group id")
return
}
announcementID := parseAnnouncementID(c)
if announcementID == "" {
response.BadRequest(c, "invalid announcement id")
return
}
if err := h.groupService.DeleteAnnouncement(userID, announcementID); err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以删除公告")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "公告已删除", nil)
}
// ==================== RESTful Action 端点 ====================
// HandleSetGroupKick 群组踢人
// POST /api/v1/groups/set_group_kick
func (h *GroupHandler) HandleSetGroupKick(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupKickParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.UserID == "" {
response.BadRequest(c, "user_id is required")
return
}
// 使用 RemoveMember 方法
err := h.groupService.RemoveMember(userID, params.GroupID, params.UserID)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以移除成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
if err == service.ErrCannotRemoveOwner {
response.Forbidden(c, "不能移除群主")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "已移除成员", nil)
}
// HandleSetGroupBan 群组单人禁言
// POST /api/v1/groups/set_group_ban
func (h *GroupHandler) HandleSetGroupBan(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupBanParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.UserID == "" {
response.BadRequest(c, "user_id is required")
return
}
// duration > 0 或 duration = -1 表示禁言duration = 0 表示解除禁言
muted := params.Duration != 0
log.Printf("[HandleSetGroupBan] 开始禁言操作: userID=%s, groupID=%s, targetUserID=%s, duration=%d, muted=%v", userID, params.GroupID, params.UserID, params.Duration, muted)
err := h.groupService.MuteMember(userID, params.GroupID, params.UserID, muted)
if err != nil {
log.Printf("[HandleSetGroupBan] 禁言操作失败: %v", err)
} else {
log.Printf("[HandleSetGroupBan] 禁言操作成功")
}
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "只有群主或管理员可以禁言成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
if err == service.ErrCannotMuteOwner {
response.Forbidden(c, "不能禁言群主")
return
}
response.InternalServerError(c, err.Error())
return
}
if muted {
response.SuccessWithMessage(c, "已禁言该成员", nil)
} else {
response.SuccessWithMessage(c, "已解除禁言", nil)
}
}
// HandleSetGroupWholeBan 群组全员禁言
// POST /api/v1/groups/set_group_whole_ban
func (h *GroupHandler) HandleSetGroupWholeBan(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupWholeBanParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
err := h.groupService.SetMuteAll(userID, params.GroupID, params.Enable)
if err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置全员禁言")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
if params.Enable {
response.SuccessWithMessage(c, "已开启全员禁言", nil)
} else {
response.SuccessWithMessage(c, "已关闭全员禁言", nil)
}
}
// HandleSetGroupAdmin 群组设置管理员
// POST /api/v1/groups/set_group_admin
func (h *GroupHandler) HandleSetGroupAdmin(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupAdminParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.UserID == "" {
response.BadRequest(c, "user_id is required")
return
}
// 根据 enable 参数设置角色
role := model.GroupRoleMember
if params.Enable {
role = model.GroupRoleAdmin
}
err := h.groupService.SetMemberRole(userID, params.GroupID, params.UserID, role)
if err != nil {
if err == service.ErrNotGroupOwner {
response.Forbidden(c, "只有群主可以设置管理员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
if err == service.ErrNotGroupMember {
response.BadRequest(c, "该用户不是群成员")
return
}
response.InternalServerError(c, err.Error())
return
}
if params.Enable {
response.SuccessWithMessage(c, "已设置为管理员", nil)
} else {
response.SuccessWithMessage(c, "已取消管理员", nil)
}
}
// HandleSetGroupName 设置群名
// POST /api/v1/groups/set_group_name
func (h *GroupHandler) HandleSetGroupName(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupNameParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.GroupName == "" {
response.BadRequest(c, "group_name is required")
return
}
updates := map[string]interface{}{
"name": params.GroupName,
}
err := h.groupService.UpdateGroup(userID, params.GroupID, updates)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "没有权限修改群组信息")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取更新后的群组信息
group, _ := h.groupService.GetGroupByID(params.GroupID)
response.Success(c, dto.GroupToResponse(group))
}
// HandleSetGroupAvatar 设置群头像
// POST /api/v1/groups/set_group_avatar
func (h *GroupHandler) HandleSetGroupAvatar(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupAvatarParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
if params.Avatar == "" {
response.BadRequest(c, "avatar is required")
return
}
updates := map[string]interface{}{
"avatar": params.Avatar,
}
err := h.groupService.UpdateGroup(userID, params.GroupID, updates)
if err != nil {
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "没有权限修改群组信息")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 获取更新后的群组信息
group, _ := h.groupService.GetGroupByID(params.GroupID)
response.Success(c, dto.GroupToResponse(group))
}
// HandleSetGroupLeave 退出群组
// POST /api/v1/groups/set_group_leave
func (h *GroupHandler) HandleSetGroupLeave(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupLeaveParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.GroupID == "" {
response.BadRequest(c, "group_id is required")
return
}
err := h.groupService.LeaveGroup(userID, params.GroupID)
if err != nil {
if err == service.ErrNotGroupMember {
response.BadRequest(c, "不是群成员")
return
}
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
response.SuccessWithMessage(c, "已退出群组", nil)
}
// HandleSetGroupAddRequest 处理加群审批
// POST /api/v1/groups/set_group_add_request
func (h *GroupHandler) HandleSetGroupAddRequest(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupAddRequestParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.Flag == "" {
response.BadRequest(c, "flag is required")
return
}
if err := h.groupService.SetGroupAddRequest(userID, params.Flag, params.Approve, params.Reason); err != nil {
if err == service.ErrGroupRequestNotFound {
response.NotFound(c, "加群申请不存在")
return
}
if err == service.ErrGroupRequestHandled {
response.BadRequest(c, "该加群申请已处理")
return
}
if err == service.ErrNotGroupAdmin {
response.Forbidden(c, "仅群主或管理员可审批")
return
}
if err == service.ErrGroupFull {
response.BadRequest(c, "群已满")
return
}
response.InternalServerError(c, err.Error())
return
}
if params.Approve {
response.SuccessWithMessage(c, "已同意加群申请", nil)
return
}
response.SuccessWithMessage(c, "已拒绝加群申请", nil)
}
// HandleRespondInvite 处理群邀请响应
// POST /api/v1/groups/respond_invite
func (h *GroupHandler) HandleRespondInvite(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
var params dto.SetGroupAddRequestParams
if err := c.ShouldBindJSON(&params); err != nil {
response.BadRequest(c, err.Error())
return
}
if params.Flag == "" {
response.BadRequest(c, "flag is required")
return
}
if err := h.groupService.RespondInvite(userID, params.Flag, params.Approve, params.Reason); err != nil {
if err == service.ErrGroupRequestNotFound {
response.NotFound(c, "邀请不存在")
return
}
if err == service.ErrGroupRequestHandled {
response.BadRequest(c, "邀请已处理")
return
}
if err == service.ErrNotRequestTarget {
response.Forbidden(c, "无权处理该邀请")
return
}
if err == service.ErrGroupFull {
response.BadRequest(c, "群已满")
return
}
response.InternalServerError(c, err.Error())
return
}
if params.Approve {
response.SuccessWithMessage(c, "已接受邀请", nil)
return
}
response.SuccessWithMessage(c, "已拒绝邀请", nil)
}
// HandleGetGroupInfo 获取群信息
// GET /api/v1/groups/get?group_id=xxx
func (h *GroupHandler) HandleGetGroupInfo(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := c.Query("group_id")
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
}
group, err := h.groupService.GetGroupByID(groupID)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 实时计算群成员数量
memberCount, _ := h.groupService.GetMemberCount(groupID)
// 创建响应并设置实时计算的member_count
resp := dto.GroupToResponse(group)
resp.MemberCount = memberCount
response.Success(c, resp)
}
// HandleGetGroupMemberList 获取群成员列表
// GET /api/v1/groups/get_members?group_id=xxx
func (h *GroupHandler) HandleGetGroupMemberList(c *gin.Context) {
userID := parseUserID(c)
if userID == "" {
response.Unauthorized(c, "")
return
}
groupID := c.Query("group_id")
if groupID == "" {
response.BadRequest(c, "group_id is required")
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "50"))
members, total, err := h.groupService.GetMembers(groupID, page, pageSize)
if err != nil {
if err == service.ErrGroupNotFound {
response.NotFound(c, "群组不存在")
return
}
response.InternalServerError(c, err.Error())
return
}
// 转换为响应格式,并预加载用户信息
result := make([]*dto.GroupMemberResponse, 0, len(members))
for _, member := range members {
memberResp := dto.GroupMemberToResponse(&member)
// 预加载用户信息
user, _ := h.userService.GetUserByID(c.Request.Context(), member.UserID)
if user != nil {
memberResp.User = dto.ConvertUserToResponse(user)
}
result = append(result, memberResp)
}
response.Paginated(c, result, total, page, pageSize)
}