Эх сурвалжийг харах

Refactor response handling to improve consistency in success and error responses across the application

Erwin Jacimino 6 сар өмнө
parent
commit
68c153327e

+ 1 - 1
middleware/in_time.py

@@ -21,7 +21,7 @@ class InTimeMiddleware(BaseHTTPMiddleware):
     """
     
     async def dispatch(self, request: Request, call_next):
-        if "admin" in request.headers.get("Origin", ""):
+        if "admin" in request.headers.get("Origin", "") or "localhost:8000" in request.headers.get("Origin", ""):
             return await call_next(request)
         authorization = request.headers.get("Authorization")
         if not authorization:

+ 9 - 2
public/main/js/app.js

@@ -557,9 +557,10 @@ async function checkCache() {
     
     if (tokenCache) {
         userToken = tokenCache;
+        console.log(userToken);
         try {
-            const data = await getUserData(userToken);
-            user = data.data;
+            user = await getUserData(userToken);
+            console.log(user);
         } catch (error) {
             console.error("Error fetching user data:", error);
             console.error("Invalid user token, clearing cache.");
@@ -592,7 +593,13 @@ async function checkCache() {
             document.querySelector("#recoveryPIN").classList.add("hidden");
             cacheMode = true;
             return true;
+        }else{
+            console.log("No hay user");
+            return false;
         }
+    }else{
+        console.log("No hay token");
+        return false;
     }
     return cacheMode;
 }

+ 6 - 7
public/main/js/service/auth.js

@@ -17,27 +17,26 @@ async function login(email, pin, table) {
   }
   if (response.status == 404) {
     const errorData = await response.json()
-    const data = errorData.error.message
+    const data = errorData.message
   } else if (response.status == 401) {
     const errorData = await response.json()
-    const data = errorData.error.message
-    showError(`${data} Intentos restantes: ${errorData.error.attempts_remaining || 0}`);
+    const data = errorData.message
+    showError(`${data} Intentos restantes: ${errorData.data.attempts_remaining || 0}`);
     throw new Error(errorData.message);
   } else if (response.status == 429) {
     const errorData = await response.json()
-    const data = errorData.error.message
+    const data = errorData.message
     showError(`${data} Intenta más tarde.`);
     throw new Error(errorData.message);
   } else if (response.status != 200) {
     console.error(response.status, response.statusText);
     const errorData = await response.json()
-    const data = errorData.error.message
+    const data = errorData.message
     showError(`${data}`);
     throw new Error(data);
   }
   const JSONdata = await response.json();
-  const data = JSONdata.data;
-  const userData = data.data;
+  const userData = JSONdata.data;
   console.log(userData);
   if (!userData || !userData.token) {
     showError("Error al iniciar sesión, Intenta mas tarde.");

+ 1 - 1
public/main/js/service/product.js

@@ -7,7 +7,7 @@ import { beforeUnloadHandler } from "../app.js";
   }
   if (!response.ok) {
     const errorData = await response.json()
-    throw new Error(errorData.error.message || `Error del servidor: ${response.status}`);
+    throw new Error(errorData.message || `Error del servidor: ${response.status}`);
   }
   const data = await response.json();
   return data.data;

+ 1 - 1
public/main/js/service/user.js

@@ -77,7 +77,7 @@ async function fetchUserSales(userId, token) {
       throw new Error(`Error fetching user sales: ${response.statusText}`);
     }
     const sales = await response.json();
-    return sales.data.sales;
+    return sales.data;
   } catch (error) {
     console.error('Error fetching user sales:', error);
     throw error;

+ 4 - 4
routes/chat.py

@@ -158,7 +158,7 @@ async def notify_users(message: NotifyRequest, _: User = Depends(get_current_use
     await broadcast.publish(channel=broadcast_channel, message=json.dumps(response))
     
     await broadcast.disconnect()
-    return success_response({"message": "Notification sent successfully"})
+    return success_response({}, message="Notificación enviada correctamente")
 
 @chat_router.get("/users")
 async def get__connected_users(q: Optional[str] = Query(None), _: User = Depends(get_current_user)):
@@ -167,12 +167,12 @@ async def get__connected_users(q: Optional[str] = Query(None), _: User = Depends
     all_users = redis_client.smembers("connected_users")
     all_users = [json.loads(user)["username"] for user in all_users]  # type: ignore
     if q is None or q.strip() == "":
-        return success_response({"users": all_users})
+        return success_response(data=all_users)
     filtered_users = [user for user in all_users if q.lower() in user.lower()]
-    return success_response({"users": filtered_users})
+    return success_response(data={"users": filtered_users})
 
 @chat_router.get("/onlines")
 async def get_online_user_count(_: User = Depends(get_current_user)):
     """Get the count of online users (solo local al worker)"""
     all_users = redis_client.smembers("connected_users")
-    return success_response({"count": len(all_users)})  # type: ignore
+    return success_response(data={"count": len(all_users)})  # type: ignore

+ 15 - 15
routes/orders.py

@@ -49,12 +49,12 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
     # Input validation
     if not items or not table:
         logger.warning(f"Invalid order data from user {current_user.email}: missing items or table")
-        return error_response({"message": ErrorResponse.MISSING_FIELDS}, status_code=400)
+        return error_response(message=ErrorResponse.MISSING_FIELDS, status_code=400)
 
     if not isinstance(table, int):
         logger.warning(f"Invalid table type from user {current_user.email}: {type(table)}")
        
-        return error_response({"message": ErrorResponse.INVALID_TABLE_TYPE}, status_code=400)
+        return error_response(message=ErrorResponse.INVALID_TABLE_TYPE, status_code=400)
 
     logger.info(f"Processing order for table {table} with {len(items)} items")
 
@@ -72,7 +72,7 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
     except Exception as e:
         error_msg = f"Error getting products: {e}"
         logger.error(error_msg)
-        return error_response({"message": error_msg}, status_code=500)
+        return error_response(message=error_msg, status_code=500)
 
     printers = {}
     
@@ -105,11 +105,11 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
                 email_thread.start()
                 
                 
-                return error_response({"message": ErrorResponse.PRINTER_DISCONNECTED}, status_code=424)
+                return error_response(message=ErrorResponse.PRINTER_DISCONNECTED, status_code=424)
                 
         except Exception as e:
             logger.error(f"Error checking printer status: {e}")
-            return error_response({"message": f"Error checking printer status: {e}"}, status_code=424)
+            return error_response(message=f"Error checking printer status: {e}", status_code=424)
 
 
     # Input validation
@@ -156,12 +156,12 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
         error_msg = f"Error with Fudo integration: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": error_msg}, status_code=500)
+        return error_response(message=error_msg, status_code=500)
 
     if product_errors:
         logger.error(f"Product errors occurred: {product_errors}")
         
-        return error_response({"message": ErrorResponse.PRODUCT_ADD_ERROR, "errors": product_errors}, status_code=424)
+        return error_response(error={"errors": product_errors}, message=ErrorResponse.PRODUCT_ADD_ERROR, status_code=424)
 
     # User validation
     try:
@@ -169,7 +169,7 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
         if not user:
             logger.warning(f"User not found: {order.customerId}")
             
-            return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=order.customerId)}, status_code=404)
+            return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=order.customerId), status_code=404)
         
         logger.info(f"Order customer validated: {user.email}")
         
@@ -177,7 +177,7 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
     except Exception as e:
         error_msg = f"Error validating user {order.customerId}: {e}"
         
-        return error_response({"message": error_msg}, status_code=500)
+        return error_response(message=error_msg, status_code=500)
     
     # Get active sale
     try:
@@ -186,7 +186,7 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
             error_msg = f"No active sale found for table {table}"
             logger.error(error_msg)
             
-            return error_response({"message": error_msg}, status_code=404)
+            return error_response(message=error_msg, status_code=404)
             
         active_sale_id = active_sale_id['id']
         logger.info(f"Active sale found for table {table}: {active_sale_id}")
@@ -194,7 +194,7 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
         error_msg = f"Error retrieving active sale for table {table}: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": error_msg}, status_code=500)
+        return error_response(message=error_msg, status_code=500)
 
     # Update user reward progress
     try:
@@ -226,13 +226,13 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
         else:
             error_msg = "Failed to create sale record"
             logger.error(error_msg)
-            return error_response({"message": error_msg}, status_code=500)
+            return error_response(message=error_msg, status_code=500)
             
     except Exception as e:
         error_msg = f"Error creating sale record: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": error_msg}, status_code=500)
+        return error_response(message=error_msg, status_code=500)
 
     # Print order
     try:
@@ -267,11 +267,11 @@ async def printer_order(order: OrderWeb, current_user: User = Depends(get_curren
     except Exception as e:
         error_msg = f"Error printing order for table {table}: {e}"
         logger.error(error_msg)
-        return error_response({"message": error_msg}, status_code=500)  
+        return error_response(message=error_msg, status_code=500)  
         # Don't fail the order for print issues, just log it
 
     logger.info(f"Logging order for table {table} with sale ID {sale}, products= {[(product.name, item.quantity) for product, item in zip(products, items)]}")
         
     logger.info(f"Order processing completed successfully for table {table}, sale ID: {sale}")
-    return success_response({"message": SuccessResponse.ORDER_SUCCESS, "new_progress": new_progress})
+    return success_response(data={"new_progress": new_progress}, message=SuccessResponse.ORDER_SUCCESS)
 

+ 15 - 15
routes/products.py

@@ -77,7 +77,7 @@ async def get_products(status: Optional[int] = Query(None), current_user = Depen
         # Filter products by status if provided
         all_products = [product for product in all_products if product['status'] == status]
 
-    return success_response({"products": all_products, "message": SuccessResponse.PRODUCTS_FETCH_SUCCESS})
+    return success_response({"products": all_products}, message= SuccessResponse.PRODUCTS_FETCH_SUCCESS)
 
 @product_router.get("/{product_id}")
 async def get_product(product_id: int, current_user = Depends(get_current_user)):
@@ -97,10 +97,10 @@ async def get_product(product_id: int, current_user = Depends(get_current_user))
     # Attempt to find product by ID
     product = product_data_service.get_by_id(product_id)
     if product:
-        return success_response({"product": product.model_dump(exclude={"promo_id", "promo_price", "promo_day"}), "message": SuccessResponse.PRODUCTS_FETCH_SUCCESS})
+        return success_response({"product": product.model_dump(exclude={"promo_id", "promo_price", "promo_day"})}, message = SuccessResponse.PRODUCTS_FETCH_SUCCESS)
 
     # Return 404 if product not found
-    return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=product_id)}, status_code=404)
+    return error_response(message = UserResponse.USER_NOT_FOUND.format(user_id=product_id), status_code=404)
 
 @product_router.get("/free-beer/{table_id}")
 async def get_free_beer(table_id: int, current_user:User = Depends(get_current_user)):
@@ -115,10 +115,10 @@ async def get_free_beer(table_id: int, current_user:User = Depends(get_current_u
     
     if current_user.reward_progress >= 100:
         print_ticket(table_id)
-        return success_response({"message": SuccessResponse.REWARD_SUCCESS}, status_code=200)
+        return success_response(message= SuccessResponse.REWARD_SUCCESS, status_code=200)
 
     # Return 404 if free beer product not found
-    return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id="free_beer")}, status_code=404)
+    return error_response(message= UserResponse.USER_NOT_FOUND.format(user_id="free_beer"), status_code=404)
 # MODERATE RISK OPERATIONS - Requires permissions >= 1 (Manager level or above)
 
 @product_router.post("/create")
@@ -140,10 +140,10 @@ async def create_product(product: ProductCreateRequest, current_user = Depends(g
     if user_data_service.permissions(current_user.id) > 0:
         # Create new product with provided data
         product_data_service.create(**product.model_dump(exclude_unset=True))
-        return success_response({"message": SuccessResponse.PRODUCT_CREATE_SUCCESS, "product": product.model_dump()}, status_code=201)
+        return success_response(product.model_dump(), message= SuccessResponse.PRODUCT_CREATE_SUCCESS, status_code=201)
     
     # Return 403 if user lacks permissions
-    return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+    return error_response(message= UserResponse.NOT_PERMITTED, status_code=403)
 
 @product_router.patch("/{product_id}/swap-status")
 async def switch_product_status(product_id: int, current_user = Depends(get_current_user)): 
@@ -166,13 +166,13 @@ async def switch_product_status(product_id: int, current_user = Depends(get_curr
         # Update only the status field of the specified product
         product = product_data_service.get_by_id(product_id)
         if not product:
-            return error_response({"message": ErrorResponse.PRODDUCT_NOT_FOUND.format(product_id=product_id)}, status_code=404)
+            return error_response(message= ErrorResponse.PRODDUCT_NOT_FOUND.format(product_id=product_id), status_code=404)
         status = 0 if product.status == 1 else 1
         product_data_service.update(product_id, status=status)
-        return success_response({"message": SuccessResponse.PRODUCT_EDIT_SUCCESS})
+        return success_response(message=SuccessResponse.PRODUCT_EDIT_SUCCESS)
     
     # Return 403 if user lacks permissions
-    return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+    return error_response(message=UserResponse.NOT_PERMITTED, status_code=403)
 
 # HIGH RISK OPERATIONS - Requires permissions == 2 (Admin level only)
 
@@ -198,10 +198,10 @@ async def delete_product(product_id: int, current_user = Depends(get_current_use
     if user_data_service.permissions(current_user.id) == 2:
         # Permanently delete the product
         product_data_service.delete(product_id)
-        return success_response({"message": SuccessResponse.PRODUCT_DELETE_SUCCESS})
+        return success_response(message=SuccessResponse.PRODUCT_DELETE_SUCCESS)
     
     # Return 403 if user lacks admin permissions    
-    return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+    return error_response(message=UserResponse.NOT_PERMITTED, status_code=403)
 
 @product_router.patch("/{product_id}/edit")
 async def edit_product(product_id: int, product: ProductEditRequest, current_user = Depends(get_current_user)):
@@ -227,10 +227,10 @@ async def edit_product(product_id: int, product: ProductEditRequest, current_use
         # Retrieve updated product to return in response
         edited_product = product_data_service.get_by_id(product_id)
         if not edited_product:
-            return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=product_id)}, status_code=404)
+            return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=product_id), status_code=404)
         
         logger.info(f"Product {product_id} edited successfully")
-        return success_response({"message": SuccessResponse.PRODUCT_EDIT_SUCCESS, "product": edited_product.model_dump()})
+        return success_response(data=edited_product.model_dump(), message=SuccessResponse.PRODUCT_EDIT_SUCCESS)
     
     # Return 403 if user lacks permissions    
-    return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+    return error_response(message=UserResponse.NOT_PERMITTED, status_code=403)

+ 1 - 1
routes/sales.py

@@ -32,4 +32,4 @@ def get_user_sales(user_id: int):
     if not sales:
         return error_response(ErrorResponse.SALE_NOT_FOUND, status_code=404)
     logger.info(f"Sales found for user {user_id}: {len(sales)} sales")
-    return success_response({"sales": [{**sale.model_dump(), "date": sale.date.isoformat()} for sale in sales], "message": "Ventas obtenidas correctamente."})
+    return success_response(data=[{**sale.model_dump(), "date": sale.date.isoformat()} for sale in sales], message="Ventas obtenidas correctamente.")

+ 1 - 1
routes/store.py

@@ -29,4 +29,4 @@ def get_table_exists(q: str = Query(..., description="q parameter")):
 
 @store_router.get("/state", response_class=JSONResponse)
 def get_store_state(_: User = Depends(get_current_user)):
-    return success_response({"state": settings.IS_OPEN_STORE})
+    return success_response(data={"state": settings.IS_OPEN_STORE})

+ 58 - 60
routes/users.py

@@ -37,9 +37,9 @@ async def exists_user(request: UserIDRequest):
         """Check if user exists"""
         user = user_data_service.get_by_id(request.id)
         if user:
-            return success_response({"exists": True, "message": UserResponse.USER_EXISTS})
+            return success_response(data={"exists": True}, message=UserResponse.USER_EXISTS)
         else:
-            return error_response({"exists": False, "message": UserResponse.USER_DOES_NOT_EXIST})
+            return error_response(error={"exists": False}, message=UserResponse.USER_DOES_NOT_EXIST)
 
 @user_router.post("/register")
 async def register_user(request: RegisterUserRequest):
@@ -52,7 +52,7 @@ async def register_user(request: RegisterUserRequest):
     if not validate_rut(request.rut):
         logger.warning(f"Registration failed for {request.email}: invalid RUT {request.rut}")
         
-        return error_response({"message": ErrorResponse.INVALID_RUT})
+        return error_response(message=ErrorResponse.INVALID_RUT)
 
     # Check if user already exists by email
     try:
@@ -60,14 +60,14 @@ async def register_user(request: RegisterUserRequest):
         if user:
             logger.warning(f"Registration failed for {request.email}: user already exists")
             
-            return error_response({"message": UserResponse.USER_ALREADY_EXISTS})
+            return error_response(message=UserResponse.USER_ALREADY_EXISTS)
             
         # Check if RUT already exists
         user = user_data_service.get_by_rut(request.rut)
         if user:
             logger.warning(f"Registration failed for {request.email}: RUT already exists")
             
-            return error_response({"message": UserResponse.USER_ALREADY_EXISTS})
+            return error_response(message=UserResponse.USER_ALREADY_EXISTS)
 
     except Exception as e:
         error_msg = f"Database error during user validation: {e}"
@@ -101,20 +101,20 @@ async def register_user(request: RegisterUserRequest):
         )
         
         
-        return success_response({"message": SuccessResponse.USER_CREATED_SUCCESS}, status_code=201)
+        return success_response(message=SuccessResponse.USER_CREATED_SUCCESS, status_code=201)
         
     except Exception as e:
         error_msg = f"Error during registration process for {request.email}: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": f"Error interno del servidor: {e}"}, status_code=500)
+        return error_response(message=f"Error interno del servidor: {e}", status_code=500)
 
 @user_router.post("/create-user")
 async def create_user(request: PinUserRequest, q: str):
     """Create a new user with PIN"""
     data = redis_client.get(f"verify:{q}")
     if not redis_client.get(f"verify:{q}"):
-        return error_response({"message": ErrorResponse.INVALID_VERIFICATION_CODE})
+        return error_response(message=ErrorResponse.INVALID_VERIFICATION_CODE)
     else:
         data = json.loads(str(data))
     name = data.get("name")
@@ -122,20 +122,20 @@ async def create_user(request: PinUserRequest, q: str):
     rut = data.get("rut")
     pin = request.pin
     if not request.pin or len(request.pin) != 4:
-        return error_response({"message": ErrorResponse.INVALID_PIN})
+        return error_response(message=ErrorResponse.INVALID_PIN)
     userID = user_data_service.create(name, email, rut, pin)
     if userID == -1:
-        return error_response({"message": UserResponse.USER_ALREADY_EXISTS})
+        return error_response(message=UserResponse.USER_ALREADY_EXISTS)
     user = user_data_service.get_by_id(userID)
     if not user:
         logger.error(f"User creation failed for {email}: user not found after creation")
-        return error_response({"message": ErrorResponse.USER_CREATION_ERROR})
+        return error_response(message=ErrorResponse.USER_CREATION_ERROR)
 
     logger.info(f"User created successfully: {email}")
-    return success_response({"message": SuccessResponse.USER_CREATED_SUCCESS, "data": {
+    return success_response(data={
         **user.model_dump(exclude={"pin_hash"}),
         "token": generate_token(user.email)
-    }})
+    }, message=SuccessResponse.USER_CREATED_SUCCESS)
 
 
 @user_router.post("/force-register")
@@ -143,24 +143,24 @@ async def force_register_user(request: ForceRegisterUserRequest, current_user: U
     """Force register a new user"""
     logger.info(f"Force register attempt for email: {request.email}")
     if (current_user.permissions or -1) >= 1:
-        return error_response({"message": UserResponse.NOT_PERMITTED})
+        return error_response(message=UserResponse.NOT_PERMITTED)
     
     
     if not request.pin or len(request.pin) != 4:
-        return error_response({"message": ErrorResponse.INVALID_PIN})
+        return error_response(message=ErrorResponse.INVALID_PIN)
     userID = user_data_service.create(request.name, request.email, request.rut, request.pin)
     if userID == -1:
-        return error_response({"message": UserResponse.USER_ALREADY_EXISTS})
+        return error_response(message=UserResponse.USER_ALREADY_EXISTS)
     user = user_data_service.get_by_id(userID)
     if not user:
         logger.error(f"User creation failed for {request.email}: user not found after creation")
-        return error_response({"message": ErrorResponse.USER_CREATION_ERROR})
+        return error_response(message=ErrorResponse.USER_CREATION_ERROR)
 
     logger.info(f"User created successfully: {request.email}")
-    return success_response({"message": SuccessResponse.USER_CREATED_SUCCESS, "data": {
+    return success_response(data={
         **user.model_dump(exclude={"pin_hash"}),
         "token": generate_token(user.email)
-    }})
+    }, message=SuccessResponse.USER_CREATED_SUCCESS)
     
 
 @user_router.post("/login")
@@ -182,7 +182,7 @@ async def login_user(request: LoginRequest, http_request: Request):
             logger.warning(f"Login attempt for blocked user: {request.email}, blocked for {blocked_minutes} minutes")
             
             return error_response(
-                {"message": UserResponse.USER_FORMAT_BLOCKED.format(time=f"{blocked_minutes} minutos")},
+                message=UserResponse.USER_FORMAT_BLOCKED.format(time=f"{blocked_minutes} minutos"),
                 status_code=403
             )
 
@@ -194,7 +194,7 @@ async def login_user(request: LoginRequest, http_request: Request):
                 logger.warning(f"Login attempt for blacklisted user: {request.email}")
                 
                 return error_response(
-                    {"message": UserResponse.USER_BLACKLISTED},
+                    message=UserResponse.USER_BLACKLISTED,
                     status_code=403
                 )
 
@@ -209,7 +209,7 @@ async def login_user(request: LoginRequest, http_request: Request):
                 if user_permissions == 0:
                     logger.warning(f"Unauthorized admin access attempt by {request.email}")
                     
-                    return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+                    return error_response(message=UserResponse.NOT_PERMITTED, status_code=403)
 
             # Clear login attempts and log successful login
             redis_client.delete(f"login_attempts:{request.email}")
@@ -217,18 +217,15 @@ async def login_user(request: LoginRequest, http_request: Request):
             
             
             return success_response({
-                "message": SuccessResponse.LOGIN_SUCCESS, 
-                "data": {
-                    "id": user.id,
-                    "name": user.name,
-                    "email": user.email,
-                    "kleincoins": user.kleincoins,
-                    "created_at": user.created_at,
-                    "token": generate_token(user.email),
-                    "reward_progress": user.reward_progress,
-                    "permissions": user.permissions
-                }
-            })
+                "id": user.id,
+                "name": user.name,
+                "email": user.email,
+                "kleincoins": user.kleincoins,
+                "created_at": user.created_at,
+                "token": generate_token(user.email),
+                "reward_progress": user.reward_progress,
+                "permissions": user.permissions
+            }, message=SuccessResponse.LOGIN_SUCCESS)
         else:
             # Failed login: increment attempts in Redis
             redis_client.incr(f"login_attempts:{request.email}")
@@ -243,50 +240,51 @@ async def login_user(request: LoginRequest, http_request: Request):
                 
                 logger.warning(f"Too many login attempts for {request.email}. User blocked.")
                 
-                return error_response({"message": ErrorResponse.TOO_MANY_ATTEMPTS}, status_code=429)
+                return error_response(message=ErrorResponse.TOO_MANY_ATTEMPTS, status_code=429)
             else:
                 logger.warning(f"Failed login attempt for {request.email}. Attempts: {attempts}")
                 
             
             # Return unauthorized with attempts remaining
-            return error_response({
-                "message": ErrorResponse.INVALID_CREDENTIALS, 
-                "attempts_remaining": 5 - attempts if attempts else 5
-            }, status_code=401)
+            return error_response(
+                error={"attempts_remaining": 5 - attempts if attempts else 5},
+                message=ErrorResponse.INVALID_CREDENTIALS, 
+                status_code=401
+            )
             
     except redis.RedisError as e:
         error_msg = f"Redis error during login for {request.email}: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": "Error interno del servidor"}, status_code=500)
+        return error_response(message="Error interno del servidor", status_code=500)
         
     except Exception as e:
         error_msg = f"Unexpected error during login for {request.email}: {e}"
         logger.error(error_msg)
         
-        return error_response({"message": "Error interno del servidor"}, status_code=500)
+        return error_response(message="Error interno del servidor", status_code=500)
 
 @user_router.delete("/delete")
 async def delete_user(request: UserIDRequest, current_user: User = Depends(get_current_user)):
     if current_user.permissions != 2:
-        return error_response({"message": UserResponse.NOT_PERMITTED}, status_code=403)
+        return error_response(message=UserResponse.NOT_PERMITTED, status_code=403)
     """Delete a user by ID"""
     user = user_data_service.delete(request.id)
     if user:
-        return success_response({"message": SuccessResponse.USER_DELETED_SUCCESS, "data": user})
+        return success_response(message=SuccessResponse.USER_DELETED_SUCCESS)
     else:
-        return error_response({"message": UserResponse.USER_NOT_FOUND}, status_code=404)
+        return error_response(message=UserResponse.USER_NOT_FOUND, status_code=404)
 
 @user_router.post("/pin-recovery")
 async def change_pin(request: PinRecoveryRequest):
     """Change a user's PIN"""
     user = user_data_service.get_by_email(request.email)
     if not user:
