瀏覽代碼

[scrobbles] Fix log data parsing for tasks and boardgames

Add pagination to task and board game detail pages
Colin Powell 3 周之前
父節點
當前提交
9437fdba60

+ 15 - 12
vrobbler/apps/scrobbles/dataclasses.py

@@ -7,6 +7,7 @@ from typing import Optional
 from dataclass_wizard import JSONWizard
 from django.contrib.auth import get_user_model
 from locations.models import GeoLocation
+from people.models import Person
 
 User = get_user_model()
 
@@ -66,8 +67,7 @@ class WithOthersLogData(JSONDataclass):
 
 @dataclass
 class BoardGameScoreLogData(JSONDataclass):
-    user_id: Optional[int] = None
-    name_str: str = ""
+    person_id: Optional[int] = None
     bgg_username: str = ""
     color: Optional[str] = None
     character: Optional[str] = None
@@ -75,19 +75,19 @@ class BoardGameScoreLogData(JSONDataclass):
     score: Optional[int] = None
     win: Optional[bool] = None
     new: Optional[bool] = None
+    rank: Optional[int] = None
+    seat_order: Optional[int] = None
+    role: Optional[str] = None
 
     @property
-    def user(self) -> Optional[User]:
-        user = None
-        if self.user_id:
-            user = User.objects.filter(id=self.user_id).first()
-        return user
+    def person(self) -> Optional[Person]:
+        return Person.objects.filter(id=self.person_id).first()
 
     @property
     def name(self) -> str:
-        name = self.name_str
-        if self.user_id:
-            name = self.user.first_name
+        name = ""
+        if self.person:
+            name = self.person.name
         return name
 
     def __str__(self) -> str:
@@ -106,17 +106,20 @@ class BoardGameLogData(LongPlayLogData):
     serial_scrobble_id: Optional[int] = None
     long_play_complete: Optional[bool] = None
     players: Optional[list[BoardGameScoreLogData]] = None
-    location: Optional[str] = None
-    geo_location_id: Optional[int] = None
+    location_id: Optional[int] = None
     difficulty: Optional[int] = None
     solo: Optional[bool] = None
     two_handed: Optional[bool] = None
+    expansion_ids: Optional[int] = None
 
     @cached_property
     def geo_location(self) -> Optional[GeoLocation]:
         if self.geo_location_id:
             return GeoLocation.objects.filter(id=self.geo_location_id).first()
 
+    @cached_property
+    def player_log(self) -> str:
+        return ", ".join([BoardGameScoreLogData(**player).__str__() for player in self.players])
 
 @dataclass
 class BookPageLogData(JSONDataclass):

+ 1 - 1
vrobbler/apps/scrobbles/models.py

@@ -736,7 +736,7 @@ class Scrobble(TimeStampedModel):
         if not log_dict:
             log_dict = {}
 
-        return logdata_cls.from_dict(log_dict)
+        return logdata_cls(**log_dict)
 
     def redirect_url(self, user_id) -> str:
         user = User.objects.filter(id=user_id).first()

+ 21 - 3
vrobbler/apps/scrobbles/views.py

@@ -19,6 +19,8 @@ from django.views.generic import DetailView, FormView, TemplateView
 from django.views.generic.edit import CreateView
 from django.views.generic.list import ListView
 from music.aggregators import live_charts, scrobble_counts, week_of_scrobbles
+
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
 from rest_framework import status
 from rest_framework.decorators import (
     api_view,
@@ -76,18 +78,34 @@ class ScrobbleableListView(ListView):
         )
         return queryset
 
-
 class ScrobbleableDetailView(DetailView):
     model = None
     slug_field = "uuid"
 
+    paginate_by = 200  # You can set this to whatever page size you want
+
     def get_context_data(self, **kwargs):
         context_data = super().get_context_data(**kwargs)
-        context_data["scrobbles"] = list()
+        scrobbles = []
         if not self.request.user.is_anonymous:
