diff --git a/compensation/models.py b/compensation/models.py
index 8e0dde35..a8584b31 100644
--- a/compensation/models.py
+++ b/compensation/models.py
@@ -248,6 +248,10 @@ class EcoAccount(AbstractCompensation):
y,
)
+ def quality_check(self) -> (bool, dict):
+ # ToDo
+ pass
+
class EcoAccountWithdraw(BaseResource):
"""
diff --git a/compensation/templates/compensation/detail/eco_account/includes/controls.html b/compensation/templates/compensation/detail/eco_account/includes/controls.html
index b09e3554..e7543612 100644
--- a/compensation/templates/compensation/detail/eco_account/includes/controls.html
+++ b/compensation/templates/compensation/detail/eco_account/includes/controls.html
@@ -13,11 +13,15 @@
{% if has_access %}
{% if is_ets_member %}
-
-
-
+ {% if obj.recorded %}
+
+ {% else %}
+
+ {% endif %}
{% endif %}
{% if is_default_member %}
diff --git a/compensation/urls.py b/compensation/urls.py
index 7b12765a..c36d45a5 100644
--- a/compensation/urls.py
+++ b/compensation/urls.py
@@ -24,6 +24,7 @@ urlaptterns_eco_acc = [
path('acc/new/', eco_account_views.new_view, name='acc-new'),
path('acc/', eco_account_views.open_view, name='acc-open'),
path('acc//log', eco_account_views.log_view, name='acc-log'),
+ path('acc//record', eco_account_views.record_view, name='acc-record'),
path('acc//edit', eco_account_views.edit_view, name='acc-edit'),
path('acc//remove', eco_account_views.remove_view, name='acc-remove'),
path('acc//state/new', eco_account_views.state_new_view, name='acc-new-state'),
diff --git a/compensation/views/eco_account_views.py b/compensation/views/eco_account_views.py
index 650a1f78..084c9a9b 100644
--- a/compensation/views/eco_account_views.py
+++ b/compensation/views/eco_account_views.py
@@ -18,8 +18,8 @@ from compensation.models import EcoAccount
from compensation.tables import EcoAccountTable
from intervention.forms import NewWithdrawForm
from konova.contexts import BaseContext
-from konova.decorators import any_group_check, default_group_required
-from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm
+from konova.decorators import any_group_check, default_group_required, conservation_office_group_required
+from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm, RecordForm
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
from konova.utils.user_checks import in_group
@@ -188,6 +188,28 @@ def log_view(request: HttpRequest, id: str):
return render(request, template, context)
+@login_required
+@conservation_office_group_required
+def record_view(request: HttpRequest, id:str):
+ """ Renders a modal form for recording an eco account
+
+ Args:
+ request (HttpRequest): The incoming request
+ id (str): The account's id
+
+ Returns:
+
+ """
+ acc = get_object_or_404(EcoAccount, id=id)
+ form = RecordForm(request.POST or None, instance=acc, user=request.user)
+ msg_succ = _("{} unrecorded") if acc.recorded else _("{} recorded")
+ msg_succ = msg_succ.format(acc.identifier)
+ return form.process_request(
+ request,
+ msg_succ
+ )
+
+
@login_required
def state_new_view(request: HttpRequest, id: str):
""" Renders a form for adding new states for an eco account
diff --git a/intervention/forms.py b/intervention/forms.py
index 5e69a755..afdf3341 100644
--- a/intervention/forms.py
+++ b/intervention/forms.py
@@ -408,9 +408,13 @@ class RunCheckForm(BaseModalForm):
def is_valid(self):
super_result = super().is_valid()
# Perform check
- result, msgs = self.instance.check_validity()
- self.errors.update(msgs)
- return result & super_result
+ msgs = self.instance.quality_check()
+ for msg in msgs:
+ self.add_error(
+ "checked_intervention",
+ msg
+ )
+ return super_result and (len(msgs) == 0)
def save(self):
with transaction.atomic():
diff --git a/intervention/models.py b/intervention/models.py
index f5867b26..40f2f672 100644
--- a/intervention/models.py
+++ b/intervention/models.py
@@ -194,39 +194,62 @@ class Intervention(BaseObject):
self.identifier = new_id
super().save(*args, **kwargs)
- def check_validity(self) -> (bool, dict):
- """ Validity check
+ def quality_check(self) -> list:
+ """ Quality check
+
+ Returns:
+ ret_msgs (list): True if quality acceptable, False otherwise
+ """
+ ret_msgs = []
+
+ self._check_quality_responsible_data(ret_msgs)
+ self._check_quality_legal_data(ret_msgs)
+
+ # ToDo: Extend for more!
+
+ return ret_msgs
+
+ def _check_quality_responsible_data(self, ret_msgs: list):
+ """ Checks data quality of related ResponsibilityData
+
+ Args:
+ ret_msgs (dict): Holds error messages
Returns:
"""
- ret_msgs = {}
- missing_str = _("Missing")
- not_missing_str = _("Exists")
+ try:
+ # Check for file numbers
+ if not self.responsible.registration_file_number or len(self.responsible.registration_file_number) == 0:
+ ret_msgs.append(_("Registration office file number missing"))
- # Check responsible data
- if self.responsible:
- if self.responsible.registration_file_number is None or len(self.responsible.registration_file_number) == 0:
- ret_msgs["Registration office file number"] = missing_str
- if self.responsible.conservation_file_number is None or len(self.responsible.conservation_file_number) == 0:
- ret_msgs["Conversation office file number"] = missing_str
- else:
- ret_msgs["responsible"] = missing_str
+ if not self.responsible.conservation_file_number or len(self.responsible.conservation_file_number) == 0:
+ ret_msgs.append(_("Conversation office file number missing"))
+ except AttributeError:
+ # responsible data not found
+ ret_msgs.append(_("Responsible data missing"))
- # Check revocation
- if self.legal.revocation:
- ret_msgs["Revocation"] = not_missing_str
+ def _check_quality_legal_data(self, ret_msgs: list):
+ """ Checks data quality of related LegalData
+
+ Args:
+ ret_msgs (dict): Holds error messages
+
+ Returns:
+
+ """
+ try:
+ # Check for a revocation
+ if self.legal.revocation:
+ ret_msgs.append(_("Revocation exists"))
- if self.legal:
if self.legal.registration_date is None:
- ret_msgs["Registration date"] = missing_str
- if self.legal.binding_date is None:
- ret_msgs["Binding on"] = missing_str
- else:
- ret_msgs["legal"] = missing_str
+ ret_msgs.append(_("Registration date missing"))
- ret_result = len(ret_msgs) == 0
- return ret_result, ret_msgs
+ if self.legal.binding_date is None:
+ ret_msgs.append(_("Binding on missing"))
+ except AttributeError:
+ ret_msgs.append(_("Legal data missing"))
def get_LANIS_link(self) -> str:
""" Generates a link for LANIS depending on the geometry
@@ -248,4 +271,4 @@ class Intervention(BaseObject):
zoom_lvl,
x,
y,
- )
\ No newline at end of file
+ )
diff --git a/intervention/templates/intervention/detail/includes/controls.html b/intervention/templates/intervention/detail/includes/controls.html
index ef263d93..77a749af 100644
--- a/intervention/templates/intervention/detail/includes/controls.html
+++ b/intervention/templates/intervention/detail/includes/controls.html
@@ -12,33 +12,37 @@
{% if has_access %}
-
- {% if is_zb_member %}
-
- {% endif %}
- {% if is_ets_member %}
-
-
- {% endif %}
- {% if is_default_member %}
-
-
- {% fa5_icon 'edit' %}
+ {% if is_zb_member %}
+
+ {% fa5_icon 'star' %}
+
+ {% endif %}
+ {% if is_ets_member %}
+ {% if intervention.recorded %}
+
+ {% fa5_icon 'bookmark' 'far' %}
+
+ {% else %}
+
+ {% fa5_icon 'bookmark' %}
+
+ {% endif %}
+ {% endif %}
+ {% if is_default_member %}
+
+
+ {% fa5_icon 'edit' %}
+
+
+
+ {% fa5_icon 'history' %}
+
+
+ {% fa5_icon 'trash' %}
-
-
- {% fa5_icon 'history' %}
-
-
- {% fa5_icon 'trash' %}
-
{% endif %}
{% endif %}
\ No newline at end of file
diff --git a/intervention/urls.py b/intervention/urls.py
index 05f580b8..97f8241c 100644
--- a/intervention/urls.py
+++ b/intervention/urls.py
@@ -8,7 +8,8 @@ Created on: 30.11.20
from django.urls import path
from intervention.views import index_view, new_view, open_view, edit_view, remove_view, new_document_view, share_view, \
- create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_withdraw_view
+ create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_withdraw_view, \
+ record_view
app_name = "intervention"
urlpatterns = [
@@ -22,6 +23,7 @@ urlpatterns = [
path('/share/', share_view, name='share'),
path('/share', create_share_view, name='share-create'),
path('/check', run_check_view, name='run-check'),
+ path('/record', record_view, name='record'),
# Withdraws
path('/withdraw/new', new_withdraw_view, name='acc-new-withdraw'),
diff --git a/intervention/views.py b/intervention/views.py
index 432fea52..f9df7265 100644
--- a/intervention/views.py
+++ b/intervention/views.py
@@ -10,9 +10,9 @@ from intervention.models import Intervention, Revocation
from intervention.tables import InterventionTable
from konova.contexts import BaseContext
from konova.decorators import *
-from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm
+from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm, RecordForm
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
-from konova.utils.message_templates import FORM_INVALID
+from konova.utils.message_templates import FORM_INVALID, INTERVENTION_INVALID
from konova.utils.user_checks import in_group
@@ -304,34 +304,11 @@ def run_check_view(request: HttpRequest, id: str):
"""
intervention = get_object_or_404(Intervention, id=id)
form = RunCheckForm(request.POST or None, instance=intervention, user=request.user)
- if request.method == "POST":
- if form.is_valid():
- form.save()
- messages.info(
- request,
- _("Check performed")
- )
- else:
- messages.error(
- request,
- _("There has been errors on this intervention:"),
- extra_tags="danger"
- )
- for error_name, error_val in form.errors.items():
- messages.error(
- request,
- _("{}: {}").format(_(error_name), _(error_val)),
- extra_tags="danger"
- )
- return redirect(request.META.get("HTTP_REFERER", "home"))
- elif request.method == "GET":
- context = {
- "form": form,
- }
- context = BaseContext(request, context).context
- return render(request, form.template, context)
- else:
- raise NotImplementedError
+ return form.process_request(
+ request,
+ msg_success=_("Check performed"),
+ msg_error=INTERVENTION_INVALID
+ )
@login_required
@@ -413,3 +390,26 @@ def new_withdraw_view(request: HttpRequest, id: str):
request,
msg_success=_("Withdraw added")
)
+
+
+@login_required
+@conservation_office_group_required
+def record_view(request: HttpRequest, id: str):
+ """ Renders a modal form for recording an intervention
+
+ Args:
+ request (HttpRequest): The incoming request
+ id (str): The intervention's id
+
+ Returns:
+
+ """
+ intervention = get_object_or_404(Intervention, id=id)
+ form = RecordForm(request.POST or None, instance=intervention, user=request.user)
+ msg_succ = _("{} unrecorded") if intervention.recorded else _("{} recorded")
+ msg_succ = msg_succ.format(intervention.identifier)
+ return form.process_request(
+ request,
+ msg_succ,
+ msg_error=_("There are errors on this intervention:")
+ )
\ No newline at end of file
diff --git a/konova/forms.py b/konova/forms.py
index 36717d98..86c75b36 100644
--- a/konova/forms.py
+++ b/konova/forms.py
@@ -20,6 +20,8 @@ from django.shortcuts import redirect, render
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
+from compensation.models import EcoAccount
+from intervention.models import Intervention
from konova.contexts import BaseContext
from konova.models import Document, BaseObject
from konova.utils.message_templates import FORM_INVALID
@@ -328,3 +330,71 @@ class NewDocumentForm(BaseModalForm):
self.instance.log.add(edited_action)
return doc
+
+
+class RecordForm(BaseModalForm):
+ """ Modal form for recording data
+
+ """
+ confirm = forms.BooleanField(
+ label=_("Confirm record"),
+ label_suffix="",
+ widget=forms.CheckboxInput(),
+ required=True,
+ )
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.form_title = _("Record data")
+ self.form_caption = _("I, {} {}, confirm that all necessary control steps have been performed by myself.").format(self.user.first_name, self.user.last_name)
+
+ if self.instance.recorded:
+ # unrecord!
+ self.fields["confirm"].label = _("Confirm unrecord")
+ self.form_title = _("Unrecord data")
+ self.form_caption = _("I, {} {}, confirm that this data must be unrecorded.").format(self.user.first_name, self.user.last_name)
+
+ implemented_cls_logic = {
+ Intervention,
+ EcoAccount
+ }
+ instance_name = self.instance.__class__
+ if instance_name not in implemented_cls_logic:
+ raise NotImplementedError
+
+ def is_valid(self):
+ """ Checks for instance's validity and data quality
+
+ Returns:
+
+ """
+ super_val = super().is_valid()
+ msgs = self.instance.quality_check()
+ for msg in msgs:
+ self.add_error(
+ "confirm",
+ msg
+ )
+ return super_val and (len(msgs) == 0)
+
+ def save(self):
+ with transaction.atomic():
+ if self.cleaned_data["confirm"]:
+ if self.instance.recorded:
+ # unrecord!
+ unrecord_action = UserActionLogEntry.objects.create(
+ user=self.user,
+ action=UserAction.UNRECORDED
+ )
+ # Do not delete the old .recorded attribute, since it shall stay in the .log list!
+ self.instance.recorded = None
+ self.instance.log.add(unrecord_action)
+ else:
+ record_action = UserActionLogEntry.objects.create(
+ user=self.user,
+ action=UserAction.RECORDED
+ )
+ self.instance.recorded = record_action
+ self.instance.log.add(record_action)
+ self.instance.save()
+ return self.instance
\ No newline at end of file
diff --git a/konova/management/commands/setup_data.py b/konova/management/commands/setup_data.py
index 396e5c18..91082bd0 100644
--- a/konova/management/commands/setup_data.py
+++ b/konova/management/commands/setup_data.py
@@ -8,7 +8,6 @@ Created on: 15.12.20
from django.utils.translation import gettext_lazy as _
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
-from user.enums import UserNotificationEnum
TEST_ORGANISATION_DATA = [
{
diff --git a/konova/utils/message_templates.py b/konova/utils/message_templates.py
index ca701dcf..109d7c83 100644
--- a/konova/utils/message_templates.py
+++ b/konova/utils/message_templates.py
@@ -9,3 +9,4 @@ from django.utils.translation import gettext_lazy as _
FORM_INVALID = _("There was an error on this form.")
+INTERVENTION_INVALID = _("There are errors in this intervention.")
diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo
index c1e769b4..189b3213 100644
Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index d9622951..0059cdea 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -16,7 +16,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-08-10 14:11+0200\n"
+"POT-Creation-Date: 2021-08-10 14:39+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -384,19 +384,19 @@ msgid "Public report"
msgstr "Öffentlicher Bericht"
#: compensation/templates/compensation/detail/compensation/includes/controls.html:17
-#: compensation/templates/compensation/detail/eco_account/includes/controls.html:17
+#: compensation/templates/compensation/detail/eco_account/includes/controls.html:28
#: intervention/templates/intervention/detail/includes/controls.html:32
msgid "Edit"
msgstr "Bearbeiten"
#: compensation/templates/compensation/detail/compensation/includes/controls.html:21
-#: compensation/templates/compensation/detail/eco_account/includes/controls.html:21
+#: compensation/templates/compensation/detail/eco_account/includes/controls.html:32
#: intervention/templates/intervention/detail/includes/controls.html:36
msgid "Show log"
msgstr "Log anzeigen"
#: compensation/templates/compensation/detail/compensation/includes/controls.html:24
-#: compensation/templates/compensation/detail/eco_account/includes/controls.html:24
+#: compensation/templates/compensation/detail/eco_account/includes/controls.html:35
#: intervention/templates/intervention/detail/includes/controls.html:39
#: venv/lib/python3.7/site-packages/django/forms/formsets.py:391
msgid "Delete"
@@ -522,6 +522,15 @@ msgstr "Zuletzt bearbeitet"
msgid "Shared with"
msgstr "Freigegeben für"
+#: compensation/templates/compensation/detail/eco_account/includes/controls.html:17
+msgid "Unrecord"
+msgstr "Entzeichnen"
+
+#: compensation/templates/compensation/detail/eco_account/includes/controls.html:21
+#: intervention/templates/intervention/detail/includes/controls.html:25
+msgid "Record"
+msgstr "Verzeichnen"
+
#: compensation/templates/compensation/detail/eco_account/includes/withdraws.html:8
#: intervention/templates/intervention/detail/includes/withdraws.html:8
msgid "Eco Account Withdraws"
@@ -538,7 +547,7 @@ msgstr "Eingriffskennung"
#: compensation/templates/compensation/detail/eco_account/includes/withdraws.html:34
#: intervention/templates/intervention/detail/includes/withdraws.html:34
-#: user/models.py:50
+#: user/models.py:51
msgid "Created"
msgstr "Erstellt"
@@ -567,22 +576,22 @@ msgid "Compensation removed"
msgstr "Kompensation entfernt"
#: compensation/views/compensation_views.py:162
-#: compensation/views/eco_account_views.py:262 intervention/views.py:96
+#: compensation/views/eco_account_views.py:275 intervention/views.py:96
msgid "Document added"
msgstr "Dokument hinzugefügt"
#: compensation/views/compensation_views.py:181
-#: compensation/views/eco_account_views.py:206
+#: compensation/views/eco_account_views.py:219
msgid "State added"
msgstr "Zustand hinzugefügt"
#: compensation/views/compensation_views.py:200
-#: compensation/views/eco_account_views.py:225
+#: compensation/views/eco_account_views.py:238
msgid "Action added"
msgstr "Maßnahme hinzugefügt"
#: compensation/views/compensation_views.py:219
-#: compensation/views/eco_account_views.py:244
+#: compensation/views/eco_account_views.py:257
msgid "Deadline added"
msgstr "Frist hinzugefügt"
@@ -602,7 +611,15 @@ msgstr "Ökokonto entfernt"
msgid "Withdraw removed"
msgstr "Abbuchung entfernt"
-#: compensation/views/eco_account_views.py:282 intervention/views.py:414
+#: compensation/views/eco_account_views.py:196
+msgid "{} unrecorded"
+msgstr "{} entzeichnet"
+
+#: compensation/views/eco_account_views.py:196
+msgid "{} recorded"
+msgstr "{} verzeichnet"
+
+#: compensation/views/eco_account_views.py:295 intervention/views.py:414
msgid "Withdraw added"
msgstr "Abbuchung hinzugefügt"
@@ -748,7 +765,7 @@ msgstr "Kompensationen und Zahlungen geprüft"
msgid "Run check"
msgstr "Prüfung vornehmen"
-#: intervention/forms.py:406
+#: intervention/forms.py:406 konova/forms.py:347
msgid ""
"I, {} {}, confirm that all necessary control steps have been performed by "
"myself."
@@ -802,12 +819,12 @@ msgstr ""
#: intervention/templates/intervention/detail/view.html:90
#: intervention/templates/intervention/detail/view.html:94
#: intervention/templates/intervention/detail/view.html:98
-msgid "Missing"
-msgstr "Fehlt"
+msgid "missing"
+msgstr "fehlt"
#: intervention/models.py:205
-msgid "Exists"
-msgstr "Existiert"
+msgid "exists"
+msgstr "vorhanden"
#: intervention/tables.py:70
msgid "Interventions"
@@ -829,10 +846,6 @@ msgstr "Neue Kompensation hinzufügen"
msgid "Remove compensation"
msgstr "Kompensation entfernen"
-#: intervention/templates/intervention/detail/includes/controls.html:25
-msgid "Record"
-msgstr "Verzeichnen"
-
#: intervention/templates/intervention/detail/includes/payments.html:8
msgid "Payments"
msgstr "Ersatzzahlungen"
@@ -1024,27 +1037,47 @@ msgstr "Datei"
msgid "Added document"
msgstr "Dokument hinzugefügt"
-#: konova/management/commands/setup_data.py:42
+#: konova/forms.py:338
+msgid "Confirm record"
+msgstr "Verzeichnen bestätigen"
+
+#: konova/forms.py:346
+msgid "Record data"
+msgstr "Daten verzeichnen"
+
+#: konova/forms.py:351
+msgid "Confirm unrecord"
+msgstr "Entzeichnen bestätigen"
+
+#: konova/forms.py:352
+msgid "Unrecord data"
+msgstr "Daten entzeichnen"
+
+#: konova/forms.py:353
+msgid "I, {} {}, confirm that this data must be unrecorded."
+msgstr "Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
+
+#: konova/management/commands/setup_data.py:41
msgid "On new related data"
msgstr "Wenn neue Daten für mich angelegt werden"
-#: konova/management/commands/setup_data.py:43
+#: konova/management/commands/setup_data.py:42
msgid "On disabled share link"
msgstr "Wenn ein Freigabelink deaktiviert wird"
-#: konova/management/commands/setup_data.py:44
+#: konova/management/commands/setup_data.py:43
msgid "On shared access removed"
msgstr "Wenn mir eine Freigabe zu Daten entzogen wird"
-#: konova/management/commands/setup_data.py:45
+#: konova/management/commands/setup_data.py:44
msgid "On shared data recorded"
msgstr "Wenn meine freigegebenen Daten verzeichnet wurden"
-#: konova/management/commands/setup_data.py:46
+#: konova/management/commands/setup_data.py:45
msgid "On shared data deleted"
msgstr "Wenn meine freigegebenen Daten gelöscht wurden"
-#: konova/management/commands/setup_data.py:47
+#: konova/management/commands/setup_data.py:46
msgid "On registered data edited"
msgstr "Wenn meine freigegebenen Daten bearbeitet wurden"
@@ -1276,11 +1309,15 @@ msgstr ""
msgid "User contact data"
msgstr "Kontaktdaten"
-#: user/models.py:51
+#: user/models.py:50
+msgid "Unrecorded"
+msgstr "Entzeichnet"
+
+#: user/models.py:52
msgid "Edited"
msgstr "Bearbeitet"
-#: user/models.py:52
+#: user/models.py:53
msgid "Deleted"
msgstr "Gelöscht"
@@ -2552,9 +2589,6 @@ msgstr ""
#~ msgid "Delete eco account"
#~ msgstr "Ökokonto löschen"
-#~ msgid "Confirm check on data"
-#~ msgstr "Datenprüfung bestätigen"
-
#~ msgid "Add new EMA"
#~ msgstr "Neue EMA hinzufügen"
diff --git a/user/models.py b/user/models.py
index ebeb5cff..d8d73206 100644
--- a/user/models.py
+++ b/user/models.py
@@ -47,6 +47,7 @@ class UserAction(models.TextChoices):
"""
CHECKED = "checked", _("Checked")
RECORDED = "recorded", _("Recorded")
+ UNRECORDED = "unrecorded", _("Unrecorded")
CREATED = "created", _("Created")
EDITED = "edited", _("Edited")
DELETED = "deleted", _("Deleted")