user creation and deletetion endpoint
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build and deploy the backend to staging / Build and push image (pull_request) Successful in 1m49s
				
			
		
			
				
	
				Run linting on the backend code / Build (pull_request) Successful in 46s
				
			
		
			
				
	
				Run testing on the backend code / Build (pull_request) Failing after 48s
				
			
		
			
				
	
				Build and release debug APK / Build APK (pull_request) Failing after 3m35s
				
			
		
			
				
	
				Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 26s
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build and deploy the backend to staging / Build and push image (pull_request) Successful in 1m49s
				
			Run linting on the backend code / Build (pull_request) Successful in 46s
				
			Run testing on the backend code / Build (pull_request) Failing after 48s
				
			Build and release debug APK / Build APK (pull_request) Failing after 3m35s
				
			Build and deploy the backend to staging / Deploy to staging (pull_request) Successful in 26s
				
			This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -18,7 +18,6 @@ PAYPAL_API_URL = "https://api-m.sandbox.paypal.com" | ||||
|  | ||||
| SUPABASE_URL = os.getenv("SUPABASE_URL", None) | ||||
| SUPABASE_KEY = os.getenv("SUPABASE_API_KEY", None) | ||||
| SUPABASE_TEST_USER_ID = os.getenv("SUPABASE_TEST_USER_ID", None) | ||||
|  | ||||
|  | ||||
| cache_dir_string = os.getenv('OSM_CACHE_DIR', './cache') | ||||
|   | ||||
| @@ -11,6 +11,7 @@ from .structs.landmark import Landmark, Toilets | ||||
| from .structs.preferences import Preferences | ||||
| from .structs.linked_landmarks import LinkedLandmarks | ||||
| from .structs.trip import Trip | ||||
| from .structs.requests import UserDeleteRequest | ||||
| from .utils.landmarks_manager import LandmarkManager | ||||
| from .utils.toilets_manager import ToiletsManager | ||||
| from .optimization.optimizer import Optimizer | ||||
| @@ -62,15 +63,16 @@ def new_trip(user_id: str = Body(...), | ||||
|         (uuid) : The uuid of the first landmark in the optimized route | ||||
|     """ | ||||
|     # Check for valid user balance. | ||||
|     logger.debug(f'user id: {user_id}') | ||||
|  | ||||
|     try :  | ||||
|         if not supabase.check_balance(user_id=user_id) : | ||||
|     try: | ||||
|         if not supabase.check_balance(user_id=user_id): | ||||
|             logger.warning('Insufficient credits to perform this action.') | ||||
|             return None | ||||
|     except Exception as exc : | ||||
|         traceback.print_exc()   | ||||
|         raise HTTPException(status_code=500, detail=str(exc)) from exc | ||||
|             return {"error": "Insufficient credits"}, 400  # Return a 400 Bad Request with an appropriate message | ||||
|     except SyntaxError as se : | ||||
|         raise HTTPException(status_code=400, detail=str(se)) from se | ||||
|     except ValueError as ve : | ||||
|         raise HTTPException(status_code=406, detail=str(ve)) from ve | ||||
|     except Exception as exc: | ||||
|         raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(exc)}") from exc | ||||
|  | ||||
|     # Check for invalid input. | ||||
|     if preferences is None: | ||||
| @@ -266,3 +268,46 @@ def get_toilets(location: tuple[float, float] = Query(...), radius: int = 500) - | ||||
|         return toilets_list | ||||
|     except KeyError as exc: | ||||
|         raise HTTPException(status_code=404, detail="No toilets found") from exc | ||||
|  | ||||
|  | ||||
| @app.post("/user/create") | ||||
| def register_user(email: str = Body(...), password: str = Body(...)) -> str: | ||||
|     try: | ||||
|         response = supabase.supabase.auth.admin.create_user({ | ||||
|             "email": email, | ||||
|             "password": password | ||||
|         }) | ||||
|  | ||||
|     except Exception as e: | ||||
|         if e.code == 'email_exists' : | ||||
|             logger.error(f"Failed to create user : {str(e.code)}") | ||||
|             raise HTTPException(status_code=422, detail=str(e)) from e | ||||
|         logger.error(f"Failed to create user : {str(e.code)}") | ||||
|         raise HTTPException(status_code=500, detail=str(e)) from e | ||||
|  | ||||
|     logger.debug(response) | ||||
|     # Extract the identity_id and user_id | ||||
|     # identity = response.user.id  # Accessing the identity | ||||
|     user_id = response.user.id | ||||
|  | ||||
|     logger.info(f"User created successfully, ID: {user_id}") | ||||
|     return user_id | ||||
|  | ||||
|  | ||||
|  | ||||
| @app.post("/user/delete") | ||||
| def delete_user(request: UserDeleteRequest): | ||||
|  | ||||
|     try: | ||||
|         response = supabase.supabase.auth.admin.delete_user(request.user_id) | ||||
|         logger.debug(response) | ||||
|     except Exception as e: | ||||
|         if e.code == 'user_not_found' : | ||||
|             logger.error(f"Failed to delete user : {str(e.code)}") | ||||
|             raise HTTPException(status_code=404, detail=str(e)) from e | ||||
|         logger.error(f"Failed to create user : {str(e.code)}") | ||||
|         raise HTTPException(status_code=500, detail=str(e)) from e | ||||
|      | ||||
|     logger.info(f"User with ID {request.user_id} deleted successfully") | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -21,10 +21,14 @@ class Supabase: | ||||
|         with open(os.path.join(PARAMETERS_DIR, 'secrets.yaml')) as f: | ||||
|             secrets = yaml.safe_load(f) | ||||
|             self.SUPABASE_URL = secrets['SUPABASE_URL'] | ||||
|             self.SUPABASE_KEY = secrets['SUPABASE_API_KEY'] | ||||
|             self.SUPABASE_ADMIN_KEY = secrets['SUPABASE_ADMIN_KEY'] | ||||
|             self.SUPABASE_TEST_USER_ID = secrets['SUPABASE_TEST_USER_ID'] | ||||
|  | ||||
|         self.supabase: Client = create_client(self.SUPABASE_URL, self.SUPABASE_KEY, options=ClientOptions(schema='public')) | ||||
|         self.supabase = create_client( | ||||
|             self.SUPABASE_URL,  | ||||
|             self.SUPABASE_ADMIN_KEY,  | ||||
|             options=ClientOptions(schema='public') | ||||
|         ) | ||||
|         self.logger.debug('Supabase client initialized.') | ||||
|  | ||||
|  | ||||
| @@ -47,24 +51,31 @@ class Supabase: | ||||
|                 .single() | ||||
|                 .execute() | ||||
|             ) | ||||
|             # Check if the response was successful and contains data | ||||
|             if response.data : | ||||
|                 credits = response.data['credit_amount'] | ||||
|                 self.logger.debug(f'Credits of user {user_id}: {credits}') | ||||
|             # self.logger.critical(response) | ||||
|  | ||||
|                 if credits > 0: | ||||
|                     self.logger.info(f'Credit balance is positive. Proceeding with trip generation') | ||||
|                     return True | ||||
|         except Exception as e: | ||||
|             if e.code == '22P02' : | ||||
|                 self.logger.error(f"Failed querying credits : {str(e)}") | ||||
|                 raise SyntaxError(f"Failed querying credits : {str(e)}") from e | ||||
|             if e.code == 'PGRST116' : | ||||
|                 self.logger.error(f"User not found : {str(e)}") | ||||
|                 raise ValueError(f"User not found : {str(e)}") from e | ||||
|             else : | ||||
|                 self.logger.error(f"An unexpected error occured while checking user balance : {str(e)}") | ||||
|                 raise Exception(f"An unexpected error occured while checking user balance : {str(e)}") from e | ||||
|  | ||||
|                 self.logger.warning(f'Insufficient balance. Trip generation cannot be granted') | ||||
|                 return False | ||||
|         # Proceed to check the user's credit balance | ||||
|         credits = response.data['credit_amount'] | ||||
|         self.logger.debug(f'Credits of user {user_id}: {credits}') | ||||
|  | ||||
|             # If user or credits not found, raise a 404 error | ||||
|             raise HTTPException(status_code=404, detail="User data not found.") | ||||
|         if credits > 0: | ||||
|             self.logger.info(f'Credit balance is positive for user {user_id}. Proceeding with trip generation.') | ||||
|             return True | ||||
|  | ||||
|         except Exception as exc: | ||||
|             raise HTTPException(status_code=500, detail="Error retrieving credit balance") from exc | ||||
|         self.logger.warning(f'Insufficient balance for user {user_id}. Trip generation cannot proceed.') | ||||
|         return False | ||||
|  | ||||
|          | ||||
|  | ||||
|     def decrement_credit_balance(self, user_id: str) -> bool: | ||||
|         """ | ||||
| @@ -82,32 +93,36 @@ class Supabase: | ||||
|                 .single() | ||||
|                 .execute() | ||||
|             ) | ||||
|             # Check if the response was successful and contains data | ||||
|             if response.data : | ||||
|                 current_credits = response.data['credit_amount'] | ||||
|                 updated_credits = current_credits - 1 | ||||
|         except Exception as e: | ||||
|             if e.code == '22P02' : | ||||
|                 self.logger.error(f"Failed decrementing credits : {str(e)}") | ||||
|                 raise SyntaxError(f"Failed decrementing credits : {str(e)}") from e | ||||
|             if e.code == 'PGRST116' : | ||||
|                 self.logger.error(f"User not found : {str(e)}") | ||||
|                 raise ValueError(f"User not found : {str(e)}") from e | ||||
|             else : | ||||
|                 self.logger.error(f"An unexpected error occured while decrementing user balance : {str(e)}") | ||||
|                 raise Exception(f"An unexpected error occured while decrementing user balance : {str(e)}") from e | ||||
|  | ||||
|                 # Update the user's credits in the table | ||||
|                 update_response = ( | ||||
|                     self.supabase.table('credits') | ||||
|                     .update({'credit_amount': updated_credits}) | ||||
|                     .eq('id', user_id) | ||||
|                     .execute() | ||||
|                 ) | ||||
|  | ||||
|                 # Check if the update was successful | ||||
|                 if update_response.data: | ||||
|                     self.logger.debug(f'Credit balance successfully decremented.') | ||||
|                     return True | ||||
|                 else: | ||||
|                     raise HTTPException(status_code=500, detail="Error decrementing credit balance.") | ||||
|         current_credits = response.data['credit_amount'] | ||||
|         updated_credits = current_credits - 1 | ||||
|  | ||||
|             # If user or credits not found, raise a 404 error | ||||
|             raise HTTPException(status_code=404, detail="User data not found.") | ||||
|         # Update the user's credits in the table | ||||
|         update_response = ( | ||||
|             self.supabase.table('credits') | ||||
|             .update({'credit_amount': updated_credits}) | ||||
|             .eq('id', user_id) | ||||
|             .execute() | ||||
|         ) | ||||
|  | ||||
|         # Check if the update was successful | ||||
|         if update_response.data: | ||||
|             self.logger.debug(f'Credit balance successfully decremented.') | ||||
|             return True | ||||
|         else: | ||||
|             raise Exception("Error decrementing credit balance.") | ||||
|  | ||||
|         except Exception: | ||||
|             # Handle exceptions (like if the user ID doesn't exist or there are database issues) | ||||
|             raise HTTPException(status_code=500, detail="Error decrementing credit balance") | ||||
|  | ||||
|     def increment_credit_balance(self, user_id: str) -> bool: | ||||
|         """ | ||||
| @@ -125,29 +140,32 @@ class Supabase: | ||||
|                 .single() | ||||
|                 .execute() | ||||
|             ) | ||||
|             # Check if the response was successful and contains data | ||||
|             if response.data : | ||||
|                 current_credits = response.data['credit_amount'] | ||||
|                 updated_credits = current_credits + 1 | ||||
|         except Exception as e: | ||||
|             if e.code == '22P02' : | ||||
|                 self.logger.error(f"Failed incrementing credits : {str(e)}") | ||||
|                 raise SyntaxError(f"Failed incrementing credits : {str(e)}") from e | ||||
|             if e.code == 'PGRST116' : | ||||
|                 self.logger.error(f"User not found : {str(e)}") | ||||
|                 raise ValueError(f"User not found : {str(e)}") from e | ||||
|             else : | ||||
|                 self.logger.error(f"An unexpected error occured while incrementing user balance : {str(e)}") | ||||
|                 raise Exception(f"An unexpected error occured while incrementing user balance : {str(e)}") from e | ||||
|  | ||||
|                 # Update the user's credits in the table | ||||
|                 update_response = ( | ||||
|                     self.supabase.table('credits') | ||||
|                     .update({'credit_amount': updated_credits}) | ||||
|                     .eq('id', user_id) | ||||
|                     .execute() | ||||
|                 ) | ||||
|  | ||||
|                 # Check if the update was successful | ||||
|                 if update_response.data: | ||||
|                     self.logger.debug(f'Credit balance successfully incremented.') | ||||
|                     return True | ||||
|                 else: | ||||
|                     raise HTTPException(status_code=500, detail="Error incrementing credit balance.") | ||||
|         current_credits = response.data['credit_amount'] | ||||
|         updated_credits = current_credits + 1 | ||||
|  | ||||
|             # If user or credits not found, raise a 404 error | ||||
|             raise HTTPException(status_code=404, detail="User data not found.") | ||||
|         # Update the user's credits in the table | ||||
|         update_response = ( | ||||
|             self.supabase.table('credits') | ||||
|             .update({'credit_amount': updated_credits}) | ||||
|             .eq('id', user_id) | ||||
|             .execute() | ||||
|         ) | ||||
|  | ||||
|         except Exception: | ||||
|             # Handle exceptions (like if the user ID doesn't exist or there are database issues) | ||||
|             raise HTTPException(status_code=500, detail="Error incrementing credit balance") | ||||
|         # Check if the update was successful | ||||
|         if update_response.data: | ||||
|             self.logger.debug(f'Credit balance successfully decremented.') | ||||
|             return True | ||||
|         else: | ||||
|             raise Exception("Error decrementing credit balance.") | ||||
|   | ||||
							
								
								
									
										4
									
								
								backend/src/structs/requests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								backend/src/structs/requests.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| from pydantic import BaseModel | ||||
|  | ||||
| class UserDeleteRequest(BaseModel): | ||||
|     user_id: str | ||||
| @@ -62,3 +62,32 @@ def test_input(invalid_client, start, preferences, status_code):   # pylint: dis | ||||
|         } | ||||
|     ) | ||||
|     assert response.status_code == status_code | ||||
|  | ||||
|  | ||||
|  | ||||
| @pytest.mark.parametrize( | ||||
|     "user_id,status_code", | ||||
|     [ | ||||
|         # No user id : | ||||
|         ({}, 422), | ||||
|         ("invalid_user_id", 400), | ||||
|         # ("12345678-1234-5678-1234-567812345678", 406) | ||||
|     ] | ||||
| ) | ||||
| def test_input(invalid_client, user_id, status_code):   # pylint: disable=redefined-outer-name | ||||
|     """ | ||||
|     Test new trip creation with invalid user ID. | ||||
|     """ | ||||
|     response = invalid_client.post( | ||||
|         "/trip/new", | ||||
|         json={ | ||||
|             "user_id": user_id, | ||||
|             "preferences": {"sightseeing": {"type": "sightseeing", "score": 5}, | ||||
|                 "nature": {"type": "nature", "score": 0}, | ||||
|                 "shopping": {"type": "shopping", "score": 0}, | ||||
|                 "max_time_minute": 20, | ||||
|                 "detour_tolerance_minute": 0}, | ||||
|             "start": [48.084588, 7.280405] | ||||
|         } | ||||
|     ) | ||||
|     assert response.status_code == status_code | ||||
|   | ||||
							
								
								
									
										68
									
								
								backend/src/tests/test_user.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								backend/src/tests/test_user.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| """Collection of tests to ensure correct handling of user data.""" | ||||
|  | ||||
| from fastapi.testclient import TestClient | ||||
| import pytest | ||||
|  | ||||
| from ..main import app | ||||
|  | ||||
| TEST_EMAIL = "dummy@example.com" | ||||
| TEST_PW = "DummyPassword123" | ||||
|  | ||||
| @pytest.fixture(scope="module") | ||||
| def client(): | ||||
|     """Client used to call the app.""" | ||||
|     return TestClient(app) | ||||
|  | ||||
|  | ||||
| def test_user_handling(client) : | ||||
|     """ | ||||
|     Test the creation of a new user. | ||||
|     """ | ||||
|     # Create a new user | ||||
|     response = client.post( | ||||
|         "/user/create",  | ||||
|         json={ | ||||
|             "email": TEST_EMAIL, | ||||
|             "password": TEST_PW | ||||
|             } | ||||
|         ) | ||||
|     # Verify user has been created | ||||
|     assert response.status_code == 200 | ||||
|     user_id = response.json() | ||||
|  | ||||
|     # # Create same user again to raise an error | ||||
|     response = client.post( | ||||
|         "/user/create",  | ||||
|         json={ | ||||
|             "email": TEST_EMAIL, | ||||
|             "password": TEST_PW | ||||
|             } | ||||
|         ) | ||||
|     # Verify user already exists | ||||
|     assert response.status_code == 422 | ||||
|  | ||||
|     # Delete the user. | ||||
|     response = client.post( | ||||
|         "/user/delete",  | ||||
|         json={ | ||||
|             "user_id": user_id | ||||
|             } | ||||
|         ) | ||||
|     print(response) | ||||
|     # Verify user has been deleted | ||||
|     assert response.status_code == 200, "Failed to delete dummy user." | ||||
|  | ||||
|  | ||||
|     # Delete the user again to raise an error | ||||
|     response = client.post( | ||||
|         "/user/delete",  | ||||
|         json={ | ||||
|             "user_id": user_id | ||||
|             } | ||||
|         ) | ||||
|     print(response) | ||||
|     # Verify user has been deleted | ||||
|     assert response.status_code == 404, "Failed to delete dummy user." | ||||
|  | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user