From 4806a6273e6784f988f653503216a851348a4e71 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 5 Nov 2022 12:49:11 -0700 Subject: [PATCH 1/3] Show average run times for imports This should give users a sense of when to start wondering if their import isn't running after all. --- bookwyrm/templates/import/import.html | 30 +++++++++++++---- bookwyrm/views/imports/import_data.py | 46 +++++++++++++++++++++------ 2 files changed, 61 insertions(+), 15 deletions(-) diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index 9657773d6..30e05c5c1 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -7,12 +7,28 @@ {% block content %}

{% trans "Import Books" %}

+ + {% if recent_avg_hours or recent_avg_minutes %} +
+

+ {% if recent_avg_hours %} + {% blocktrans trimmed with hours=recent_avg_hours|floatformat:0|intcomma %} + On average, recent imports have taken {{ hours }} hours. + {% endblocktrans %} + {% else %} + {% blocktrans trimmed with minutes=recent_avg_minutes|floatformat:0|intcomma %} + On average, recent imports have taken {{ minutes }} minutes. + {% endblocktrans %} + {% endif %} +

+
+ {% endif %} +
{% csrf_token %}
-
{% endblock %} diff --git a/bookwyrm/views/imports/import_data.py b/bookwyrm/views/imports/import_data.py index 063545895..c7184ca81 100644 --- a/bookwyrm/views/imports/import_data.py +++ b/bookwyrm/views/imports/import_data.py @@ -1,10 +1,14 @@ """ import books from another app """ from io import TextIOWrapper +import datetime from django.contrib.auth.decorators import login_required +from django.db.models import Avg, ExpressionWrapper, F, fields +from django.core.paginator import Paginator from django.http import HttpResponseBadRequest from django.shortcuts import redirect from django.template.response import TemplateResponse +from django.utils import timezone from django.utils.decorators import method_decorator from django.utils.translation import gettext_lazy as _ from django.views import View @@ -17,6 +21,7 @@ from bookwyrm.importers import ( StorygraphImporter, OpenLibraryImporter, ) +from bookwyrm.settings import PAGE_LENGTH # pylint: disable= no-self-use @method_decorator(login_required, name="dispatch") @@ -25,16 +30,39 @@ class Import(View): def get(self, request): """load import page""" - return TemplateResponse( - request, - "import/import.html", - { - "import_form": forms.ImportForm(), - "jobs": models.ImportJob.objects.filter(user=request.user).order_by( - "-created_date" - ), - }, + jobs = models.ImportJob.objects.filter(user=request.user).order_by( + "-created_date" ) + paginated = Paginator(jobs, PAGE_LENGTH) + page = paginated.get_page(request.GET.get("page")) + data = { + "import_form": forms.ImportForm(), + "jobs": page, + "page_range": paginated.get_elided_page_range( + page.number, on_each_side=2, on_ends=1 + ), + } + + last_week = timezone.now() - datetime.timedelta(days=7) + recent_avg = ( + models.ImportJob.objects.filter(created_date__gte=last_week, complete=True) + .annotate( + runtime=ExpressionWrapper( + F("updated_date") - F("created_date"), + output_field=fields.DurationField(), + ) + ) + .aggregate(Avg("runtime")) + .get("runtime__avg") + ) + if recent_avg: + seconds = recent_avg.total_seconds() + if seconds > 60**2: + data["recent_avg_hours"] = recent_avg.seconds / (60**2) + else: + data["recent_avg_minutes"] = recent_avg.seconds / 60 + + return TemplateResponse(request, "import/import.html", data) def post(self, request): """ingest a goodreads csv""" From 3c2f2c10bf583b055d35608b2325cc8e91e597f0 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 5 Nov 2022 13:11:03 -0700 Subject: [PATCH 2/3] Show recent imports in a table --- bookwyrm/models/import_job.py | 7 ++++ bookwyrm/templates/import/import.html | 55 +++++++++++++++++++++---- bookwyrm/views/imports/import_status.py | 8 +--- 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index 060f11ede..b6a6ded41 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -1,4 +1,5 @@ """ track progress of goodreads imports """ +import math import re import dateutil.parser @@ -53,6 +54,12 @@ class ImportJob(models.Model): """How many books do you want to import???""" return self.items.count() + @property + def percent_complete(self): + """How far along?""" + item_count = self.item_count + return math.floor((item_count - self.pending_item_count) / item_count * 100) + @property def pending_item_count(self): """And how many pending items??""" diff --git a/bookwyrm/templates/import/import.html b/bookwyrm/templates/import/import.html index 30e05c5c1..3757d37ef 100644 --- a/bookwyrm/templates/import/import.html +++ b/bookwyrm/templates/import/import.html @@ -89,14 +89,53 @@

{% trans "Recent Imports" %}

- {% if not jobs %} -

{% trans "No recent imports" %}

- {% endif %} - +
+ + + + + + + + {% if not jobs %} + + + + {% endif %} + {% for job in jobs %} + + + + + + + {% endfor %} +
+ {% trans "Date Created" %} + + {% trans "Last Updated" %} + + {% trans "Items" %} + + {% trans "Status" %} +
+ {% trans "No recent imports" %} +
+ {{ job.created_date }} + {{ job.updated_date }}{{ job.item_count|intcomma }} + {% if job.complete %} + + {% trans "Completed" %} + + {% else %} + + {% blocktrans trimmed with percent=job.percent_complete %} + Active, {{ percent }}% complete + {% endblocktrans %} + + {% endif %} +
+
{% include 'snippets/pagination.html' with page=jobs path=request.path %}
diff --git a/bookwyrm/views/imports/import_status.py b/bookwyrm/views/imports/import_status.py index ffad36774..2f6b13bba 100644 --- a/bookwyrm/views/imports/import_status.py +++ b/bookwyrm/views/imports/import_status.py @@ -1,6 +1,4 @@ """ import books from another app """ -import math - from django.contrib.auth.decorators import login_required from django.core.exceptions import PermissionDenied from django.core.paginator import Paginator @@ -38,7 +36,7 @@ class ImportStatus(View): fail_count = items.filter( fail_reason__isnull=False, book_guess__isnull=True ).count() - pending_item_count = job.pending_items.count() + pending_item_count = job.pending_item_count data = { "job": job, "items": page, @@ -50,9 +48,7 @@ class ImportStatus(View): "show_progress": True, "item_count": item_count, "complete_count": item_count - pending_item_count, - "percent": math.floor( # pylint: disable=c-extension-no-member - (item_count - pending_item_count) / item_count * 100 - ), + "percent": job.percent_complete, # hours since last import item update "inactive_time": (job.updated_date - timezone.now()).seconds / 60 / 60, "legacy": not job.mappings, From 9cfcad20e01e8a8c3c34b19847b3e7bd5a9612bb Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 5 Nov 2022 13:33:57 -0700 Subject: [PATCH 3/3] Avoid divide by zero error --- bookwyrm/models/import_job.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index b6a6ded41..20a5662f9 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -58,6 +58,8 @@ class ImportJob(models.Model): def percent_complete(self): """How far along?""" item_count = self.item_count + if not item_count: + return 0 return math.floor((item_count - self.pending_item_count) / item_count * 100) @property