diff --git a/octobot/community/authentication.py b/octobot/community/authentication.py index 3b40136d4..523e88104 100644 --- a/octobot/community/authentication.py +++ b/octobot/community/authentication.py @@ -607,6 +607,8 @@ async def _initialize_account(self, minimal=False, fetch_private_data=True): await self._ensure_init_community_feed() except authentication.AuthenticationError as err: self.logger.info(f"Login aborted: no authenticated session: {err}") + if await self.has_login_info(): + await self.logout() except authentication.UnavailableError as e: self.logger.exception(e, True, f"Error when fetching community data, " f"please check your internet connection.") @@ -803,7 +805,8 @@ async def _auth_handler(self): except authentication.FailedAuthentication as e: if should_warn: self.logger.warning(f"Invalid authentication details, please re-authenticate. {e}") - await self.logout() + if await self.has_login_info(): + await self.logout() except authentication.UnavailableError: raise except Exception as e: diff --git a/octobot/community/models/community_public_data.py b/octobot/community/models/community_public_data.py index bb009dd99..3d289c527 100644 --- a/octobot/community/models/community_public_data.py +++ b/octobot/community/models/community_public_data.py @@ -23,8 +23,9 @@ def __init__(self): self.products = _DataElement({}, False) def set_products(self, products): - self.products.value = {product[enums.ProductKeys.ID.value]: product for product in products} - self.products.fetched = True + if products: + self.products.value = {product[enums.ProductKeys.ID.value]: product for product in products} + self.products.fetched = True def get_product_slug(self, product_id): return self.products.value[product_id][enums.ProductKeys.SLUG.value] diff --git a/octobot/community/supabase_backend/community_supabase_client.py b/octobot/community/supabase_backend/community_supabase_client.py index fa33ca0ae..a8d17e9d1 100644 --- a/octobot/community/supabase_backend/community_supabase_client.py +++ b/octobot/community/supabase_backend/community_supabase_client.py @@ -122,7 +122,7 @@ async def sign_up(self, email: str, password: str) -> None: async def sign_out(self, options: gotrue.types.SignOutOptions) -> None: try: await self.auth.sign_out(options) - except gotrue.errors.AuthApiError: + except (postgrest.exceptions.APIError, gotrue.errors.AuthApiError): pass def _requires_email_validation(self, user: gotrue.types.User) -> bool: @@ -137,7 +137,7 @@ async def restore_session(self): async def refresh_session(self, refresh_token: typing.Union[str, None] = None): try: await self.auth.refresh_session(refresh_token=refresh_token) - except gotrue.errors.AuthError as err: + except (postgrest.exceptions.APIError, gotrue.errors.AuthError) as err: raise authentication.AuthenticationError(f"Community auth error: {err}") from err async def sign_in_with_otp_token(self, token): @@ -229,16 +229,21 @@ async def fetch_checkout_url(self, payment_method: str, redirect_url: str) -> di return json.loads(json.loads(resp)["message"]) async def fetch_bot(self, bot_id) -> dict: - try: - # https://postgrest.org/en/stable/references/api/resource_embedding.html#hint-disambiguation - return (await self.table("bots").select("*,bot_deployment:bot_deployments!bots_current_deployment_id_fkey(*)").eq( - enums.BotKeys.ID.value, bot_id - ).execute()).data[0] - except IndexError: - raise errors.BotNotFoundError(f"Can't find bot with id: {bot_id}") + with jwt_expired_auth_raiser(): + try: + # https://postgrest.org/en/stable/references/api/resource_embedding.html#hint-disambiguation + return (await self.table("bots").select("*,bot_deployment:bot_deployments!bots_current_deployment_id_fkey(*)").eq( + enums.BotKeys.ID.value, bot_id + ).execute()).data[0] + except IndexError: + raise errors.BotNotFoundError(f"Can't find bot with id: {bot_id}") async def fetch_bots(self) -> list: - return (await self.table("bots").select("*,bot_deployment:bot_deployments!bots_current_deployment_id_fkey!inner(*)").execute()).data + with jwt_expired_auth_raiser(): + return ( + await self.table("bots").select( + "*,bot_deployment:bot_deployments!bots_current_deployment_id_fkey!inner(*)" + ).execute()).data async def create_bot(self, deployment_type: enums.DeploymentTypes) -> dict: created_bot = (await self.table("bots").insert({ @@ -305,19 +310,23 @@ async def fetch_startup_info(self, bot_id) -> dict: return resp.data[0] async def fetch_products(self, category_types: list[str]) -> list: - return ( - await self.table("products").select( - "*," - "category:product_categories!inner(slug, name_translations, type, metadata)," - "results:product_results!products_current_result_id_fkey(" - " profitability," - " reference_market_profitability" - ")" - ).eq( - enums.ProductKeys.VISIBILITY.value, "public" - ).in_("category.type", category_types) - .execute() - ).data + try: + return ( + await self.table("products").select( + "*," + "category:product_categories!inner(slug, name_translations, type, metadata)," + "results:product_results!products_current_result_id_fkey(" + " profitability," + " reference_market_profitability" + ")" + ).eq( + enums.ProductKeys.VISIBILITY.value, "public" + ).in_("category.type", category_types) + .execute() + ).data + except postgrest.exceptions.APIError as err: + commons_logging.get_logger(__name__).error(f"Error when fetching products: {err}") + return [] async def fetch_subscribed_products_urls(self) -> list: resp = await self.rpc("get_subscribed_products_urls").execute() @@ -934,4 +943,14 @@ async def aclose(self): except RuntimeError: # happens when the event loop is closed already pass - self.production_anon_client = None \ No newline at end of file + self.production_anon_client = None + + +@contextlib.contextmanager +def jwt_expired_auth_raiser(): + try: + yield + except postgrest.exceptions.APIError as err: + if "JWT expired" in str(err): + raise authentication.AuthenticationError(f"Please re-login to your OctoBot account: {err}") from err + raise