From 5c0b1c412d30775a8f51c89b1686aaf8088a6705 Mon Sep 17 00:00:00 2001 From: mipel Date: Thu, 19 Aug 2021 13:44:06 +0200 Subject: [PATCH] EMA * fixes created timestamp in detail views where modified needs to be displayed * adds fallback timestamp if data has not been edited, yet --> show created timestamp * fixes bug where deleting of certain data didn't redirect to the index view * adds quality_check() method for EMA, needed for recording * adds all functions which are provided for compensations to EMA * adds/updates translations --- compensation/models.py | 14 +- .../detail/compensation/view.html | 4 +- .../compensation/detail/eco_account/view.html | 4 +- compensation/views/compensation_views.py | 2 +- ema/models.py | 12 + .../ema/detail/includes/actions.html | 61 +++++ .../ema/detail/includes/controls.html | 40 +++ .../ema/detail/includes/deadlines.html | 61 +++++ .../ema/detail/includes/documents.html | 59 +++++ .../ema/detail/includes/states-after.html | 62 +++++ .../ema/detail/includes/states-before.html | 62 +++++ ema/templates/ema/detail/view.html | 100 ++++++++ ema/urls.py | 19 +- ema/views.py | 227 +++++++++++++++++- intervention/models.py | 2 +- konova/forms.py | 4 +- locale/de/LC_MESSAGES/django.mo | Bin 18712 -> 18748 bytes locale/de/LC_MESSAGES/django.po | 2 +- 18 files changed, 717 insertions(+), 18 deletions(-) create mode 100644 ema/templates/ema/detail/includes/actions.html create mode 100644 ema/templates/ema/detail/includes/controls.html create mode 100644 ema/templates/ema/detail/includes/deadlines.html create mode 100644 ema/templates/ema/detail/includes/documents.html create mode 100644 ema/templates/ema/detail/includes/states-after.html create mode 100644 ema/templates/ema/detail/includes/states-before.html create mode 100644 ema/templates/ema/detail/view.html diff --git a/compensation/models.py b/compensation/models.py index ee78a46e..3393dd9b 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -257,9 +257,17 @@ class EcoAccount(AbstractCompensation): y, ) - def quality_check(self) -> (bool, dict): - # ToDo - pass + def quality_check(self) -> list: + """ Quality check + + Returns: + ret_msgs (list): Holds error messages + """ + ret_msgs = [] + + # ToDo: Add check methods! + + return ret_msgs class EcoAccountWithdraw(BaseResource): diff --git a/compensation/templates/compensation/detail/compensation/view.html b/compensation/templates/compensation/detail/compensation/view.html index 16084e2d..63d00aa2 100644 --- a/compensation/templates/compensation/detail/compensation/view.html +++ b/compensation/templates/compensation/detail/compensation/view.html @@ -63,9 +63,9 @@ {% trans 'Last modified' %} - {{obj.created.timestamp|default_if_none:""|naturalday}} + {{obj.modified.timestamp|default_if_none:""|naturalday}}
- {{obj.created.user.username}} + {{obj.modified.user.username}} diff --git a/compensation/templates/compensation/detail/eco_account/view.html b/compensation/templates/compensation/detail/eco_account/view.html index 51d0645d..3f9ddb75 100644 --- a/compensation/templates/compensation/detail/eco_account/view.html +++ b/compensation/templates/compensation/detail/eco_account/view.html @@ -55,9 +55,9 @@ {% trans 'Last modified' %} - {{obj.created.timestamp|default_if_none:""|naturalday}} + {{obj.modified.timestamp|default_if_none:""|naturalday}}
- {{obj.created.user.username}} + {{obj.modified.user.username}} diff --git a/compensation/views/compensation_views.py b/compensation/views/compensation_views.py index 7d4bbcd1..0403af29 100644 --- a/compensation/views/compensation_views.py +++ b/compensation/views/compensation_views.py @@ -141,7 +141,7 @@ def remove_view(request: HttpRequest, id: str): return form.process_request( request=request, msg_success=_("Compensation removed"), - redirect_url="", + redirect_url=reverse("compensation:index"), ) diff --git a/ema/models.py b/ema/models.py index e5aee4cb..aab3a86f 100644 --- a/ema/models.py +++ b/ema/models.py @@ -72,3 +72,15 @@ class Ema(AbstractCompensation): x, y, ) + + def quality_check(self) -> list: + """ Quality check + + Returns: + ret_msgs (list): Holds error messages + """ + ret_msgs = [] + + # ToDo: Add check methods! + + return ret_msgs \ No newline at end of file diff --git a/ema/templates/ema/detail/includes/actions.html b/ema/templates/ema/detail/includes/actions.html new file mode 100644 index 00000000..8fab1234 --- /dev/null +++ b/ema/templates/ema/detail/includes/actions.html @@ -0,0 +1,61 @@ +{% load i18n l10n fontawesome_5 humanize %} +
+
+
+
+
+ {{obj.actions.count}} + {% trans 'Actions' context 'Compensation' %} +
+
+
+
+ {% if is_default_member and has_access %} + + {% endif %} +
+
+
+
+
+ + + + + + + + + + + {% for action in obj.actions.all %} + + + + + + + {% endfor %} + +
+ {% trans 'Action type' %} + + {% trans 'Amount' context 'Compensation' %} + + {% trans 'Comment' %} + + {% trans 'Action' %} +
+ {{ action.action_type }} + {{ action.amount|floatformat:2|intcomma }} {{ action.unit_humanize }}{{ action.comment|default_if_none:"" }} + {% if is_default_member and has_access %} + + {% endif %} +
+
+
\ No newline at end of file diff --git a/ema/templates/ema/detail/includes/controls.html b/ema/templates/ema/detail/includes/controls.html new file mode 100644 index 00000000..9dc960fa --- /dev/null +++ b/ema/templates/ema/detail/includes/controls.html @@ -0,0 +1,40 @@ +{% load i18n l10n fontawesome_5 %} + +
+ + + + + + + {% if has_access %} + {% if is_ets_member %} + {% if obj.recorded %} + + {% else %} + + {% endif %} + {% endif %} + {% if is_default_member %} + + + + + + {% endif %} + {% endif %} +
\ No newline at end of file diff --git a/ema/templates/ema/detail/includes/deadlines.html b/ema/templates/ema/detail/includes/deadlines.html new file mode 100644 index 00000000..63ed3b67 --- /dev/null +++ b/ema/templates/ema/detail/includes/deadlines.html @@ -0,0 +1,61 @@ +{% load i18n l10n fontawesome_5 %} +
+
+
+
+
+ {{obj.deadlines.count}} + {% trans 'Deadlines' %} +
+
+
+
+ {% if is_default_member and has_access %} + + {% endif %} +
+
+
+
+
+ + + + + + + + + + + {% for deadline in obj.deadlines.all %} + + + + + + + {% endfor %} + +
+ {% trans 'Type' %} + + {% trans 'Date' %} + + {% trans 'Comment' %} + + {% trans 'Action' %} +
+ {% trans deadline.type_humanized %} + {{ deadline.date }}{{ deadline.comment }} + {% if is_default_member and has_access %} + + {% endif %} +
+
+
\ No newline at end of file diff --git a/ema/templates/ema/detail/includes/documents.html b/ema/templates/ema/detail/includes/documents.html new file mode 100644 index 00000000..0670bbe7 --- /dev/null +++ b/ema/templates/ema/detail/includes/documents.html @@ -0,0 +1,59 @@ +{% load i18n l10n fontawesome_5 %} +
+
+
+
+
+ {{obj.documents.count}} + {% trans 'Documents' %} +
+
+
+
+ {% if is_default_member and has_access %} + + {% endif %} +
+
+
+
+
+ + + + + + + + + + {% for doc in obj.documents.all %} + + + + + + {% endfor %} + +
+ {% trans 'Title' %} + + {% trans 'Comment' %} + + {% trans 'Action' %} +
+ + {{ doc.title }} + + {{ doc.comment }} + {% if is_default_member and has_access %} + + {% endif %} +
+
+
\ No newline at end of file diff --git a/ema/templates/ema/detail/includes/states-after.html b/ema/templates/ema/detail/includes/states-after.html new file mode 100644 index 00000000..02253b38 --- /dev/null +++ b/ema/templates/ema/detail/includes/states-after.html @@ -0,0 +1,62 @@ +{% load i18n l10n fontawesome_5 %} +
+
+
+
+
+ {{obj.after_states.count}} + {% trans 'States after' %} +
+
+
+
+ {% if is_default_member and has_access %} + + {% endif %} +
+
+
+
+
+ {% if sum_before_states > sum_after_states %} +
+ {% trans 'Missing surfaces according to states before: ' %}{{ diff_states|floatformat:2 }} m² +
+ {% endif %} + + + + + + + + + + {% for state in after_states %} + + + + + + {% endfor %} + +
+ {% trans 'Biotope type' %} + + {% trans 'Surface' %} + + {% trans 'Action' %} +
+ {{ state.biotope_type }} + {{ state.surface|floatformat:2 }} m² + {% if is_default_member and has_access %} + + {% endif %} +
+
+
\ No newline at end of file diff --git a/ema/templates/ema/detail/includes/states-before.html b/ema/templates/ema/detail/includes/states-before.html new file mode 100644 index 00000000..74220659 --- /dev/null +++ b/ema/templates/ema/detail/includes/states-before.html @@ -0,0 +1,62 @@ +{% load i18n l10n fontawesome_5 %} +
+
+
+
+
+ {{obj.before_states.count}} + {% trans 'States before' %} +
+
+
+
+ {% if is_default_member and has_access %} + + {% endif %} +
+
+
+
+
+ {% if sum_before_states < sum_after_states %} +
+ {% trans 'Missing surfaces according to states after: ' %}{{ diff_states|floatformat:2 }} m² +
+ {% endif %} + + + + + + + + + + {% for state in before_states %} + + + + + + {% endfor %} + +
+ {% trans 'Biotope type' %} + + {% trans 'Surface' %} + + {% trans 'Action' %} +
+ {{ state.biotope_type }} + {{ state.surface|floatformat:2 }} m² + {% if is_default_member and has_access %} + + {% endif %} +
+
+
\ No newline at end of file diff --git a/ema/templates/ema/detail/view.html b/ema/templates/ema/detail/view.html new file mode 100644 index 00000000..57a73c8e --- /dev/null +++ b/ema/templates/ema/detail/view.html @@ -0,0 +1,100 @@ +{% extends 'base.html' %} +{% load i18n l10n static fontawesome_5 humanize %} + +{% block head %} + +{% endblock %} + +{% block body %} + +
+
+

