Skip to content

Commit 9832e92

Browse files
committed
move generation of frab-style json schedule to separate file
1 parent d375a70 commit 9832e92

File tree

2 files changed

+137
-102
lines changed

2 files changed

+137
-102
lines changed

apps/schedule/feeds.py

Lines changed: 9 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
import json
2-
from datetime import timedelta
32
from icalendar import Calendar, Event
43
from flask import request, abort, current_app as app, redirect, url_for, Response
54
from flask_cors import cross_origin
65
from flask_login import current_user
7-
from math import ceil
86

9-
from main import external_url
10-
from models import event_year, event_start, event_end
7+
from models import event_year
118
from models.user import User
129
from models.cfp import Proposal
1310

1411
from ..common import feature_flag, feature_enabled, json_response
15-
from .schedule_xml import export_frab, get_day_start_end, get_duration
12+
from .schedule_json import export_frab_json
13+
from .schedule_xml import export_frab
1614
from .historic import feed_historic
1715
from .data import (
1816
_get_scheduled_proposals,
1917
_get_proposal_dict,
2018
_convert_time_to_str,
2119
_get_upcoming,
2220
)
23-
from . import event_tz, schedule
21+
from . import schedule
2422

2523

2624
def _format_event_description(event):
@@ -37,9 +35,9 @@ def _format_event_description(event):
3735
venue_str = event["venue"]
3836
if event["map_link"]:
3937
venue_str = f'{venue_str} ({event["map_link"]})'
40-
footer_block.append(f'Venue: {venue_str}')
38+
footer_block.append(f"Venue: {venue_str}")
4139
if footer_block:
42-
description += '\n\n' + '\n'.join(footer_block)
40+
description += "\n\n" + "\n".join(footer_block)
4341

4442
return description
4543

@@ -78,102 +76,10 @@ def schedule_frab_json(year):
7876
.all()
7977
)
8078

