38844939b5
- Changed API tags from "Admin-Users" to "Admin-Authorization" for better clarity in user management endpoints. - Removed unused endpoints for retrieving users by company ID and role, streamlining the user management functionality. - Updated user entity and forms to reflect new example values for improved clarity in API documentation. - Enhanced pagination handling in user listing responses, ensuring consistent metadata structure. - Updated API documentation to reflect changes in endpoint structure and response formats, improving clarity for API consumers.
267 lines
6.5 KiB
Go
267 lines
6.5 KiB
Go
package user
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
"tm/pkg/logger"
|
|
orm "tm/pkg/mongo"
|
|
"tm/pkg/response"
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
)
|
|
|
|
// Repository defines methods for user data access
|
|
type Repository interface {
|
|
Login(ctx context.Context, id string) error
|
|
Create(ctx context.Context, user *User) error
|
|
Update(ctx context.Context, user *User) error
|
|
Delete(ctx context.Context, id string) error
|
|
GetByID(ctx context.Context, id string) (*User, error)
|
|
GetByEmail(ctx context.Context, email string) (*User, error)
|
|
GetByUsername(ctx context.Context, username string) (*User, error)
|
|
Search(ctx context.Context, form *SearchUsersForm, pagination *response.Pagination) ([]User, int64, error)
|
|
}
|
|
|
|
// userRepository implements the Repository interface using the MongoDB ORM
|
|
type userRepository struct {
|
|
ormRepo orm.Repository[User]
|
|
logger logger.Logger
|
|
}
|
|
|
|
// NewUserRepository creates a new user repository
|
|
func NewUserRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Repository {
|
|
// Create indexes using the ORM's index management
|
|
indexes := []orm.Index{
|
|
*orm.CreateTextIndex("search_idx", "full_name", "email", "username"),
|
|
}
|
|
|
|
// Create indexes
|
|
err := mongoManager.CreateIndexes("users", indexes)
|
|
if err != nil {
|
|
logger.Warn("Failed to create user indexes", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
}
|
|
|
|
// Create ORM repository
|
|
ormRepo := orm.NewRepository[User](mongoManager.GetCollection("users"), logger)
|
|
|
|
return &userRepository{
|
|
ormRepo: ormRepo,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Login updates the last login timestamp
|
|
func (r *userRepository) Login(ctx context.Context, id string) error {
|
|
// Get user first
|
|
user, err := r.GetByID(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Update last login timestamp
|
|
user.LastLoginAt = &[]int64{time.Now().Unix()}[0]
|
|
user.SetUpdatedAt(time.Now().Unix())
|
|
|
|
// Update in database
|
|
err = r.ormRepo.Update(ctx, user)
|
|
if err != nil {
|
|
r.logger.Error("Failed to update last login", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"user_id": id,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("Last login updated successfully", map[string]interface{}{
|
|
"user_id": id,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Create creates a new user
|
|
func (r *userRepository) Create(ctx context.Context, user *User) error {
|
|
// Set created timestamp using Unix timestamp
|
|
now := time.Now().Unix()
|
|
user.SetCreatedAt(now)
|
|
|
|
// Use ORM to create user
|
|
err := r.ormRepo.Create(ctx, user)
|
|
if err != nil {
|
|
r.logger.Error("Failed to create user", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"email": user.Email,
|
|
"user_id": user.ID,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("User created successfully", map[string]interface{}{
|
|
"user_id": user.ID,
|
|
"email": user.Email,
|
|
"role": user.Role,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// Update updates a user
|
|
func (r *userRepository) Update(ctx context.Context, user *User) error {
|
|
// Set updated timestamp using Unix timestamp
|
|
user.SetUpdatedAt(time.Now().Unix())
|
|
|
|
// Use ORM to update user
|
|
err := r.ormRepo.Update(ctx, user)
|
|
if err != nil {
|
|
r.logger.Error("Failed to update user", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"user_id": user.ID,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("User updated successfully", map[string]interface{}{
|
|
"user_id": user.ID,
|
|
"email": user.Email,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetByID retrieves a user by ID
|
|
func (r *userRepository) GetByID(ctx context.Context, id string) (*User, error) {
|
|
user, err := r.ormRepo.FindByID(ctx, id)
|
|
if err != nil {
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return nil, errors.New("user not found")
|
|
}
|
|
r.logger.Error("Failed to get user by ID", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"user_id": id,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// GetByEmail retrieves a user by email
|
|
func (r *userRepository) GetByEmail(ctx context.Context, email string) (*User, error) {
|
|
user, err := r.ormRepo.FindOne(ctx, bson.M{"email": email})
|
|
if err != nil {
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return nil, errors.New("user not found")
|
|
}
|
|
r.logger.Error("Failed to get user by email", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"email": email,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// GetByUsername retrieves a user by username
|
|
func (r *userRepository) GetByUsername(ctx context.Context, username string) (*User, error) {
|
|
user, err := r.ormRepo.FindOne(ctx, bson.M{"username": username})
|
|
if err != nil {
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return nil, errors.New("user not found")
|
|
}
|
|
r.logger.Error("Failed to get user by username", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"username": username,
|
|
})
|
|
return nil, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// Delete deletes a user (soft delete by setting status to inactive)
|
|
func (r *userRepository) Delete(ctx context.Context, id string) error {
|
|
// Get user first
|
|
_, err := r.GetByID(ctx, id)
|
|
if err != nil {
|
|
r.logger.Error("Failed to delete user", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"user_id": id,
|
|
})
|
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
|
return errors.New("user not found")
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
// Delete in database
|
|
err = r.ormRepo.Delete(ctx, id)
|
|
if err != nil {
|
|
r.logger.Error("Failed to delete user", map[string]interface{}{
|
|
"error": err.Error(),
|
|
"user_id": id,
|
|
})
|
|
return err
|
|
}
|
|
|
|
r.logger.Info("User deleted successfully", map[string]interface{}{
|
|
"user_id": id,
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// List retrieves users with pagination
|
|
func (r *userRepository) Search(ctx context.Context, form *SearchUsersForm, pagination *response.Pagination) ([]User, int64, error) {
|
|
filter := bson.M{}
|
|
|
|
if form.Search != nil {
|
|
filter["$or"] = bson.A{
|
|
bson.M{"full_name": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
bson.M{"email": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
bson.M{"username": bson.M{"$regex": form.Search, "$options": "i"}},
|
|
}
|
|
}
|
|
|
|
if form.Status != nil {
|
|
filter["status"] = form.Status
|
|
}
|
|
|
|
if form.Role != nil {
|
|
filter["role"] = form.Role
|
|
}
|
|
|
|
// Build sort
|
|
sort := "created_at"
|
|
if pagination.SortBy != "" {
|
|
sort = pagination.SortBy
|
|
}
|
|
|
|
sortOrder := "desc"
|
|
if pagination.SortOrder != "" {
|
|
sortOrder = pagination.SortOrder
|
|
}
|
|
|
|
// Build pagination
|
|
paginationBuilder := orm.NewPaginationBuilder().
|
|
Limit(pagination.Limit).
|
|
Skip(pagination.Offset).
|
|
SortBy(sort, sortOrder).
|
|
Build()
|
|
|
|
// Use ORM to find users
|
|
result, err := r.ormRepo.FindAll(ctx, filter, paginationBuilder)
|
|
if err != nil {
|
|
r.logger.Error("Failed to list users", map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return nil, 0, err
|
|
}
|
|
|
|
return result.Items, result.TotalCount, nil
|
|
}
|