|
3 | 3 | from flask import request, abort, current_app as app, Response
|
4 | 4 | from flask_cors import cross_origin
|
5 | 5 | from flask_login import current_user
|
| 6 | +from math import ceil |
6 | 7 |
|
7 |
| -from models import event_year |
| 8 | +from main import external_url |
| 9 | +from models import event_year, event_start, event_end |
8 | 10 | from models.user import User
|
9 | 11 | from models.cfp import Proposal
|
10 | 12 |
|
|
17 | 19 | _convert_time_to_str,
|
18 | 20 | _get_upcoming,
|
19 | 21 | )
|
20 |
| -from . import schedule |
| 22 | +from . import event_tz, schedule |
21 | 23 |
|
22 | 24 |
|
23 | 25 | def _format_event_description(event):
|
@@ -46,6 +48,136 @@ def schedule_json(year):
|
46 | 48 | return Response(json.dumps(schedule), mimetype="application/json")
|
47 | 49 |
|
48 | 50 |
|
| 51 | +@schedule.route("/schedule/schedule-<int:year>.json") # TODO validate url with upstream |
| 52 | +@cross_origin(methods=["GET"]) |
| 53 | +def schedule_json_schema(year): |
| 54 | + if year != event_year(): |
| 55 | + return feed_historic(year, "json") |
| 56 | + |
| 57 | + if not feature_enabled('SCHEDULE'): |
| 58 | + abort(404) |
| 59 | + |
| 60 | + def duration_hhmm(duration_minutes): |
| 61 | + if not duration_minutes or duration_minutes < 1: |
| 62 | + return "00:00" |
| 63 | + return "{}:{}".format( |
| 64 | + int(duration_minutes/60), |
| 65 | + str(duration_minutes%60).zfill(2), |
| 66 | + ) |
| 67 | + |
| 68 | + schedule = ( |
| 69 | + Proposal.query.filter( |
| 70 | + Proposal.is_accepted, |
| 71 | + Proposal.scheduled_time.isnot(None), |
| 72 | + Proposal.scheduled_venue_id.isnot(None), |
| 73 | + Proposal.scheduled_duration.isnot(None), |
| 74 | + ) |
| 75 | + .order_by(Proposal.scheduled_time) |
| 76 | + .all() |
| 77 | + ) |
| 78 | + |
| 79 | + duration_days = ceil((event_end() - event_end()).total_seconds / 86400), |
| 80 | + |
| 81 | + rooms = [ |
| 82 | + proposal.scheduled_venue.name |
| 83 | + for proposal in schedule |
| 84 | + ] |
| 85 | + |
| 86 | + schedule_json = { |
| 87 | + "version": "1.0-public", |
| 88 | + "conference": { |
| 89 | + "acronym": "emf{}".format(event_year()), |
| 90 | + "days": [], |
| 91 | + "daysCount": duration_days, |
| 92 | + "end": event_end().strftime("%Y-%m-%d"), |
| 93 | + "rooms": [ |
| 94 | + { |
| 95 | + "name": room, |
| 96 | + } |
| 97 | + for room in rooms |
| 98 | + ], |
| 99 | + "start": event_start().strftime("%Y-%m-%d"), |
| 100 | + "time_zone_name": event_tz, |
| 101 | + "timeslot_duration": "00:10", |
| 102 | + "title": "Electromagnetic Field {}".format(event_year()), |
| 103 | + "url": external_url("main"), |
| 104 | + }, |
| 105 | + } |
| 106 | + |
| 107 | + for day in range(0, duration_days): |
| 108 | + day_dt = event_start() + timedelta(days=day) |
| 109 | + day_schedule = { |
| 110 | + "date": day_dt.strftime("%Y-%m-%d"), |
| 111 | + "day_end": (day_dt.replace(hour=3, minute=59, second=59) + timedelta(days=1)).isoformat(), |
| 112 | + "day_start": day_dt.replace(hour=4, minute=0, second=0).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 | + "abstract": None, # The proposal model does not implement abstracts |
| 132 | + "attachments": [], |
| 133 | + "date": event_tz.localize(proposal.start_date).isoformat(), |
| 134 | + "description": proposal.description, |
| 135 | + "do_not_record": False if proposal.may_record else True, |
| 136 | + "duration": duration_hhmm(proposal.duration_minutes), |
| 137 | + "guid": None, |
| 138 | + "id": proposal.id, |
| 139 | + # This assumes there will never be a non-english talk, |
| 140 | + # which is probably fine for a conference in the UK. |
| 141 | + "language": "en", |
| 142 | + "links": sorted(links), |
| 143 | + "persons": [ |
| 144 | + { |
| 145 | + "name": name.strip(), |
| 146 | + "public_name": name.strip(), |
| 147 | + } |
| 148 | + for person in (proposal.published_names or proposal.user.name).split(",") |
| 149 | + ], |
| 150 | + "recording_license": "CC BY-SA 3.0", |
| 151 | + "room": room, |
| 152 | + "slug": "emf{}-{}-{}".format( |
| 153 | + event_year(), |
| 154 | + proposal.id, |
| 155 | + proposal.slug, |
| 156 | + ), |
| 157 | + "start": event_tz.localize(proposal.start_date).strftime("%H:%M"), |
| 158 | + "subtitle": None, |
| 159 | + "title": proposal.display_title, |
| 160 | + "track": None, # TODO does emf have tracks? |
| 161 | + "type": proposal.type, |
| 162 | + "url": external_url( |
| 163 | + ".item", |
| 164 | + year=event_year(), |
| 165 | + proposal_id=proposal.id, |
| 166 | + slug=proposal.slug, |
| 167 | + ), |
| 168 | + }) |
| 169 | + schedule_json["conference"]["days"].append(day_schedule) |
| 170 | + |
| 171 | + return Response(json.dumps({ |
| 172 | + "schedule": schedule_json, |
| 173 | + "$schema": "https://c3voc.de/schedule/schema.json", |
| 174 | + "generator": { |
| 175 | + "name": "emfcamp-website", |
| 176 | + "url": "https://github.com/emfcamp/Website", |
| 177 | + }, |
| 178 | + }), mimetype="application/json") |
| 179 | + |
| 180 | + |
49 | 181 | @schedule.route("/schedule/<int:year>.frab")
|
50 | 182 | def schedule_frab(year):
|
51 | 183 | if year != event_year():
|
|
0 commit comments