Skip to content

Commit f73dfd4

Browse files
authored
Merge branch 'master' into css_do_over_2
2 parents 0406d6c + 7b780c3 commit f73dfd4

6 files changed

Lines changed: 97 additions & 19 deletions

File tree

src/program/forms.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,7 @@ class Meta:
268268
"title",
269269
"abstract",
270270
"allow_video_recording",
271+
"allow_video_streaming",
271272
"duration",
272273
"tags",
273274
"slides_url",
@@ -313,8 +314,9 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
313314
self.fields["track"].empty_label = None
314315
self.fields["track"].queryset = EventTrack.objects.filter(camp=camp)
315316

316-
# make sure video_recording checkbox defaults to checked
317+
# make sure video_recording and streaming checkbox defaults to checked
317318
self.fields["allow_video_recording"].initial = True
319+
self.fields["allow_video_streaming"].initial = True
318320

319321
if event_type.name not in [TALK, LIGHTNING_TALK]:
320322
# Only talk or lightning talk should show the slides_url field
@@ -374,6 +376,7 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
374376

375377
# no video recording for music acts
376378
del self.fields["allow_video_recording"]
379+
del self.fields["allow_video_streaming"]
377380

378381
elif event_type.name == RECREATIONAL_EVENT:
379382
# fix label and help_text for the title field
@@ -394,6 +397,7 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
394397

395398
# no video recording for music acts
396399
del self.fields["allow_video_recording"]
400+
del self.fields["allow_video_streaming"]
397401

398402
elif event_type.name in [TALK, LIGHTNING_TALK]:
399403
# fix label and help_text for the title field
@@ -439,6 +443,7 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
439443

440444
# no video recording for workshops
441445
del self.fields["allow_video_recording"]
446+
del self.fields["allow_video_streaming"]
442447

443448
elif event_type.name == RECREATIONAL_EVENT:
444449
# fix label and help_text for the title field
@@ -459,6 +464,7 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
459464

460465
# no video recording for recreational events
461466
del self.fields["allow_video_recording"]
467+
del self.fields["allow_video_streaming"]
462468

463469
elif event_type.name == MEETUP:
464470
# fix label and help_text for the title field
@@ -479,6 +485,7 @@ def __init__(self, camp, event_type=None, matrix=None, *args, **kwargs):
479485

480486
# no video recording for meetups
481487
del self.fields["allow_video_recording"]
488+
del self.fields["allow_video_streaming"]
482489

