Enhance Customer Module with Validation and Username Handling
- Introduced a new ValidationService for customer operations to ensure valid username formats. - Updated customer service and handler to utilize the new validation service, enhancing input validation during registration and updates. - Modified CreateCustomerForm and UpdateCustomerForm to enforce username validation rules. - Adjusted repository indexing to improve search efficiency by refining the text index for customer data. - Ensured consistent handling of usernames across the customer module, improving overall data integrity and user experience.
This commit is contained in:
+4
-3
@@ -146,14 +146,15 @@ func main() {
|
|||||||
"repositories": []string{"customer", "user", "company", "category", "tender", "feedback", "tender_approval", "inquiry"},
|
"repositories": []string{"customer", "user", "company", "category", "tender", "feedback", "tender_approval", "inquiry"},
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize validation service
|
// Initialize validation services
|
||||||
userValidator := user.NewValidationService()
|
userValidator := user.NewValidationService()
|
||||||
|
customerValidator := customer.NewValidationService()
|
||||||
|
|
||||||
// Initialize services with repositories
|
// Initialize services with repositories
|
||||||
userService := user.NewService(userRepository, logger, userAuthService, userValidator, notificationSDK)
|
userService := user.NewService(userRepository, logger, userAuthService, userValidator, notificationSDK)
|
||||||
categoryService := company_category.NewService(categoryRepository, logger)
|
categoryService := company_category.NewService(categoryRepository, logger)
|
||||||
companyService := company.NewService(companyRepository, categoryService, logger)
|
companyService := company.NewService(companyRepository, categoryService, logger)
|
||||||
customerService := customer.NewService(customerRepository, logger, customerAuthService, companyService, redisClient, notificationSDK)
|
customerService := customer.NewService(customerRepository, logger, customerAuthService, companyService, redisClient, notificationSDK, customerValidator)
|
||||||
tenderService := tender.NewService(tenderRepository, companyService, logger)
|
tenderService := tender.NewService(tenderRepository, companyService, logger)
|
||||||
feedbackService := feedback.NewService(feedbackRepo, tenderService, companyService, logger)
|
feedbackService := feedback.NewService(feedbackRepo, tenderService, companyService, logger)
|
||||||
tenderApprovalService := tender_approval.NewService(tenderApprovalRepository, tenderService, logger)
|
tenderApprovalService := tender_approval.NewService(tenderApprovalRepository, tenderService, logger)
|
||||||
@@ -166,7 +167,7 @@ func main() {
|
|||||||
|
|
||||||
// Initialize handlers with services
|
// Initialize handlers with services
|
||||||
userHandler := user.NewHandler(userService, logger, userValidator, userAuthService)
|
userHandler := user.NewHandler(userService, logger, userValidator, userAuthService)
|
||||||
customerHandler := customer.NewHandler(customerService, userHandler, customerAuthService, logger)
|
customerHandler := customer.NewHandler(customerService, userHandler, customerAuthService, logger, customerValidator)
|
||||||
companyHandler := company.NewHandler(companyService, userHandler, logger)
|
companyHandler := company.NewHandler(companyService, userHandler, logger)
|
||||||
categoryHandler := company_category.NewHandler(categoryService, logger)
|
categoryHandler := company_category.NewHandler(categoryService, logger)
|
||||||
tenderHandler := tender.NewHandler(tenderService, logger)
|
tenderHandler := tender.NewHandler(tenderService, logger)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type CreateCustomerForm struct {
|
|||||||
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
|
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
|
||||||
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
|
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
|
||||||
Companies []string `json:"companies,omitempty" valid:"optional"`
|
Companies []string `json:"companies,omitempty" valid:"optional"`
|
||||||
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
|
Username string `json:"username" valid:"required,username,length(3|30)" example:"user"`
|
||||||
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
|
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
|
||||||
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
|
Password string `json:"password" valid:"required,length(8|128)" example:"User!1234"`
|
||||||
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
|
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
|
||||||
@@ -25,7 +25,7 @@ type UpdateCustomerForm struct {
|
|||||||
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
|
Type string `json:"type" valid:"required,in(individual|company|government)" example:"individual"`
|
||||||
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
|
Role string `json:"role" valid:"required,in(admin|analyst)" example:"analyst"`
|
||||||
Companies []string `json:"companies,omitempty" valid:"optional"`
|
Companies []string `json:"companies,omitempty" valid:"optional"`
|
||||||
Username string `json:"username" valid:"required,alphanum,length(3|30)" example:"user"`
|
Username string `json:"username" valid:"required,username,length(3|30)" example:"user"`
|
||||||
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
|
Email string `json:"email" valid:"required,email" example:"user@opplens.com"`
|
||||||
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
|
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)" example:"+1234567890"`
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ type ChangePasswordForm struct {
|
|||||||
|
|
||||||
type UpdateProfileForm struct {
|
type UpdateProfileForm struct {
|
||||||
FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)"`
|
FullName *string `json:"full_name,omitempty" valid:"optional,length(2|100)"`
|
||||||
Username *string `json:"username,omitempty" valid:"optional,alphanum,length(3|30)"`
|
Username *string `json:"username,omitempty" valid:"optional,username,length(3|30)"`
|
||||||
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)"`
|
Phone *string `json:"phone,omitempty" valid:"optional,length(10|20)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,17 @@ type Handler struct {
|
|||||||
authService authorization.AuthorizationService
|
authService authorization.AuthorizationService
|
||||||
userHandler *user.Handler
|
userHandler *user.Handler
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
|
validator ValidationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHandler creates a new customer handler
|
// NewHandler creates a new customer handler
|
||||||
func NewHandler(service Service, userHandler *user.Handler, authService authorization.AuthorizationService, logger logger.Logger) *Handler {
|
func NewHandler(service Service, userHandler *user.Handler, authService authorization.AuthorizationService, logger logger.Logger, validator ValidationService) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
service: service,
|
service: service,
|
||||||
authService: authService,
|
authService: authService,
|
||||||
userHandler: userHandler,
|
userHandler: userHandler,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
validator: validator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Re
|
|||||||
// Create indexes using the ORM's index management
|
// Create indexes using the ORM's index management
|
||||||
indexes := []orm.Index{
|
indexes := []orm.Index{
|
||||||
*orm.CreateUniqueIndex("username_idx", bson.D{{Key: "username", Value: 1}}),
|
*orm.CreateUniqueIndex("username_idx", bson.D{{Key: "username", Value: 1}}),
|
||||||
*orm.CreateTextIndex("search_idx", "full_name", "email", "username", "phone"),
|
*orm.CreateTextIndex("search_idx", "email", "username"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create indexes
|
// Create indexes
|
||||||
|
|||||||
@@ -60,10 +60,11 @@ type customerService struct {
|
|||||||
companyService company.Service
|
companyService company.Service
|
||||||
redisClient redis.Client
|
redisClient redis.Client
|
||||||
notification notification.SDK
|
notification notification.SDK
|
||||||
|
validator ValidationService
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new customer service
|
// New creates a new customer service
|
||||||
func NewService(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, companyService company.Service, redisClient redis.Client, notificationSDK notification.SDK) Service {
|
func NewService(repository Repository, logger logger.Logger, authService authorization.AuthorizationService, companyService company.Service, redisClient redis.Client, notificationSDK notification.SDK, validator ValidationService) Service {
|
||||||
return &customerService{
|
return &customerService{
|
||||||
repository: repository,
|
repository: repository,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
@@ -71,6 +72,7 @@ func NewService(repository Repository, logger logger.Logger, authService authori
|
|||||||
companyService: companyService,
|
companyService: companyService,
|
||||||
redisClient: redisClient,
|
redisClient: redisClient,
|
||||||
notification: notificationSDK,
|
notification: notificationSDK,
|
||||||
|
validator: validator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +84,11 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
|
|||||||
return nil, errors.New("customer with this email already exists")
|
return nil, errors.New("customer with this email already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check validator
|
||||||
|
if !s.validator.IsValidUsername(form.Username) {
|
||||||
|
return nil, errors.New("invalid username format")
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that all company IDs exist
|
// Verify that all company IDs exist
|
||||||
var Companies []string
|
var Companies []string
|
||||||
if len(form.Companies) > 0 {
|
if len(form.Companies) > 0 {
|
||||||
@@ -307,6 +314,11 @@ func (s *customerService) Update(ctx context.Context, id string, form *UpdateCus
|
|||||||
customer.Email = form.Email
|
customer.Email = form.Email
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check validator
|
||||||
|
if !s.validator.IsValidUsername(form.Username) {
|
||||||
|
return nil, errors.New("invalid username format")
|
||||||
|
}
|
||||||
|
|
||||||
// Check if username already exists (if changing username)
|
// Check if username already exists (if changing username)
|
||||||
if form.Username != "" && strings.ToLower(form.Username) != customer.Username {
|
if form.Username != "" && strings.ToLower(form.Username) != customer.Username {
|
||||||
existingCustomer, _ := s.repository.GetByUsername(ctx, strings.ToLower(form.Username))
|
existingCustomer, _ := s.repository.GetByUsername(ctx, strings.ToLower(form.Username))
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package customer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/asaskevich/govalidator"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidationService defines validation methods for customer operations
|
||||||
|
type ValidationService interface {
|
||||||
|
IsValidUsername(username string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// validationService implements the ValidationService interface
|
||||||
|
type validationService struct {
|
||||||
|
usernameRegex *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewValidationService creates a new validation service
|
||||||
|
func NewValidationService() ValidationService {
|
||||||
|
// Compile the username regex pattern
|
||||||
|
usernameRegex := regexp.MustCompile(`^[a-zA-Z0-9](?:[a-zA-Z0-9._]*[a-zA-Z0-9])?$`)
|
||||||
|
|
||||||
|
// Register custom validator with govalidator
|
||||||
|
govalidator.CustomTypeTagMap.Set("username", govalidator.CustomTypeValidator(func(i interface{}, o interface{}) bool {
|
||||||
|
username, ok := i.(string)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return usernameRegex.MatchString(username)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return &validationService{
|
||||||
|
usernameRegex: usernameRegex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidUsername checks if a username matches the required pattern
|
||||||
|
func (v *validationService) IsValidUsername(username string) bool {
|
||||||
|
return v.usernameRegex.MatchString(username)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user