2025-06-19 10:30:46 +08:00

228 lines
5.7 KiB
Go

package biz
import (
"context"
"time"
"github.com/guxuan/hailin_service/internal/config"
"github.com/guxuan/hailin_service/internal/mods/rbac/dal"
"github.com/guxuan/hailin_service/internal/mods/rbac/schema"
"github.com/guxuan/hailin_service/pkg/cachex"
"github.com/guxuan/hailin_service/pkg/crypto/hash"
"github.com/guxuan/hailin_service/pkg/errors"
"github.com/guxuan/hailin_service/pkg/util"
)
// User management for RBAC
type User struct {
Cache cachex.Cacher
Trans *util.Trans
UserDAL *dal.User
UserRoleDAL *dal.UserRole
}
// Query users from the data access object based on the provided parameters and options.
func (a *User) Query(ctx context.Context, params schema.UserQueryParam) (*schema.UserQueryResult, error) {
params.Pagination = true
result, err := a.UserDAL.Query(ctx, params, schema.UserQueryOptions{
QueryOptions: util.QueryOptions{
OrderFields: []util.OrderByParam{
{Field: "created_at", Direction: util.DESC},
},
OmitFields: []string{"password"},
},
})
if err != nil {
return nil, err
}
if userIDs := result.Data.ToIDs(); len(userIDs) > 0 {
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
InUserIDs: userIDs,
}, schema.UserRoleQueryOptions{
JoinRole: true,
})
if err != nil {
return nil, err
}
userRolesMap := userRoleResult.Data.ToUserIDMap()
for _, user := range result.Data {
user.Roles = userRolesMap[user.ID]
}
}
return result, nil
}
// Get the specified user from the data access object.
func (a *User) Get(ctx context.Context, id string) (*schema.User, error) {
user, err := a.UserDAL.Get(ctx, id, schema.UserQueryOptions{
QueryOptions: util.QueryOptions{
OmitFields: []string{"password"},
},
})
if err != nil {
return nil, err
} else if user == nil {
return nil, errors.NotFound("", "User not found")
}
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
UserID: id,
})
if err != nil {
return nil, err
}
user.Roles = userRoleResult.Data
return user, nil
}
// Create a new user in the data access object.
func (a *User) Create(ctx context.Context, formItem *schema.UserForm) (*schema.User, error) {
existsUsername, err := a.UserDAL.ExistsUsername(ctx, formItem.Username)
if err != nil {
return nil, err
} else if existsUsername {
return nil, errors.BadRequest("", "Username already exists")
}
user := &schema.User{
ID: util.NewXID(),
CreatedAt: time.Now(),
}
if formItem.Password == "" {
formItem.Password = config.C.General.DefaultLoginPwd
}
if err := formItem.FillTo(user); err != nil {
return nil, err
}
err = a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.UserDAL.Create(ctx, user); err != nil {
return err
}
for _, userRole := range formItem.Roles {
userRole.ID = util.NewXID()
userRole.UserID = user.ID
userRole.CreatedAt = time.Now()
if err := a.UserRoleDAL.Create(ctx, userRole); err != nil {
return err
}
}
return nil
})
if err != nil {
return nil, err
}
user.Roles = formItem.Roles
return user, nil
}
// Update the specified user in the data access object.
func (a *User) Update(ctx context.Context, id string, formItem *schema.UserForm) error {
user, err := a.UserDAL.Get(ctx, id)
if err != nil {
return err
} else if user == nil {
return errors.NotFound("", "User not found")
} else if user.Username != formItem.Username {
existsUsername, err := a.UserDAL.ExistsUsername(ctx, formItem.Username)
if err != nil {
return err
} else if existsUsername {
return errors.BadRequest("", "Username already exists")
}
}
if err := formItem.FillTo(user); err != nil {
return err
}
user.UpdatedAt = time.Now()
return a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.UserDAL.Update(ctx, user); err != nil {
return err
}
if err := a.UserRoleDAL.DeleteByUserID(ctx, id); err != nil {
return err
}
for _, userRole := range formItem.Roles {
if userRole.ID == "" {
userRole.ID = util.NewXID()
}
userRole.UserID = user.ID
if userRole.CreatedAt.IsZero() {
userRole.CreatedAt = time.Now()
}
userRole.UpdatedAt = time.Now()
if err := a.UserRoleDAL.Create(ctx, userRole); err != nil {
return err
}
}
return a.Cache.Delete(ctx, config.CacheNSForUser, id)
})
}
// Delete the specified user from the data access object.
func (a *User) Delete(ctx context.Context, id string) error {
exists, err := a.UserDAL.Exists(ctx, id)
if err != nil {
return err
} else if !exists {
return errors.NotFound("", "User not found")
}
return a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.UserDAL.Delete(ctx, id); err != nil {
return err
}
if err := a.UserRoleDAL.DeleteByUserID(ctx, id); err != nil {
return err
}
return a.Cache.Delete(ctx, config.CacheNSForUser, id)
})
}
func (a *User) ResetPassword(ctx context.Context, id string) error {
exists, err := a.UserDAL.Exists(ctx, id)
if err != nil {
return err
} else if !exists {
return errors.NotFound("", "User not found")
}
hashPass, err := hash.GeneratePassword(config.C.General.DefaultLoginPwd)
if err != nil {
return errors.BadRequest("", "Failed to generate hash password: %s", err.Error())
}
return a.Trans.Exec(ctx, func(ctx context.Context) error {
if err := a.UserDAL.UpdatePasswordByID(ctx, id, hashPass); err != nil {
return err
}
return nil
})
}
func (a *User) GetRoleIDs(ctx context.Context, id string) ([]string, error) {
userRoleResult, err := a.UserRoleDAL.Query(ctx, schema.UserRoleQueryParam{
UserID: id,
}, schema.UserRoleQueryOptions{
QueryOptions: util.QueryOptions{
SelectFields: []string{"role_id"},
},
})
if err != nil {
return nil, err
}
return userRoleResult.Data.ToRoleIDs(), nil
}