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 }