Implement phone number validation for customer and user registration and updates
Added functionality to check for existing customers and users by phone number during registration and updates. Updated the handler, service, and repository layers to include phone number checks, ensuring unique phone numbers across customers and users.
This commit is contained in:
@@ -55,6 +55,7 @@ func (h *Handler) CreateCustomer(c echo.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "customer with this email already exists" ||
|
if err.Error() == "customer with this email already exists" ||
|
||||||
err.Error() == "customer with this username already exists" ||
|
err.Error() == "customer with this username already exists" ||
|
||||||
|
err.Error() == "customer with this phone number already exists" ||
|
||||||
err.Error() == "company with this name already exists" ||
|
err.Error() == "company with this name already exists" ||
|
||||||
err.Error() == "company with this registration number already exists" ||
|
err.Error() == "company with this registration number already exists" ||
|
||||||
err.Error() == "company with this tax ID already exists" {
|
err.Error() == "company with this tax ID already exists" {
|
||||||
@@ -128,6 +129,7 @@ func (h *Handler) UpdateCustomer(c echo.Context) error {
|
|||||||
}
|
}
|
||||||
if err.Error() == "customer with this email already exists" ||
|
if err.Error() == "customer with this email already exists" ||
|
||||||
err.Error() == "customer with this username already exists" ||
|
err.Error() == "customer with this username already exists" ||
|
||||||
|
err.Error() == "customer with this phone number already exists" ||
|
||||||
err.Error() == "company with this name already exists" ||
|
err.Error() == "company with this name already exists" ||
|
||||||
err.Error() == "company with this registration number already exists" ||
|
err.Error() == "company with this registration number already exists" ||
|
||||||
err.Error() == "company with this tax ID already exists" {
|
err.Error() == "company with this tax ID already exists" {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type Repository interface {
|
|||||||
GetByID(ctx context.Context, id string) (*Customer, error)
|
GetByID(ctx context.Context, id string) (*Customer, error)
|
||||||
GetByEmail(ctx context.Context, email string) (*Customer, error)
|
GetByEmail(ctx context.Context, email string) (*Customer, error)
|
||||||
GetByUsername(ctx context.Context, username string) (*Customer, error)
|
GetByUsername(ctx context.Context, username string) (*Customer, error)
|
||||||
|
GetByPhone(ctx context.Context, phone string) (*Customer, error)
|
||||||
GetByIDs(ctx context.Context, ids []string) ([]Customer, error)
|
GetByIDs(ctx context.Context, ids []string) ([]Customer, error)
|
||||||
GetByRole(ctx context.Context, role CustomerRole) ([]Customer, error)
|
GetByRole(ctx context.Context, role CustomerRole) ([]Customer, error)
|
||||||
GetByCompanies(ctx context.Context, companies []string) ([]Customer, error)
|
GetByCompanies(ctx context.Context, companies []string) ([]Customer, error)
|
||||||
@@ -50,6 +51,8 @@ func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Re
|
|||||||
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", "email", "username"),
|
*orm.CreateTextIndex("search_idx", "email", "username"),
|
||||||
|
*orm.CreateUniqueIndex("phone_idx", bson.D{{Key: "phone", Value: 1}}).
|
||||||
|
WithPartialFilterExpression(bson.M{"phone": bson.M{"$type": "string", "$ne": ""}}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create indexes
|
// Create indexes
|
||||||
@@ -166,6 +169,24 @@ func (r *customerRepository) GetByEmail(ctx context.Context, email string) (*Cus
|
|||||||
return customer, nil
|
return customer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByPhone retrieves a customer by phone number
|
||||||
|
func (r *customerRepository) GetByPhone(ctx context.Context, phone string) (*Customer, error) {
|
||||||
|
filter := bson.M{"phone": phone}
|
||||||
|
customer, err := r.ormRepo.FindOne(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||||
|
return nil, ErrCustomerNotFound
|
||||||
|
}
|
||||||
|
r.logger.Error("Failed to get customer by phone", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"phone": phone,
|
||||||
|
})
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return customer, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetByUsername retrieves a customer by username
|
// GetByUsername retrieves a customer by username
|
||||||
func (r *customerRepository) GetByUsername(ctx context.Context, username string) (*Customer, error) {
|
func (r *customerRepository) GetByUsername(ctx context.Context, username string) (*Customer, error) {
|
||||||
filter := bson.M{"username": username}
|
filter := bson.M{"username": username}
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ func (s *customerService) Register(ctx context.Context, form *CreateCustomerForm
|
|||||||
return nil, errors.New("customer with this username already exists")
|
return nil, errors.New("customer with this username already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Phone != nil && *form.Phone != "" {
|
||||||
|
existingCustomer, _ = s.repository.GetByPhone(ctx, *form.Phone)
|
||||||
|
if existingCustomer != nil {
|
||||||
|
return nil, errors.New("customer with this phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check validator
|
// Check validator
|
||||||
if !s.validator.IsValidUsername(form.Username) {
|
if !s.validator.IsValidUsername(form.Username) {
|
||||||
return nil, errors.New("invalid username format")
|
return nil, errors.New("invalid username format")
|
||||||
@@ -373,6 +380,12 @@ func (s *customerService) Update(ctx context.Context, id string, form *UpdateCus
|
|||||||
}
|
}
|
||||||
|
|
||||||
if form.Phone != nil && (customer.Phone == nil || *form.Phone != *customer.Phone) {
|
if form.Phone != nil && (customer.Phone == nil || *form.Phone != *customer.Phone) {
|
||||||
|
if *form.Phone != "" {
|
||||||
|
existingCustomer, _ := s.repository.GetByPhone(ctx, *form.Phone)
|
||||||
|
if existingCustomer != nil && existingCustomer.ID.Hex() != id {
|
||||||
|
return nil, errors.New("customer with this phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
customer.Phone = form.Phone
|
customer.Phone = form.Phone
|
||||||
infoChanged = true
|
infoChanged = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type Repository interface {
|
|||||||
UpdatePasswordReset(ctx context.Context, id, hashedPassword, updatedBy string) error
|
UpdatePasswordReset(ctx context.Context, id, hashedPassword, updatedBy string) error
|
||||||
GetByEmail(ctx context.Context, email string) (*User, error)
|
GetByEmail(ctx context.Context, email string) (*User, error)
|
||||||
GetByUsername(ctx context.Context, username string) (*User, error)
|
GetByUsername(ctx context.Context, username string) (*User, error)
|
||||||
|
GetByPhone(ctx context.Context, phone string) (*User, error)
|
||||||
GetByIDs(ctx context.Context, userIDs []string) ([]User, error)
|
GetByIDs(ctx context.Context, userIDs []string) ([]User, error)
|
||||||
Search(ctx context.Context, form *SearchUsersForm, pagination *response.Pagination) (*orm.PaginatedResult[User], error)
|
Search(ctx context.Context, form *SearchUsersForm, pagination *response.Pagination) (*orm.PaginatedResult[User], error)
|
||||||
}
|
}
|
||||||
@@ -38,6 +39,8 @@ 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.CreateTextIndex("search_idx", "full_name", "email", "username"),
|
*orm.CreateTextIndex("search_idx", "full_name", "email", "username"),
|
||||||
|
*orm.CreateUniqueIndex("phone_idx", bson.D{{Key: "phone", Value: 1}}).
|
||||||
|
WithPartialFilterExpression(bson.M{"phone": bson.M{"$type": "string", "$ne": ""}}),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create indexes
|
// Create indexes
|
||||||
@@ -250,6 +253,23 @@ func (r *userRepository) GetByEmail(ctx context.Context, email string) (*User, e
|
|||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByPhone retrieves a user by phone number
|
||||||
|
func (r *userRepository) GetByPhone(ctx context.Context, phone string) (*User, error) {
|
||||||
|
user, err := r.ormRepo.FindOne(ctx, bson.M{"phone": phone})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||||
|
return nil, errors.New("user not found")
|
||||||
|
}
|
||||||
|
r.logger.Error("Failed to get user by phone", map[string]interface{}{
|
||||||
|
"error": err.Error(),
|
||||||
|
"phone": phone,
|
||||||
|
})
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetByUsername retrieves a user by username
|
// GetByUsername retrieves a user by username
|
||||||
func (r *userRepository) GetByUsername(ctx context.Context, username string) (*User, error) {
|
func (r *userRepository) GetByUsername(ctx context.Context, username string) (*User, error) {
|
||||||
user, err := r.ormRepo.FindOne(ctx, bson.M{"username": username})
|
user, err := r.ormRepo.FindOne(ctx, bson.M{"username": username})
|
||||||
|
|||||||
@@ -77,6 +77,13 @@ func (s *userService) Register(ctx context.Context, form *CreateUserForm) (*User
|
|||||||
return nil, errors.New("username already exists")
|
return nil, errors.New("username already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if form.Phone != nil && *form.Phone != "" {
|
||||||
|
existingUser, _ = s.repository.GetByPhone(ctx, *form.Phone)
|
||||||
|
if existingUser != nil {
|
||||||
|
return nil, errors.New("phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Hash password
|
// Hash password
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), bcrypt.DefaultCost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -185,6 +192,12 @@ func (s *userService) Update(ctx context.Context, id string, form *UpdateUserFor
|
|||||||
}
|
}
|
||||||
|
|
||||||
if form.Phone != nil {
|
if form.Phone != nil {
|
||||||
|
if *form.Phone != "" {
|
||||||
|
existingUser, _ := s.repository.GetByPhone(ctx, *form.Phone)
|
||||||
|
if existingUser != nil && existingUser.ID.Hex() != id {
|
||||||
|
return nil, errors.New("phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
user.Phone = form.Phone
|
user.Phone = form.Phone
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +587,12 @@ func (s *userService) UpdateProfile(ctx context.Context, userID string, form *Up
|
|||||||
user.Position = form.Position
|
user.Position = form.Position
|
||||||
}
|
}
|
||||||
if form.Phone != nil {
|
if form.Phone != nil {
|
||||||
|
if *form.Phone != "" {
|
||||||
|
existingUser, _ := s.repository.GetByPhone(ctx, *form.Phone)
|
||||||
|
if existingUser != nil && existingUser.ID.Hex() != userID {
|
||||||
|
return errors.New("phone number already exists")
|
||||||
|
}
|
||||||
|
}
|
||||||
user.Phone = form.Phone
|
user.Phone = form.Phone
|
||||||
}
|
}
|
||||||
if form.ProfileImage != nil {
|
if form.ProfileImage != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user