Skip to content

Commit

Permalink
Stream Archive URLs (#23)
Browse files Browse the repository at this point in the history
* Define `StreamArchiveURL` model and create migration
* Register `StreamArchiveURL` admin and add inline to Stream admin
* Add stream archive URLs as nested serializer on `StreamSerializer`
* Set fk related name to `archive_urls`
* Make archive urls nested serializer writable on `StreamSerializer`
* Make `archive_urls` not required on serializer
* Test partial update (PATCH) on Stream, to update `archive_urls` of a Stream

Closes #20
  • Loading branch information
munshkr committed May 30, 2022
1 parent 70505cf commit a82aeb5
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 1 deletion.
11 changes: 11 additions & 0 deletions events/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
EventStreamURL,
EventSupportURL,
Stream,
StreamArchiveURL,
StreamNotification,
)

Expand All @@ -23,6 +24,11 @@ class EventSupportURLInline(admin.TabularInline):
extra = 1


class StreamArchiveURLInline(admin.TabularInline):
model = StreamArchiveURL
extra = 2


class CustomAPIKeyAdmin(APIKeyModelAdmin):
list_display = [*APIKeyModelAdmin.list_display, "is_web"]
search_fields = [*APIKeyModelAdmin.search_fields, "is_web"]
Expand All @@ -47,6 +53,7 @@ class StreamAdmin(admin.ModelAdmin):
form = StreamForm
ordering = ("-starts_at",)
list_filter = ("event",)
inlines = [StreamArchiveURLInline]

def get_event_name(self, obj):
return obj.event.name
Expand All @@ -66,9 +73,13 @@ def get_date_range(self, obj):
class StreamNotificationAdmin(admin.ModelAdmin):
list_display = ("stream", "kind", "sent_at")

class StreamArchiveURLAdmin(admin.ModelAdmin):
list_display = ("stream", "url", "name")


admin.site.unregister(APIKey)
admin.site.register(CustomAPIKey, CustomAPIKeyAdmin)
admin.site.register(Event, EventAdmin)
admin.site.register(Stream, StreamAdmin)
admin.site.register(StreamNotification, StreamNotificationAdmin)
admin.site.register(StreamArchiveURL, StreamArchiveURLAdmin)
26 changes: 26 additions & 0 deletions events/migrations/0019_streamarchiveurl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 3.1.13 on 2022-05-30 20:28

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('events', '0018_eventsupporturl'),
]

operations = [
migrations.CreateModel(
name='StreamArchiveURL',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('url', models.URLField()),
('name', models.CharField(blank=True, max_length=255)),
('stream', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='archive_urls', to='events.stream')),
],
options={
'unique_together': {('stream', 'url')},
},
),
]
12 changes: 12 additions & 0 deletions events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,15 @@ class Kinds(models.TextChoices):

def __str__(self):
return f"[{self.kind}] {self.stream}"


class StreamArchiveURL(models.Model):
stream = models.ForeignKey(Stream, on_delete=models.CASCADE, related_name="archive_urls")
url = models.URLField()
name = models.CharField(max_length=255, blank=True)

def __str__(self):
return self.url

class Meta:
unique_together = ("stream", "url")
28 changes: 27 additions & 1 deletion events/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from rest_framework import serializers
from django.db import transaction

from events.models import Event, EventStreamURL, EventSupportURL, Stream
from events.models import (Event, EventStreamURL, EventSupportURL, Stream,
StreamArchiveURL)


class EventStreamURLSerializer(serializers.HyperlinkedModelSerializer):
Expand Down Expand Up @@ -50,14 +52,38 @@ class Meta:
exclude = ("rtmp_url",)


class StreamArchiveURLSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = StreamArchiveURL
fields = ("url", "name")


class StreamSerializer(serializers.HyperlinkedModelSerializer):
recordings = serializers.SerializerMethodField()
key = serializers.CharField(required=False)
archive_urls = StreamArchiveURLSerializer(many=True, required=False)

class Meta:
model = Stream
fields = "__all__"

@transaction.atomic
def create(self, validated_data):
archive_urls_data = validated_data.pop('archive_urls', [])
stream = Stream.objects.create(**validated_data)
for archive_url_data in archive_urls_data:
StreamArchiveURL.objects.create(stream=stream, **archive_url_data)
return stream

@transaction.atomic
def update(self, instance, validated_data):
archive_urls_data = validated_data.pop('archive_urls', [])
instance = super().update(instance, validated_data)
instance.archive_urls.all().delete()
for archive_url_data in archive_urls_data:
instance.archive_urls.create(**archive_url_data)
return instance

def get_recordings(self, stream):
request = self.context.get("request")
return [request.build_absolute_uri(path) for path in stream.recording_paths]
Expand Down
26 changes: 26 additions & 0 deletions events/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,32 @@ def test_retrieve_stream_from_web_client_no_key(self):
self.assertTrue("key" not in response.data)
self.assertTrue("publisher_email" not in response.data)

def test_update_stream_set_archive_urls(self):
"""
Ensure we can update archive URLs for Stream.
"""
event = self.create_some_event()
stream = self.create_some_stream(event)
self.authenticate_with_api_key(is_web=False)

data = {
"archive_urls": [
{ "url": "https://archive.org/foo", "name": "archive.org" },
{ "url": "https://youtube.com/foo", "name": "youtube.com" },
]
}
response = self.client.patch(
reverse("stream-detail", kwargs={"pk": stream.pk}), data, format="json"
)

# Assert response
self.assertEqual(response.status_code, status.HTTP_200_OK, response.data)
self.assertEqual(response.data.get("archive_urls"), data["archive_urls"])

# Assert database
self.assertEqual(stream.archive_urls.count(), 2)

def create_some_event(self):
starts_at = timezone.make_aware(datetime.today())
ends_at = starts_at + timedelta(hours=2)
Expand Down

0 comments on commit a82aeb5

Please sign in to comment.