{{obj.identifier}}

+
+
+ {% include 'ema/detail/includes/controls.html' %} +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + +
{% trans 'Title' %}{{obj.title}}
{% trans 'Recorded' %} + {% if obj.recorded is None %} + + {% fa5_icon 'bookmark' 'far' %} + + {% else %} + + {% fa5_icon 'bookmark' %} + + {% endif %} +
{% trans 'Last modified' %} + {% if obj.modified %} + {{obj.modified.timestamp|default_if_none:""|naturalday}} +
+ {{obj.modified.user.username}} + {% else %} + {{obj.created.timestamp|default_if_none:""|naturalday}} +
+ {{obj.created.user.username}} + + {% endif %} +
{% trans 'Shared with' %} + {% for user in obj.users.all %} + {% include 'user/includes/contact_modal_button.html' %} + {% endfor %} +
+
+
+
+ {% include 'map/geom_form.html' %} +
+
+
+ +
+
+ {% include 'ema/detail/includes/states-before.html' %} +
+
+ {% include 'ema/detail/includes/states-after.html' %} +
+
+
+
+ {% include 'ema/detail/includes/actions.html' %} +
+
+ {% include 'ema/detail/includes/deadlines.html' %} +
+
+
+
+ {% include 'ema/detail/includes/documents.html' %} +
+
+ + +{% with 'btn-modal' as btn_class %} + {% include 'modal/modal_form_script.html' %} +{% endwith %} + +{% endblock %} \ No newline at end of file diff --git a/ema/urls.py b/ema/urls.py index 97cef3b3..c3f5bd31 100644 --- a/ema/urls.py +++ b/ema/urls.py @@ -6,11 +6,28 @@ Created on: 19.08.21 """ from django.urls import path -from ema.views import index_view, new_view, open_view +from ema.views import * app_name = "ema" urlpatterns = [ path("", index_view, name="index"), path("new/", new_view, name="new"), path("", open_view, name="open"), + path('/log', log_view, name='log'), + path('/edit', edit_view, name='edit'), + path('/remove', remove_view, name='remove'), + path('/record', record_view, name='record'), + path('/state/new', state_new_view, name='new-state'), + path('/action/new', action_new_view, name='new-action'), + path('/deadline/new', deadline_new_view, name="new-deadline"), + + # Documents + # Document remove route can be found in konova/urls.py + path('/document/new/', document_new_view, name='new-doc'), + + # Generic state routes + path('state//remove', state_remove_view, name='state-remove'), + + # Generic action routes + path('action//remove', action_remove_view, name='action-remove'), ] \ No newline at end of file diff --git a/ema/views.py b/ema/views.py index febf4f4c..2f6a6650 100644 --- a/ema/views.py +++ b/ema/views.py @@ -1,16 +1,24 @@ from django.contrib.auth.decorators import login_required +from django.db.models import Sum from django.http import HttpRequest from django.shortcuts import render, get_object_or_404 +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ +import compensation +from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm from ema.tables import EmaTable from konova.contexts import BaseContext from konova.decorators import conservation_office_group_required from ema.models import Ema +from konova.forms import RemoveModalForm, NewDocumentForm, SimpleGeomForm, RecordForm +from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP +from konova.utils.user_checks import in_group @login_required def index_view(request: HttpRequest): - """ Renders the index view for MAEs + """ Renders the index view for EMAs Args: request (HttpRequest): The incoming request @@ -38,7 +46,7 @@ def index_view(request: HttpRequest): @login_required @conservation_office_group_required def new_view(request: HttpRequest): - """ Renders the form for a new MAE + """ Renders the form for a new EMA Args: request (HttpRequest): The incoming request @@ -54,17 +62,224 @@ def new_view(request: HttpRequest): @login_required def open_view(request: HttpRequest, id: str): - """ Renders the form for a new MAE + """ Renders the detail view of an EMA Args: request (HttpRequest): The incoming request - id (str): The MAE id + id (str): The EMA id + + Returns: + + """ + template = "ema/detail/view.html" + ema = get_object_or_404(Ema, id=id, deleted=None) + + geom_form = SimpleGeomForm(instance=ema) + _user = request.user + is_data_shared = ema.is_shared_with(_user) + + # Order states according to surface + before_states = ema.before_states.all().order_by("-surface") + after_states = ema.after_states.all().order_by("-surface") + + # Precalculate logical errors between before- and after-states + # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling + sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0 + sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 + diff_states = abs(sum_before_states - sum_after_states) + + context = { + "obj": ema, + "geom_form": geom_form, + "has_access": is_data_shared, + "before_states": before_states, + "after_states": after_states, + "sum_before_states": sum_before_states, + "sum_after_states": sum_after_states, + "diff_states": diff_states, + "is_default_member": in_group(_user, DEFAULT_GROUP), + "is_zb_member": in_group(_user, ZB_GROUP), + "is_ets_member": in_group(_user, ETS_GROUP), + "LANIS_LINK": ema.get_LANIS_link(), + } + context = BaseContext(request, context).context + return render(request, template, context) + + +@login_required +def log_view(request: HttpRequest, id: str): + """ Renders a log view using modal + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id Returns: """ ema = get_object_or_404(Ema, id=id) - template = "generic_index.html" - context = {} + template = "modal/modal_generic.html" + body_template = "log.html" + + context = { + "modal_body_template": body_template, + "log": ema.log.all(), + "modal_title": _("Log"), + } context = BaseContext(request, context).context return render(request, template, context) + + +@login_required +def edit_view(request: HttpRequest, id: str): + get_object_or_404(Ema, id=id) + + +@login_required +def remove_view(request: HttpRequest, id: str): + """ Renders a modal view for removing the EMA + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id + + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = RemoveModalForm(request.POST or None, instance=ema, user=request.user) + return form.process_request( + request=request, + msg_success=_("EMA removed"), + redirect_url=reverse("ema:index"), + ) + + +@login_required +def record_view(request: HttpRequest, id: str): + """ Renders a modal view for recording the EMA + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id + + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = RecordForm(request.POST or None, instance=ema, user=request.user) + return form.process_request( + request=request, + msg_success=_("EMA recorded"), + ) + + +@login_required +def state_new_view(request: HttpRequest, id: str): + """ Renders a form for adding new states for an EMA + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id to which the new state will be related + + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = NewStateModalForm(request.POST or None, instance=ema, user=request.user) + return form.process_request( + request, + msg_success=_("State added") + ) + + +@login_required +def action_new_view(request: HttpRequest, id: str): + """ Renders a form for adding new actions for an EMA + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id to which the new state will be related + + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = NewActionModalForm(request.POST or None, instance=ema, user=request.user) + return form.process_request( + request, + msg_success=_("Action added") + ) + + +@login_required +def deadline_new_view(request: HttpRequest, id: str): + """ Renders a form for adding new states for an EMA + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id to which the new state will be related + + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = NewDeadlineModalForm(request.POST or None, instance=ema, user=request.user) + return form.process_request( + request, + msg_success=_("Deadline added") + ) + + +@login_required +def document_new_view(request: HttpRequest, id: str): + """ Renders a form for uploading new documents + + Args: + request (HttpRequest): The incoming request + id (str): The EMA's id to which the new document will be related + Returns: + + """ + ema = get_object_or_404(Ema, id=id) + form = NewDocumentForm(request.POST or None, request.FILES or None, instance=ema, user=request.user) + return form.process_request( + request, + msg_success=_("Document added") + ) + + +@login_required +def state_remove_view(request: HttpRequest, id: str): + """ Renders a form for removing an EMA state + + Args: + request (HttpRequest): The incoming request + id (str): The state's id + + Returns: + + """ + return compensation.views.compensation_views.state_remove_view( + request, + id + ) + + +@login_required +def action_remove_view(request: HttpRequest, id: str): + """ Renders a form for removing an EMA state + + Args: + request (HttpRequest): The incoming request + id (str): The state's id + + Returns: + + """ + # Reuses the route logic from compensation view + return compensation.views.compensation_views.action_remove_view( + request, + id + ) + diff --git a/intervention/models.py b/intervention/models.py index 67d75d04..22bbf943 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -174,7 +174,7 @@ class Intervention(BaseObject): """ Quality check Returns: - ret_msgs (list): True if quality acceptable, False otherwise + ret_msgs (list): Holds error messages """ ret_msgs = [] diff --git a/konova/forms.py b/konova/forms.py index 474f7f77..7142f6cf 100644 --- a/konova/forms.py +++ b/konova/forms.py @@ -22,6 +22,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from compensation.models import EcoAccount +from ema.models import Ema from intervention.models import Intervention from konova.contexts import BaseContext from konova.models import Document, BaseObject @@ -370,7 +371,8 @@ class RecordForm(BaseModalForm): implemented_cls_logic = { Intervention, - EcoAccount + EcoAccount, + Ema, } instance_name = self.instance.__class__ if instance_name not in implemented_cls_logic: diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index cef9d83300f94b684dc238d14b28dc8143893605..6841eca927d6953bc99f76d2e42a536ffe34059c 100644 GIT binary patch delta 4858 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

