From da9b4fae00bd9b25d55ab455a5e94f43e8332877 Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Sat, 16 Sep 2023 16:25:06 +0200
Subject: [PATCH] Improve managing of print jobs

---
 CHANGELOG.rst                                 | 18 +++++++++++++
 aleksis/apps/kort/frontend/index.js           |  8 ++++++
 aleksis/apps/kort/models.py                   |  3 +++
 aleksis/apps/kort/rules.py                    |  6 +++++
 .../kort/printer/detail_content.html          | 20 ++++++++++++++-
 .../kort/printer/print_job_delete.html        | 25 +++++++++++++++++++
 aleksis/apps/kort/urls.py                     |  5 ++++
 aleksis/apps/kort/views.py                    | 12 ++++++++-
 8 files changed, 95 insertions(+), 2 deletions(-)
 create mode 100644 aleksis/apps/kort/templates/kort/printer/print_job_delete.html

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 4840d61..f457431 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,24 @@ All notable changes to this project will be documented in this file.
 The format is based on `Keep a Changelog`_,
 and this project adheres to `Semantic Versioning`_.
 
+Unreleased
+----------
+
+Added
+~~~~~
+
+* Deletion of print jobs is now possible.
+
+Changed
+~~~~~~~
+
+* The printer queue is now displayed with an improved design.
+
+Fixed
+~~~~~
+
+* Order of print jobs is now from new to old.
+
 `0.3.1`_ - 2023-09-10
 ---------------------
 
diff --git a/aleksis/apps/kort/frontend/index.js b/aleksis/apps/kort/frontend/index.js
index 12baed9..d1cf2cb 100644
--- a/aleksis/apps/kort/frontend/index.js
+++ b/aleksis/apps/kort/frontend/index.js
@@ -132,6 +132,14 @@ export default {
         byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
       },
     },
