Skip to content

Feat: 2024년 세션은 pretalx를 사용하도록 수정 #159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions pyconkr/external_apis/pretalx/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from __future__ import annotations

import logging
import traceback
import typing
import urllib.parse

import requests
from django.conf import settings

from .serializers import PretalxPaginatedSessionSerializer

logger = logging.getLogger(__name__)

RequestMethodType = typing.Literal["GET", "OPTIONS", "HEAD", "POST", "PUT", "PATCH", "DELETE"]


class PretalxException(Exception):
pass


class PretalxClient:
DEFAULT_TIMEOUT = 5

def _request(self, method: RequestMethodType, endpoint: str, *args: tuple, **kwargs: dict) -> requests.Response:
url = urllib.parse.urljoin(settings.PRETALX.API_URL, endpoint)
request_default_headers = {
"Authorization": f"Token {settings.PRETALX.API_KEY}",
"Content-Type": "application/json",
} | kwargs.pop("headers", {})
request_default_kwargs = {
"headers": request_default_headers,
"timeout": self.DEFAULT_TIMEOUT,
} | kwargs

try:
return requests.request(method, url, *args, **request_default_kwargs)
except Exception as e:
logger.error(traceback.format_exception(e))
raise PretalxException("Pretalx API 요청에 실패했습니다.") from e

def retrieve_sessions(self, event_name: str, only_confirmed: bool = True) -> dict:
"""세션 목록 조회"""
endpoint = f"api/events/{event_name}/submissions" + ("?state=confirmed" if only_confirmed else "")

try:
result = self._request("GET", endpoint)
result.raise_for_status()

parsed_result = PretalxPaginatedSessionSerializer(data=result.json())
parsed_result.is_valid(raise_exception=True)
return parsed_result.validated_data
except Exception as e:
raise PretalxException("세션 목록을 가져오지 못했습니다, 잠시 후에 다시 시도해주세요.") from e


pretalx_client = PretalxClient()
66 changes: 66 additions & 0 deletions pyconkr/external_apis/pretalx/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
from rest_framework import serializers


class PretalxSpeakerSerializer(serializers.Serializer):
code = serializers.CharField()
name = serializers.CharField()
biography = serializers.CharField()
avatar = serializers.CharField()


class PretalxSlotSerializer(serializers.Serializer):
start = serializers.DateTimeField()
end = serializers.DateTimeField()
room = serializers.CharField()
room_id = serializers.IntegerField()


class PretalxQuestionSerializer(serializers.Serializer):
id = serializers.IntegerField()
question = serializers.DictField()
required = serializers.BooleanField()
target = serializers.CharField()
options = serializers.ListField()


class PretalxAnswerSerializer(serializers.Serializer):
id = serializers.IntegerField()
question = PretalxQuestionSerializer()
answer = serializers.CharField()
answer_file = serializers.CharField()
submission = serializers.CharField()
person = serializers.CharField()
options = serializers.ListField()


class PretalxSessionSerializer(serializers.Serializer):
code = serializers.CharField()
submission_type = serializers.CharField()
submission_type_id = serializers.IntegerField()
state = serializers.CharField()

image = serializers.CharField()
title = serializers.CharField()
abstract = serializers.CharField()
description = serializers.CharField()
notes = serializers.CharField()
internal_notes = serializers.CharField()
content_locale = serializers.CharField()

slot = PretalxSlotSerializer()
duration = serializers.IntegerField()
do_not_record = serializers.BooleanField()
is_featured = serializers.BooleanField()

speakers = PretalxSpeakerSerializer(many=True)
answers = PretalxAnswerSerializer(many=True)

tags = serializers.ListField()
tag_ids = serializers.ListField()


class PretalxPaginatedSessionSerializer(serializers.Serializer):
count = serializers.IntegerField()
next = serializers.CharField()
previous = serializers.CharField()
results = PretalxSessionSerializer(many=True)
11 changes: 10 additions & 1 deletion pyconkr/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""

import os
import pathlib
import types

# Build paths inside the project like this: BASE_DIR / "subdir".
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
Expand Down Expand Up @@ -246,3 +246,12 @@
LOGIN_URL = "/accounts/login/"

AWS_QUERYSTRING_AUTH = False

# External APIs
PRETALX = types.SimpleNamespace(
API_URL=os.getenv("PRETALX_API_URL", "https://pretalx.com"),
API_KEY=os.getenv("PRETALX_API_KEY", ""),
EVENT_NAME={
"2024": os.getenv("PRETALX_EVENT_TITLE_2024", "pyconkr2024"),
},
)
28 changes: 26 additions & 2 deletions session/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from django.conf import settings
from drf_spectacular.utils import OpenApiExample, OpenApiResponse, extend_schema
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.viewsets import ModelViewSet

from pyconkr.external_apis.pretalx.client import pretalx_client
from pyconkr.external_apis.pretalx.serializers import PretalxSessionSerializer
from session.models import Session
from session.serializers import SessionListSerializer, SessionSerializer

Expand All @@ -13,8 +17,28 @@ class SessionViewSet(ModelViewSet):
def get_serializer_class(self):
if self.action == "list":
return SessionListSerializer
else:
return SessionSerializer
return SessionSerializer

def get_queryset(self):
return super().get_queryset().filter(category__year=self.request.version)

@extend_schema(
examples={
200: OpenApiResponse(
response=str,
examples=[
OpenApiExample(name="2023년 세션 목록", value=SessionListSerializer(many=True)),
OpenApiExample(name="2024년 이후 세션 목록 (Pretalx)", value=PretalxSessionSerializer(many=True)),
],
),
},
)
def list(self, request, *args, **kwargs):
if request.version == 2023 or request.version not in settings.PRETALX.EVENT_NAME:
return super().list(request, *args, **kwargs)

pretalx_event_name = settings.PRETALX.EVENT_NAME[request.version]
return pretalx_client.retrieve_sessions(
event_name=pretalx_event_name,
only_confirmed=settings.DEBUG,
)["results"]
Loading