81-
duration_days = ceil((event_end() - event_end()).total_seconds / 86400)
82-
83-
rooms = [proposal.scheduled_venue.name for proposal in schedule]
84-
85-
schedule_json = {
86-
"version": "1.0-public",
87-
"conference": {
88-
"acronym": "emf{}".format(event_year()),
89-
"days": [],
90-
"daysCount": duration_days,
91-
"end": event_end().strftime("%Y-%m-%d"),
92-
"rooms": [
93-
{
94-
"name": room,
95-
}
96-
for room in rooms
97-
],
98-
"start": event_start().strftime("%Y-%m-%d"),
99-
"time_zone_name": event_tz,
100-
"timeslot_duration": "00:10",
101-
"title": "Electromagnetic Field {}".format(event_year()),
102-
"url": external_url("main"),
103-
},
104-
}
105-
106-
for day in range(0, duration_days):
107-
day_dt = event_start() + timedelta(days=day)
108-
day_start, day_end = get_day_start_end(day_dt)
109-
day_schedule = {
110-
"date": day_dt.strftime("%Y-%m-%d"),
111-
"day_end": day_start.isoformat(),
112-
"day_start": day_end.isoformat(),
113-
"index": day,
114-
"rooms": {},
115-
}
116-
for room in rooms:
117-
day_schedule["rooms"][room] = []
118-
for proposal in schedule:
119-
if proposal.scheduled_venue.name != room:
120-
# TODO find a better way to do that
121-
continue
122-
links = {
123-
proposal.c3voc_url,
124-
proposal.youtube_url,
125-
proposal.thumbnail_url,
126-
proposal.map_link,
127-
}
128-
links.discard(None)
129-
links.discard("")
130-
day_schedule["rooms"][room].append(
131-
{
132-
"abstract": None, # The proposal model does not implement abstracts
133-
"attachments": [],
134-
"date": event_tz.localize(proposal.start_date).isoformat(),
135-
"description": proposal.description,
136-
"do_not_record": proposal.video_privacy != "public",
137-
"duration": get_duration(proposal.start_date, proposal.end_date),
138-
"guid": None,
139-
"id": proposal.id,
140-
# This assumes there will never be a non-english talk,
141-
# which is probably fine for a conference in the UK.
142-
"language": "en",
143-
"links": sorted(links),
144-
"persons": [
145-
{
146-
"name": name.strip(),
147-
"public_name": name.strip(),
148-
}
149-
for name in (proposal.published_names or proposal.user.name).split(",")
150-
],
151-
"recording_license": "CC BY-SA 3.0",
152-
"room": room,
153-
"slug": "emf{}-{}-{}".format(
154-
event_year(),
155-
proposal.id,
156-
proposal.slug,
157-
),
158-
"start": event_tz.localize(proposal.start_date).strftime("%H:%M"),
159-
"subtitle": None,
160-
"title": proposal.display_title,
161-
"track": None,
162-
"type": proposal.type,
163-
"url": external_url(
164-
".item",
165-
year=event_year(),
166-
proposal_id=proposal.id,
167-
slug=proposal.slug,
168-
),
169-
}
170-
)
171-
schedule_json["conference"]["days"].append(day_schedule)
172-
17379
return Response(
17480
json.dumps(
17581
{
176-
"schedule": schedule_json,
82+
"schedule": export_frab_json(schedule),
17783
"$schema": "https://c3voc.de/schedule/schema.json",
17884
"generator": {
17985
"name": "emfcamp-website",
@@ -187,7 +93,8 @@ def schedule_frab_json(year):
18793

18894
@schedule.route("/schedule/<int:year>.frab")
18995
def schedule_frab(year):
190-
return redirect(url_for('schedule_frab_xml', year=year), code=301)
96+
return redirect(url_for("schedule_frab_xml", year=year), code=301)
97+
19198

19299
@schedule.route("/schedule/frab-<int:year>.xml")
193100
def schedule_frab_xml(year):

apps/schedule/schedule_json.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
from datetime import timedelta
2+
from math import ceil
3+
4+
from main import external_url
5+
from models import event_end, event_start, event_year
6+
7+
from . import event_tx
8+
from .schedule_xml import get_day_start_end, get_duration
9+
10+
11+
def events_per_day_and_room(schedule):
12+
days = {
13+
current_date.date(): {
14+
"index": index + 1,
15+
"start": get_day_start_end(event_start() + timedelta(days=index))[0],
16+
"end": get_day_start_end(event_start() + timedelta(days=index))[1],
17+
"rooms": {},
18+
}
19+
for index, current_date in enumerate(
20+
event_start() + timedelta(days=i) for i in range((event_end() - event_start()).days + 1)
21+
)
22+
}
23+
24+
for proposal in schedule:
25+
talk_date = proposal.start_date.date()
26+
if talk.start_date.hour < 4 and talk_date != event_start().date():
27+
talk_date -= timedelta(days=1)
28+
if talk_date not in days:
29+
# Event is outside the scheduled event duration.
30+
continue
31+
if proposal.scheduled_venue.name not in days[talk_date]:
32+
days[talk_date][proposal.scheduled_venue.name] = [proposal]
33+
else:
34+
days[talk_date][proposal.scheduled_venue.name].append(proposal)
35+
36+
return days.values()
37+
38+
39+
def export_frab_json(schedule):
40+
duration_days = ceil((event_end() - event_end()).total_seconds / 86400)
41+
42+
rooms = set([proposal.scheduled_venue.name for proposal in schedule])
43+
44+
schedule_json = {
45+
"version": "1.0-public",
46+
"conference": {
47+
"acronym": "emf{}".format(event_year()),
48+
"days": [],
49+
"daysCount": duration_days,
50+
"end": event_end().strftime("%Y-%m-%d"),
51+
"rooms": [
52+
{
53+
"name": room,
54+
}
55+
for room in sorted(rooms)
56+
],
57+
"start": event_start().strftime("%Y-%m-%d"),
58+
"time_zone_name": event_tz,
59+
"timeslot_duration": "00:10",
60+
"title": "Electromagnetic Field {}".format(event_year()),
61+
"url": external_url("main"),
62+
},
63+
}
64+
65+
for day in events_per_day_and_room:
66+
day_schedule = {
67+
"date": day["start"].strftime("%Y-%m-%d"),
68+
"day_end": day["start"].isoformat(),
69+
"day_start": day["end"].isoformat(),
70+
"index": day["index"],
71+
"rooms": {},
72+
}
73+
for room, events in sorted(day["rooms"].items()):
74+
day_schedule["rooms"][room] = []
75+
for proposal in events:
76+
links = {
77+
proposal.c3voc_url,
78+
proposal.youtube_url,
79+
proposal.thumbnail_url,
80+
proposal.map_link,
81+
}
82+
links.discard(None)
83+
links.discard("")
84+
day_schedule["rooms"][room].append(
85+
{
86+
"abstract": None, # The proposal model does not implement abstracts
87+
"attachments": [],
88+
"date": event_tz.localize(proposal.start_date).isoformat(),
89+
"description": proposal.description,
90+
"do_not_record": proposal.video_privacy != "public",
91+
"duration": get_duration(proposal.start_date, proposal.end_date),
92+
"guid": None,
93+
"id": proposal.id,
94+
# This assumes there will never be a non-english talk,
95+
# which is probably fine for a conference in the UK.
96+
"language": "en",
97+
"links": sorted(links),
98+
"persons": [
99+
{
100+
"name": name.strip(),
101+
"public_name": name.strip(),
102+
}
103+
for name in (proposal.published_names or proposal.user.name).split(",")
104+
],
105+
"recording_license": "CC BY-SA 3.0",
106+
"room": room,
107+
"slug": "emf{}-{}-{}".format(
108+
event_year(),
109+
proposal.id,
110+
proposal.slug,
111+
),
112+
"start": event_tz.localize(proposal.start_date).strftime("%H:%M"),
113+
"subtitle": None,
114+
"title": proposal.display_title,
115+
# Contrary to the infobeamer frab module, the json module does not allow users to set colours
116+
# for tracks themselves. It instead relies on the schedule itself to provide those colours.
117+
"track": None,
118+
"type": proposal.type,
119+
"url": external_url(
120+
".item",
121+
year=event_year(),
122+
proposal_id=proposal.id,
123+
slug=proposal.slug,
124+
),
125+
}
126+
)
127+
schedule_json["conference"]["days"].append(day_schedule)
128+
return schedule_json

0 commit comments

Comments
 (0)