ZrUgePNC$4E zFsLM;oX{~KsRgVLpdn^xF$z=}kx($Ug^`LAh-nqn5-m|slhW@mXPcSiv%6={?tlNg zd*F?&&a+#cP`5v9o8c$LF=iB=i8N*<<%R^c8Z$S=7#HW^di)CgxH{Fd5hJKSk1_Zn zj=*+|!#~^hE(}sXZ`*HRk})9@muAdJ9t5qW7*BmBCgOcaN3+B}UyB-e3u>YkTi9i*52O08wr)gapb5v} z4*VW=q89Qw4#xq^!>|lvh{cS>80I(C6tvR2Q5_efCippO<-fGgpSJZqs6bys^?wJI zkuFpwyHVry+2=m?m0dM4sQyWqjiWH6h^A4{3ky-(z6!OXr%*3EgUUcNYT`W@z*jL0 zPoOe&+CIOC3g`+dpg~kd<1)SRQc>gQWRibPkVk_eEVfQXO;Cv%=zi1yi%~BwM+I7s zO7WAZ{>`Y&wW9X^4a~(8ScHA3g=S=Vffr|ye+^VhgH}+D3SzJEqPD8Zx(k)T1Ge6Qx(%Td6twbFw&4OQ(q7bxK1FrBikk2m zsy*x`Z!cqUEcF16!z$DYmm>$>tVF&4H0u2()B=C!)k9_<1x5B6>aZNM^)sk}x=}0a zMWysR)Ic%ZG4)TyNmzjD_cK%m>QNbJL}g|N>MR{V&36=&b^kjlXwNR9?qxsnaWZj1 zb>MKK2A+=Eq90)aZbD6P5Os);p#u90>P(!o?cJz;A0rpR^rIG%Fq%v>6Q zoTNbmoJSqTf1~zDVTM68MqoTDkYsBiDihODTQv){Rr632KZfPF6*b{|cspK1WiCIT z{D)I0$@e0gf(oDtb%^dm4ZIXJ(K^&Xn^A$a;83bDlKMf^792rk@bA_hRA%~6;|$pL z$Pgz<50X(Y1aUZ);7_m&Nrq{%zK%K6Kf*%v@ka}|*;K46@^beUYD2$~cgFnOY4%CWjQF}NWM_?UBV?9RUI^-sq2Gl3{0LI`cRKIhm4D@1^ zW6YQMBK6XnjX8`TV!rPG_F`|v$54@FygjLOs% zRI2+i9(@zMlqaGxF&Z^)F>1UTTYnHkN@YC-`M7lxDy7>{d)ikrt88V%vAx`aaZFbYL1DM{U(b9I5-?PeF$+d>UUr9EJQJ z#4JLs_zCL{)ZYF9wI!!e1AmA*{g+T@B)*)iVHu9YI@H!Zi#j_euo}O`&;$yV)4dcu zic0kc)b-keO5t;;y?g<+HTy9O-@*j!K?QUbbryUT-j+n7G7^tE)S0LSO+*D=T|xde zz}>cCAu6@YF&jgumHig^e4FE_0j^>;MttA9J-K+A`VUY6r&oF@4qB%mub5g?rZ=JH z*;N_xR?tR+0y&0?^sKFah8l1Xb1z9XGK^f{y%tRg58r1vqQJGqW3b+xK+2>J* z^%YdVwh)DM3h$s&^^tw>1uCG38Q#{UVhQyERH`39vTc^4-g^ZV=poeBy@^`syO@Rl z!XSp-=8cz+3NTbgK`;Ig73uw`0qQUV>rs)qw*Inx{x)iWzo7#C1eK9*PyvR|^v+BG zS5eQzeEf~|DCX$?U!tJMqBxQoU>qt{WvF{Q!+J0Js4qet#wDo!D^LNfvGpw&L45~m zA-ho5vlaDT2Xe#BTR2Mhe~^M!l772)y^3)X^*d3S`86t)4X6z5#vJ@3YDMoOH+bmo z=EAf)yg(PACVm(-{v#NH8&QF8##o)|?G(n~OQ=)*F6wk%L3JFo^(ePFA?QT8hZC~H z0}iWpdlE976n8KoCHx!u88^*e|%nc7Lb%whu0(s5|w>fZY@_+T%{w%{J-ne1hPXp7PWVaxBLHO4+hPlrq zXE<^0{^V@untM8Vh7;o^q$D~c-7zV_v~TU}b;uzz57@e|eO}51fBUS$!Ho9V)t?Rf EACln!WdHyG diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index c26bd1b1..96e44af1 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -1276,7 +1276,7 @@ msgstr "Filter anwenden" #: templates/log.html:7 msgid "Timestamp" -msgstr "" +msgstr "Zeitpunkt" #: templates/log.html:13 msgid "User"