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",