From f36f6564e29368a571ae4b4775a33081a0258d74 Mon Sep 17 00:00:00 2001 From: lcduong Date: Thu, 14 Nov 2024 09:07:28 +0700 Subject: [PATCH 01/12] change create_world api response --- server/venueless/api/views.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 322bea15..6044b2a4 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -123,6 +123,12 @@ class CreateWorldView(APIView): authentication_classes = [] # disables authentication permission_classes = [] + @staticmethod + def get_protocol(url): + parsed = urlparse(url) + protocol = parsed.scheme + return protocol.lower() + @staticmethod def post(request, *args, **kwargs) -> JsonResponse: payload = CreateWorldView.get_payload_from_token(request) @@ -198,6 +204,14 @@ def post(request, *args, **kwargs) -> JsonResponse: {"error": "An unexpected error occurred"}, status=500 ) + site_url = settings.SITE_URL + protocol = CreateWorldView.get_protocol(site_url) + domain_path = "{}{}/{}".format( + settings.DOMAIN_PATH, + settings.BASE_PATH, + request.data.get("id"), + ) + world.domain = "{}://{}".format(protocol, domain_path) return JsonResponse(model_to_dict(world, exclude=["roles"]), status=201) else: return JsonResponse( From 17349b337ae4a30ea43faae389fc2a29be53c644 Mon Sep 17 00:00:00 2001 From: lcduong Date: Thu, 14 Nov 2024 09:24:53 +0700 Subject: [PATCH 02/12] Update code --- server/venueless/api/views.py | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 6044b2a4..c8a18038 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -156,20 +156,18 @@ def post(request, *args, **kwargs) -> JsonResponse: # if world already exists, update it, otherwise create a new world world_id = request.data.get("id") + domain_path = "{}{}/{}".format( + settings.DOMAIN_PATH, + settings.BASE_PATH, + request.data.get("id"), + ) try: if not world_id: raise ValidationError("World ID is required") if World.objects.filter(id=world_id).exists(): world = World.objects.get(id=world_id) world.title = title - world.domain = ( - "{}{}/{}".format( - settings.DOMAIN_PATH, - settings.BASE_PATH, - request.data.get("id"), - ) - or "" - ) + world.domain = domain_path or "" world.locale = request.data.get("locale") or "en" world.timezone = request.data.get("timezone") or "UTC" world.save() @@ -177,12 +175,7 @@ def post(request, *args, **kwargs) -> JsonResponse: world = World.objects.create( id=world_id, title=title, - domain="{}{}/{}".format( - settings.DOMAIN_PATH, - settings.BASE_PATH, - request.data.get("id"), - ) - or "", + domain=domain_path or "", locale=request.data.get("locale") or "en", timezone=request.data.get("timezone") or "UTC", config=config, @@ -206,11 +199,6 @@ def post(request, *args, **kwargs) -> JsonResponse: site_url = settings.SITE_URL protocol = CreateWorldView.get_protocol(site_url) - domain_path = "{}{}/{}".format( - settings.DOMAIN_PATH, - settings.BASE_PATH, - request.data.get("id"), - ) world.domain = "{}://{}".format(protocol, domain_path) return JsonResponse(model_to_dict(world, exclude=["roles"]), status=201) else: From baa65d070e19e91473e29c01ca6ab6ba4fbca41a Mon Sep 17 00:00:00 2001 From: lcduong Date: Thu, 14 Nov 2024 14:07:29 +0700 Subject: [PATCH 03/12] Update code --- server/venueless/api/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index c8a18038..1305fb78 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -167,7 +167,7 @@ def post(request, *args, **kwargs) -> JsonResponse: if World.objects.filter(id=world_id).exists(): world = World.objects.get(id=world_id) world.title = title - world.domain = domain_path or "" + world.domain = domain_path world.locale = request.data.get("locale") or "en" world.timezone = request.data.get("timezone") or "UTC" world.save() @@ -175,7 +175,7 @@ def post(request, *args, **kwargs) -> JsonResponse: world = World.objects.create( id=world_id, title=title, - domain=domain_path or "", + domain=domain_path, locale=request.data.get("locale") or "en", timezone=request.data.get("timezone") or "UTC", config=config, From 77c1c4b389113291cf288b0c66b790051ea573c1 Mon Sep 17 00:00:00 2001 From: lcduong Date: Mon, 18 Nov 2024 10:29:10 +0700 Subject: [PATCH 04/12] Update code --- server/venueless/api/utils.py | 6 ++++++ server/venueless/api/views.py | 17 ++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) create mode 100644 server/venueless/api/utils.py diff --git a/server/venueless/api/utils.py b/server/venueless/api/utils.py new file mode 100644 index 00000000..042ad00c --- /dev/null +++ b/server/venueless/api/utils.py @@ -0,0 +1,6 @@ +from urllib.parse import urlparse + +def get_protocol(url): + parsed = urlparse(url) + protocol = parsed.scheme + return protocol.lower() diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 1305fb78..1652eb99 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -31,6 +31,7 @@ from venueless.core.services.world import notify_schedule_change, notify_world_change from ..core.models import Room, World +from .utils import get_protocol logger = logging.getLogger(__name__) @@ -123,12 +124,6 @@ class CreateWorldView(APIView): authentication_classes = [] # disables authentication permission_classes = [] - @staticmethod - def get_protocol(url): - parsed = urlparse(url) - protocol = parsed.scheme - return protocol.lower() - @staticmethod def post(request, *args, **kwargs) -> JsonResponse: payload = CreateWorldView.get_payload_from_token(request) @@ -180,6 +175,11 @@ def post(request, *args, **kwargs) -> JsonResponse: timezone=request.data.get("timezone") or "UTC", config=config, ) + + site_url = settings.SITE_URL + protocol = get_protocol(site_url) + world.domain = "{}://{}".format(protocol, domain_path) + return JsonResponse(model_to_dict(world, exclude=["roles"]), status=201) except IntegrityError as e: logger.error(f"Database integrity error while saving world: {e}") return JsonResponse( @@ -196,11 +196,6 @@ def post(request, *args, **kwargs) -> JsonResponse: return JsonResponse( {"error": "An unexpected error occurred"}, status=500 ) - - site_url = settings.SITE_URL - protocol = CreateWorldView.get_protocol(site_url) - world.domain = "{}://{}".format(protocol, domain_path) - return JsonResponse(model_to_dict(world, exclude=["roles"]), status=201) else: return JsonResponse( {"error": "World cannot be created due to missing permission"}, From 63813f6d0ca1797fb866f8d530a1b23dc34c1315 Mon Sep 17 00:00:00 2001 From: lcduong Date: Mon, 18 Nov 2024 10:37:04 +0700 Subject: [PATCH 05/12] Fix isort, flake8 in pipeline --- server/venueless/api/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/venueless/api/utils.py b/server/venueless/api/utils.py index 042ad00c..c41a6a54 100644 --- a/server/venueless/api/utils.py +++ b/server/venueless/api/utils.py @@ -1,5 +1,6 @@ from urllib.parse import urlparse + def get_protocol(url): parsed = urlparse(url) protocol = parsed.scheme From 81c8710c5a885d0e271a4f82fe66ee50349a0586 Mon Sep 17 00:00:00 2001 From: lcduong Date: Mon, 2 Dec 2024 16:08:11 +0700 Subject: [PATCH 06/12] Config attendee role --- server/venueless/api/views.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 1652eb99..bec058c8 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -149,6 +149,8 @@ def post(request, *args, **kwargs) -> JsonResponse: title = titles.get(locale) or titles.get("en") or title_default + attendee_trait_grants = request.data.get("traits", {}).get("attendee", '') + # if world already exists, update it, otherwise create a new world world_id = request.data.get("id") domain_path = "{}{}/{}".format( @@ -165,6 +167,11 @@ def post(request, *args, **kwargs) -> JsonResponse: world.domain = domain_path world.locale = request.data.get("locale") or "en" world.timezone = request.data.get("timezone") or "UTC" + world.trait_grants = { + "admin": ["admin"], + "attendee": [attendee_trait_grants] if attendee_trait_grants else ['attendee'], + "scheduleuser": ["schedule-update"], + } world.save() else: world = World.objects.create( @@ -174,6 +181,11 @@ def post(request, *args, **kwargs) -> JsonResponse: locale=request.data.get("locale") or "en", timezone=request.data.get("timezone") or "UTC", config=config, + trait_grants={ + "admin": ["admin"], + "attendee": [attendee_trait_grants] if attendee_trait_grants else ['attendee'], + "scheduleuser": ["schedule-update"], + }, ) site_url = settings.SITE_URL From d1766116bd1c0d8d569b78e224ea23694894f968 Mon Sep 17 00:00:00 2001 From: lcduong Date: Mon, 2 Dec 2024 16:34:37 +0700 Subject: [PATCH 07/12] Fix black in pipeline --- server/venueless/api/views.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index bec058c8..04374b17 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -149,7 +149,7 @@ def post(request, *args, **kwargs) -> JsonResponse: title = titles.get(locale) or titles.get("en") or title_default - attendee_trait_grants = request.data.get("traits", {}).get("attendee", '') + attendee_trait_grants = request.data.get("traits", {}).get("attendee", "") # if world already exists, update it, otherwise create a new world world_id = request.data.get("id") @@ -169,7 +169,11 @@ def post(request, *args, **kwargs) -> JsonResponse: world.timezone = request.data.get("timezone") or "UTC" world.trait_grants = { "admin": ["admin"], - "attendee": [attendee_trait_grants] if attendee_trait_grants else ['attendee'], + "attendee": ( + [attendee_trait_grants] + if attendee_trait_grants + else ["attendee"] + ), "scheduleuser": ["schedule-update"], } world.save() @@ -183,7 +187,11 @@ def post(request, *args, **kwargs) -> JsonResponse: config=config, trait_grants={ "admin": ["admin"], - "attendee": [attendee_trait_grants] if attendee_trait_grants else ['attendee'], + "attendee": ( + [attendee_trait_grants] + if attendee_trait_grants + else ["attendee"] + ), "scheduleuser": ["schedule-update"], }, ) From aea462b038d20a315072c324985004a1b6da84a1 Mon Sep 17 00:00:00 2001 From: lcduong Date: Tue, 3 Dec 2024 15:43:00 +0700 Subject: [PATCH 08/12] Update code --- server/venueless/api/views.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 04374b17..c7c020d6 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -150,6 +150,11 @@ def post(request, *args, **kwargs) -> JsonResponse: title = titles.get(locale) or titles.get("en") or title_default attendee_trait_grants = request.data.get("traits", {}).get("attendee", "") + trait_grants = { + "admin": ["admin"], + "attendee": [attendee_trait_grants] if attendee_trait_grants else ["attendee"], + "scheduleuser": ["schedule-update"], + } # if world already exists, update it, otherwise create a new world world_id = request.data.get("id") @@ -167,15 +172,7 @@ def post(request, *args, **kwargs) -> JsonResponse: world.domain = domain_path world.locale = request.data.get("locale") or "en" world.timezone = request.data.get("timezone") or "UTC" - world.trait_grants = { - "admin": ["admin"], - "attendee": ( - [attendee_trait_grants] - if attendee_trait_grants - else ["attendee"] - ), - "scheduleuser": ["schedule-update"], - } + world.trait_grants = trait_grants world.save() else: world = World.objects.create( @@ -185,15 +182,7 @@ def post(request, *args, **kwargs) -> JsonResponse: locale=request.data.get("locale") or "en", timezone=request.data.get("timezone") or "UTC", config=config, - trait_grants={ - "admin": ["admin"], - "attendee": ( - [attendee_trait_grants] - if attendee_trait_grants - else ["attendee"] - ), - "scheduleuser": ["schedule-update"], - }, + trait_grants=trait_grants, ) site_url = settings.SITE_URL From 44ba409670088fc82e268697eef05a727f2a867a Mon Sep 17 00:00:00 2001 From: lcduong Date: Tue, 3 Dec 2024 15:54:04 +0700 Subject: [PATCH 09/12] Update code --- server/venueless/api/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index c7c020d6..62f68883 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -152,7 +152,9 @@ def post(request, *args, **kwargs) -> JsonResponse: attendee_trait_grants = request.data.get("traits", {}).get("attendee", "") trait_grants = { "admin": ["admin"], - "attendee": [attendee_trait_grants] if attendee_trait_grants else ["attendee"], + "attendee": ( + [attendee_trait_grants] if attendee_trait_grants else ["attendee"] + ), "scheduleuser": ["schedule-update"], } From f8f6b0e4c3d054c6af6db821cd374f106ce40fb0 Mon Sep 17 00:00:00 2001 From: lcduong Date: Fri, 6 Dec 2024 12:03:53 +0700 Subject: [PATCH 10/12] Configure video settings for talks --- server/venueless/api/task.py | 129 ++++++++++++++++++++++++++++++++++ server/venueless/api/views.py | 3 +- server/venueless/settings.py | 3 + 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 server/venueless/api/task.py diff --git a/server/venueless/api/task.py b/server/venueless/api/task.py new file mode 100644 index 00000000..10412ed0 --- /dev/null +++ b/server/venueless/api/task.py @@ -0,0 +1,129 @@ +import datetime +import datetime as dt +import logging +import uuid + +import jwt +import requests +from celery import shared_task +from django.conf import settings + +from venueless.core.models.auth import ShortToken +from venueless.core.models.world import World + +logger = logging.getLogger(__name__) + + +def generate_video_token(world, days, number, traits, long=False): + """ + Generate video token + :param world: World object + :param days: A integer representing the number of days the token is valid + :param number: A integer representing the number of tokens to generate + :param traits: A dictionary representing the traits of the token + :param long: A boolean representing if the token is long or short + :return: A list of tokens + """ + jwt_secrets = world.config.get("JWT_secrets", []) + if not jwt_secrets: + logger.error("JWT_secrets is missing or empty in the configuration") + return + jwt_config = jwt_secrets[0] + secret = jwt_config.get("secret") + audience = jwt_config.get("audience") + issuer = jwt_config.get("issuer") + iat = datetime.datetime.utcnow() + exp = iat + datetime.timedelta(days=days) + result = [] + bulk_create = [] + for _ in range(number): + payload = { + "iss": issuer, + "aud": audience, + "exp": exp, + "iat": iat, + "uid": str(uuid.uuid4()), + "traits": traits, + } + token = jwt.encode(payload, secret, algorithm="HS256") + if long: + result.append(token) + else: + st = ShortToken(world=world, long_token=token, expires=exp) + result.append(st.short_token) + bulk_create.append(st) + + if not long: + ShortToken.objects.bulk_create(bulk_create) + return result + + +def generate_talk_token(video_settings, video_tokens, event_slug): + """ + Generate talk token + :param video_settings: A dictionary representing the video settings + :param video_tokens: A list of video tokens + :param event_slug: A string representing the event slug + :return: A token + """ + iat = dt.datetime.utcnow() + exp = iat + dt.timedelta(days=30) + payload = { + "exp": exp, + "iat": iat, + "video_tokens": video_tokens, + "slug": event_slug, + } + token = jwt.encode(payload, video_settings.get("secret"), algorithm="HS256") + return token + + +@shared_task(bind=True, max_retries=5, default_retry_delay=60) +def configure_video_settings_for_talks(self,world_id, days, number, traits, long=False): + """ + Configure video settings for talks + :param self: instance of the task + :param world_id: A integer representing the world id + :param days: A integer representing the number of days the token is valid + :param number: A integer representing the number of tokens to generate + :param traits: A dictionary representing the traits of the token + :param long: A boolean representing if the token is long or short + """ + world = World.objects.get(id=world_id) + event_slug = world_id + jwt_secrets = world.config.get("JWT_secrets", []) + if not jwt_secrets: + logger.error("JWT_secrets is missing or empty in the configuration") + return + jwt_config = jwt_secrets[0] + video_tokens = generate_video_token(world, days, number, traits, long) + talk_token = generate_talk_token(jwt_config, video_tokens, event_slug) + header = { + "Content-Type": "application/json", + "Authorization": f"Bearer {talk_token}", + } + payload = { + "video_settings": { + "audience": jwt_config.get("audience"), + "issuer": jwt_config.get("issuer"), + "secret": jwt_config.get("secret"), + } + } + try: + requests.post('{}/api/configure-video-settings/'.format(settings.EVENTYAY_TALK_BASE_PATH), json=payload, headers=header) + world.config['pretalx'] = { + "event": event_slug, + "domain": "{}".format(settings.EVENTYAY_TALK_BASE_PATH), + "pushed": datetime.datetime.now().isoformat(), + "connected": True + } + world.save() + except requests.exceptions.ConnectionError as e: + logger.error("Connection error: %s", str(e)) + self.retry(exc=e) + except requests.exceptions.Timeout as e: + logger.error("Request timed out: %s", str(e)) + self.retry(exc=e) + except requests.exceptions.RequestException as e: + logger.error("Request failed: %s", str(e)) + self.retry(exc=e) diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index 62f68883..a5bc8cc5 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -31,6 +31,7 @@ from venueless.core.services.world import notify_schedule_change, notify_world_change from ..core.models import Room, World +from .task import configure_video_settings_for_talks from .utils import get_protocol logger = logging.getLogger(__name__) @@ -186,7 +187,7 @@ def post(request, *args, **kwargs) -> JsonResponse: config=config, trait_grants=trait_grants, ) - + configure_video_settings_for_talks.delay(world_id, days=30, number=1, traits=["schedule-update"], long=True) site_url = settings.SITE_URL protocol = get_protocol(site_url) world.domain = "{}://{}".format(protocol, domain_path) diff --git a/server/venueless/settings.py b/server/venueless/settings.py index 648942d3..d2fe5f17 100644 --- a/server/venueless/settings.py +++ b/server/venueless/settings.py @@ -202,6 +202,9 @@ MEDIA_URL = os.getenv( "VENUELESS_MEDIA_URL", config.get("urls", "media", fallback="/media/") ) +EVENTYAY_TALK_BASE_PATH = config.get( + "urls", "eventyay-talk", fallback="https://app-test.eventyay.com/talk" +) WEBSOCKET_PROTOCOL = os.getenv( "VENUELESS_WEBSOCKET_PROTOCOL", From 320205ade457ffdca8841d82e136d513860d10f2 Mon Sep 17 00:00:00 2001 From: odkhang Date: Fri, 6 Dec 2024 15:12:24 +0700 Subject: [PATCH 11/12] Fix black in pipeline --- server/venueless/api/task.py | 14 ++++++++++---- server/venueless/api/views.py | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/server/venueless/api/task.py b/server/venueless/api/task.py index 10412ed0..5f2a5fce 100644 --- a/server/venueless/api/task.py +++ b/server/venueless/api/task.py @@ -79,7 +79,9 @@ def generate_talk_token(video_settings, video_tokens, event_slug): @shared_task(bind=True, max_retries=5, default_retry_delay=60) -def configure_video_settings_for_talks(self,world_id, days, number, traits, long=False): +def configure_video_settings_for_talks( + self, world_id, days, number, traits, long=False +): """ Configure video settings for talks :param self: instance of the task @@ -110,12 +112,16 @@ def configure_video_settings_for_talks(self,world_id, days, number, traits, long } } try: - requests.post('{}/api/configure-video-settings/'.format(settings.EVENTYAY_TALK_BASE_PATH), json=payload, headers=header) - world.config['pretalx'] = { + requests.post( + "{}/api/configure-video-settings/".format(settings.EVENTYAY_TALK_BASE_PATH), + json=payload, + headers=header, + ) + world.config["pretalx"] = { "event": event_slug, "domain": "{}".format(settings.EVENTYAY_TALK_BASE_PATH), "pushed": datetime.datetime.now().isoformat(), - "connected": True + "connected": True, } world.save() except requests.exceptions.ConnectionError as e: diff --git a/server/venueless/api/views.py b/server/venueless/api/views.py index a5bc8cc5..1ca1d1cb 100644 --- a/server/venueless/api/views.py +++ b/server/venueless/api/views.py @@ -187,7 +187,9 @@ def post(request, *args, **kwargs) -> JsonResponse: config=config, trait_grants=trait_grants, ) - configure_video_settings_for_talks.delay(world_id, days=30, number=1, traits=["schedule-update"], long=True) + configure_video_settings_for_talks.delay( + world_id, days=30, number=1, traits=["schedule-update"], long=True + ) site_url = settings.SITE_URL protocol = get_protocol(site_url) world.domain = "{}://{}".format(protocol, domain_path) From 6da5b502071e553cd0dab6164c4aad119bb4c4d1 Mon Sep 17 00:00:00 2001 From: odkhang Date: Fri, 6 Dec 2024 16:50:02 +0700 Subject: [PATCH 12/12] Update code --- server/venueless/api/task.py | 54 +++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/server/venueless/api/task.py b/server/venueless/api/task.py index 5f2a5fce..88d46fa0 100644 --- a/server/venueless/api/task.py +++ b/server/venueless/api/task.py @@ -91,27 +91,29 @@ def configure_video_settings_for_talks( :param traits: A dictionary representing the traits of the token :param long: A boolean representing if the token is long or short """ - world = World.objects.get(id=world_id) - event_slug = world_id - jwt_secrets = world.config.get("JWT_secrets", []) - if not jwt_secrets: - logger.error("JWT_secrets is missing or empty in the configuration") - return - jwt_config = jwt_secrets[0] - video_tokens = generate_video_token(world, days, number, traits, long) - talk_token = generate_talk_token(jwt_config, video_tokens, event_slug) - header = { - "Content-Type": "application/json", - "Authorization": f"Bearer {talk_token}", - } - payload = { - "video_settings": { - "audience": jwt_config.get("audience"), - "issuer": jwt_config.get("issuer"), - "secret": jwt_config.get("secret"), - } - } try: + if not isinstance(world_id, str) or not world_id.isalnum(): + raise ValueError("Invalid world_id format") + world = World.objects.get(id=world_id) + event_slug = world_id + jwt_secrets = world.config.get("JWT_secrets", []) + if not jwt_secrets: + logger.error("JWT_secrets is missing or empty in the configuration") + return + jwt_config = jwt_secrets[0] + video_tokens = generate_video_token(world, days, number, traits, long) + talk_token = generate_talk_token(jwt_config, video_tokens, event_slug) + header = { + "Content-Type": "application/json", + "Authorization": f"Bearer {talk_token}", + } + payload = { + "video_settings": { + "audience": jwt_config.get("audience"), + "issuer": jwt_config.get("issuer"), + "secret": jwt_config.get("secret"), + } + } requests.post( "{}/api/configure-video-settings/".format(settings.EVENTYAY_TALK_BASE_PATH), json=payload, @@ -127,9 +129,11 @@ def configure_video_settings_for_talks( except requests.exceptions.ConnectionError as e: logger.error("Connection error: %s", str(e)) self.retry(exc=e) - except requests.exceptions.Timeout as e: - logger.error("Request timed out: %s", str(e)) - self.retry(exc=e) - except requests.exceptions.RequestException as e: - logger.error("Request failed: %s", str(e)) + except requests.exceptions.HTTPError as e: + if e.response.status_code in (401, 403, 404): + logger.error("Non-retryable error: %s", str(e)) + raise + logger.error("HTTP error: %s", str(e)) self.retry(exc=e) + except ValueError as e: + logger.error("Error configuring video settings: %s", e)