Files
tm_back/internal/user/repository.go
T
n.nakhostin 20aee91467 Refactor Customer and User Repository Methods for ObjectID Handling
- Updated GetByIDs methods in customer and user repositories to convert string IDs to bson.ObjectID, ensuring proper handling of MongoDB object IDs.
- Enhanced error handling for ID conversion to provide clearer feedback when invalid IDs are provided.
- Modified notification service calls in customer and user services to use context.Background() for asynchronous email sending, improving concurrency management.
- Ensured consistent handling of company IDs in the customer repository for retrieving customers by companies.
2025-10-01 13:19:34 +03:30

287 lines
7.1 KiB
Go

package user
import (
"context"
"errors"
"time"
"tm/pkg/logger"
orm "tm/pkg/mongo"
"tm/pkg/response"
"go.mongodb.org/mongo-driver/v2/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)
GetByIDs(ctx context.Context, userIDs []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 NewRepository(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
}
// GetByIDs retrieves users by IDs
func (r *userRepository) GetByIDs(ctx context.Context, userIDs []string) ([]User, error) {
objectIDs := make([]bson.ObjectID, 0)
for _, id := range userIDs {
objectID, err := bson.ObjectIDFromHex(id)
if err != nil {
return nil, err
}
objectIDs = append(objectIDs, objectID)
}
users, err := r.ormRepo.FindAll(ctx, bson.M{"_id": bson.M{"$in": objectIDs}}, orm.NewPaginationBuilder().Limit(len(userIDs)).Build())
if err != nil {
return nil, err
}
return users.Items, 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
}