From 591bc739ecbe62d45c001774e25a92177f16835b Mon Sep 17 00:00:00 2001 From: mipel Date: Thu, 22 Jul 2021 10:00:59 +0200 Subject: [PATCH] Table filters * adds table filtering for InterventionTable * adds default ordering * moves user-access filtering from view to InterventionTableFiler * adds generic render_icn method for BaseTable (for usage with fontawesome5) * adds translations * improves table.html template --- intervention/filters.py | 113 ++++++++++++++++++++++++++++++++ intervention/tables.py | 39 ++++++++++- intervention/views.py | 6 +- konova/static/css/konova.css | 4 ++ konova/utils/tables.py | 10 +++ locale/de/LC_MESSAGES/django.mo | Bin 5865 -> 6339 bytes locale/de/LC_MESSAGES/django.po | 77 +++++++++++++++------- templates/table.html | 8 ++- 8 files changed, 228 insertions(+), 29 deletions(-) create mode 100644 intervention/filters.py diff --git a/intervention/filters.py b/intervention/filters.py new file mode 100644 index 00000000..0a56b36b --- /dev/null +++ b/intervention/filters.py @@ -0,0 +1,113 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 22.07.21 + +""" +import django_filters +from django import forms +from django.contrib.auth.models import User +from django.db.models import QuerySet, Q + +from django.utils.translation import gettext_lazy as _ +from intervention.models import Intervention + + +class InterventionTableFilter(django_filters.FilterSet): + q = django_filters.Filter( + method='_filter_by_keyword', + widget=forms.HiddenInput(), # use search bar in template, we only need the filter logic in here! + ) + sa = django_filters.BooleanFilter( + method='_filter_show_all', + label=_("Show all"), + label_suffix=_(""), + widget=forms.CheckboxInput() + ) + sr = django_filters.BooleanFilter( + method='_filter_show_recorded', + label=_("Show recorded"), + label_suffix=_(""), + widget=forms.CheckboxInput() + ) + # Gemarkung ##ToDo + g = django_filters.CharFilter( + field_name="name", + lookup_expr="icontains", + label=_(""), + label_suffix=_(""), + widget=forms.TextInput( + attrs={ + "placeholder": _("District"), + "title": _("Search for district") + } + ), + ) + # Kreis + ## ToDo + # Flur + ## ToDo + # Zähler + ## ToDo + # Nenner + ## ToDo + + class Meta: + model = Intervention + fields = [] + + def __init__(self, user: User, *args, **kwargs): + self.user = user + super().__init__(*args, **kwargs) + + def _filter_by_keyword(self, queryset, name, value) -> QuerySet: + """ Filters queryset depending on value of search bar input + + Args: + queryset (): + name (): + value (): + + Returns: + + """ + # build filter expression + q = Q(title__icontains=value) | Q(identifier__icontains=value) + return queryset.filter(q) + + def _filter_show_all(self, queryset, name, value) -> QuerySet: + """ Filters queryset depending on value of 'show_all' setting + + Args: + queryset (): + name (): + value (): + + Returns: + + """ + if not value: + return queryset.filter( + users__in=[self.user], # requesting user has access + ) + else: + return queryset + + def _filter_show_recorded(self, queryset, name, value) -> QuerySet: + """ Filters queryset depending on value of 'show_recorded' setting + + Args: + queryset (): + name (): + value (): + + Returns: + + """ + if not value: + return queryset.filter( + recorded_on=None, + ) + else: + return queryset diff --git a/intervention/tables.py b/intervention/tables.py index dea5ec7f..a59490e8 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -5,11 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 01.12.20 """ +from django.http import HttpRequest 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.filters import InterventionTableFilter from intervention.models import Intervention from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT from konova.utils.tables import BaseTable @@ -39,6 +41,12 @@ class InterventionTable(BaseTable): empty_values=[], accessor="recorded_on", ) + e = tables.Column( + verbose_name=_("Editable"), + orderable=True, + empty_values=[], + accessor="users", + ) lm = tables.Column( verbose_name=_("Last edit"), orderable=True, @@ -58,10 +66,16 @@ class InterventionTable(BaseTable): class Meta(BaseTable.Meta): template_name = "django_tables2/bootstrap4.html" - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) + def __init__(self, request: HttpRequest, *args, **kwargs): self.title = _("Interventions") self.add_new_url = reverse("intervention:new") + qs = kwargs.get("queryset", None) + self.filter = InterventionTableFilter( + user=request.user, + data=request.GET, + queryset=qs, + ) + super().__init__(request, self.filter, *args, **kwargs) def render_id(self, value, record: Intervention): """ Renders the id column for an intervention @@ -128,6 +142,27 @@ class InterventionTable(BaseTable): ) return format_html(html) + def render_e(self, value, record: Intervention): + """ Renders the registered column for an intervention + + Args: + value (str): The identifier value + record (Intervention): The intervention record + + Returns: + + """ + html = "" + has_access = value.filter( + username=self.user.username + ).exists() + + html += self.render_icn( + tooltip=_("Full access granted") if has_access else _("Access not granted"), + icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit", + ) + 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 722a7e05..a899344e 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -24,11 +24,13 @@ def index_view(request: HttpRequest): A rendered view """ template = "generic_index.html" - user = request.user + + # Filtering by user access is performed in table filter inside of InterventionTableFilter class interventions = Intervention.objects.filter( deleted_on=None, # not deleted next_version=None, # only newest versions - users__in=[user], # requesting user has access + ).order_by( + "-created_on" ) table = InterventionTable( request=request, diff --git a/konova/static/css/konova.css b/konova/static/css/konova.css index dceb780e..af50f043 100644 --- a/konova/static/css/konova.css +++ b/konova/static/css/konova.css @@ -37,6 +37,10 @@ Declare some basic colours color:var(--rlp-red); } +.rlp-r-inv{ + color:var(--rlp-red); +} + html { position: relative; min-height: 100%; diff --git a/konova/utils/tables.py b/konova/utils/tables.py index 196515ac..9cbcfc5f 100644 --- a/konova/utils/tables.py +++ b/konova/utils/tables.py @@ -126,6 +126,16 @@ class BaseTable(tables.tables.Table): icon ) + def render_icn(self, tooltip: str = None, icn_class: str = None): + """ + Returns a rendered fontawesome icon + """ + return format_html( + "", + tooltip, + icn_class, + ) + class ChoicesColumnForm(BaseForm): select = forms.ChoiceField( diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 11732223371648ad128147e6435b07eeb00915c4..0558cdf2045e4d1dc303e0d7ea60c94e95809d2b 100644 GIT binary patch delta 2561 zcmZ|QTWl0n9LMnkMcGnr1!_TRnTi#Pt%7oCMKE(|}5( z1q-kp$DqYR+<{7PFDj9zF~<1jIVv-`@d{ppr%@T6!AW=)EAS^&LX+uT9Tz)GkVmEr zl|Usj;U?;J$6{{!{@5Z;WJaTd;=Xv_`RFp>42N5$uc8Xj~Hj^IMBbExNoScy|vU$v`6 z4Y(S$g6pt;6o(Fvas49GoQsW|Jhk76N@zFI#5{^x;ivkjsDsx~hwwNm)6Y>a{)PH1 zFQH~Soed=yQ;uw_S%_NNTGZKTM!na9{Fx2>T#ucot=W$n?~uFhd*0nR>TbM^+KN-C zCHew2@UN%=FQN`p9*s2c3|xX`sF}6nZJ2V;`%x?PDryCex%+P+iT0V3RCF3YL>;!T zP#OM)jAbr3V>D7nGf^`vbJz2n^HB*dMh#StT9H-Awwtx6m1{?}>%^)0{v#?nl?PC# zwjVX{3FiQ6CC;K={2R4JT80XkgY&TstMD<@3Y@?N_&sVuQ|MePS%T`n0t@v0FQcMU z*^HW5r}JTC+f6U3gM+BAbe-!z8sanQq)Q|4KvDSJCYBHK=Hb>xeSq4q_D%CzcZ9ncq=}AB0 zZBL~m8)gs0hGLDWOcbUPQMNa~CAKn|iu`!mWnQhg{=U(%DfT}S<^I}n&$_5Y>>1;u6pvAQTeOvPCxA06?9~m7H%tO`mfLI3x%^5 zH4U5&z4a;kzk_x8LEy!$AI5DevXQsPhRNK!g)MmnS3CAH*^AS5lqdzp?p4x(*=R#* PiO#@A+|9KY9Uk>BlK~&B delta 2157 zcmYk-TTE0(9LMqh%C@*$Km^4r?Ru*Pgo044MG&a1RoimsJ z%z=v)4@$kedH!QYX(wh9{tPn@M_=MX8Obz@;{)Vl`^KBm#Jb9~50>IjI2*5` z+CRa3e1Tb*8!*epLgaVPN>UZ8M0HeyL2N`dT!oWyBl5A&xTvE&_zHHTACKZhJb{|n z0BQoi;|v@`t!Wr1;0P9Jsn4ir;Mt6-j*6URsEJf^(SUV037b$8+Jc(k=gx1DuIvaZ zLp`W|d)<9Ms-FQQ8Fm)^O7)+v!62%G%b1JT)d26KX8aJeC)dTMaq{qQ#`WuvHpo;ZEnFs9|8+D}8RtQ^&T5o*FqQ4?-) zzqg_W-h{Qd3$^m!Q0>lSk$>uTfs6KL$a%#zxPf}$HolJc@HGsw+(InIVqAf0*X6$7 zi&fm8biZH01>BFJ+Re{NjaQyS{*|g~zG(EB)nh;R-;i%LEMZxiX%#AUi!qs6)S+re zP3#L)`(D&r^b0aq8$`OaYe+I}7?rU{s5A1^qoN1LP_QEA2z4e-p$0mQIy>j^O&oIHKSyQU^D(Mcn2CBI3pJrhsKZoSzz@xv$*)0p|~>mH&turw_IAeq=X18=#^TokKOegj(5kBq=t6I&{yGkLB{C zoP%0QE3}oU=hvae*^0_o6a$QJF)B*Qm#97e8g+;cB7NDf zsFnVKZ{ZzOhxw!>gfsCCti>AaKxLv2HL)R7zki`7^bc~@lizutP*Kr9n)Pym{%s?n zNohqY9}zrft93(ZBC3fJLffPP)8#!XmBg#WVqyxROpYV8)$PPWg5p_Qs$z3dubBRM zXuq^V6}HVb5PHwG%1wk;v5ZibRO*Qji4dVJX&~kkDl1c1GwJ{?B9;*Ih%)VeBNY{$ za_#>t-B7g0Dz(H?Vg*q}d`zUvDk^K-jSijC{r{rv(w3x)_Fb>zTKB~}+W+>cNH-)u0^@q!Xp=604AAdLyi|mYc zSwm-Mye05B-W+U-_Xg)CZUy&^i$}8C5;wD>8QBdx)G8cRvvA_TM87Y7Ja6-i;!sy4 px-Hbw(HZ%4d#oeexh=fA%$9A9g(Hc!{N{}K*@Df9nkn7B{{WhByFCB^ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index ba953669..b3fae2c3 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -3,13 +3,15 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # -#: konova/forms.py:69 user/forms.py:38 +#: intervention/filters.py:21 intervention/filters.py:27 +#: intervention/filters.py:34 intervention/filters.py:35 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 15:07+0200\n" +"POT-Creation-Date: 2021-07-22 09:31+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -20,12 +22,12 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: compensation/tables.py:18 compensation/tables.py:71 intervention/forms.py:26 -#: intervention/tables.py:22 +#: intervention/tables.py:23 msgid "Identifier" msgstr "Kennung" #: compensation/tables.py:23 compensation/tables.py:76 intervention/forms.py:33 -#: intervention/tables.py:27 +#: intervention/tables.py:28 msgid "Title" msgstr "Titel" @@ -47,17 +49,17 @@ msgid "Compensation" msgstr "Kompensation" #: compensation/tables.py:54 compensation/tables.py:107 -#: intervention/tables.py:79 intervention/tables.py:139 +#: intervention/tables.py:92 intervention/tables.py:179 msgid "Open {}" msgstr "Öffne {}" #: compensation/tables.py:59 compensation/tables.py:112 -#: intervention/tables.py:143 +#: intervention/tables.py:183 msgid "Edit {}" msgstr "Bearbeite {}" #: compensation/tables.py:63 compensation/tables.py:116 -#: intervention/tables.py:147 +#: intervention/tables.py:187 msgid "Delete {}" msgstr "Lösche {}" @@ -65,6 +67,22 @@ msgstr "Lösche {}" msgid "Eco Accounts" msgstr "Ökokonten" +#: intervention/filters.py:20 +msgid "Show all" +msgstr "Alle anzeigen" + +#: intervention/filters.py:26 +msgid "Show recorded" +msgstr "Verzeichnete anzeigen" + +#: intervention/filters.py:38 +msgid "District" +msgstr "Gemarkung" + +#: intervention/filters.py:39 +msgid "Search for district" +msgstr "Nach Gemarkung suchen" + #: intervention/forms.py:29 msgid "Generated automatically if none was given" msgstr "Wird automatisch erzeugt, falls nicht angegeben" @@ -133,57 +151,69 @@ msgstr "Neuer Eingriff" msgid "Edit intervention" msgstr "Eingriff bearbeiten" -#: intervention/tables.py:32 +#: intervention/tables.py:33 msgid "Checked" msgstr "Geprüft" -#: intervention/tables.py:38 +#: intervention/tables.py:39 msgid "Registered" msgstr "Verzeichnet" -#: intervention/tables.py:44 +#: intervention/tables.py:45 +msgid "Editable" +msgstr "Freigegeben" + +#: intervention/tables.py:51 msgid "Last edit" msgstr "Zuletzt bearbeitet" -#: intervention/tables.py:64 +#: intervention/tables.py:70 msgid "Interventions" msgstr "Eingriffe" -#: intervention/tables.py:79 intervention/tables.py:136 +#: intervention/tables.py:92 intervention/tables.py:176 #: intervention/templates/intervention/open.html:8 #: konova/templates/konova/home.html:11 templates/navbar.html:22 msgid "Intervention" msgstr "Eingriff" -#: intervention/tables.py:98 +#: intervention/tables.py:111 msgid "Not checked yet" msgstr "Noch nicht geprüft" -#: intervention/tables.py:102 +#: intervention/tables.py:115 msgid "Checked on {} by {}" msgstr "Am {} von {} geprüft worden" -#: intervention/tables.py:121 +#: intervention/tables.py:134 msgid "Not registered yet" msgstr "Noch nicht verzeichnet" -#: intervention/tables.py:125 +#: intervention/tables.py:138 msgid "Registered on {} by {}" msgstr "Am {} von {} verzeichnet worden" +#: intervention/tables.py:167 +msgid "Full access granted" +msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden" + +#: intervention/tables.py:167 +msgid "Access not granted" +msgstr "Nicht freigegeben - Datensatz nur lesbar" + #: intervention/templates/intervention/open.html:12 msgid "Edit" msgstr "Bearbeiten" -#: intervention/views.py:60 +#: intervention/views.py:63 msgid "Intervention {} added" msgstr "Eingriff {} hinzugefügt" -#: intervention/views.py:63 intervention/views.py:116 +#: intervention/views.py:66 intervention/views.py:119 msgid "Invalid input" msgstr "Eingabe fehlerhaft" -#: intervention/views.py:113 +#: intervention/views.py:116 msgid "{} edited" msgstr "{} bearbeitet" @@ -371,10 +401,14 @@ msgstr "Starte Suche" msgid "Results per page" msgstr "Treffer pro Seite" -#: templates/table.html:70 +#: templates/table.html:70 templates/table.html:77 msgid "Filter" msgstr "" +#: templates/table.html:79 +msgid "Apply filter" +msgstr "Filter anwenden" + #: user/forms.py:23 msgid "Notifications" msgstr "Benachrichtigungen" @@ -1697,9 +1731,6 @@ msgstr "" #~ msgid "Process management" #~ msgstr "Vorgangsverwaltung" -#~ msgid "Show process" -#~ msgstr "Zeige Vorgänge" - #~ msgid "New process" #~ msgstr "Neuer Vorgang" diff --git a/templates/table.html b/templates/table.html index 1f5c39c3..9ae8d06a 100644 --- a/templates/table.html +++ b/templates/table.html @@ -26,9 +26,9 @@ {% endcomment %}
-
+
- +