-        return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=request.email)}, status_code=404)
+        return error_response(message= UserResponse.USER_NOT_FOUND.format(user_id=request.email), status_code=404)
 
     real_token = recovery_service.get_token(user.id)
     if real_token and real_token != request.token:
-        return error_response({"message": "Invalid token"})
+        return error_response(message= "Invalid token")
     logger.info(f"Pin change, to {request.new_pin} for user {user.email}")
     user_data_service.update(user_id=user.id, pin_hash=request.new_pin)
     sender = get_email_sender()
@@ -296,41 +294,41 @@ async def change_pin(request: PinRecoveryRequest):
         body=PIN_SUCCESSFULLY["body"].format(app_name=APPNAME, date=datetime.now().strftime("%Y-%m-%d"), time=datetime.now().strftime("%H:%M:%S"), name=user.name)
     )
 
-    return success_response({"message": "Recovery email sent"})
+    return success_response(message= "Recovery email sent")
 
 @user_router.post("/reward")
 async def reward_user(request: UserRewardRequest, user: User = Depends(get_current_user)):
     """Reward a user with 1 free beer"""
     if user.reward_progress < 100:
-        return error_response({"message": UserResponse.REWARD_INSUFFICIENT_PROGRESS.format(progress=user.reward_progress)})
+        return error_response(message=UserResponse.REWARD_INSUFFICIENT_PROGRESS.format(progress=user.reward_progress))
     if not user:
