Bladeren bron

[lifeevents] Add life events to scrobbles

Colin Powell 11 maanden geleden
bovenliggende
commit
e15d253d58

+ 16 - 0
vrobbler/apps/lifeevents/admin.py

@@ -0,0 +1,16 @@
+from django.contrib import admin
+
+from lifeevents.models import LifeEvent
+
+from scrobbles.admin import ScrobbleInline
+
+
+@admin.register(LifeEvent)
+class EventAdmin(admin.ModelAdmin):
+    date_hierarchy = "created"
+    list_display = ("title",)
+    search_fields = ("title",)
+    ordering = ("-created",)
+    inlines = [
+        ScrobbleInline,
+    ]

+ 79 - 0
vrobbler/apps/lifeevents/migrations/0001_initial.py

@@ -0,0 +1,79 @@
+# Generated by Django 4.2.11 on 2024-05-07 13:37
+
+from django.db import migrations, models
+import django_extensions.db.fields
+import taggit.managers
+import uuid
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ("scrobbles", "0055_rename_scrobble_log_scrobble_log"),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="LifeEvent",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "created",
+                    django_extensions.db.fields.CreationDateTimeField(
+                        auto_now_add=True, verbose_name="created"
+                    ),
+                ),
+                (
+                    "modified",
+                    django_extensions.db.fields.ModificationDateTimeField(
+                        auto_now=True, verbose_name="modified"
+                    ),
+                ),
+                (
+                    "uuid",
+                    models.UUIDField(
+                        blank=True,
+                        default=uuid.uuid4,
+                        editable=False,
+                        null=True,
+                    ),
+                ),
+                (
+                    "title",
+                    models.CharField(blank=True, max_length=255, null=True),
+                ),
+                (
+                    "run_time_seconds",
+                    models.IntegerField(blank=True, null=True),
+                ),
+                (
+                    "run_time_ticks",
+                    models.PositiveBigIntegerField(blank=True, null=True),
+                ),
+                ("description", models.TextField(blank=True, null=True)),
+                (
+                    "genre",
+                    taggit.managers.TaggableManager(
+                        blank=True,
+                        help_text="A comma-separated list of tags.",
+                        through="scrobbles.ObjectWithGenres",
+                        to="scrobbles.Genre",
+                        verbose_name="Tags",
+                    ),
+                ),
+            ],
+            options={
+                "abstract": False,
+            },
+        ),
+    ]

+ 0 - 0
vrobbler/apps/lifeevents/migrations/__init__.py


+ 39 - 0
vrobbler/apps/lifeevents/models.py

@@ -0,0 +1,39 @@
+from django.apps import apps
+from django.db import models
+from django.urls import reverse
+import pendulum
+from lifeevents.dataclasses import LifeEventMetadata
+from scrobbles.mixins import ScrobblableMixin
+
+BNULL = {"blank": True, "null": True}
+
+
+class LifeEvent(ScrobblableMixin):
+    COMPLETION_PERCENT = 100
+
+    description = models.TextField(**BNULL)
+
+    def get_absolute_url(self):
+        return reverse(
+            "life-events:life-event_detail", kwargs={"slug": self.uuid}
+        )
+
+    @property
+    def metadata_class(self):
+        return LifeEventMetadata
+
+    @classmethod
+    def find_or_create(cls, title: str) -> "LifeEvent":
+        return cls.objects.filter(title=title).first()
+
+    def scrobble_for_user(self, user_id):
+        Scrobble = apps.get_model("scrobbles", "Scrobble")
+        return Scrobble.objects.create(
+            user_id=user_id, life_event=self, timestamp=pendulum.now()
+        )
+
+    def scrobbles(self, user_id):
+        Scrobble = apps.get_model("scrobbles", "Scrobble")
+        return Scrobble.objects.filter(
+            user_id=user_id, life_event=self
+        ).order_by("-timestamp")

+ 14 - 0
vrobbler/apps/lifeevents/urls.py

@@ -0,0 +1,14 @@
+from django.urls import path
+from lifeevents import views
+
+app_name = "events"
+
+
+urlpatterns = [
+    path("events/", views.EventListView.as_view(), name="event_list"),
+    path(
+        "event/<slug:slug>/",
+        views.EventDetailView.as_view(),
+        name="event_detail",
+    ),
+]

+ 12 - 0
vrobbler/apps/lifeevents/views.py

@@ -0,0 +1,12 @@
+from django.views import generic
+from lifeevents.models import LifeEvent
+
+
+class EventListView(generic.ListView):
+    model = LifeEvent
+    paginate_by = 20
+
+
+class EventDetailView(generic.DetailView):
+    model = LifeEvent
+    slug_field = "uuid"

+ 2 - 0
vrobbler/apps/scrobbles/admin.py

