Skip to content
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,6 @@ dmypy.json

# NodeJS/npm
node_modules/

# Pretalx export files
*_python-asia-*.json
15 changes: 7 additions & 8 deletions app/home/templates/home/sections/speakers-section.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,25 @@ <h2 class="font-td_pinoy text-6xl text-orange-2 text-center m-0">Speakers</h2>
</div>
<div class="speakers-wrapper flex items-center gap-[30px] flex-row flex-wrap justify-between">
{% for speaker in speakers %}
{% if speaker.avatar_url %}
<div class="rounded-[24px] flex flex-col gap-5 w-full max-w-[100%] lg:max-w-[250px] grow items-center">
<div class="overflow-hidden flex-shrink-0 w-[250px] h-[250px]">
{% if speaker.photo_url %}
<img src="{{ speaker.photo_url }}" class="w-[250px] h-[250px] object-cover rounded-[85px]"
alt="{{ speaker.full_name }} - Image" style="height: 250px;">
{% else %}
<img src="#" class="w-[250px] h-[250px] object-cover rounded-[85px]"
alt="{{ speaker.full_name }} - Image" style="height: 250px;">
{% endif %}
<img src="{{ speaker.avatar_url }}" class="w-[250px] h-[250px] object-cover rounded-[85px]"
alt="{{ speaker.name }} - Image" width="250" height="250">
</div>
<div>
<h3 class="font-bantayog text-brown-1 text-2xl uppercase">{{ speaker.full_name }}</h3>
<h3 class="font-bantayog text-brown-1 text-2xl uppercase">{{ speaker.name }}</h3>
{% if speaker.title %}<p class="font-nunito text-brown-2 text-[13px] mb-2">{{ speaker.title }}</p>{% endif %}
{% if speaker.introduction %}
<p class="font-nunito text-brown-2 text-[13px]">{{ speaker.introduction|truncatewords:30 }}</p>
{% elif speaker.bio %}
<p class="font-nunito text-brown-2 text-[13px]">{{ speaker.bio|truncatewords:30 }}</p>
{% elif speaker.biography %}
<p class="font-nunito text-brown-2 text-[13px]">{{ speaker.biography|truncatewords:30 }}</p>
{% endif %}
</div>
</div>
{% endif %}
{% empty %}
<p class="text-center text-brown-2">No speakers available yet.</p>
{% endfor %}
Expand Down
10 changes: 8 additions & 2 deletions app/home/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from app.speakers.models import Speaker
from app.sponsors.models import Sponsor
from config.constants import SPONSOR_TYPE_ORDER
from services.pretalx_service import PretalxService


class HomeView(BuildableTemplateView):
Expand All @@ -25,9 +26,14 @@ def get_sponsors(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
service = PretalxService()
context["sponsors_by_type"] = self.get_sponsors()
context["featured_speakers"] = Speaker.objects.filter(is_featured=True).order_by("first_name", "last_name")
context["speakers"] = Speaker.objects.filter(is_featured=False).order_by("first_name", "last_name")
featured_speakers = Speaker.objects.filter(is_featured=True).order_by("first_name", "last_name")
context["featured_speakers"] = featured_speakers
keynote_names = {s.full_name for s in featured_speakers}
context["speakers"] = [
s for s in service.get_speakers("python-asia-2026")["results"] if s.get("name") not in keynote_names
]
return context


Expand Down
7 changes: 7 additions & 0 deletions config/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,13 @@

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.db.DatabaseCache",
"LOCATION": "django_cache",
}
}

# Build directory for bakery
BUILD_DIR = BASE_DIR / "build"
BAKERY_VIEWS = ("app.home.views.HomeView",)
Expand Down
4 changes: 4 additions & 0 deletions deploy/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ uv sync
echo "Applying database migrations..."
uv run manage.py migrate --noinput

# Create cache table
echo "Creating cache table..."
uv run manage.py createcachetable

# Collect static files
echo "Collecting static files..."
uv run manage.py collectstatic --noinput
46 changes: 38 additions & 8 deletions services/pretalx_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import requests
from django.core.cache import cache

from config.environment import settings


class PretalxService:
def __init__(self, base_url: str):
self.base_url = settings.PRETALX.BASE_URL.rstrip("/")
def __init__(self, base_url: str | None = None):
self.base_url = base_url or settings.PRETALX.BASE_URL.rstrip("/")
self.headers = {
"Authorization": f"Token {settings.PRETALX.API_TOKEN}",
"Content-Type": "application/json",
}

Expand All @@ -17,14 +17,39 @@ def get_event(self, event_slug: str):
return response.json() if response.ok else response.raise_for_status()

def get_submissions(self, event_slug: str):
url = f"{self.base_url}/api/events/{event_slug}/submissions/"
cache_key = f"pretalx_submissions_{event_slug}"
cached = cache.get(cache_key)
if cached:
return cached
url = f"{self.base_url}/api/events/{event_slug}/submissions/?page_size=999"
response = requests.get(url, headers=self.headers)
return response.json() if response.ok else response.raise_for_status()
data = response.json() if response.ok else response.raise_for_status()
cache.set(cache_key, data)
return data

def get_speakers(self, event_slug: str):
url = f"{self.base_url}/api/events/{event_slug}/speakers/"
response = requests.get(url, headers=self.headers)
return response.json() if response.ok else response.raise_for_status()
try:
cache_key = f"pretalx_speakers_{event_slug}"
cached = cache.get(cache_key)
if cached:
return cached

url = f"{self.base_url}/api/events/{event_slug}/speakers/?page_size=999"
response = requests.get(url, headers=self.headers)
data = response.json() if response.ok else response.raise_for_status()

submissions = self.get_submissions(event_slug)
confirmed_codes = {sub["code"] for sub in submissions.get("results", []) if sub.get("state") == "confirmed"}

data["results"] = [
speaker
for speaker in data.get("results", [])
if any(code in confirmed_codes for code in speaker.get("submissions", []))
]
cache.set(cache_key, data)
return data
except requests.RequestException:
return {"results": []}

def get_talks(self, event_slug: str):
url = f"{self.base_url}/api/events/{event_slug}/talks?limit=999&state=confirmed"
Expand All @@ -40,3 +65,8 @@ def send_feedback(self, event_slug: str, submission_id: str, feedback: dict):
url = f"{self.base_url}/api/events/{event_slug}/submissions/{submission_id}/feedback/"
response = requests.post(url, json=feedback, headers=self.headers)
return response.json() if response.ok else response.raise_for_status()

def get_sessions(self, event_slug: str):
url = f"{self.base_url}/api/events/{event_slug}/sessions/"
response = requests.get(url, headers=self.headers)
return response.json() if response.ok else response.raise_for_status()
4,966 changes: 4,964 additions & 2 deletions static/css/app.css

Large diffs are not rendered by default.