-        return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=request.id)}, status_code=404)
+        return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=request.id), status_code=404)
     
     user_data_service.set_reward_progress(user.id, 0)
     print_ticket(request.tableNumber)
-    return success_response({"message": SuccessResponse.REWARD_SUCCESS, "data": {
+    return success_response(data={
         "id": user.id,
         "name": user.name,
         "email": user.email,
         "reward_progress": 0
-    }})
+    }, message=SuccessResponse.REWARD_SUCCESS)
 
 @user_router.get("/user")
 async def get_cur_user(current_user:User = Depends(get_current_user)):
     """Get current user information"""
-    return success_response({"data": current_user.model_dump(exclude={"pin_hash", "kleincoins", "rut"})})
+    return success_response(data=current_user.model_dump(exclude={"pin_hash", "kleincoins", "rut"}))
 
 @user_router.get("/all")
 async def get_all_users():
     """Get all users"""
     users = list(map(lambda u: u.model_dump(), user_data_service.get_all()))
-    return success_response({"data": users})
+    return success_response(data=users)
 
 @user_router.get("/next")
 async def get_next_user_id():
     """Get the next user ID"""
     next_id = user_data_service.get_next_id()
-    return success_response({"next_id": next_id})
+    return success_response(data={"next_id": next_id})
 from fastapi import Query
 
 verify_router = APIRouter()
