9037cb5917
- Updated the notification handling logic to utilize a new SDK for sending notifications, improving the flexibility and scalability of the notification system. - Introduced new methods in the notification service for sending notifications to users and customers based on various target audience types, enhancing the notification delivery capabilities. - Added a new endpoint to assign companies to a customer, improving customer management functionalities. - Refactored the customer entity and forms to replace 'CompanyIDs' with 'Companies', ensuring consistency across the data model. - Enhanced API documentation with Swagger comments for the new endpoint and updated notification structures, ensuring clarity for API consumers.
278 lines
6.9 KiB
Go
278 lines
6.9 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 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
|
|
}
|
|
|
|
// GetByIDs retrieves users by IDs
|
|
func (r *userRepository) GetByIDs(ctx context.Context, userIDs []string) ([]User, error) {
|
|
users, err := r.ormRepo.FindAll(ctx, bson.M{"_id": bson.M{"$in": userIDs}}, 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
|
|
}
|