Integrate Notification Service into Tender Management System

- Added a new notification service to handle various notification types (email, SMS, push, OTP).
- Implemented configuration for the notification service, allowing customization via environment variables.
- Updated user and customer services to utilize the notification service for sending welcome emails and status updates.
- Introduced a builder pattern for constructing notification requests, enhancing usability and flexibility.
- Enhanced error handling and logging for notification operations, ensuring robust service integration.
- Updated documentation to include usage examples and configuration details for the new notification SDK.
This commit is contained in:
n.nakhostin
2025-09-16 15:35:36 +03:30
parent 05a307e345
commit 108629278a
15 changed files with 1429 additions and 21 deletions
+13 -10
View File
@@ -7,10 +7,12 @@ import (
"errors"
"fmt"
"math/big"
"strings"
"time"
"tm/internal/company"
"tm/pkg/logger"
"tm/pkg/notification"
"tm/pkg/redis"
"tm/pkg/response"
@@ -49,16 +51,18 @@ type customerService struct {
authService authorization.AuthorizationService
companyService company.Service
redisClient redis.Client
notification notification.SDK
}
// New creates a new customer service
func New(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, companyService company.Service, redisClient redis.Client) Service {
func New(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, companyService company.Service, redisClient redis.Client, notificationSDK notification.SDK) Service {
return &customerService{
repository: repository,
logger: logger,
authService: authService,
companyService: companyService,
redisClient: redisClient,
notification: notificationSDK,
}
}
@@ -125,6 +129,8 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
"company_ids": companyIDs,
})
go s.notification.SendEmail(ctx, customer.Email, fmt.Sprintf("Welcome to Tender Management\nUsername: %s\nPassword: %s", customer.Username, form.Password), customer.ID.Hex())
return customer.ToResponse(nil), nil
}
@@ -293,7 +299,7 @@ func (s *customerService) Delete(ctx context.Context, id string) error {
// UpdateStatus updates customer status
func (s *customerService) UpdateStatus(ctx context.Context, id string, form *UpdateStatusForm) error {
// Get customer to check if exists
_, err := s.repository.GetByID(ctx, id)
customer, err := s.repository.GetByID(ctx, id)
if err != nil {
return errors.New("customer not found")
}
@@ -315,6 +321,8 @@ func (s *customerService) UpdateStatus(ctx context.Context, id string, form *Upd
"status": form.Status,
})
go s.notification.SendEmail(ctx, customer.Email, fmt.Sprintf("Your account has been %s", strings.ToUpper(form.Status)), customer.ID.Hex())
return nil
}
@@ -769,14 +777,7 @@ func (s *customerService) RequestResetPassword(ctx context.Context, form *Reques
}
// Send OTP via email
// err = s.emailService.SendPasswordResetOTP(ctx, form.Email, otpCode)
// if err != nil {
// s.logger.Error("Failed to send password reset OTP", map[string]interface{}{
// "error": err.Error(),
// "email": form.Email,
// })
// return nil, errors.New("failed to send verification code")
// }
go s.notification.SendEmail(ctx, form.Email, fmt.Sprintf("Your password reset code is: %s", otpCode), customer.ID.Hex())
s.logger.Info("Password reset OTP sent successfully", map[string]interface{}{
"email": form.Email,
@@ -964,6 +965,8 @@ func (s *customerService) ResetPassword(ctx context.Context, form *ResetPassword
"customer_id": customer.ID,
})
go s.notification.SendEmail(ctx, tokenData.Email, "Your password has been reset successfully", customer.ID.Hex())
return &ResetPasswordResponse{
Message: "Password reset successfully",
Success: true,
+19 -9
View File
@@ -3,10 +3,12 @@ package user
import (
"context"
"errors"
"fmt"
"strings"
"time"
"tm/pkg/authorization"
"tm/pkg/logger"
"tm/pkg/notification"
"tm/pkg/response"
"go.mongodb.org/mongo-driver/v2/bson"
@@ -34,19 +36,21 @@ type Service interface {
// userService implements the Service interface
type userService struct {
repository Repository
logger logger.Logger
authService authorization.AuthorizationService
validator ValidationService
repository Repository
logger logger.Logger
authService authorization.AuthorizationService
validator ValidationService
notification notification.SDK
}
// NewUserService creates a new user service
func NewUserService(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, validator ValidationService) Service {
func NewUserService(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, validator ValidationService, notificationSDK notification.SDK) Service {
return &userService{
repository: repository,
logger: logger,
authService: authService,
validator: validator,
repository: repository,
logger: logger,
authService: authService,
validator: validator,
notification: notificationSDK,
}
}
@@ -112,6 +116,8 @@ func (s *userService) Register(ctx context.Context, form *CreateUserForm) (*User
"role": user.Role,
})
go s.notification.SendEmail(ctx, form.Email, fmt.Sprintf("Welcome to Tender Management\nUsername: %s\nPassword: %s", form.Username, form.Password), user.ID.Hex())
return user.ToResponse(), nil
}
@@ -214,6 +220,8 @@ func (s *userService) UpdateStatus(ctx context.Context, id string, form *UpdateU
"status": form.Status,
})
go s.notification.SendEmail(ctx, user.Email, fmt.Sprintf("Your account has been %s", strings.ToUpper(form.Status)), user.ID.Hex())
return nil
}
@@ -442,6 +450,8 @@ func (s *userService) ChangePassword(ctx context.Context, userID string, form *C
"user_id": userID,
})
go s.notification.SendEmail(ctx, user.Email, "Your password has been reset successfully", user.ID.Hex())
return nil
}