483490
else:
484491
raise ImproperlyConfigured(
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Generated by Django 4.2.20 on 2025-04-21 17:36
2+
3+
from django.db import migrations, models
4+
5+
def update_streaming(apps, schema_editor):
6+
# We can't import the models directly as it may be a newer
7+
# version than this migration expects. We use the historical version.
8+
Event = apps.get_model("program", "Event")
9+
EventProposal = apps.get_model("program", "EventProposal")
10+
11+
Event.objects.filter(video_recording=True).update(video_streaming=True)
12+
Event.objects.filter(video_recording=False).update(video_streaming=False)
13+
EventProposal.objects.filter(allow_video_recording=False).update(allow_video_streaming=False)
14+
EventProposal.objects.filter(allow_video_recording=True).update(allow_video_streaming=True)
15+
16+
class Migration(migrations.Migration):
17+
18+
dependencies = [
19+
('program', '0105_cascade_delete_event_urls'),
20+
]
21+
22+
operations = [
23+
migrations.AddField(
24+
model_name='event',
25+
name='video_streaming',
26+
field=models.BooleanField(default=True, help_text='Do we intend to stream video of this event?'),
27+
),
28+
migrations.AddField(
29+
model_name='eventproposal',
30+
name='allow_video_streaming',
31+
field=models.BooleanField(default=False, help_text='Uncheck if you do not want the event live streamed.'),
32+
),
33+
migrations.RunPython(update_streaming),
34+
]

src/program/models.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,11 @@ class EventProposal(ExportModelOperationsMixin("event_proposal"), UserSubmittedM
544544
help_text="Recordings are made available under the <b>CC BY-SA 4.0</b> license. Uncheck if you do not want the event recorded, or if you cannot accept the license.",
545545
)
546546

547+
allow_video_streaming = models.BooleanField(
548+
default=False,
549+
help_text="Uncheck if you do not want the event live streamed.",
550+
)
551+
547552
duration = models.IntegerField(
548553
blank=True,
549554
help_text="How much time (in minutes) should we set aside for this event?",
@@ -609,6 +614,7 @@ def mark_as_approved(self, request=None):
609614
event.event_type = self.event_type
610615
event.proposal = self
611616
event.video_recording = self.allow_video_recording
617+
event.video_streaming = self.allow_video_streaming
612618
event.save()
613619
# loop through the speaker_proposals linked to this event_proposal and associate any related speaker objects with this event
614620
for sp in self.speakers.all():
@@ -1207,10 +1213,12 @@ def get_ics_event(self):
12071213
domain = Site.objects.get_current().domain
12081214
speakers = ", ".join(self.event.speakers.all().values_list("name", flat=True))
12091215
recorded = "Yes" if self.event.video_recording else "No"
1216+
streamed = "Yes" if self.event.video_streaming else "No"
12101217
ievent["description"] = (
12111218
f"URL: https://{domain}{self.event.get_absolute_url()}\n\n"
12121219
f"Speaker(s): {speakers}\n\n"
12131220
f"Recorded: {recorded}\n\n"
1221+
f"Streamed: {streamed}\n\n"
12141222
f"{self.event.abstract}"
12151223
)
12161224
ievent["dtstart"] = icalendar.vDatetime(self.when.lower).to_ical()
@@ -1308,6 +1316,11 @@ class Event(ExportModelOperationsMixin("event"), CampRelatedModel):
13081316
help_text="Do we intend to record video of this event?",
13091317
)
13101318

1319+
video_streaming = models.BooleanField(
1320+
default=True,
1321+
help_text="Do we intend to stream video of this event?",
1322+
)
1323+
13111324
proposal = models.OneToOneField(
13121325
"program.EventProposal",
13131326
null=True,
@@ -1378,10 +1391,14 @@ def serialize(self):
13781391
"event_type": self.event_type.name,
13791392
}
13801393

1381-
if self.video_recording:
1382-
video_state = "to-be-recorded"
1394+
if self.video_recording and self.video_streaming:
1395+
video_state = "to-be-streamed-to-be-recorded"
1396+
elif self.video_recording:
1397+
video_state = "to-be-recorded-not-to-be-streamed"
1398+
elif self.video_streaming:
1399+
video_state = "to-be-streamed-not-to-be-recorded"
13831400
else:
1384-
video_state = "not-to-be-recorded"
1401+
video_state = "not-to-be-recorded-not-to-be-streamed"
13851402

13861403
data["video_state"] = video_state
13871404

@@ -1513,10 +1530,14 @@ def serialize(self, user=None):
15131530
"timeslots": self.timeslots,
15141531
}
15151532

1516-
if self.event.video_recording:
1517-
video_state = "to-be-recorded"
1533+
if self.event.video_recording and self.event.video_streaming:
1534+
video_state = "to-be-recorded-to-be-streamed"
1535+
elif self.event.video_recording:
1536+
video_state = "to-be-recorded-not-to-be-streamed"
1537+
elif self.event.video_streaming:
1538+
video_state = "to-be-streamed-not-to-be-recorded"
15181539
else:
1519-
video_state = "not-to-be-recorded"
1540+
video_state = "not-to-be-recorded-not-to-be-streamed"
15201541

15211542
data["video_state"] = video_state
15221543