-            context_data["scrobbles"] = self.object.scrobble_set.filter(
+            scrobbles = self.object.scrobble_set.filter(
                 user=self.request.user
             ).order_by("-timestamp")
+
+        paginator = Paginator(scrobbles, self.paginate_by)
+        page_number = self.request.GET.get("page")
+
+        try:
+            page_obj = paginator.page(page_number)
+        except PageNotAnInteger:
+            page_obj = paginator.page(1)
+        except EmptyPage:
+            page_obj = paginator.page(paginator.num_pages)
+
+        context_data["page_obj"] = page_obj
+        context_data["scrobbles"] = page_obj.object_list
+        context_data["is_paginated"] = paginator.num_pages > 1
+
         return context_data
 
 

+ 13 - 3
vrobbler/apps/tasks/models.py

@@ -23,6 +23,16 @@ class TaskLogData(JSONDataclass):
     todoist_type: Optional[str] = None
     notes: Optional[dict] = None
 
+    def notes_as_str(self) -> str:
+        """Return formatted notes with line breaks and no keys"""
+        note_block = ""
+        if not self.notes:
+            return note_block
+
+        for id, content in self.notes.items():
+            note_block += content + "</br>"
+        return note_block
+
 
 class Task(LongPlayScrobblableMixin):
     """Basically a holder for Todoist Tasks
@@ -42,9 +52,9 @@ class Task(LongPlayScrobblableMixin):
     def strings(self) -> ScrobblableConstants:
         return ScrobblableConstants(verb="Doing", tags="memo")
 
-    # @property
-    # def logdata_cls(self):
-    #    return TaskLogData
+    @property
+    def logdata_cls(self):
+        return TaskLogData
 
     def source_url_for_user(self, user_id) -> str:
         url = ""

+ 22 - 2
vrobbler/templates/boardgames/boardgame_detail.html

@@ -56,7 +56,7 @@
                     <tr>
                         <th scope="col">Date</th>
                         <th scope="col">Publisher</th>
-                        <th scope="col">Screenshot</th>
+                        <th scope="col">Players</th>
                     </tr>
                 </thead>
                 <tbody>
@@ -64,12 +64,32 @@
                     <tr>
                         <td>{{scrobble.local_timestamp}}</td>
                         <td>{{scrobble.media_obj.publisher}}</td>
-                        <td>{% if scrobble.screenshot%}<img src="{{scrobble.screenshot.url}}" width=250 />{% endif %}</td>
+                        <td>{% if scrobble.logdata.player_log %}{{scrobble.logdata.player_log}}{% else %}No data{% endif %}</td>
                     </tr>
                     {% endfor %}
                 </tbody>
             </table>
         </div>
     </div>
+
+    {% if is_paginated %}
+    <div class="pagination">
+        {% if page_obj.has_previous %}
+        <a href="?page={{ page_obj.previous_page_number }}">&laquo; Previous</a>
+        {% endif %}
+
+        {% for num in page_obj.paginator.page_range %}
+        {% if num == page_obj.number %}
+            <strong>{{ num }}</strong>
+        {% else %}
+            <a href="?page={{ num }}">{{ num }}</a>
+        {% endif %}
+        {% endfor %}
+
+        {% if page_obj.has_next %}
+        <a href="?page={{ page_obj.next_page_number }}">Next &raquo;</a>
+        {% endif %}
+    </div>
+    {% endif %}
 </div>
 {% endblock %}

+ 24 - 1
vrobbler/templates/tasks/task_detail.html

@@ -22,6 +22,7 @@
         width: 600px;
         margin-left: 10px;
     }
+    .pagination a { padding: 0 5px 0 5px; }
 </style>
 {% endblock %}
 
@@ -47,12 +48,14 @@
 <div class="row">
     <div class="col-md">
         <h3>Last scrobbles</h3>
+
         <div class="table-responsive">
             <table class="table table-striped table-sm">
                 <thead>
                     <tr>
                         <th scope="col">Date</th>
                         <th scope="col">Description</th>
+                        <th scope="col">Notes</th>
                         <th scope="col">Source</th>
                     </tr>
                 </thead>
@@ -61,13 +64,33 @@
                     <tr>
                         <td>{{scrobble.local_timestamp}}</td>
                         <td><a href="{{scrobble.get_media_source_url}}">{{scrobble.logdata.description}}</a></td>
+                        <td>{{scrobble.logdata.notes_as_str|safe}}</td>
                         <td>{{scrobble.source}}</td>
-                        <td>{{scrobble.log.notes}}</td>
                     </tr>
                     {% endfor %}
                 </tbody>
             </table>
         </div>
     </div>
+
+    {% if is_paginated %}
+    <div class="pagination">
+        {% if page_obj.has_previous %}
+        <a href="?page={{ page_obj.previous_page_number }}">&laquo; Previous</a>
+        {% endif %}
+
+        {% for num in page_obj.paginator.page_range %}
+        {% if num == page_obj.number %}
+            <strong>{{ num }}</strong>
+        {% else %}
+            <a href="?page={{ num }}">{{ num }}</a>
+        {% endif %}
+        {% endfor %}
+
+        {% if page_obj.has_next %}
+        <a href="?page={{ page_obj.next_page_number }}">Next &raquo;</a>
+        {% endif %}
+    </div>
+    {% endif %}
 </div>
 {% endblock %}