fix: 用户锁定判断

This commit is contained in:
yokowu
2025-07-24 21:31:56 +08:00
parent a684613271
commit e12b5b26d6
5 changed files with 48 additions and 15 deletions

View File

@@ -36,7 +36,7 @@ type UserUsecase interface {
type UserRepo interface {
List(ctx context.Context, page *web.Pagination) ([]*db.User, *db.PageInfo, error)
Update(ctx context.Context, id string, fn func(*db.User, *db.UserUpdateOne) error) (*db.User, error)
Update(ctx context.Context, id string, fn func(*db.Tx, *db.User, *db.UserUpdateOne) error) (*db.User, error)
Delete(ctx context.Context, id string) error
InitAdmin(ctx context.Context, username, password string) error
CreateUser(ctx context.Context, user *db.User) (*db.User, error)

View File

@@ -12,6 +12,7 @@ var LocalFS embed.FS
var (
ErrPermission = web.NewBadRequestErr("err-permission")
ErrUserNotFound = web.NewBadRequestErr("err-user-not-found")
ErrUserLock = web.NewBadRequestErr("err-user-lock")
ErrPassword = web.NewBadRequestErr("err-password")
ErrInviteCodeInvalid = web.NewBadRequestErr("err-invite-code-invalid")
ErrEmailInvalid = web.NewBadRequestErr("err-email-invalid")

View File

@@ -4,6 +4,9 @@ other = "无权操作"
[err-user-not-found]
other = "用户不存在"
[err-user-lock]
other = "用户已锁定"
[err-password]
other = "密码错误"

View File

@@ -74,12 +74,14 @@ func (r *UserRepo) AdminByName(ctx context.Context, username string) (*db.Admin,
}
func (r *UserRepo) GetByName(ctx context.Context, username string) (*db.User, error) {
return r.db.User.Query().Where(
user.Or(
user.Username(username),
user.Email(username),
),
).Only(ctx)
return r.db.User.Query().
Where(
user.Or(
user.Username(username),
user.Email(username),
),
).
Only(ctx)
}
func (r *UserRepo) ValidateInviteCode(ctx context.Context, code string) (*db.InviteCode, error) {
@@ -167,12 +169,12 @@ func (r *UserRepo) CreateInviteCode(ctx context.Context, userID string, code str
}
func (r *UserRepo) AdminList(ctx context.Context, page *web.Pagination) ([]*db.Admin, *db.PageInfo, error) {
q := r.db.Admin.Query()
q := r.db.Admin.Query().Order(admin.ByCreatedAt(sql.OrderDesc()))
return q.Page(ctx, page.Page, page.Size)
}
func (r *UserRepo) List(ctx context.Context, page *web.Pagination) ([]*db.User, *db.PageInfo, error) {
q := r.db.User.Query()
q := r.db.User.Query().Order(user.ByCreatedAt(sql.OrderDesc()))
return q.Page(ctx, page.Page, page.Size)
}
@@ -241,7 +243,7 @@ func (r *UserRepo) UpdateSetting(ctx context.Context, fn func(*db.Setting, *db.S
return res, err
}
func (r *UserRepo) Update(ctx context.Context, id string, fn func(*db.User, *db.UserUpdateOne) error) (*db.User, error) {
func (r *UserRepo) Update(ctx context.Context, id string, fn func(*db.Tx, *db.User, *db.UserUpdateOne) error) (*db.User, error) {
uid, err := uuid.Parse(id)
if err != nil {
return nil, err
@@ -254,7 +256,7 @@ func (r *UserRepo) Update(ctx context.Context, id string, fn func(*db.User, *db.
return err
}
up := tx.User.UpdateOneID(u.ID)
if err = fn(u, up); err != nil {
if err = fn(tx, u, up); err != nil {
return err
}
return up.Exec(ctx)
@@ -372,6 +374,9 @@ func (r *UserRepo) OAuthLogin(ctx context.Context, platform consts.UserPlatform,
if err != nil {
return nil, errcode.ErrNotInvited.Wrap(err)
}
if ui.Edges.User.Status != consts.UserStatusActive {
return nil, errcode.ErrUserLock
}
if ui.AvatarURL != req.AvatarURL {
if err = entx.WithTx(ctx, r.db, func(tx *db.Tx) error {
return r.updateAvatar(ctx, tx, ui, req.AvatarURL)
@@ -409,6 +414,9 @@ func (r *UserRepo) SignUpOrIn(ctx context.Context, platform consts.UserPlatform,
First(ctx)
if err == nil {
u = ui.Edges.User
if u.Status != consts.UserStatusActive {
return errcode.ErrUserLock
}
if ui.AvatarURL != req.AvatarURL {
if err = r.updateAvatar(ctx, tx, ui, req.AvatarURL); err != nil {
return err

View File

@@ -19,6 +19,7 @@ import (
"github.com/chaitin/MonkeyCode/backend/config"
"github.com/chaitin/MonkeyCode/backend/consts"
"github.com/chaitin/MonkeyCode/backend/db"
"github.com/chaitin/MonkeyCode/backend/db/apikey"
"github.com/chaitin/MonkeyCode/backend/domain"
"github.com/chaitin/MonkeyCode/backend/ent/types"
"github.com/chaitin/MonkeyCode/backend/errcode"
@@ -206,6 +207,9 @@ func (u *UserUsecase) Login(ctx context.Context, req *domain.LoginReq) (*domain.
if err != nil {
return nil, errcode.ErrUserNotFound.Wrap(err)
}
if user.Status != consts.UserStatusActive {
return nil, errcode.ErrUserLock
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
return nil, errcode.ErrPassword.Wrap(err)
}
@@ -394,17 +398,34 @@ func (u *UserUsecase) UpdateSetting(ctx context.Context, req *domain.UpdateSetti
return cvt.From(s, &domain.Setting{}), nil
}
func (u *UserUsecase) cleanApiKey(ctx context.Context, tx *db.Tx, user *db.User) error {
if apikey, err := tx.ApiKey.Query().Where(apikey.UserID(user.ID)).First(ctx); err == nil {
if err := tx.ApiKey.DeleteOneID(apikey.ID).Exec(ctx); err != nil {
return err
}
rkey := "sk-" + apikey.Key
return u.redis.Del(ctx, rkey).Err()
}
return nil
}
func (u *UserUsecase) Update(ctx context.Context, req *domain.UpdateUserReq) (*domain.User, error) {
user, err := u.repo.Update(ctx, req.ID, func(_ *db.User, u *db.UserUpdateOne) error {
user, err := u.repo.Update(ctx, req.ID, func(tx *db.Tx, old *db.User, up *db.UserUpdateOne) error {
if req.Status != nil {
u.SetStatus(*req.Status)
if *req.Status == consts.UserStatusLocked {
if err := u.cleanApiKey(ctx, tx, old); err != nil {
return err
}
}
up.SetStatus(*req.Status)
}
if req.Password != nil {
hash, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
if err != nil {
return err
}
u.SetPassword(string(hash))
up.SetPassword(string(hash))
}
return nil
})
@@ -613,7 +634,7 @@ func (u *UserUsecase) WithOAuthCallback(ctx context.Context, req *domain.OAuthCa
}
func (u *UserUsecase) ProfileUpdate(ctx context.Context, req *domain.ProfileUpdateReq) (*domain.User, error) {
user, err := u.repo.Update(ctx, req.UID, func(old *db.User, uuo *db.UserUpdateOne) error {
user, err := u.repo.Update(ctx, req.UID, func(_ *db.Tx, old *db.User, uuo *db.UserUpdateOne) error {
if req.Avatar != nil {
uuo.SetAvatarURL(*req.Avatar)
}