@@ -24,6 +24,7 @@ class ScrobbleInline(admin.TabularInline):
         "board_game",
         "geo_location",
         "web_page",
+        "life_event",
         "user",
     )
     exclude = (
@@ -118,6 +119,7 @@ class ScrobbleAdmin(admin.ModelAdmin):
         "board_game",
         "geo_location",
         "web_page",
+        "life_event",
     )
     list_filter = (
         "is_paused",

+ 45 - 0
vrobbler/apps/scrobbles/migrations/0056_scrobble_life_event_alter_scrobble_media_type.py

@@ -0,0 +1,45 @@
+# Generated by Django 4.2.11 on 2024-05-07 13:37
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("lifeevents", "0001_initial"),
+        ("scrobbles", "0055_rename_scrobble_log_scrobble_log"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="scrobble",
+            name="life_event",
+            field=models.ForeignKey(
+                blank=True,
+                null=True,
+                on_delete=django.db.models.deletion.DO_NOTHING,
+                to="lifeevents.lifeevent",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="scrobble",
+            name="media_type",
+            field=models.CharField(
+                choices=[
+                    ("Video", "Video"),
+                    ("Track", "Track"),
+                    ("PodcastEpisode", "Podcast episode"),
+                    ("SportEvent", "Sport event"),
+                    ("Book", "Book"),
+                    ("VideoGame", "Video game"),
+                    ("BoardGame", "Board game"),
+                    ("GeoLocation", "GeoLocation"),
+                    ("WebPage", "Web Page"),
+                    ("LifeEvent", "Life event"),
+                ],
+                default="Video",
+                max_length=14,
+            ),
+        ),
+    ]

+ 7 - 0
vrobbler/apps/scrobbles/models.py

@@ -39,6 +39,7 @@ from videogames import retroarch
 from videogames.models import VideoGame
 from videos.models import Series, Video
 from webpages.models import WebPage
+from lifeevents.models import LifeEvent
 
 from vrobbler.apps.scrobbles.constants import MEDIA_END_PADDING_SECONDS
 
@@ -481,6 +482,7 @@ class Scrobble(TimeStampedModel):
         BOARD_GAME = "BoardGame", "Board game"
         GEO_LOCATION = "GeoLocation", "GeoLocation"
         WEBPAGE = "WebPage", "Web Page"
+        LIFE_EVENT = "LifeEvent", "Life event"
 
     uuid = models.UUIDField(editable=False, **BNULL)
     video = models.ForeignKey(Video, on_delete=models.DO_NOTHING, **BNULL)
@@ -502,6 +504,9 @@ class Scrobble(TimeStampedModel):
         GeoLocation, on_delete=models.DO_NOTHING, **BNULL
     )
     web_page = models.ForeignKey(WebPage, on_delete=models.DO_NOTHING, **BNULL)
+    life_event = models.ForeignKey(
+        LifeEvent, on_delete=models.DO_NOTHING, **BNULL
+    )
     media_type = models.CharField(
         max_length=14, choices=MediaType.choices, default=MediaType.VIDEO
     )
@@ -809,6 +814,8 @@ class Scrobble(TimeStampedModel):
             media_obj = self.geo_location
         if self.web_page:
             media_obj = self.web_page
+        if self.life_event:
+            media_obj = self.life_event
         return media_obj
 
     def __str__(self):

+ 1 - 0
vrobbler/settings-testing.py

@@ -110,6 +110,7 @@ INSTALLED_APPS = [
     "videogames",
     "locations",
     "webpages",
+    "lifeevents",
     "mathfilters",
     "rest_framework",
     "allauth",

+ 1 - 0
vrobbler/settings.py

@@ -124,6 +124,7 @@ INSTALLED_APPS = [
     "videogames",
     "locations",
     "webpages",
+    "lifeevents",
     "mathfilters",
     "rest_framework",
     "allauth",

+ 2 - 0
vrobbler/urls.py

@@ -11,6 +11,7 @@ from vrobbler.apps.podcasts import urls as podcast_urls
 from vrobbler.apps.videogames import urls as videogame_urls
 from vrobbler.apps.boardgames import urls as boardgame_urls
 from vrobbler.apps.locations import urls as locations_urls
+from vrobbler.apps.lifeevents import urls as lifeevents_urls
 from vrobbler.apps.webpages import urls as webpages_urls
 from vrobbler.apps.music.api.views import (
     AlbumViewSet,
@@ -71,6 +72,7 @@ urlpatterns = [
     path("", include(locations_urls, namespace="locations")),
     path("", include(webpages_urls, namespace="webpages")),
     path("", include(podcast_urls, namespace="podcasts")),
+    path("", include(lifeevents_urls, namespace="life-events")),
     path("", include(scrobble_urls, namespace="scrobbles")),
     path(
         "", scrobbles_views.RecentScrobbleList.as_view(), name="vrobbler-home"