fixed blocking important issues

This commit is contained in:
Mazyar
2026-05-30 12:29:45 +03:30
parent bb221f3cda
commit ad702f24bf
14 changed files with 174 additions and 72 deletions
+5 -5
View File
@@ -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{
+7
View File
@@ -0,0 +1,7 @@
package customer
import "errors"
var (
ErrCustomerNotFound = errors.New("customer not found")
)
+6 -5
View File
@@ -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")
+45 -8
View File
@@ -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