From bbba05b49b1fc9c0f4aa82a3d8dff1edb2ab3f00 Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Sun, 19 Nov 2023 19:35:23 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(store.py):=20replace=20gener?= =?UTF-8?q?ic=20exception=20handling=20with=20custom=20exceptions=20to=20p?= =?UTF-8?q?rovide=20more=20specific=20error=20messages=20and=20status=20co?= =?UTF-8?q?des=20=F0=9F=94=80=20merge(exceptions.py):=20add=20custom=20exc?= =?UTF-8?q?eptions=20with=20status=20codes=20to=20handle=20specific=20erro?= =?UTF-8?q?rs=20in=20the=20store=20service=20=F0=9F=94=80=20merge(service.?= =?UTF-8?q?py):=20replace=20ValueError=20with=20custom=20exceptions=20in?= =?UTF-8?q?=20the=20store=20service=20to=20provide=20more=20specific=20err?= =?UTF-8?q?or=20messages=20and=20status=20codes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/langflow/api/v1/store.py | 16 +++++------- .../langflow/services/store/exceptions.py | 25 +++++++++++++++++++ .../langflow/services/store/service.py | 22 ++++++++-------- 3 files changed, 42 insertions(+), 21 deletions(-) create mode 100644 src/backend/langflow/services/store/exceptions.py diff --git a/src/backend/langflow/api/v1/store.py b/src/backend/langflow/api/v1/store.py index cef75e069..bdcc05245 100644 --- a/src/backend/langflow/api/v1/store.py +++ b/src/backend/langflow/api/v1/store.py @@ -4,9 +4,11 @@ from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query from httpx import HTTPStatusError + from langflow.services.auth import utils as auth_utils from langflow.services.database.models.user.user import User from langflow.services.deps import get_settings_service, get_store_service +from langflow.services.store.exceptions import CustomException from langflow.services.store.schema import ( CreateComponentResponse, DownloadComponentResponse, @@ -127,17 +129,11 @@ async def get_components( limit=limit, store_api_Key=store_api_Key, ) - except Exception as exc: - if isinstance(exc, HTTPStatusError): - if exc.response.status_code == 403: - raise HTTPException(status_code=403, detail="Forbidden") - elif isinstance(exc, ValueError): - if "Check your API key" in str(exc): - raise HTTPException(status_code=401, detail=str(exc)) - elif "filter by likes" in str(exc) or "filter your components" in str(exc): - raise HTTPException(status_code=400, detail=str(exc)) + except CustomException as exc: + if isinstance(exc, ValueError): + raise HTTPException(status_code=500, detail=str(exc)) from exc - raise HTTPException(status_code=500, detail=str(exc)) + raise HTTPException(status_code=exc.status_code, detail=str(exc)) from exc @router.get("/components/{component_id}", response_model=DownloadComponentResponse) diff --git a/src/backend/langflow/services/store/exceptions.py b/src/backend/langflow/services/store/exceptions.py new file mode 100644 index 000000000..058b21652 --- /dev/null +++ b/src/backend/langflow/services/store/exceptions.py @@ -0,0 +1,25 @@ +class CustomException(Exception): + def __init__(self, detail, status_code): + super().__init__(detail) + self.status_code = status_code + + +# Define custom exceptions with status codes +class UnauthorizedError(CustomException): + def __init__(self, detail="Unauthorized access"): + super().__init__(detail, 401) + + +class ForbiddenError(CustomException): + def __init__(self, detail="Forbidden"): + super().__init__(detail, 403) + + +class APIKeyError(CustomException): + def __init__(self, detail="API key error"): + super().__init__(detail, 401) + + +class FilterError(CustomException): + def __init__(self, detail="Filter error"): + super().__init__(detail, 400) diff --git a/src/backend/langflow/services/store/service.py b/src/backend/langflow/services/store/service.py index 22da0613b..f6ad10c03 100644 --- a/src/backend/langflow/services/store/service.py +++ b/src/backend/langflow/services/store/service.py @@ -4,9 +4,8 @@ from uuid import UUID import httpx from httpx import HTTPError, HTTPStatusError -from loguru import logger - from langflow.services.base import Service +from langflow.services.store.exceptions import APIKeyError, FilterError, ForbiddenError from langflow.services.store.schema import ( CreateComponentResponse, DownloadComponentResponse, @@ -19,6 +18,7 @@ from langflow.services.store.utils import ( process_tags_for_post, update_components_with_user_data, ) +from loguru import logger if TYPE_CHECKING: from langflow.services.settings.service import SettingsService @@ -196,7 +196,7 @@ class StoreService(Service): liked_filter = self.build_liked_filter() filter_conditions.append(liked_filter) elif liked and not store_api_Key: - raise ValueError("You must provide an API key to filter by likes") + raise APIKeyError("You must provide an API key to filter by likes") if filter_by_user and store_api_Key: user_data = user_data_var.get() @@ -204,7 +204,7 @@ class StoreService(Service): raise ValueError("No user data") filter_conditions.append({"user_created": {"_eq": user_data["id"]}}) elif filter_by_user and not store_api_Key: - raise ValueError("You must provide an API key to filter your components") + raise APIKeyError("You must provide an API key to filter your components") else: filter_conditions.append({"status": {"_in": ["public", "Public"]}}) @@ -256,7 +256,7 @@ class StoreService(Service): return results_objects, metadata - async def get_liked_by_user_components(self, component_ids: List[UUID], api_key: str) -> List[str]: + async def get_liked_by_user_components(self, component_ids: List[str], api_key: str) -> List[str]: # Get fields id # filter should be "id is in component_ids AND liked_by directus_users_id token is api_key" # return the ids @@ -339,7 +339,7 @@ class StoreService(Service): try: errors = response.json() message = errors["errors"][0]["message"] - raise ValueError(message) + raise FilterError(message) except UnboundLocalError: pass raise ValueError(f"Upload failed: {exc}") @@ -447,9 +447,9 @@ class StoreService(Service): comp_count = metadata.get("filter_count", 0) except HTTPStatusError as exc: if exc.response.status_code == 403: - raise ValueError("You are not authorized to access this public resource") + raise ForbiddenError("You are not authorized to access this public resource") elif exc.response.status_code == 401: - raise ValueError("You are not authorized to access this resource. Please check your API key.") + raise APIKeyError("You are not authorized to access this resource. Please check your API key.") try: if result and not metadata: if len(result) >= limit: @@ -464,9 +464,9 @@ class StoreService(Service): comp_count = 0 except HTTPStatusError as exc: if exc.response.status_code == 403: - raise ValueError("You are not authorized to access this public resource") + raise ForbiddenError("You are not authorized to access this public resource") elif exc.response.status_code == 401: - raise ValueError("You are not authorized to access this resource. Please check your API key.") + raise APIKeyError("You are not authorized to access this resource. Please check your API key.") if store_api_Key: # Now, from the result, we need to get the components @@ -482,5 +482,5 @@ class StoreService(Service): # If we get an error here, it means the user is not authorized authorized = False else: - authorized = True + authorized = await self.check_api_key(store_api_Key) return ListComponentResponseModel(results=result, authorized=authorized, count=comp_count)