@@ -365,7 +363,7 @@ async def pin_forgot_post(request: UserMail):
 
     user = user_data_service.get_by_email(request.email)
     if not user:
-        return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=request.email)}, status_code=404)
+        return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=request.email), status_code=404)
 
     recovery_key = recovery_service.generate_recovery_key(user.id)
     sender = get_email_sender()
@@ -375,20 +373,20 @@ async def pin_forgot_post(request: UserMail):
         body=PIN_RECOVERY_MAIL["body"].format(app_name=APPNAME, verification_code=recovery_key,name=user.name)
     )
     # Send recovery_key to user's email
-    return success_response({"message": SuccessResponse.RECOVERY_EMAIL_SENT})
+    return success_response(message=SuccessResponse.RECOVERY_EMAIL_SENT)
 
 @recovery_pin_router.post("/validate")
 async def pin_forgot_validate(request: PinRecoveryValidateRequest):
     """Validate the PIN recovery code"""    
     user = user_data_service.get_by_email(request.email)
     if not user:
-        return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=request.email)}, status_code=404)
+        return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=request.email), status_code=404)
     recovery_data = recovery_service.get_recovery_data(user.id)
     logger.info(f"Recovery data for {request.email}: {recovery_data}|{request.code}")
     if recovery_data.code == -1:
-        return error_response({"message": UserResponse.USER_NOT_FOUND.format(user_id=request.email)}, status_code=404)
+        return error_response(message=UserResponse.USER_NOT_FOUND.format(user_id=request.email), status_code=404)
     if recovery_data.code != request.code:
-        return error_response({"message": "Invalid recovery code"})
+        return error_response(message="Invalid recovery code")
     token = uuid4().hex
     recovery_service.add_token(user.id, token)
-    return success_response({"message": "Recovery code validated successfully", "token": token})
+    return success_response(data={"token": token}, message="Recovery code validated successfully")

+ 10 - 5
utils/responses.py

@@ -1,23 +1,28 @@
-from typing import Union
+from typing import Optional, Union
 
 from fastapi.responses import JSONResponse
 
-def success_response(data: dict, success: bool = True, status_code: int = 200):
+def success_response(data: Union[dict, list, str, None] = None, message: Optional[str] = None, status_code: int = 200, success: bool = True):
     return JSONResponse(status_code=status_code, content={
         "success": success,
+        "message": message,
         "error": None,
         "data": data
     })
 
-def error_response(error: Union[str, Exception, dict], status_code: int = 500):
+def error_response(error: Union[str, Exception, dict, list, None]=None, message: Optional[str] = None, status_code: int = 500):
+
+        
     if isinstance(error, dict):
         return JSONResponse(status_code=status_code, content={
             "success": False,
-            "error": error,
+            "data": error,
+            "message": message,
             "data": None
         })
     return JSONResponse(status_code=status_code, content={
             "success": False,
-            "error": str(error),
+            "data": str(error),
+            "message": message,
             "data": None
         })