feat: explicit names for meetecho recordings (#8062)
* feat: explicit names for meetecho recordings * fix: better regex and kebab-styled-endpoint-name * fix: spaces around comparison operator
This commit is contained in:
parent
9873439cdc
commit
8881010051
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2015-2020, All Rights Reserved
|
||||
# Copyright The IETF Trust 2015-2024, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
import base64
|
||||
import datetime
|
||||
|
@ -222,6 +222,70 @@ class CustomApiTests(TestCase):
|
|||
event = doc.latest_event()
|
||||
self.assertEqual(event.by, recman)
|
||||
|
||||
def test_api_set_meetecho_recording_name(self):
|
||||
url = urlreverse("ietf.meeting.views.api_set_meetecho_recording_name")
|
||||
recmanrole = RoleFactory(group__type_id="ietf", name_id="recman")
|
||||
recman = recmanrole.person
|
||||
meeting = MeetingFactory(type_id="ietf")
|
||||
session = SessionFactory(group__type_id="wg", meeting=meeting)
|
||||
apikey = PersonalApiKey.objects.create(endpoint=url, person=recman)
|
||||
name = "testname"
|
||||
|
||||
# error cases
|
||||
r = self.client.post(url, {})
|
||||
self.assertContains(r, "Missing apikey parameter", status_code=400)
|
||||
|
||||
badrole = RoleFactory(group__type_id="ietf", name_id="ad")
|
||||
badapikey = PersonalApiKey.objects.create(endpoint=url, person=badrole.person)
|
||||
badrole.person.user.last_login = timezone.now()
|
||||
badrole.person.user.save()
|
||||
r = self.client.post(url, {"apikey": badapikey.hash()})
|
||||
self.assertContains(r, "Restricted to role: Recording Manager", status_code=403)
|
||||
|
||||
r = self.client.post(url, {"apikey": apikey.hash()})
|
||||
self.assertContains(r, "Too long since last regular login", status_code=400)
|
||||
recman.user.last_login = timezone.now()
|
||||
recman.user.save()
|
||||
|
||||
r = self.client.get(url, {"apikey": apikey.hash()})
|
||||
self.assertContains(r, "Method not allowed", status_code=405)
|
||||
|
||||
r = self.client.post(url, {"apikey": apikey.hash()})
|
||||
self.assertContains(r, "Missing session_id parameter", status_code=400)
|
||||
|
||||
r = self.client.post(url, {"apikey": apikey.hash(), "session_id": session.pk})
|
||||
self.assertContains(r, "Missing name parameter", status_code=400)
|
||||
|
||||
bad_pk = int(Session.objects.order_by("-pk").first().pk) + 1
|
||||
r = self.client.post(
|
||||
url,
|
||||
{
|
||||
"apikey": apikey.hash(),
|
||||
"session_id": bad_pk,
|
||||
"name": name,
|
||||
},
|
||||
)
|
||||
self.assertContains(r, "Session not found", status_code=400)
|
||||
|
||||
r = self.client.post(
|
||||
url,
|
||||
{
|
||||
"apikey": apikey.hash(),
|
||||
"session_id": "foo",
|
||||
"name": name,
|
||||
},
|
||||
)
|
||||
self.assertContains(r, "Invalid session_id", status_code=400)
|
||||
|
||||
r = self.client.post(
|
||||
url, {"apikey": apikey.hash(), "session_id": session.pk, "name": name}
|
||||
)
|
||||
self.assertContains(r, "Done", status_code=200)
|
||||
|
||||
session.refresh_from_db()
|
||||
self.assertEqual(session.meetecho_recording_name, name)
|
||||
|
||||
|
||||
def test_api_add_session_attendees_deprecated(self):
|
||||
# Deprecated test - should be removed when we stop accepting a simple list of user PKs in
|
||||
# the add_session_attendees() view
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2017, All Rights Reserved
|
||||
# Copyright The IETF Trust 2017-2024, All Rights Reserved
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import include
|
||||
|
@ -39,6 +39,8 @@ urlpatterns = [
|
|||
url(r'^iesg/position', views_ballot.api_set_position),
|
||||
# Let Meetecho set session video URLs
|
||||
url(r'^meeting/session/video/url$', meeting_views.api_set_session_video_url),
|
||||
# Let Meetecho tell us the name of its recordings
|
||||
url(r'^meeting/session/recording-name$', meeting_views.api_set_meetecho_recording_name),
|
||||
# Meeting agenda + floorplan data
|
||||
url(r'^meeting/(?P<num>[A-Za-z0-9._+-]+)/agenda-data$', meeting_views.api_get_agenda_data),
|
||||
# Meeting session materials
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright The IETF Trust 2024, All Rights Reserved
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("meeting", "0008_remove_schedtimesessassignment_notes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="session",
|
||||
name="meetecho_recording_name",
|
||||
field=models.CharField(
|
||||
blank=True, help_text="Name of the meetecho recording", max_length=64
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1042,6 +1042,7 @@ class Session(models.Model):
|
|||
on_agenda = models.BooleanField(default=True, help_text='Is this session visible on the meeting agenda?')
|
||||
has_onsite_tool = models.BooleanField(default=False, help_text="Does this session use the officially supported onsite and remote tooling?")
|
||||
chat_room = models.CharField(blank=True, max_length=32, help_text='Name of Zulip stream, if different from group acronym')
|
||||
meetecho_recording_name = models.CharField(blank=True, max_length=64, help_text="Name of the meetecho recording")
|
||||
|
||||
tombstone_for = models.ForeignKey('Session', blank=True, null=True, help_text="This session is the tombstone for a session that was rescheduled", on_delete=models.CASCADE)
|
||||
|
||||
|
@ -1332,17 +1333,23 @@ class Session(models.Model):
|
|||
return None
|
||||
|
||||
def _session_recording_url_label(self):
|
||||
otsa = self.official_timeslotassignment()
|
||||
if otsa is None:
|
||||
return None
|
||||
if self.meeting.type.slug == "ietf" and self.has_onsite_tool:
|
||||
session_label = f"IETF{self.meeting.number}-{self.group.acronym.upper()}-{self.official_timeslotassignment().timeslot.time.strftime('%Y%m%d-%H%M')}"
|
||||
session_label = f"IETF{self.meeting.number}-{self.group.acronym.upper()}-{otsa.timeslot.time.strftime('%Y%m%d-%H%M')}"
|
||||
else:
|
||||
session_label = f"IETF-{self.group.acronym.upper()}-{self.official_timeslotassignment().timeslot.time.strftime('%Y%m%d-%H%M')}"
|
||||
session_label = f"IETF-{self.group.acronym.upper()}-{otsa.timeslot.time.strftime('%Y%m%d-%H%M')}"
|
||||
return session_label
|
||||
|
||||
def session_recording_url(self):
|
||||
url_formatter = getattr(settings, "MEETECHO_SESSION_RECORDING_URL", "")
|
||||
url = None
|
||||
if url_formatter and self.video_stream_url:
|
||||
url = url_formatter.format(session_label=self._session_recording_url_label())
|
||||
name = self.meetecho_recording_name
|
||||
if name is None or name.strip() == "":
|
||||
name = self._session_recording_url_label()
|
||||
if url_formatter.strip() != "" and name is not None:
|
||||
url = url_formatter.format(session_label=name)
|
||||
return url
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2021, All Rights Reserved
|
||||
# Copyright The IETF Trust 2021-2024, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Tests of models in the Meeting application"""
|
||||
import datetime
|
||||
|
@ -172,6 +172,10 @@ class SessionTests(TestCase):
|
|||
settings.MEETECHO_SESSION_RECORDING_URL = "http://player.example.com?{session_label}"
|
||||
self.assertEqual(session.session_recording_url(), "http://player.example.com?LABEL")
|
||||
|
||||
session.meetecho_recording_name="actualname"
|
||||
session.save()
|
||||
self.assertEqual(session.session_recording_url(), "http://player.example.com?actualname")
|
||||
|
||||
def test_session_recording_url_label_ietf(self):
|
||||
session = SessionFactory(
|
||||
meeting__type_id='ietf',
|
||||
|
|
|
@ -4270,6 +4270,45 @@ class OldUploadRedirect(RedirectView):
|
|||
def get_redirect_url(self, **kwargs):
|
||||
return reverse_lazy('ietf.meeting.views.session_details',kwargs=self.kwargs)
|
||||
|
||||
|
||||
@require_api_key
|
||||
@role_required("Recording Manager")
|
||||
@csrf_exempt
|
||||
def api_set_meetecho_recording_name(request):
|
||||
"""Set name for meetecho recording
|
||||
|
||||
parameters:
|
||||
apikey: the poster's personal API key
|
||||
session_id: id of the session to update
|
||||
name: the name to use for the recording at meetecho player
|
||||
"""
|
||||
def err(code, text):
|
||||
return HttpResponse(text, status=code, content_type='text/plain')
|
||||
|
||||
if request.method != "POST":
|
||||
return HttpResponseNotAllowed(
|
||||
content="Method not allowed", content_type="text/plain", permitted_methods=('POST',)
|
||||
)
|
||||
|
||||
session_id = request.POST.get('session_id', None)
|
||||
if session_id is None:
|
||||
return err(400, 'Missing session_id parameter')
|
||||
name = request.POST.get('name', None)
|
||||
if name is None:
|
||||
return err(400, 'Missing name parameter')
|
||||
|
||||
try:
|
||||
session = Session.objects.get(pk=session_id)
|
||||
except Session.DoesNotExist:
|
||||
return err(400, f"Session not found with session_id '{session_id}'")
|
||||
except ValueError:
|
||||
return err(400, "Invalid session_id: {session_id}")
|
||||
|
||||
session.meetecho_recording_name = name
|
||||
session.save()
|
||||
|
||||
return HttpResponse("Done", status=200, content_type='text/plain')
|
||||
|
||||
@require_api_key
|
||||
@role_required('Recording Manager')
|
||||
@csrf_exempt
|
||||
|
|
Loading…
Reference in a new issue