342 lines
7.1 KiB
Go
342 lines
7.1 KiB
Go
// 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
|
|
}
|