fixed blocking important issues
This commit is contained in:
@@ -36,7 +36,7 @@ func (s *customerService) AdminResetPassword(ctx context.Context, actorID, targe
|
||||
|
||||
customer, err := s.repository.GetByID(ctx, targetID)
|
||||
if err != nil {
|
||||
if err.Error() == "customer not found" {
|
||||
if errors.Is(err, ErrCustomerNotFound) {
|
||||
return nil, errCustomerNotFound
|
||||
}
|
||||
s.logger.Error("Failed to load customer for password reset", map[string]interface{}{
|
||||
@@ -68,9 +68,10 @@ func (s *customerService) AdminResetPassword(ctx context.Context, actorID, targe
|
||||
return nil, errCustResetPasswordFailed
|
||||
}
|
||||
|
||||
customer.Password = string(hashedPassword)
|
||||
customer.UpdatedBy = &actorID
|
||||
if err := s.repository.Update(ctx, customer); err != nil {
|
||||
if err := s.repository.UpdatePasswordReset(ctx, targetID, string(hashedPassword), actorID); err != nil {
|
||||
if errors.Is(err, ErrCustomerNotFound) {
|
||||
return nil, errCustomerNotFound
|
||||
}
|
||||
s.logger.Error("Failed to persist reset password", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"customer_id": targetID,
|
||||
@@ -83,7 +84,6 @@ func (s *customerService) AdminResetPassword(ctx context.Context, actorID, targe
|
||||
"error": err.Error(),
|
||||
"customer_id": targetID,
|
||||
})
|
||||
return nil, errCustResetPasswordFailed
|
||||
}
|
||||
|
||||
s.auditLogger.Log(ctx, audit.Entry{
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package customer
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrCustomerNotFound = errors.New("customer not found")
|
||||
)
|
||||
@@ -1,6 +1,7 @@
|
||||
package customer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"tm/internal/user"
|
||||
"tm/pkg/authorization"
|
||||
@@ -268,14 +269,14 @@ func (h *Handler) ResetCustomerPassword(c echo.Context) error {
|
||||
targetID := c.Param("id")
|
||||
result, err := h.service.AdminResetPassword(c.Request().Context(), actorID, targetID)
|
||||
if err != nil {
|
||||
switch err.Error() {
|
||||
case errInvalidCustomerID.Error():
|
||||
switch {
|
||||
case errors.Is(err, errInvalidCustomerID):
|
||||
return response.BadRequest(c, "Invalid id", "")
|
||||
case errCustomerNotFound.Error():
|
||||
case errors.Is(err, errCustomerNotFound):
|
||||
return response.NotFound(c, "Customer not found")
|
||||
case errCannotResetCustPassword.Error():
|
||||
case errors.Is(err, errCannotResetCustPassword):
|
||||
return response.Conflict(c, "Cannot reset password for this user")
|
||||
case errCustResetPasswordRate.Error():
|
||||
case errors.Is(err, errCustResetPasswordRate):
|
||||
return response.TooManyRequests(c, "Too many password reset requests")
|
||||
default:
|
||||
return response.InternalServerError(c, "Failed to reset password")
|
||||
|
||||
@@ -3,12 +3,14 @@ package customer
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"tm/pkg/logger"
|
||||
orm "tm/pkg/mongo"
|
||||
"tm/pkg/response"
|
||||
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
mongopkg "go.mongodb.org/mongo-driver/v2/mongo"
|
||||
)
|
||||
|
||||
// Repository defines the interface for customer data operations
|
||||
@@ -16,6 +18,7 @@ type Repository interface {
|
||||
Login(ctx context.Context, id, deviceToken string) error
|
||||
Register(ctx context.Context, customer *Customer) error
|
||||
Update(ctx context.Context, customer *Customer) error
|
||||
UpdatePasswordReset(ctx context.Context, id, hashedPassword, updatedBy string) error
|
||||
UpdateStatus(ctx context.Context, id string, status CustomerStatus) error
|
||||
GetByID(ctx context.Context, id string) (*Customer, error)
|
||||
GetByEmail(ctx context.Context, email string) (*Customer, error)
|
||||
@@ -30,8 +33,9 @@ type Repository interface {
|
||||
|
||||
// customerRepository implements the Repository interface using the MongoDB ORM
|
||||
type customerRepository struct {
|
||||
ormRepo orm.Repository[Customer]
|
||||
logger logger.Logger
|
||||
ormRepo orm.Repository[Customer]
|
||||
collection *mongopkg.Collection
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
func collection() string {
|
||||
@@ -55,11 +59,13 @@ func NewRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Re
|
||||
}
|
||||
|
||||
// Create ORM repository
|
||||
ormRepo := orm.NewRepository[Customer](mongoManager.GetCollection(collection()), logger)
|
||||
collection := mongoManager.GetCollection(collection())
|
||||
ormRepo := orm.NewRepository[Customer](collection, logger)
|
||||
|
||||
return &customerRepository{
|
||||
ormRepo: ormRepo,
|
||||
logger: logger,
|
||||
ormRepo: ormRepo,
|
||||
collection: collection,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +134,7 @@ func (r *customerRepository) GetByID(ctx context.Context, id string) (*Customer,
|
||||
customer, err := r.ormRepo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||
return nil, errors.New("customer not found")
|
||||
return nil, ErrCustomerNotFound
|
||||
}
|
||||
r.logger.Error("Failed to get customer by ID", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
@@ -146,7 +152,7 @@ func (r *customerRepository) GetByEmail(ctx context.Context, email string) (*Cus
|
||||
customer, err := r.ormRepo.FindOne(ctx, filter)
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||
return nil, errors.New("customer not found")
|
||||
return nil, ErrCustomerNotFound
|
||||
}
|
||||
r.logger.Error("Failed to get customer by email", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
@@ -164,7 +170,7 @@ func (r *customerRepository) GetByUsername(ctx context.Context, username string)
|
||||
customer, err := r.ormRepo.FindOne(ctx, filter)
|
||||
if err != nil {
|
||||
if errors.Is(err, orm.ErrDocumentNotFound) {
|
||||
return nil, errors.New("customer not found")
|
||||
return nil, ErrCustomerNotFound
|
||||
}
|
||||
r.logger.Error("Failed to get customer by username", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
@@ -295,6 +301,37 @@ func (r *customerRepository) Update(ctx context.Context, customer *Customer) err
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdatePasswordReset atomically persists a new password hash and audit fields.
|
||||
func (r *customerRepository) UpdatePasswordReset(ctx context.Context, id, hashedPassword, updatedBy string) error {
|
||||
now := time.Now().Unix()
|
||||
updateDoc := bson.M{
|
||||
"$set": bson.M{
|
||||
"password": hashedPassword,
|
||||
"updated_at": now,
|
||||
"updated_by": updatedBy,
|
||||
},
|
||||
}
|
||||
|
||||
objectID, err := bson.ObjectIDFromHex(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid id format: %w", err)
|
||||
}
|
||||
|
||||
result, err := r.collection.UpdateOne(ctx, bson.M{"_id": objectID}, updateDoc)
|
||||
if err != nil {
|
||||
r.logger.Error("Failed to update password reset", map[string]interface{}{
|
||||
"error": err.Error(),
|
||||
"customer_id": id,
|
||||
})
|
||||
return err
|
||||
}
|
||||
if result.MatchedCount == 0 {
|
||||
return ErrCustomerNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete deletes a customer (hard delete)
|
||||
func (r *customerRepository) Delete(ctx context.Context, id string) error {
|
||||
// Get customer first
|
||||
|
||||
Reference in New Issue
Block a user