From 67f415c2e37668166bdbc47c3114dd7b5862ca7c Mon Sep 17 00:00:00 2001 From: mipel Date: Wed, 21 Jul 2021 15:40:34 +0200 Subject: [PATCH] Intervention tables and model adjustments * adds user access relation to certain models * adds pagination to tables * adds checked_on/_by attributes to intervention model * adds custom column rendering for checked and registered columns * adds first simple index filtering of default interventions for user * adds translations --- compensation/models.py | 4 ++ intervention/models.py | 19 +++++-- intervention/tables.py | 54 +++++++++++++++++- intervention/views.py | 4 +- konova/models.py | 6 +- konova/static/css/konova.css | 28 +++++++++- konova/sub_settings/django_settings.py | 2 +- konova/utils/tables.py | 22 ++++++++ locale/de/LC_MESSAGES/django.mo | Bin 5619 -> 5865 bytes locale/de/LC_MESSAGES/django.po | 74 +++++++++++++++---------- 10 files changed, 170 insertions(+), 43 deletions(-) diff --git a/compensation/models.py b/compensation/models.py index 9d3e0ca5..ceca5733 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 17.11.20 """ +from django.contrib.auth.models import User from django.contrib.gis.db import models from django.core.validators import MinValueValidator from django.utils import timezone @@ -74,6 +75,9 @@ class Compensation(BaseObject): geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) + # Users having access on this object + users = models.ManyToManyField(User) + @staticmethod def _generate_new_identifier() -> str: """ Generates a new identifier for the intervention object diff --git a/intervention/models.py b/intervention/models.py index 58cebcfb..f8243079 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -33,22 +33,29 @@ class Intervention(BaseObject): geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) + # Checks + checked_on = models.DateTimeField(default=None, null=True, blank=True) + checked_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') + # Refers to "zugelassen am" registration_date = models.DateField(null=True, blank=True) # Refers to "Bestandskraft am" - binding_date = models.DateField(null=True, blank=True) + binding_on = models.DateField(null=True, blank=True) # Refers to "verzeichnen" - recorded_on = models.DateTimeField(default=None) - recorded_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) + recorded_on = models.DateTimeField(default=None, null=True, blank=True) + recorded_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') # Holds which intervention is simply a newer version of this dataset - next_version = models.ForeignKey("Intervention", null=True, on_delete=models.DO_NOTHING) + next_version = models.ForeignKey("Intervention", null=True, blank=True, on_delete=models.DO_NOTHING) # Compensation or payments, one-directional - payments = models.ManyToManyField(Payment, related_name="+") - compensations = models.ManyToManyField(Compensation, related_name="+") + payments = models.ManyToManyField(Payment, related_name="+", blank=True) + compensations = models.ManyToManyField(Compensation, related_name="+", blank=True) + + # Users having access on this object + users = models.ManyToManyField(User) def delete(self, *args, **kwargs): """ Custom delete functionality diff --git a/intervention/tables.py b/intervention/tables.py index 9d19ea7c..dea5ec7f 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -7,9 +7,11 @@ Created on: 01.12.20 """ from django.urls import reverse from django.utils.html import format_html +from django.utils.timezone import localtime from django.utils.translation import gettext_lazy as _ from intervention.models import Intervention +from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT from konova.utils.tables import BaseTable import django_tables2 as tables @@ -28,11 +30,13 @@ class InterventionTable(BaseTable): c = tables.Column( verbose_name=_("Checked"), orderable=True, - accessor="recorded_on", + empty_values=[], + accessor="checked_on", ) r = tables.Column( verbose_name=_("Registered"), orderable=True, + empty_values=[], accessor="recorded_on", ) lm = tables.Column( @@ -52,7 +56,7 @@ class InterventionTable(BaseTable): """ class Meta(BaseTable.Meta): - pass + template_name = "django_tables2/bootstrap4.html" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -78,6 +82,52 @@ class InterventionTable(BaseTable): ) return format_html(html) + def render_c(self, value, record: Intervention): + """ Renders the checked column for an intervention + + Args: + value (str): The identifier value + record (Intervention): The intervention record + + Returns: + + """ + html = "" + checked = value is not None + tooltip = _("Not checked yet") + if checked: + value = localtime(value) + checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + tooltip = _("Checked on {} by {}").format(checked_on, record.checked_by) + html += self.render_checked_star( + tooltip=tooltip, + icn_filled=checked, + ) + return format_html(html) + + def render_r(self, value, record: Intervention): + """ Renders the registered column for an intervention + + Args: + value (str): The identifier value + record (Intervention): The intervention record + + Returns: + + """ + html = "" + checked = value is not None + tooltip = _("Not registered yet") + if checked: + value = localtime(value) + checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) + tooltip = _("Registered on {} by {}").format(checked_on, record.checked_by) + html += self.render_bookmark( + tooltip=tooltip, + icn_filled=checked, + ) + return format_html(html) + def render_ac(self, value, record): """ Renders possible actions for this record, such as delete. diff --git a/intervention/views.py b/intervention/views.py index ba7b1c66..722a7e05 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -26,7 +26,9 @@ def index_view(request: HttpRequest): template = "generic_index.html" user = request.user interventions = Intervention.objects.filter( - + deleted_on=None, # not deleted + next_version=None, # only newest versions + users__in=[user], # requesting user has access ) table = InterventionTable( request=request, diff --git a/konova/models.py b/konova/models.py index 5bf5b2a8..eb96dc76 100644 --- a/konova/models.py +++ b/konova/models.py @@ -35,9 +35,9 @@ class BaseObject(BaseResource): """ identifier = models.CharField(max_length=1000, null=True, blank=True) title = models.CharField(max_length=1000, null=True, blank=True) - deleted_on = models.DateTimeField(null=True) - deleted_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name="+") - comment = models.TextField() + deleted_on = models.DateTimeField(null=True, blank=True) + deleted_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name="+") + comment = models.TextField(null=True, blank=True) class Meta: abstract = True diff --git a/konova/static/css/konova.css b/konova/static/css/konova.css index 5f311331..dceb780e 100644 --- a/konova/static/css/konova.css +++ b/konova/static/css/konova.css @@ -72,7 +72,7 @@ a { text-decoration: none; } -nav{ +.navbar{ background-color: var(--rlp-red); } @@ -144,9 +144,35 @@ nav{ cursor: pointer; } +.dropdown-item.selected{ + background-color: var(--rlp-gray-light); +} + input:focus, textarea:focus, select:focus{ border: 1px solid var(--rlp-red) !important; box-shadow: 0 0 3px var(--rlp-red) !important; -moz-box-shadow: 0 0 3px var(--rlp-red) !important; -webkit-box-shadow: 0 0 3px var(--rlp-red) !important; +} + +.check-star{ + color: goldenrod; +} +.registered-bookmark{ + color: green; +} + +/* PAGINATION */ +.page-item > .page-link{ + color: var(--rlp-red); +} +.page-link:focus{ + border: 1px solid var(--rlp-red) !important; + box-shadow: 0 0 3px var(--rlp-red) !important; + -moz-box-shadow: 0 0 3px var(--rlp-red) !important; + -webkit-box-shadow: 0 0 3px var(--rlp-red) !important; +} +.page-item.active > .page-link{ + background-color: var(--rlp-red); + border-color: var(--rlp-red); } \ No newline at end of file diff --git a/konova/sub_settings/django_settings.py b/konova/sub_settings/django_settings.py index 20b28fa8..e06c1382 100644 --- a/konova/sub_settings/django_settings.py +++ b/konova/sub_settings/django_settings.py @@ -144,7 +144,7 @@ AUTH_PASSWORD_VALIDATORS = [ LANGUAGE_CODE = 'en-us' -DEFAULT_DATE_TIME_FORMAT = 'YYYY-MM-DD hh:mm:ss' +DEFAULT_DATE_TIME_FORMAT = '%d.%m.%Y %H:%M:%S' TIME_ZONE = 'Europe/Berlin' diff --git a/konova/utils/tables.py b/konova/utils/tables.py index 65f9f4e3..196515ac 100644 --- a/konova/utils/tables.py +++ b/konova/utils/tables.py @@ -104,6 +104,28 @@ class BaseTable(tables.tables.Table): icon ) + def render_checked_star(self, tooltip: str = None, icn_filled: bool = False): + """ + Returns a star icon + """ + icon = "fas fa-star check-star" if icn_filled else "far fa-star" + return format_html( + "", + tooltip, + icon + ) + + def render_bookmark(self, tooltip: str = None, icn_filled: bool = False): + """ + Returns a bookmark icon + """ + icon = "fas fa-bookmark registered-bookmark" if icn_filled else "far fa-bookmark" + return format_html( + "", + tooltip, + icon + ) + class ChoicesColumnForm(BaseForm): select = forms.ChoiceField( diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 9e5396ebe88a173815768b23c5ad880c3d173614..11732223371648ad128147e6435b07eeb00915c4 100644 GIT binary patch delta 2295 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 E0W{^Kq5uE@ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index f1595f1e..ba953669 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#: konova/forms.py:67 user/forms.py:38 +#: konova/forms.py:69 user/forms.py:38 #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-21 13:28+0200\n" +"POT-Creation-Date: 2021-07-21 15:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,49 +19,49 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: compensation/tables.py:18 compensation/tables.py:68 intervention/forms.py:26 -#: intervention/tables.py:19 +#: compensation/tables.py:18 compensation/tables.py:71 intervention/forms.py:26 +#: intervention/tables.py:22 msgid "Identifier" msgstr "Kennung" -#: compensation/tables.py:23 compensation/tables.py:73 intervention/forms.py:33 -#: intervention/tables.py:24 +#: compensation/tables.py:23 compensation/tables.py:76 intervention/forms.py:33 +#: intervention/tables.py:27 msgid "Title" msgstr "Titel" -#: compensation/tables.py:28 compensation/tables.py:78 +#: compensation/tables.py:28 compensation/tables.py:81 msgid "Created on" msgstr "Erstellt" -#: compensation/tables.py:33 compensation/tables.py:83 +#: compensation/tables.py:33 compensation/tables.py:86 msgid "Actions" msgstr "Aktionen" -#: compensation/tables.py:41 +#: compensation/tables.py:44 msgid "Compensations" msgstr "Kompensationen" -#: compensation/tables.py:48 compensation/tables.py:98 +#: compensation/tables.py:51 compensation/tables.py:104 #: konova/templates/konova/home.html:49 templates/navbar.html:28 msgid "Compensation" msgstr "Kompensation" -#: compensation/tables.py:51 compensation/tables.py:101 -#: intervention/tables.py:74 intervention/tables.py:88 +#: compensation/tables.py:54 compensation/tables.py:107 +#: intervention/tables.py:79 intervention/tables.py:139 msgid "Open {}" msgstr "Öffne {}" -#: compensation/tables.py:56 compensation/tables.py:106 -#: intervention/tables.py:92 +#: compensation/tables.py:59 compensation/tables.py:112 +#: intervention/tables.py:143 msgid "Edit {}" msgstr "Bearbeite {}" -#: compensation/tables.py:60 compensation/tables.py:110 -#: intervention/tables.py:96 +#: compensation/tables.py:63 compensation/tables.py:116 +#: intervention/tables.py:147 msgid "Delete {}" msgstr "Lösche {}" -#: compensation/tables.py:91 +#: compensation/tables.py:97 msgid "Eco Accounts" msgstr "Ökokonten" @@ -133,41 +133,57 @@ msgstr "Neuer Eingriff" msgid "Edit intervention" msgstr "Eingriff bearbeiten" -#: intervention/tables.py:29 +#: intervention/tables.py:32 msgid "Checked" msgstr "Geprüft" -#: intervention/tables.py:34 +#: intervention/tables.py:38 msgid "Registered" msgstr "Verzeichnet" -#: intervention/tables.py:39 +#: intervention/tables.py:44 msgid "Last edit" msgstr "Zuletzt bearbeitet" -#: intervention/tables.py:59 +#: intervention/tables.py:64 msgid "Interventions" msgstr "Eingriffe" -#: intervention/tables.py:74 intervention/tables.py:85 +#: intervention/tables.py:79 intervention/tables.py:136 #: intervention/templates/intervention/open.html:8 #: konova/templates/konova/home.html:11 templates/navbar.html:22 msgid "Intervention" msgstr "Eingriff" +#: intervention/tables.py:98 +msgid "Not checked yet" +msgstr "Noch nicht geprüft" + +#: intervention/tables.py:102 +msgid "Checked on {} by {}" +msgstr "Am {} von {} geprüft worden" + +#: intervention/tables.py:121 +msgid "Not registered yet" +msgstr "Noch nicht verzeichnet" + +#: intervention/tables.py:125 +msgid "Registered on {} by {}" +msgstr "Am {} von {} verzeichnet worden" + #: intervention/templates/intervention/open.html:12 msgid "Edit" msgstr "Bearbeiten" -#: intervention/views.py:58 +#: intervention/views.py:60 msgid "Intervention {} added" msgstr "Eingriff {} hinzugefügt" -#: intervention/views.py:61 intervention/views.py:114 +#: intervention/views.py:63 intervention/views.py:116 msgid "Invalid input" msgstr "Eingabe fehlerhaft" -#: intervention/views.py:111 +#: intervention/views.py:113 msgid "{} edited" msgstr "{} bearbeitet" @@ -183,19 +199,19 @@ msgstr "Hierfür müssen Sie Administrator sein!" msgid "You need to be part of another user group." msgstr "Hierfür müssen Sie einer anderen Nutzergruppe angehören!" -#: konova/forms.py:40 +#: konova/forms.py:42 msgid "Not editable" msgstr "Nicht editierbar" -#: konova/forms.py:66 +#: konova/forms.py:68 msgid "Confirm" msgstr "Bestätigen" -#: konova/forms.py:78 +#: konova/forms.py:80 msgid "Remove" msgstr "Entferne" -#: konova/forms.py:80 +#: konova/forms.py:82 msgid "You are about to remove {} {}" msgstr "Sie sind dabei {} {} zu löschen"