// Code generated by hertz generator. package space import ( "allapp/biz/router/middleware" "allapp/db" "allapp/db/repo" "allapp/utils" "allapp/utils/errorx" "allapp/utils/idgen" "allapp/utils/redisx" "allapp/utils/response" "context" space "allapp/biz/model/space" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/protocol/consts" ) // KickOutUser 踢出某人 // @router /space/kick [POST] func KickOutUser(ctx context.Context, c *app.RequestContext) { var req space.KickOutUserParams if err := c.BindAndValidate(&req); err != nil { c.String(consts.StatusBadRequest, err.Error()) return } userID := middleware.GetUserID(ctx) spaceID := middleware.GetSpaceID(ctx) hasPermission, err := CheckUserPermission(ctx, userID, spaceID) if err != nil { errorx.AddError(c, err) return } if !hasPermission { response.Fail(c).Message("无权限操作").Send() return } if err := LeaveSpace(ctx, req.UserId, spaceID); err != nil { errorx.AddError(c, err) return } response.Success(c).Send() } // QuitSpace . // @router /space/quit [POST] func QuitSpace(ctx context.Context, c *app.RequestContext) { var req space.QuitSpaceParams if err := c.BindAndValidate(&req); err != nil { c.String(consts.StatusBadRequest, err.Error()) return } userID := middleware.GetUserID(ctx) spaceID := req.SpaceId // 检查权限 role, exists, err := redisx.GetUserSpaceRole(ctx, userID, spaceID) if err != nil { errorx.AddError(c, err) return } if !exists { response.Fail(c).Message("已不在该空间内").Send() return } err = db.WithTx(ctx, func(q *repo.Queries) error { if role == 0 { } return nil }) response.Success(c).Send() } // JoinSpace . // @router /space/join [POST] func JoinSpace(ctx context.Context, c *app.RequestContext) { var err error var req space.JoinSpaceParams err = c.BindAndValidate(&req) if err != nil { c.String(consts.StatusBadRequest, err.Error()) return } resp := new(space.JoinSpaceResult) userID := middleware.GetUserID(ctx) oldSpaceID := middleware.GetSpaceID(ctx) inviteCode := req.InviteCode spaceByInviteCode, err := db.Queries.FindSpaceByInviteCode(ctx, inviteCode) if err != nil { if errorx.IsNotFound(err) { response.Fail(c).Message("邀请码错误或已过期").Send() return } errorx.AddError(c, err) return } joinSpaceID := spaceByInviteCode.ID // 检查权限 role, exists, err := redisx.GetUserSpaceRole(ctx, userID, oldSpaceID) if err != nil { errorx.AddError(c, err) return } err = db.WithTx(ctx, func(q *repo.Queries) error { // 判断权限, 如果角色为 0 则解散 if exists && role == 0 { users, err2 := q.ListSpaceUsers(ctx, oldSpaceID) if err2 != nil { return err2 } for _, user := range users { if err2 := LeaveSpace(ctx, user.UserID, oldSpaceID); err2 != nil { return err2 } } } else { // 退出就行 if err2 := q.DeleteSpaceUser(ctx, repo.DeleteSpaceUserParams{ SpaceID: oldSpaceID, UserID: userID, }); err2 != nil { return err2 } if err2 := redisx.RemoveUserSpace(ctx, userID, oldSpaceID); err2 != nil { return err2 } // 再加入 if err2 := q.InsertSpaceUser(ctx, repo.InsertSpaceUserParams{ ID: idgen.NextId(), UserID: userID, SpaceID: joinSpaceID, Role: 0, }); err2 != nil { return err2 } if err2 := redisx.AddOrUpdateUserSpace(ctx, userID, joinSpaceID, 0); err2 != nil { return err2 } } return nil }) c.JSON(consts.StatusOK, resp) } // ListSpaceUsers . // @router /space/users [POST] func ListSpaceUsers(ctx context.Context, c *app.RequestContext) { var err error var req space.ListSpaceUsersParams err = c.BindAndValidate(&req) if err != nil { c.String(consts.StatusBadRequest, err.Error()) return } resp := new(space.ListSpaceUsersResult) // 查询 users, err := db.Queries.ListSpaceUsers(ctx, req.SpaceId) if err != nil { errorx.AddError(c, err) return } spaceUsers := make([]*space.SpaceUser, 0, len(users)) for _, user := range users { spaceUsers = append(spaceUsers, &space.SpaceUser{ UserId: user.UserID, UserName: user.UserName, UserAvatar: user.UserAvatar, Role: user.Role, }) } resp.Users = spaceUsers response.Success(c).Data(spaceUsers).Send() } // CheckUserPermission 检查是否有权限 func CheckUserPermission(ctx context.Context, userID int64, spaceID int64) (bool, error) { inSpace, err := redisx.InSpace(ctx, userID, spaceID) if err != nil { return false, err } if !inSpace { return false, nil } role, exists, err := redisx.GetUserSpaceRole(ctx, userID, spaceID) if err != nil { return false, err } if !exists { return false, nil } return role == 0, nil } // LeaveSpace 处理用户离开空间逻辑(包括删除空间用户、清理 Redis、创建新空间) func LeaveSpace(ctx context.Context, userID, spaceID int64) error { return db.WithTx(ctx, func(q *repo.Queries) error { // 1. 删除数据库空间用户 if err := q.DeleteSpaceUser(ctx, repo.DeleteSpaceUserParams{ UserID: userID, SpaceID: spaceID, }); err != nil { return err } // 确保该用户加入了缓存 err := InitUserSpaces(ctx, userID) if err != nil { return err } // 2. 删除 Redis 缓存 if err := redisx.RemoveUserSpace(ctx, userID, spaceID); err != nil { return err } // 3. 确保用户至少有一个空间 if err := EnsureUserHasSpaceWithTx(ctx, q, userID); err != nil { return err } return nil }) } // InitUserSpaces 初始化用户空间信息 func InitUserSpaces(ctx context.Context, userID int64) error { hasSpace, err := redisx.HasUserSpaces(ctx, userID) if err != nil { return err } if hasSpace { return nil } spaces, err := db.Queries.ListUserSpaces(ctx, userID) if err != nil { return err } spaceRoles := make(map[int64]int32, len(spaces)) for _, row := range spaces { spaceRoles[row.ID] = row.Role } return redisx.SetUserSpaces(ctx, userID, spaceRoles) } // EnsureUserHasSpaceWithTx 确保用户至少有一个空间,如果没有则创建新空间 // 注意:不管理事务,需要在外层传入 q *repo.Queries func EnsureUserHasSpaceWithTx(ctx context.Context, q *repo.Queries, userID int64) error { // 1. 查询用户现有空间 spaces, err := redisx.GetUserSpaces(ctx, userID) if err != nil { return err } if len(spaces) > 0 { // 已经有空间,无需创建 return nil } // 2. 没有空间则创建 var inviteCode string for { code := utils.GenerateCode(6) _, err := q.FindSpaceByInviteCode(ctx, code) if errorx.IsNotFound(err) { inviteCode = code break } else if err != nil { return err } } newSpaceID := idgen.NextId() // 插入新空间 if err := q.InsertSpace(ctx, repo.InsertSpaceParams{ ID: newSpaceID, InviteCode: inviteCode, }); err != nil { return err } // 插入空间用户 if err := q.InsertSpaceUser(ctx, repo.InsertSpaceUserParams{ ID: idgen.NextId(), SpaceID: newSpaceID, UserID: userID, }); err != nil { return err } // 同步到 Redis if err := redisx.AddOrUpdateUserSpace(ctx, userID, newSpaceID, 0); err != nil { return err } return nil }