diff --git a/src/backoffice/forms.py b/src/backoffice/forms.py index 592c4916..77fd2167 100644 --- a/src/backoffice/forms.py +++ b/src/backoffice/forms.py @@ -2,6 +2,16 @@ from django import forms from program.models import Event, Speaker +class AddRecordingForm(forms.ModelForm): + recording_url = forms.URLField( + label="Recording URL", help_text="Add a URL to the recording.", required=False + ) + + class Meta: + model = Event + fields = ["video_recording", "recording_url"] + + class AutoScheduleValidateForm(forms.Form): schedule = forms.ChoiceField( choices=( diff --git a/src/backoffice/templates/add_recording.html b/src/backoffice/templates/add_recording.html new file mode 100644 index 00000000..0381fd48 --- /dev/null +++ b/src/backoffice/templates/add_recording.html @@ -0,0 +1,32 @@ +{% extends 'base.html' %} +{% load bornhack %} + +{% block content %} +
+
+
+ BackOffice - Add Event recordings +
+
+
+ The Content team can add video links to all events that are configured to be recorded +
+ {% if event_list %} +
+ {{ formset.management_form }} + {% csrf_token %} + {% for form, event in formset|zip:event_list %} + {% include "includes/eventrecording_detail_panel.html" %} + {% endfor %} + + Cancel +
+ {% else %} +
There is no events missing links to recordings.
+ Cancel + {% endif %} +
+
+
+{% endblock content %} + diff --git a/src/backoffice/templates/index.html b/src/backoffice/templates/index.html index 9070d1f5..9fb5d31a 100644 --- a/src/backoffice/templates/index.html +++ b/src/backoffice/templates/index.html @@ -107,6 +107,10 @@

SpeakerProposals

Use these views to see all SpeakerProposals

+ +

Add Recordings

+

Use this view to add recordings to events

+
{% endif %} {% if perms.camps.orgateam_permission %} diff --git a/src/backoffice/urls.py b/src/backoffice/urls.py index 3a547e13..80692f5d 100644 --- a/src/backoffice/urls.py +++ b/src/backoffice/urls.py @@ -1,6 +1,7 @@ from django.urls import include, path from .views import ( + AddRecordingView, ApproveFeedbackView, ApproveNamesView, AutoScheduleApplyView, @@ -537,6 +538,8 @@ urlpatterns = [ ApproveFeedbackView.as_view(), name="approve_event_feedback", ), + # add recording url objects + path("add_recording", AddRecordingView.as_view(), name="add_eventrecording",), # economy path( "economy/", diff --git a/src/backoffice/views.py b/src/backoffice/views.py index 248a3427..e79a7c01 100644 --- a/src/backoffice/views.py +++ b/src/backoffice/views.py @@ -49,6 +49,8 @@ from program.models import ( EventType, Speaker, SpeakerProposal, + Url, + UrlType, ) from program.utils import save_speaker_availability from shop.models import Order, OrderProductRelation @@ -62,6 +64,7 @@ from .forms import ( AutoScheduleValidateForm, EventScheduleForm, SpeakerForm, + AddRecordingForm, ) from .mixins import ( ContentTeamPermissionMixin, @@ -191,6 +194,68 @@ class ApproveFeedbackView(CampViewMixin, ContentTeamPermissionMixin, FormView): ) +class AddRecordingView(CampViewMixin, ContentTeamPermissionMixin, FormView): + """ + This view shows a list of events that is set to be recorded, but without a recording URL attached. + """ + + model = Event + template_name = "add_recording.html" + + def setup(self, *args, **kwargs): + super().setup(*args, **kwargs) + self.queryset = Event.objects.filter( + track__camp=self.camp, video_recording=True + ).exclude( + urls__url_type__name="Recording" + ) + + self.form_class = modelformset_factory( + Event, + form=AddRecordingForm, + min_num=self.queryset.count(), + validate_min=True, + max_num=self.queryset.count(), + validate_max=True, + extra=0, + ) + + def get_context_data(self, *args, **kwargs): + """ + Include the queryset used for the modelformset_factory so we have + some idea which object is which in the template + Why the hell do the forms in the formset not include the object? + """ + context = super().get_context_data(*args, **kwargs) + context["event_list"] = self.queryset + context["formset"] = self.form_class(queryset=self.queryset) + return context + + def form_valid(self, form): + form.save() + + for event_data in form.cleaned_data: + if event_data['recording_url']: + url = event_data['recording_url'] + if not event_data['id'].urls.filter(url=url).exists(): + recording_url = Url() + recording_url.event = event_data['id'] + recording_url.url = url + recording_url.url_type = UrlType.objects.get(name="Recording") + recording_url.save() + + if form.changed_objects: + messages.success( + self.request, f"Updated {len(form.changed_objects)} Event" + ) + return redirect(self.get_success_url()) + + def get_success_url(self, *args, **kwargs): + return reverse( + "backoffice:add_eventrecording", kwargs={"camp_slug": self.camp.slug} + ) + + ########################## # MANAGE FACILITIES VIEWS diff --git a/src/program/templates/includes/eventrecording_detail_panel.html b/src/program/templates/includes/eventrecording_detail_panel.html new file mode 100644 index 00000000..8ed824bd --- /dev/null +++ b/src/program/templates/includes/eventrecording_detail_panel.html @@ -0,0 +1,49 @@ +{% load bootstrap3 %} +{% load commonmark %} +
+
+ Recording for Event: {{ event.title }} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Camp{{ event.track.camp.title }}
Track{{ event.track.name }}
Type{{ event.event_type.name }}
URLs + {% if event.urls.exists %} + {% for url in event.urls.all %} +

{{ url.url_type }}: {{ url.url }}

+ {% endfor %} + {% else %} +

No URLs found.

+ {% endif %} +
Video URL (legacy){{ event.video_url }}
+ {% if form %} + {% bootstrap_form form %} + {% elif buttoninclude %} + {% include buttoninclude %} + {% endif %} +
+
+ diff --git a/src/utils/management/commands/bootstrap_devsite.py b/src/utils/management/commands/bootstrap_devsite.py index e64f087b..e52e4ac6 100644 --- a/src/utils/management/commands/bootstrap_devsite.py +++ b/src/utils/management/commands/bootstrap_devsite.py @@ -823,7 +823,7 @@ class Command(BaseCommand): year = camp.camp.lower.year self.output("Creating event_tracks for {}...".format(year)) tracks[1] = EventTrack.objects.create( - camp=camp, name="BornHack", slug=camp.slug + camp=camp, name="BornHack {}".format(year), slug=camp.slug ) return tracks