diff --git a/apps/api/schedule.py b/apps/api/schedule.py index f775d8d72..8441b8ac2 100644 --- a/apps/api/schedule.py +++ b/apps/api/schedule.py @@ -17,10 +17,16 @@ def _require_video_api_key(func): @wraps(func) def wrapper(*args, **kwargs): auth_header = request.headers.get("authorization", None) - if not auth_header or not auth_header.startswith("Bearer "): + if not auth_header: + abort(401) + + if auth_header.startswith("bearer "): + bearer_token = auth_header.removeprefix("bearer ") + elif auth_header.startswith("Bearer "): + bearer_token = auth_header.removeprefix("Bearer ") + else: abort(401) - bearer_token = auth_header.removeprefix("Bearer ") if not compare_digest(bearer_token, app.config["VIDEO_API_KEY"]): abort(401) @@ -46,6 +52,7 @@ def patch(self, proposal_id): "thumbnail_url", "c3voc_url", "video_recording_lost", + "video_download_url", } if set(payload.keys()) - ALLOWED_ATTRIBUTES: abort(400) @@ -60,10 +67,7 @@ def patch(self, proposal_id): return { "id": proposal.id, "slug": proposal.slug, - "youtube_url": proposal.youtube_url, - "thumbnail_url": proposal.thumbnail_url, - "c3voc_url": proposal.c3voc_url, - "video_recording_lost": proposal.video_recording_lost, + **{a: getattr(proposal, a) for a in ALLOWED_ATTRIBUTES} } diff --git a/apps/schedule/data.py b/apps/schedule/data.py index f128b719e..a17c98116 100644 --- a/apps/schedule/data.py +++ b/apps/schedule/data.py @@ -53,6 +53,8 @@ def _get_proposal_dict(proposal: Proposal, favourites_ids): video_res["youtube"] = proposal.youtube_url if proposal.thumbnail_url: video_res["preview_image"] = proposal.thumbnail_url + if proposal.video_download_url: + video_res["video_download_url"] = proposal.video_download_url video_res["recording_lost"] = proposal.video_recording_lost if video_res: res["video"] = video_res diff --git a/apps/schedule/schedule_xml.py b/apps/schedule/schedule_xml.py index c06b966e4..8672be7d4 100644 --- a/apps/schedule/schedule_xml.py +++ b/apps/schedule/schedule_xml.py @@ -119,6 +119,9 @@ def add_event(room, event): _add_sub_with_text(event_node, "subtitle", "") + if vdu := event.get("video", {}).get("video_download_url"): + _add_sub_with_text(event_node, "video_download_url", vdu) + add_persons(event_node, event) add_recording(event_node, event) diff --git a/migrations/versions/a666c0f102e2_add_video_download_url.py b/migrations/versions/a666c0f102e2_add_video_download_url.py new file mode 100644 index 000000000..505625180 --- /dev/null +++ b/migrations/versions/a666c0f102e2_add_video_download_url.py @@ -0,0 +1,28 @@ +"""add video download url + +Revision ID: a666c0f102e2 +Revises: 7249f66e2ae0 +Create Date: 2024-08-26 23:39:26.318321 + +""" + +# revision identifiers, used by Alembic. +revision = 'a666c0f102e2' +down_revision = '7249f66e2ae0' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('proposal', sa.Column('video_download_url', sa.String(), nullable=True)) + op.add_column('proposal_version', sa.Column('video_download_url', sa.String(), autoincrement=False, nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('proposal_version', 'video_download_url') + op.drop_column('proposal', 'video_download_url') + # ### end Alembic commands ### diff --git a/models/cfp.py b/models/cfp.py index abd92ec15..61f2c990e 100644 --- a/models/cfp.py +++ b/models/cfp.py @@ -440,6 +440,13 @@ class Proposal(BaseModel): youtube_url = db.Column(db.String) thumbnail_url = db.Column(db.String) video_recording_lost = db.Column(db.Boolean, default=False) + video_download_url = db.Column( + db.String, + doc=""" + Canonical, potentially ephemeral source for the video recording. + Used to automate release of videos to other platforms, in particular media.ccc.de. + """, + ) type_might_require_ticket = False tickets = db.relationship("EventTicket", backref="proposal")