src/program/templates/event_detail.html

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,25 @@ <h4>
4141
<h4>Metadata for <i>{{ event.title }}</i></h4>
4242
<strong>To be recorded</strong>:
4343
<span class="fa-stack">
44-
<i class="fas fa-video fa-stack-1x"></i>
4544
{% if event.video_recording %}
46-
<i class="far fa-circle fa-stack-2x"></i>
45+
<i class="fas fa-floppy-disk fa-stack-1x"></i>
4746
{% else %}
47+
<i class="fas fa-floppy-disk fa-stack-1x"></i>
4848
<i class="fas fa-ban fa-stack-2x text-danger"></i>
4949
{% endif %}
5050
</span>
5151
{{ event.video_recording|yesno:"Yes,No" }}
52+
<br>
53+
<strong>To be streamed</strong>:
54+
<span class="fa-stack">
55+
{% if event.video_streaming %}
56+
<i class="far fa-broadcast-tower fa-stack-1x"></i>
57+
{% else %}
58+
<i class="fas fa-broadcast-tower fa-stack-1x"></i>
59+
<i class="fas fa-ban fa-stack-2x text-danger"></i>
60+
{% endif %}
61+
</span>
62+
{{ event.video_streaming|yesno:"Yes,No" }}
5263
<hr>
5364

5465
<h4>URLs for <i>{{ event.title }}</i></h4>

src/program/templates/includes/event_list_table.html

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
<th data-priority="2">Event Type</th>
99
<th data-priority="100" class="text-center">Tags</th>
1010
<th data-priority="3">Speakers</th>
11-
<th data-priority="100"><i class="fas fa-video"></i></th>
11+
<th data-priority="100"><i class="fas fa-video" title="Recording" alt="Recording"></i></th>
12+
<th data-priority="100"><i class="fas fa-floppy-disk" title="Recording" alt="Recording"></i></th>
13+
<th data-priority="100"><i class="fas fa-broadcast-tower" title="Streaming" alt="Streaming"></i></th>
1214
<th data-priority="1">Scheduled</th>
1315
</tr>
1416
</thead>
@@ -37,15 +39,17 @@
3739
N/A
3840
{% endfor %}
3941
</td>
40-
<td class="text-center"><span class="hidden">{{ event.video_recording }}</span>{{ event.video_recording|truefalseicon }}</td>
41-
<td data-order="{{ event.event_slots.all.0.when.lower|date:"YmdHis" }}">
42-
{% for slot in event.event_slots.all %}
43-
{{ slot.event_location.icon_html }} {{ slot.event_location.name }} at {{ slot.when.lower }}<br>
44-
{% empty %}
45-
<i>Not scheduled yet</i>
46-
{% endfor %}
47-
</td>
48-
</tr>
42+
<td class="text-center"><span class="hidden">{% if event.video_recording or event.video_streaming %}True</span>{{ True|truefalseicon }}{% else %}False</span>{{ False|truefalseicon }}{% endif %}</td>
43+
<td class="text-center" title="Recording: {{ event.video_recording|yesno }}"><span class="hidden">{{ event.video_recording }}</span>{{ event.video_recording|truefalseicon }}</td>
44+
<td class="text-center" title="Streaming: {{ event.video_streaming|yesno }}"><span class="hidden">{{ event.video_streaming }}</span>{{ event.video_streaming|truefalseicon }}</td>
45+
<td data-order="{{ event.event_slots.all.0.when.lower|date:"YmdHis" }}">
46+
{% for slot in event.event_slots.all %}
47+
{{ slot.event_location.icon_html }} {{ slot.event_location.name }} at {{ slot.when.lower }}<br>
48+
{% empty %}
49+
<i>Not scheduled yet</i>
50+
{% endfor %}
51+
</td>
52+
</tr>
4953
{% endif %}
5054
{% endfor %}
5155
</tbody>

src/utils/management/commands/bootstrap_devsite.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class Meta:
229229
title = factory.Faker("sentence")
230230
abstract = output_fake_md_description()
231231
allow_video_recording = factory.Iterator([True, True, True, False])
232+
allow_video_streaming = factory.Iterator([True, True, True, False])
232233
submission_notes = factory.Iterator(["", output_fake_description()])
233234
use_provided_speaker_laptop = factory.Iterator([True, False])
234235

0 commit comments

Comments
 (0)