From 3c0a75755b2af57194038827cf0b9481b7c8bb84 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Mon, 30 Sep 2024 17:10:28 -0400 Subject: [PATCH] [tasks] Fix source url generation --- vrobbler/apps/scrobbles/dataclasses.py | 2 +- vrobbler/apps/scrobbles/mixins.py | 20 ++++++++-- vrobbler/apps/scrobbles/utils.py | 8 +++- ...002_task_source_task_source_url_pattern.py | 31 +++++++++++++++ vrobbler/apps/tasks/models.py | 39 ++++++++++++++++--- 5 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 vrobbler/apps/tasks/migrations/0002_task_source_task_source_url_pattern.py diff --git a/vrobbler/apps/scrobbles/dataclasses.py b/vrobbler/apps/scrobbles/dataclasses.py index 7f43c2e..cc0856d 100644 --- a/vrobbler/apps/scrobbles/dataclasses.py +++ b/vrobbler/apps/scrobbles/dataclasses.py @@ -99,7 +99,7 @@ class BoardGameScoreLogData(JSONDataclass): @dataclass class BoardGameLogData(LongPlayLogData): serial_scrobble_id: Optional[int] = None - long_play_complete: bool = False + long_play_complete: Optional[bool] = None players: Optional[list[BoardGameScoreLogData]] = None location: Optional[str] = None geo_location_id: Optional[int] = None diff --git a/vrobbler/apps/scrobbles/mixins.py b/vrobbler/apps/scrobbles/mixins.py index 75ed383..8d01b01 100644 --- a/vrobbler/apps/scrobbles/mixins.py +++ b/vrobbler/apps/scrobbles/mixins.py @@ -114,10 +114,24 @@ class LongPlayScrobblableMixin(ScrobblableMixin): def get_longplay_finish_url(self): return reverse("scrobbles:longplay-finish", kwargs={"uuid": self.uuid}) + def first_long_play_scrobble_for_user(self, user) -> Optional["Scrobble"]: + return ( + get_scrobbles_for_media(self, user) + .filter( + log__long_play_complete=False, + log__serial_scrobble_id__isnull=True, + ) + .order_by("timestamp") + .first() + ) + def last_long_play_scrobble_for_user(self, user) -> Optional["Scrobble"]: return ( get_scrobbles_for_media(self, user) - .filter(long_play_complete=False) - .order_by("-timestamp") - .first() + .filter( + log__long_play_complete=False, + log__serial_scrobble_id__isnull=False, + ) + .order_by("timestamp") + .last() ) diff --git a/vrobbler/apps/scrobbles/utils.py b/vrobbler/apps/scrobbles/utils.py index 6fbcd39..6c1cbe5 100644 --- a/vrobbler/apps/scrobbles/utils.py +++ b/vrobbler/apps/scrobbles/utils.py @@ -48,10 +48,14 @@ def get_scrobbles_for_media(media_obj, user: User) -> models.QuerySet: media_query = models.Q(book=media_obj) if media_class == "VideoGame": media_query = models.Q(video_game=media_obj) + if media_class == "Brickset": + media_query = models.Q(brickset=media_obj) + if media_class == "Task": + media_query = models.Q(task=media_obj) if not media_query: - logger.warn("Do not know about media {media_class} 🙍") - return [] + logger.warn(f"Do not know about media {media_class} 🙍") + return QuerySet() return Scrobble.objects.filter(media_query, user=user) diff --git a/vrobbler/apps/tasks/migrations/0002_task_source_task_source_url_pattern.py b/vrobbler/apps/tasks/migrations/0002_task_source_task_source_url_pattern.py new file mode 100644 index 0000000..7cda228 --- /dev/null +++ b/vrobbler/apps/tasks/migrations/0002_task_source_task_source_url_pattern.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.16 on 2024-09-30 20:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("tasks", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="task", + name="source", + field=models.CharField(blank=True, max_length=255, null=True), + ), + migrations.AddField( + model_name="task", + name="source_url_pattern", + field=models.CharField( + blank=True, + choices=[ + ("Shortcut", "https://app.shortcut.com/sure/story/{id}"), + ("Todoist", "https://app.todoist.com/app/task/{id}"), + ], + max_length=255, + null=True, + ), + ), + ] diff --git a/vrobbler/apps/tasks/models.py b/vrobbler/apps/tasks/models.py index 69e2f6e..53ecaa1 100644 --- a/vrobbler/apps/tasks/models.py +++ b/vrobbler/apps/tasks/models.py @@ -1,30 +1,43 @@ +from dataclasses import dataclass from enum import Enum from typing import Optional + from django.apps import apps from django.db import models from django.urls import reverse from scrobbles.dataclasses import LongPlayLogData -from scrobbles.mixins import ScrobblableMixin +from scrobbles.mixins import LongPlayScrobblableMixin BNULL = {"blank": True, "null": True} +TASK_SOURCE_URL_PATTERNS = [ + ("https://app.shortcut.com/sure/story/{id}", "Shortcut"), + ("https://app.todoist.com/app/task/{id}", "Todoist"), +] + +@dataclass class TaskLogData(LongPlayLogData): - serial_scrobble_id: Optional[int] - long_play_complete: bool = False + source_id: Optional[str] = None + serial_scrobble_id: Optional[int] = None + long_play_complete: Optional[bool] = None class TaskType(Enum): - WOODS = "Professional" - ROAD = "Amateur" + PRO = "Professional" + AMATEUR = "Amateur" -class Task(ScrobblableMixin): +class Task(LongPlayScrobblableMixin): """Basically a holder for task sources ... Shortcut, JIRA, Todoist, Org-mode and any other otherwise generic tasks. """ + source = models.CharField(max_length=255, **BNULL) + source_url_pattern = models.CharField( + max_length=255, choices=TASK_SOURCE_URL_PATTERNS, **BNULL + ) description = models.TextField(**BNULL) def __str__(self): @@ -37,6 +50,20 @@ class Task(ScrobblableMixin): def logdata_cls(self): return TaskLogData + def source_url_for_user(self, user_id): + url = str(self.source_url_pattern).replace("{id}", "") + scrobble = self.scrobbles(user_id).first() + if scrobble.logdata.source_id and self.source_url_pattern: + url = str(self.source_url_pattern).format( + id=scrobble.logdata.source_id + ) + + return url + + def subtitle_for_user(self, user_id): + scrobble = self.scrobbles(user_id).first() + return scrobble.logdata.source_id or "" + @classmethod def find_or_create(cls, title: str) -> "Task": return cls.objects.filter(title=title).first()