+    {
+      path: "jobs/:pk/delete/",
+      component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
+      name: "kort.deletePrintJob",
+      props: {
+        byTheGreatnessOfTheAlmightyAleksolotlISwearIAmWorthyOfUsingTheLegacyBaseTemplate: true,
+      },
+    },
     {
       path: "layouts/",
       component: () => import("aleksis.core/components/LegacyBaseTemplate.vue"),
diff --git a/aleksis/apps/kort/models.py b/aleksis/apps/kort/models.py
index ad4a435..7f6eec6 100644
--- a/aleksis/apps/kort/models.py
+++ b/aleksis/apps/kort/models.py
@@ -192,6 +192,9 @@ class CardPrinter(ExtensibleModel):
         """Return OAuth2 scope name to access PDF file via API."""
         return f"{self.SCOPE_PREFIX}_{self.id}"
 
+    def get_jobs(self):
+        return self.jobs.all().order_by("-created")
+
     class Meta:
         verbose_name = _("Card printer")
         verbose_name_plural = _("Card printers")
diff --git a/aleksis/apps/kort/rules.py b/aleksis/apps/kort/rules.py
index c05ab9a..506258b 100644
--- a/aleksis/apps/kort/rules.py
+++ b/aleksis/apps/kort/rules.py
@@ -34,6 +34,12 @@ delete_card_printer_predicate = view_card_printer_predicate & (
 )
 add_perm("kort.delete_cardprinter_rule", delete_card_printer_predicate)
 
+delete_card_print_job_predicate = has_person & (
+    has_global_perm("kort.delete_cardprintjob") | has_object_perm("kort.delete_cardprintjob")
+)
+add_perm("kort.delete_cardprintjob_rule", delete_card_print_job_predicate)
+
+
 view_card_layouts_predicate = has_person & (
     has_global_perm("kort.view_cardlayout") | has_any_object("kort.view_cardlayout", CardLayout)
 )
diff --git a/aleksis/apps/kort/templates/kort/printer/detail_content.html b/aleksis/apps/kort/templates/kort/printer/detail_content.html
index 9618a4b..e186014 100644
--- a/aleksis/apps/kort/templates/kort/printer/detail_content.html
+++ b/aleksis/apps/kort/templates/kort/printer/detail_content.html
@@ -80,6 +80,7 @@
           <div class="card-title">{% trans "Print jobs" %}</div>
           <table>
             <tr>
+              <th></th>
               <th>
                 {% trans "Card" %}
               </th>
@@ -89,9 +90,19 @@
               <th>
                 {% trans "Status" %}
               </th>
+              <th></th>
             </tr>
-            {% for job in printer.jobs.all %}
+            {% for job in printer.get_jobs %}
               <tr>
+                <td>
+                  {% if job.status == "finished" %}
+                  <i class="material-icons iconify green-text" data-icon="mdi:check-circle-outline"></i>
+                  {% elif job.status == "failed" %}
+                  <i class="material-icons iconify red-text" data-icon="mdi:alert-circle-outline"></i>
+                  {% else %}
+                  <i class="material-icons iconify orange-text" data-icon="mdi:dots-horizontal"></i>
+                  {% endif %}
+                </td>
                 <td>
                   <a href="{% url "card" job.card.pk %}">
                     {{ job.card }}
@@ -103,6 +114,13 @@
                 <td>
                   {{ job.status }} {% if job.status_text %}({{ job.status_text }}){% endif %}
                 </td>
+                <td>
+                  {% if job.status == "registered" %}
+                  <a class="btn-flat waves-effect waves-light center" href="{% url 'delete_print_job' job.pk %}">
+                    <i class="material-icons iconify red-text" data-icon="mdi:delete-outline"></i>
+                  </a>
+                  {% endif %}
+                </td>
               </tr>
             {% endfor %}
           </table>
diff --git a/aleksis/apps/kort/templates/kort/printer/print_job_delete.html b/aleksis/apps/kort/templates/kort/printer/print_job_delete.html
new file mode 100644
index 0000000..05fd4e6
--- /dev/null
+++ b/aleksis/apps/kort/templates/kort/printer/print_job_delete.html
@@ -0,0 +1,25 @@
+{# -*- engine:django -*- #}
+
+{% extends "core/base.html" %}
+
+{% load i18n rules material_form %}
+{% load render_table from django_tables2 %}
+
+{% block browser_title %}{% blocktrans %}Delete Card Print Job{% endblocktrans %}{% endblock %}
+{% block no_page_title %}{% endblock %}
+
+{% block content %}
+  <p class="flow-text">{% trans "Do you really want to delete the following card print job?" %}</p>
+  {{ object }}
+  <form method="post" action="">
+    {% csrf_token %}
+    <a href="{% url "card_printers" %}" class="modal-close waves-effect waves-green btn">
+      <i class="material-icons left iconify" data-icon="mdi:arrow-left"></i>
+      {% trans "Go back" %}
+    </a>
+    <button type="submit" name="delete" class="modal-close waves-effect waves-light red btn">
+      <i class="material-icons left iconify" data-icon="mdi:delete-outline"></i>
+      {% trans "Delete" %}
+    </button>
+  </form>
+{% endblock %}
\ No newline at end of file
diff --git a/aleksis/apps/kort/urls.py b/aleksis/apps/kort/urls.py
index 06e9f01..564ea85 100644
--- a/aleksis/apps/kort/urls.py
+++ b/aleksis/apps/kort/urls.py
@@ -29,6 +29,11 @@ urlpatterns = [
         views.CardPrinterConfigView.as_view(),
         name="card_printer_config",
     ),
+    path(
+        "jobs/<int:pk>/delete/",
+        views.CardPrintJobDeleteView.as_view(),
+        name="delete_print_job",
+    ),
     path("layouts/", views.CardLayoutListView.as_view(), name="card_layouts"),
     path("layouts/create/", views.CardLayoutCreateView.as_view(), name="create_card_layout"),
     path("layouts/<int:pk>/", views.CardLayoutDetailView.as_view(), name="card_layout"),
diff --git a/aleksis/apps/kort/views.py b/aleksis/apps/kort/views.py
index 7e51033..64dd241 100644
--- a/aleksis/apps/kort/views.py
+++ b/aleksis/apps/kort/views.py
@@ -24,7 +24,7 @@ from aleksis.apps.kort.forms import (
     CardPrinterForm,
     PrinterSelectForm,
 )
-from aleksis.apps.kort.models import Card, CardLayout, CardPrinter, PrintStatus
+from aleksis.apps.kort.models import Card, CardLayout, CardPrinter, CardPrintJob, PrintStatus
 from aleksis.apps.kort.tables import (
     CardLayoutTable,
     CardPrinterTable,
@@ -307,6 +307,16 @@ class CardPrinterDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDele
     success_message = _("The card printer has been deleted successfully.")
 
 
+class CardPrintJobDeleteView(PermissionRequiredMixin, RevisionMixin, AdvancedDeleteView):
+    """View used to delete a card print job."""
+
+    permission_required = "kort.delete_cardprintjob_rule"
+    success_url = reverse_lazy("card_printers")
+    template_name = "kort/printer/print_job_delete.html"
+    model = CardPrintJob
+    success_message = _("The card print job has been deleted successfully.")
+
+
 class CardPrinterDetailView(PermissionRequiredMixin, RevisionMixin, DetailView):
     permission_required = "kort.view_cardprinter_rule"
     model = CardPrinter
-- 
GitLab