4ddc468fea
- Implemented GetUserByTenantID method in userRepository to retrieve the first user associated with a given tenant ID. - Added corresponding GetUserByTenantID method in userService to facilitate user retrieval by tenant ID. - Updated UserService and UserRepository interfaces to include the new method, ensuring consistency across the application. - Enhanced auth middleware to store user information in context based on tenant ID, improving user management. These changes enhance user retrieval capabilities by allowing access to user data based on tenant associations, improving overall application functionality.
187 lines
5.6 KiB
Go
187 lines
5.6 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
"github.com/Tencent/WeKnora/internal/types/interfaces"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var (
|
|
ErrUserNotFound = errors.New("user not found")
|
|
ErrUserAlreadyExists = errors.New("user already exists")
|
|
ErrTokenNotFound = errors.New("token not found")
|
|
)
|
|
|
|
// userRepository implements user repository interface
|
|
type userRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewUserRepository creates a new user repository
|
|
func NewUserRepository(db *gorm.DB) interfaces.UserRepository {
|
|
return &userRepository{db: db}
|
|
}
|
|
|
|
// CreateUser creates a user
|
|
func (r *userRepository) CreateUser(ctx context.Context, user *types.User) error {
|
|
return r.db.WithContext(ctx).Create(user).Error
|
|
}
|
|
|
|
// GetUserByID gets a user by ID
|
|
func (r *userRepository) GetUserByID(ctx context.Context, id string) (*types.User, error) {
|
|
var user types.User
|
|
if err := r.db.WithContext(ctx).Where("id = ?", id).First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
// GetUserByEmail gets a user by email
|
|
func (r *userRepository) GetUserByEmail(ctx context.Context, email string) (*types.User, error) {
|
|
var user types.User
|
|
if err := r.db.WithContext(ctx).Where("email = ?", email).First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
// GetUserByUsername gets a user by username
|
|
func (r *userRepository) GetUserByUsername(ctx context.Context, username string) (*types.User, error) {
|
|
var user types.User
|
|
if err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
// GetUserByTenantID gets the first user (owner) of a tenant
|
|
func (r *userRepository) GetUserByTenantID(ctx context.Context, tenantID uint64) (*types.User, error) {
|
|
var user types.User
|
|
if err := r.db.WithContext(ctx).Where("tenant_id = ?", tenantID).Order("created_at ASC").First(&user).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrUserNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &user, nil
|
|
}
|
|
|
|
// UpdateUser updates a user
|
|
func (r *userRepository) UpdateUser(ctx context.Context, user *types.User) error {
|
|
return r.db.WithContext(ctx).Save(user).Error
|
|
}
|
|
|
|
// DeleteUser deletes a user
|
|
func (r *userRepository) DeleteUser(ctx context.Context, id string) error {
|
|
return r.db.WithContext(ctx).Where("id = ?", id).Delete(&types.User{}).Error
|
|
}
|
|
|
|
// ListUsers lists users with pagination
|
|
func (r *userRepository) ListUsers(ctx context.Context, offset, limit int) ([]*types.User, error) {
|
|
var users []*types.User
|
|
query := r.db.WithContext(ctx).Order("created_at DESC")
|
|
|
|
if limit > 0 {
|
|
query = query.Limit(limit)
|
|
}
|
|
|
|
if offset > 0 {
|
|
query = query.Offset(offset)
|
|
}
|
|
|
|
if err := query.Find(&users).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return users, nil
|
|
}
|
|
|
|
// SearchUsers searches users by username or email
|
|
func (r *userRepository) SearchUsers(ctx context.Context, query string, limit int) ([]*types.User, error) {
|
|
var users []*types.User
|
|
searchPattern := "%" + query + "%"
|
|
|
|
dbQuery := r.db.WithContext(ctx).
|
|
Where("username ILIKE ? OR email ILIKE ?", searchPattern, searchPattern).
|
|
Where("is_active = ?", true).
|
|
Order("username ASC")
|
|
|
|
if limit > 0 {
|
|
dbQuery = dbQuery.Limit(limit)
|
|
} else {
|
|
dbQuery = dbQuery.Limit(20) // default limit
|
|
}
|
|
|
|
if err := dbQuery.Find(&users).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return users, nil
|
|
}
|
|
|
|
// authTokenRepository implements auth token repository interface
|
|
type authTokenRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewAuthTokenRepository creates a new auth token repository
|
|
func NewAuthTokenRepository(db *gorm.DB) interfaces.AuthTokenRepository {
|
|
return &authTokenRepository{db: db}
|
|
}
|
|
|
|
// CreateToken creates an auth token
|
|
func (r *authTokenRepository) CreateToken(ctx context.Context, token *types.AuthToken) error {
|
|
return r.db.WithContext(ctx).Create(token).Error
|
|
}
|
|
|
|
// GetTokenByValue gets a token by its value
|
|
func (r *authTokenRepository) GetTokenByValue(ctx context.Context, tokenValue string) (*types.AuthToken, error) {
|
|
var token types.AuthToken
|
|
if err := r.db.WithContext(ctx).Where("token = ?", tokenValue).First(&token).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, ErrTokenNotFound
|
|
}
|
|
return nil, err
|
|
}
|
|
return &token, nil
|
|
}
|
|
|
|
// GetTokensByUserID gets all tokens for a user
|
|
func (r *authTokenRepository) GetTokensByUserID(ctx context.Context, userID string) ([]*types.AuthToken, error) {
|
|
var tokens []*types.AuthToken
|
|
if err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&tokens).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return tokens, nil
|
|
}
|
|
|
|
// UpdateToken updates a token
|
|
func (r *authTokenRepository) UpdateToken(ctx context.Context, token *types.AuthToken) error {
|
|
return r.db.WithContext(ctx).Save(token).Error
|
|
}
|
|
|
|
// DeleteToken deletes a token
|
|
func (r *authTokenRepository) DeleteToken(ctx context.Context, id string) error {
|
|
return r.db.WithContext(ctx).Where("id = ?", id).Delete(&types.AuthToken{}).Error
|
|
}
|
|
|
|
// DeleteExpiredTokens deletes all expired tokens
|
|
func (r *authTokenRepository) DeleteExpiredTokens(ctx context.Context) error {
|
|
return r.db.WithContext(ctx).Where("expires_at < NOW()").Delete(&types.AuthToken{}).Error
|
|
}
|
|
|
|
// RevokeTokensByUserID revokes all tokens for a user
|
|
func (r *authTokenRepository) RevokeTokensByUserID(ctx context.Context, userID string) error {
|
|
return r.db.WithContext(ctx).Model(&types.AuthToken{}).Where("user_id = ?", userID).Update("is_revoked", true).Error
|
|
}
|