#169 Admin on teams
* adds admin column on team index view * refactors Team model, so multiple members can become admins * adds team migration for switch from fkey->m2m structure * renames 'Group' to 'Permission' on user index view to avoid confusion between 'Groups' and Teams * adds new autocomplete route for team-admin selection based on already selected members of the TeamForm
This commit is contained in:
parent
eb3b9eb5c1
commit
8aa3fbd97a
@ -108,6 +108,29 @@ class ShareTeamAutocomplete(Select2QuerySetView):
|
|||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
class TeamAdminAutocomplete(Select2QuerySetView):
|
||||||
|
""" Autocomplete for share with teams
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_queryset(self):
|
||||||
|
if self.request.user.is_anonymous:
|
||||||
|
return User.objects.none()
|
||||||
|
qs = User.objects.filter(
|
||||||
|
id__in=self.forwarded.get("members", [])
|
||||||
|
).exclude(
|
||||||
|
id__in=self.forwarded.get("admins", [])
|
||||||
|
)
|
||||||
|
if self.q:
|
||||||
|
# Due to privacy concerns only a full username match will return the proper user entry
|
||||||
|
qs = qs.filter(
|
||||||
|
name__icontains=self.q
|
||||||
|
)
|
||||||
|
qs = qs.order_by(
|
||||||
|
"username"
|
||||||
|
)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class KonovaCodeAutocomplete(Select2GroupQuerySetView):
|
class KonovaCodeAutocomplete(Select2GroupQuerySetView):
|
||||||
"""
|
"""
|
||||||
Provides simple autocomplete functionality for codes
|
Provides simple autocomplete functionality for codes
|
||||||
|
@ -326,7 +326,7 @@ class SimpleGeomForm(BaseForm):
|
|||||||
features = []
|
features = []
|
||||||
features_json = geom.get("features", [])
|
features_json = geom.get("features", [])
|
||||||
for feature in features_json:
|
for feature in features_json:
|
||||||
g = gdal.OGRGeometry(json.dumps(feature["geometry"]), srs=DEFAULT_SRID_RLP)
|
g = gdal.OGRGeometry(json.dumps(feature.get("geometry", feature)), srs=DEFAULT_SRID_RLP)
|
||||||
if g.geom_type not in ["Polygon", "MultiPolygon"]:
|
if g.geom_type not in ["Polygon", "MultiPolygon"]:
|
||||||
self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered."))
|
self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered."))
|
||||||
is_valid = False
|
is_valid = False
|
||||||
|
@ -72,6 +72,7 @@ class AutocompleteTestCase(BaseTestCase):
|
|||||||
"codes-conservation-office-autocomplete",
|
"codes-conservation-office-autocomplete",
|
||||||
"share-user-autocomplete",
|
"share-user-autocomplete",
|
||||||
"share-team-autocomplete",
|
"share-team-autocomplete",
|
||||||
|
"team-admin-autocomplete",
|
||||||
]
|
]
|
||||||
for test in tests:
|
for test in tests:
|
||||||
self.client.login(username=self.superuser.username, password=self.superuser_pw)
|
self.client.login(username=self.superuser.username, password=self.superuser_pw)
|
||||||
|
@ -274,7 +274,7 @@ class BaseTestCase(TestCase):
|
|||||||
team = Team.objects.get_or_create(
|
team = Team.objects.get_or_create(
|
||||||
name="Testteam",
|
name="Testteam",
|
||||||
description="Testdescription",
|
description="Testdescription",
|
||||||
admin=self.superuser,
|
admins__in=[self.superuser],
|
||||||
)[0]
|
)[0]
|
||||||
team.users.add(self.superuser)
|
team.users.add(self.superuser)
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from konova.autocompletes import EcoAccountAutocomplete, \
|
|||||||
InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete, LawCodeAutocomplete, \
|
InterventionAutocomplete, CompensationActionCodeAutocomplete, BiotopeCodeAutocomplete, LawCodeAutocomplete, \
|
||||||
RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete, ProcessTypeCodeAutocomplete, \
|
RegistrationOfficeCodeAutocomplete, ConservationOfficeCodeAutocomplete, ProcessTypeCodeAutocomplete, \
|
||||||
ShareUserAutocomplete, BiotopeExtraCodeAutocomplete, CompensationActionDetailCodeAutocomplete, \
|
ShareUserAutocomplete, BiotopeExtraCodeAutocomplete, CompensationActionDetailCodeAutocomplete, \
|
||||||
ShareTeamAutocomplete, HandlerCodeAutocomplete
|
ShareTeamAutocomplete, HandlerCodeAutocomplete, TeamAdminAutocomplete
|
||||||
from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
|
from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
|
||||||
from konova.sso.sso import KonovaSSOClient
|
from konova.sso.sso import KonovaSSOClient
|
||||||
from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content, map_client_proxy_view
|
from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content, map_client_proxy_view
|
||||||
@ -58,6 +58,7 @@ urlpatterns = [
|
|||||||
path("atcmplt/codes/handler", HandlerCodeAutocomplete.as_view(), name="codes-handler-autocomplete"),
|
path("atcmplt/codes/handler", HandlerCodeAutocomplete.as_view(), name="codes-handler-autocomplete"),
|
||||||
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
path("atcmplt/share/u", ShareUserAutocomplete.as_view(), name="share-user-autocomplete"),
|
||||||
path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"),
|
path("atcmplt/share/t", ShareTeamAutocomplete.as_view(), name="share-team-autocomplete"),
|
||||||
|
path("atcmplt/team/admin", TeamAdminAutocomplete.as_view(), name="team-admin-autocomplete"),
|
||||||
]
|
]
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
|
Binary file not shown.
@ -26,7 +26,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-05-30 09:16+0200\n"
|
"POT-Creation-Date: 2022-05-30 11:51+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -65,7 +65,7 @@ msgstr "Verantwortliche Stelle"
|
|||||||
#: intervention/forms/forms.py:64 intervention/forms/forms.py:81
|
#: intervention/forms/forms.py:64 intervention/forms/forms.py:81
|
||||||
#: intervention/forms/forms.py:97 intervention/forms/forms.py:113
|
#: intervention/forms/forms.py:97 intervention/forms/forms.py:113
|
||||||
#: intervention/forms/forms.py:154 intervention/forms/modalForms.py:49
|
#: intervention/forms/forms.py:154 intervention/forms/modalForms.py:49
|
||||||
#: intervention/forms/modalForms.py:63 user/forms.py:196
|
#: intervention/forms/modalForms.py:63 user/forms.py:196 user/forms.py:260
|
||||||
msgid "Click for selection"
|
msgid "Click for selection"
|
||||||
msgstr "Auswählen..."
|
msgstr "Auswählen..."
|
||||||
|
|
||||||
@ -138,11 +138,11 @@ msgstr "Zuständigkeitsbereich"
|
|||||||
#: analysis/templates/analysis/reports/includes/intervention/amount.html:17
|
#: analysis/templates/analysis/reports/includes/intervention/amount.html:17
|
||||||
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:8
|
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:8
|
||||||
#: analysis/templates/analysis/reports/includes/intervention/laws.html:17
|
#: analysis/templates/analysis/reports/includes/intervention/laws.html:17
|
||||||
#: compensation/tables.py:41
|
#: compensation/tables.py:38
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:64
|
#: compensation/templates/compensation/detail/compensation/view.html:64
|
||||||
#: intervention/tables.py:40
|
#: intervention/tables.py:38
|
||||||
#: intervention/templates/intervention/detail/view.html:68
|
#: intervention/templates/intervention/detail/view.html:68
|
||||||
#: user/models/user_action.py:20
|
#: user/models/user_action.py:21
|
||||||
msgid "Checked"
|
msgid "Checked"
|
||||||
msgstr "Geprüft"
|
msgstr "Geprüft"
|
||||||
|
|
||||||
@ -154,14 +154,14 @@ msgstr "Geprüft"
|
|||||||
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9
|
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9
|
||||||
#: analysis/templates/analysis/reports/includes/intervention/laws.html:20
|
#: analysis/templates/analysis/reports/includes/intervention/laws.html:20
|
||||||
#: analysis/templates/analysis/reports/includes/old_data/amount.html:18
|
#: analysis/templates/analysis/reports/includes/old_data/amount.html:18
|
||||||
#: compensation/tables.py:47 compensation/tables.py:230
|
#: compensation/tables.py:44 compensation/tables.py:219
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:78
|
#: compensation/templates/compensation/detail/compensation/view.html:83
|
||||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
|
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:45
|
#: compensation/templates/compensation/detail/eco_account/view.html:45
|
||||||
#: ema/tables.py:44 ema/templates/ema/detail/view.html:35
|
#: ema/tables.py:44 ema/templates/ema/detail/view.html:35
|
||||||
#: intervention/tables.py:46
|
#: intervention/tables.py:44
|
||||||
#: intervention/templates/intervention/detail/view.html:82
|
#: intervention/templates/intervention/detail/view.html:87
|
||||||
#: user/models/user_action.py:21
|
#: user/models/user_action.py:22
|
||||||
msgid "Recorded"
|
msgid "Recorded"
|
||||||
msgstr "Verzeichnet"
|
msgstr "Verzeichnet"
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ msgid "Other registration office"
|
|||||||
msgstr "Andere Zulassungsbehörden"
|
msgstr "Andere Zulassungsbehörden"
|
||||||
|
|
||||||
#: analysis/templates/analysis/reports/includes/compensation/card_compensation.html:11
|
#: analysis/templates/analysis/reports/includes/compensation/card_compensation.html:11
|
||||||
#: compensation/tables.py:68
|
#: compensation/tables.py:65
|
||||||
#: intervention/templates/intervention/detail/includes/compensations.html:8
|
#: intervention/templates/intervention/detail/includes/compensations.html:8
|
||||||
#: intervention/templates/intervention/report/report.html:45
|
#: intervention/templates/intervention/report/report.html:45
|
||||||
msgid "Compensations"
|
msgid "Compensations"
|
||||||
@ -227,7 +227,7 @@ msgid "Surface"
|
|||||||
msgstr "Fläche"
|
msgstr "Fläche"
|
||||||
|
|
||||||
#: analysis/templates/analysis/reports/includes/intervention/card_intervention.html:10
|
#: analysis/templates/analysis/reports/includes/intervention/card_intervention.html:10
|
||||||
#: intervention/tables.py:67
|
#: intervention/tables.py:65
|
||||||
msgid "Interventions"
|
msgid "Interventions"
|
||||||
msgstr "Eingriffe"
|
msgstr "Eingriffe"
|
||||||
|
|
||||||
@ -285,8 +285,8 @@ msgid "Type"
|
|||||||
msgstr "Typ"
|
msgstr "Typ"
|
||||||
|
|
||||||
#: analysis/templates/analysis/reports/includes/old_data/amount.html:24
|
#: analysis/templates/analysis/reports/includes/old_data/amount.html:24
|
||||||
#: compensation/tables.py:90 intervention/forms/modalForms.py:375
|
#: compensation/tables.py:87 intervention/forms/modalForms.py:375
|
||||||
#: intervention/forms/modalForms.py:382 intervention/tables.py:89
|
#: intervention/forms/modalForms.py:382 intervention/tables.py:87
|
||||||
#: intervention/templates/intervention/detail/view.html:19
|
#: intervention/templates/intervention/detail/view.html:19
|
||||||
#: konova/templates/konova/includes/quickstart/interventions.html:4
|
#: konova/templates/konova/includes/quickstart/interventions.html:4
|
||||||
#: templates/navbars/navbar.html:22
|
#: templates/navbars/navbar.html:22
|
||||||
@ -294,7 +294,7 @@ msgid "Intervention"
|
|||||||
msgstr "Eingriff"
|
msgstr "Eingriff"
|
||||||
|
|
||||||
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34
|
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34
|
||||||
#: compensation/tables.py:274
|
#: compensation/tables.py:263
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:20
|
#: compensation/templates/compensation/detail/eco_account/view.html:20
|
||||||
#: intervention/forms/modalForms.py:348 intervention/forms/modalForms.py:355
|
#: intervention/forms/modalForms.py:348 intervention/forms/modalForms.py:355
|
||||||
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:4
|
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:4
|
||||||
@ -314,9 +314,9 @@ msgstr "Vor"
|
|||||||
msgid "Show only unrecorded"
|
msgid "Show only unrecorded"
|
||||||
msgstr "Nur unverzeichnete anzeigen"
|
msgstr "Nur unverzeichnete anzeigen"
|
||||||
|
|
||||||
#: compensation/forms/forms.py:32 compensation/tables.py:26
|
#: compensation/forms/forms.py:32 compensation/tables.py:23
|
||||||
#: compensation/tables.py:205 ema/tables.py:29 intervention/forms/forms.py:28
|
#: compensation/tables.py:194 ema/tables.py:29 intervention/forms/forms.py:28
|
||||||
#: intervention/tables.py:25
|
#: intervention/tables.py:23
|
||||||
#: intervention/templates/intervention/detail/includes/compensations.html:30
|
#: intervention/templates/intervention/detail/includes/compensations.html:30
|
||||||
msgid "Identifier"
|
msgid "Identifier"
|
||||||
msgstr "Kennung"
|
msgstr "Kennung"
|
||||||
@ -326,8 +326,8 @@ msgstr "Kennung"
|
|||||||
msgid "Generated automatically"
|
msgid "Generated automatically"
|
||||||
msgstr "Automatisch generiert"
|
msgstr "Automatisch generiert"
|
||||||
|
|
||||||
#: compensation/forms/forms.py:44 compensation/tables.py:31
|
#: compensation/forms/forms.py:44 compensation/tables.py:28
|
||||||
#: compensation/tables.py:210
|
#: compensation/tables.py:199
|
||||||
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28
|
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:32
|
#: compensation/templates/compensation/detail/compensation/view.html:32
|
||||||
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
|
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
|
||||||
@ -337,7 +337,7 @@ msgstr "Automatisch generiert"
|
|||||||
#: ema/tables.py:34 ema/templates/ema/detail/includes/documents.html:28
|
#: ema/tables.py:34 ema/templates/ema/detail/includes/documents.html:28
|
||||||
#: ema/templates/ema/detail/view.html:31
|
#: ema/templates/ema/detail/view.html:31
|
||||||
#: ema/templates/ema/report/report.html:12 intervention/forms/forms.py:40
|
#: ema/templates/ema/report/report.html:12 intervention/forms/forms.py:40
|
||||||
#: intervention/tables.py:30
|
#: intervention/tables.py:28
|
||||||
#: intervention/templates/intervention/detail/includes/compensations.html:33
|
#: intervention/templates/intervention/detail/includes/compensations.html:33
|
||||||
#: intervention/templates/intervention/detail/includes/documents.html:28
|
#: intervention/templates/intervention/detail/includes/documents.html:28
|
||||||
#: intervention/templates/intervention/detail/view.html:31
|
#: intervention/templates/intervention/detail/view.html:31
|
||||||
@ -675,62 +675,62 @@ msgstr ""
|
|||||||
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
|
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
|
||||||
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
|
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
|
||||||
|
|
||||||
#: compensation/tables.py:36 compensation/tables.py:215 ema/tables.py:39
|
#: compensation/tables.py:33 compensation/tables.py:204 ema/tables.py:39
|
||||||
#: intervention/tables.py:35 konova/filters/mixins.py:98
|
#: intervention/tables.py:33 konova/filters/mixins.py:98
|
||||||
msgid "Parcel gmrkng"
|
msgid "Parcel gmrkng"
|
||||||
msgstr "Gemarkung"
|
msgstr "Gemarkung"
|
||||||
|
|
||||||
#: compensation/tables.py:53 compensation/tables.py:236 ema/tables.py:50
|
#: compensation/tables.py:50 compensation/tables.py:225 ema/tables.py:50
|
||||||
#: intervention/tables.py:52
|
#: intervention/tables.py:50
|
||||||
msgid "Editable"
|
msgid "Editable"
|
||||||
msgstr "Freigegeben"
|
msgstr "Freigegeben"
|
||||||
|
|
||||||
#: compensation/tables.py:59 compensation/tables.py:242 ema/tables.py:56
|
#: compensation/tables.py:56 compensation/tables.py:231 ema/tables.py:56
|
||||||
#: intervention/tables.py:58
|
#: intervention/tables.py:56
|
||||||
msgid "Last edit"
|
msgid "Last edit"
|
||||||
msgstr "Zuletzt bearbeitet"
|
msgstr "Zuletzt bearbeitet"
|
||||||
|
|
||||||
#: compensation/tables.py:90 compensation/tables.py:274 ema/tables.py:89
|
#: compensation/tables.py:87 compensation/tables.py:263 ema/tables.py:89
|
||||||
#: intervention/tables.py:89
|
#: intervention/tables.py:87
|
||||||
msgid "Open {}"
|
msgid "Open {}"
|
||||||
msgstr "Öffne {}"
|
msgstr "Öffne {}"
|
||||||
|
|
||||||
#: compensation/tables.py:170
|
#: compensation/tables.py:163
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:81
|
#: compensation/templates/compensation/detail/compensation/view.html:86
|
||||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:58
|
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:58
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:48
|
#: compensation/templates/compensation/detail/eco_account/view.html:48
|
||||||
#: ema/tables.py:131 ema/templates/ema/detail/view.html:38
|
#: ema/tables.py:130 ema/templates/ema/detail/view.html:38
|
||||||
#: intervention/tables.py:167
|
#: intervention/tables.py:161
|
||||||
#: intervention/templates/intervention/detail/view.html:85
|
#: intervention/templates/intervention/detail/view.html:90
|
||||||
msgid "Not recorded yet"
|
msgid "Not recorded yet"
|
||||||
msgstr "Noch nicht verzeichnet"
|
msgstr "Noch nicht verzeichnet"
|
||||||
|
|
||||||
#: compensation/tables.py:175 compensation/tables.py:334 ema/tables.py:136
|
#: compensation/tables.py:166 compensation/tables.py:321 ema/tables.py:133
|
||||||
#: intervention/tables.py:172
|
#: intervention/tables.py:164
|
||||||
msgid "Recorded on {} by {}"
|
msgid "Recorded on {} by {}"
|
||||||
msgstr "Am {} von {} verzeichnet worden"
|
msgstr "Am {} von {} verzeichnet worden"
|
||||||
|
|
||||||
#: compensation/tables.py:197 compensation/tables.py:356 ema/tables.py:157
|
#: compensation/tables.py:186 compensation/tables.py:343 ema/tables.py:154
|
||||||
#: intervention/tables.py:193
|
#: intervention/tables.py:185
|
||||||
msgid "Full access granted"
|
msgid "Full access granted"
|
||||||
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
|
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
|
||||||
|
|
||||||
#: compensation/tables.py:197 compensation/tables.py:356 ema/tables.py:157
|
#: compensation/tables.py:186 compensation/tables.py:343 ema/tables.py:154
|
||||||
#: intervention/tables.py:193
|
#: intervention/tables.py:185
|
||||||
msgid "Access not granted"
|
msgid "Access not granted"
|
||||||
msgstr "Nicht freigegeben - Datensatz nur lesbar"
|
msgstr "Nicht freigegeben - Datensatz nur lesbar"
|
||||||
|
|
||||||
#: compensation/tables.py:220
|
#: compensation/tables.py:209
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:36
|
#: compensation/templates/compensation/detail/eco_account/view.html:36
|
||||||
#: konova/templates/konova/widgets/progressbar.html:3
|
#: konova/templates/konova/widgets/progressbar.html:3
|
||||||
msgid "Available"
|
msgid "Available"
|
||||||
msgstr "Verfügbar"
|
msgstr "Verfügbar"
|
||||||
|
|
||||||
#: compensation/tables.py:251
|
#: compensation/tables.py:240
|
||||||
msgid "Eco Accounts"
|
msgid "Eco Accounts"
|
||||||
msgstr "Ökokonten"
|
msgstr "Ökokonten"
|
||||||
|
|
||||||
#: compensation/tables.py:329
|
#: compensation/tables.py:318
|
||||||
msgid "Not recorded yet. Can not be used for deductions, yet."
|
msgid "Not recorded yet. Can not be used for deductions, yet."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
|
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
|
||||||
@ -782,7 +782,7 @@ msgstr "Menge"
|
|||||||
#: intervention/templates/intervention/detail/includes/documents.html:39
|
#: intervention/templates/intervention/detail/includes/documents.html:39
|
||||||
#: intervention/templates/intervention/detail/includes/payments.html:39
|
#: intervention/templates/intervention/detail/includes/payments.html:39
|
||||||
#: intervention/templates/intervention/detail/includes/revocation.html:43
|
#: intervention/templates/intervention/detail/includes/revocation.html:43
|
||||||
#: templates/log.html:10 user/templates/user/team/index.html:32
|
#: templates/log.html:10 user/templates/user/team/index.html:33
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "Aktionen"
|
msgstr "Aktionen"
|
||||||
|
|
||||||
@ -975,43 +975,43 @@ msgstr "Nein"
|
|||||||
msgid "Is Coherence keeping compensation"
|
msgid "Is Coherence keeping compensation"
|
||||||
msgstr "Ist Kohärenzsicherungsmaßnahme"
|
msgstr "Ist Kohärenzsicherungsmaßnahme"
|
||||||
|
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:71
|
#: compensation/templates/compensation/detail/compensation/view.html:76
|
||||||
#: intervention/templates/intervention/detail/view.html:75
|
#: intervention/templates/intervention/detail/view.html:80
|
||||||
msgid "Checked on "
|
msgid "Checked on "
|
||||||
msgstr "Geprüft am "
|
msgstr "Geprüft am "
|
||||||
|
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:71
|
#: compensation/templates/compensation/detail/compensation/view.html:76
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:85
|
#: compensation/templates/compensation/detail/compensation/view.html:90
|
||||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56
|
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:52
|
#: compensation/templates/compensation/detail/eco_account/view.html:52
|
||||||
#: ema/templates/ema/detail/view.html:42
|
#: ema/templates/ema/detail/view.html:42
|
||||||
#: intervention/templates/intervention/detail/view.html:75
|
#: intervention/templates/intervention/detail/view.html:80
|
||||||
#: intervention/templates/intervention/detail/view.html:89
|
#: intervention/templates/intervention/detail/view.html:94
|
||||||
msgid "by"
|
msgid "by"
|
||||||
msgstr "von"
|
msgstr "von"
|
||||||
|
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:85
|
#: compensation/templates/compensation/detail/compensation/view.html:90
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:52
|
#: compensation/templates/compensation/detail/eco_account/view.html:52
|
||||||
#: ema/templates/ema/detail/view.html:42
|
#: ema/templates/ema/detail/view.html:42
|
||||||
#: intervention/templates/intervention/detail/view.html:89
|
#: intervention/templates/intervention/detail/view.html:94
|
||||||
msgid "Recorded on "
|
msgid "Recorded on "
|
||||||
msgstr "Verzeichnet am"
|
msgstr "Verzeichnet am"
|
||||||
|
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:92
|
#: compensation/templates/compensation/detail/compensation/view.html:97
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:75
|
#: compensation/templates/compensation/detail/eco_account/view.html:75
|
||||||
#: compensation/templates/compensation/report/compensation/report.html:24
|
#: compensation/templates/compensation/report/compensation/report.html:24
|
||||||
#: compensation/templates/compensation/report/eco_account/report.html:37
|
#: compensation/templates/compensation/report/eco_account/report.html:37
|
||||||
#: ema/templates/ema/detail/view.html:61
|
#: ema/templates/ema/detail/view.html:61
|
||||||
#: ema/templates/ema/report/report.html:24
|
#: ema/templates/ema/report/report.html:24
|
||||||
#: intervention/templates/intervention/detail/view.html:108
|
#: intervention/templates/intervention/detail/view.html:113
|
||||||
#: intervention/templates/intervention/report/report.html:87
|
#: intervention/templates/intervention/report/report.html:87
|
||||||
msgid "Last modified"
|
msgid "Last modified"
|
||||||
msgstr "Zuletzt bearbeitet"
|
msgstr "Zuletzt bearbeitet"
|
||||||
|
|
||||||
#: compensation/templates/compensation/detail/compensation/view.html:106
|
#: compensation/templates/compensation/detail/compensation/view.html:111
|
||||||
#: compensation/templates/compensation/detail/eco_account/view.html:89
|
#: compensation/templates/compensation/detail/eco_account/view.html:89
|
||||||
#: ema/templates/ema/detail/view.html:75
|
#: ema/templates/ema/detail/view.html:75
|
||||||
#: intervention/templates/intervention/detail/view.html:122
|
#: intervention/templates/intervention/detail/view.html:127
|
||||||
msgid "Shared with"
|
msgid "Shared with"
|
||||||
msgstr "Freigegeben für"
|
msgstr "Freigegeben für"
|
||||||
|
|
||||||
@ -1050,7 +1050,7 @@ msgstr "Eingriffskennung"
|
|||||||
|
|
||||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:37
|
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:37
|
||||||
#: intervention/templates/intervention/detail/includes/deductions.html:34
|
#: intervention/templates/intervention/detail/includes/deductions.html:34
|
||||||
#: user/models/user_action.py:23
|
#: user/models/user_action.py:24
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr "Erstellt"
|
msgstr "Erstellt"
|
||||||
|
|
||||||
@ -1087,8 +1087,8 @@ msgstr "Keine Flächenmenge für Abbuchungen eingegeben. Bitte bearbeiten."
|
|||||||
#: intervention/templates/intervention/detail/view.html:55
|
#: intervention/templates/intervention/detail/view.html:55
|
||||||
#: intervention/templates/intervention/detail/view.html:59
|
#: intervention/templates/intervention/detail/view.html:59
|
||||||
#: intervention/templates/intervention/detail/view.html:63
|
#: intervention/templates/intervention/detail/view.html:63
|
||||||
#: intervention/templates/intervention/detail/view.html:95
|
#: intervention/templates/intervention/detail/view.html:100
|
||||||
#: intervention/templates/intervention/detail/view.html:99
|
#: intervention/templates/intervention/detail/view.html:104
|
||||||
msgid "Missing"
|
msgid "Missing"
|
||||||
msgstr "fehlt"
|
msgstr "fehlt"
|
||||||
|
|
||||||
@ -1142,17 +1142,17 @@ msgid "Compensation {} edited"
|
|||||||
msgstr "Kompensation {} bearbeitet"
|
msgstr "Kompensation {} bearbeitet"
|
||||||
|
|
||||||
#: compensation/views/compensation.py:182 compensation/views/eco_account.py:173
|
#: compensation/views/compensation.py:182 compensation/views/eco_account.py:173
|
||||||
#: ema/views.py:240 intervention/views.py:332
|
#: ema/views.py:240 intervention/views.py:338
|
||||||
msgid "Edit {}"
|
msgid "Edit {}"
|
||||||
msgstr "Bearbeite {}"
|
msgstr "Bearbeite {}"
|
||||||
|
|
||||||
#: compensation/views/compensation.py:261 compensation/views/eco_account.py:359
|
#: compensation/views/compensation.py:268 compensation/views/eco_account.py:359
|
||||||
#: ema/views.py:194 intervention/views.py:536
|
#: ema/views.py:194 intervention/views.py:542
|
||||||
msgid "Log"
|
msgid "Log"
|
||||||
msgstr "Log"
|
msgstr "Log"
|
||||||
|
|
||||||
#: compensation/views/compensation.py:605 compensation/views/eco_account.py:727
|
#: compensation/views/compensation.py:612 compensation/views/eco_account.py:727
|
||||||
#: ema/views.py:558 intervention/views.py:682
|
#: ema/views.py:558 intervention/views.py:688
|
||||||
msgid "Report {}"
|
msgid "Report {}"
|
||||||
msgstr "Bericht {}"
|
msgstr "Bericht {}"
|
||||||
|
|
||||||
@ -1173,32 +1173,32 @@ msgid "Eco-account removed"
|
|||||||
msgstr "Ökokonto entfernt"
|
msgstr "Ökokonto entfernt"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:380 ema/views.py:282
|
#: compensation/views/eco_account.py:380 ema/views.py:282
|
||||||
#: intervention/views.py:635
|
#: intervention/views.py:641
|
||||||
msgid "{} unrecorded"
|
msgid "{} unrecorded"
|
||||||
msgstr "{} entzeichnet"
|
msgstr "{} entzeichnet"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:380 ema/views.py:282
|
#: compensation/views/eco_account.py:380 ema/views.py:282
|
||||||
#: intervention/views.py:635
|
#: intervention/views.py:641
|
||||||
msgid "{} recorded"
|
msgid "{} recorded"
|
||||||
msgstr "{} verzeichnet"
|
msgstr "{} verzeichnet"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:804 ema/views.py:628
|
#: compensation/views/eco_account.py:804 ema/views.py:628
|
||||||
#: intervention/views.py:433
|
#: intervention/views.py:439
|
||||||
msgid "{} has already been shared with you"
|
msgid "{} has already been shared with you"
|
||||||
msgstr "{} wurde bereits für Sie freigegeben"
|
msgstr "{} wurde bereits für Sie freigegeben"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:809 ema/views.py:633
|
#: compensation/views/eco_account.py:809 ema/views.py:633
|
||||||
#: intervention/views.py:438
|
#: intervention/views.py:444
|
||||||
msgid "{} has been shared with you"
|
msgid "{} has been shared with you"
|
||||||
msgstr "{} ist nun für Sie freigegeben"
|
msgstr "{} ist nun für Sie freigegeben"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:816 ema/views.py:640
|
#: compensation/views/eco_account.py:816 ema/views.py:640
|
||||||
#: intervention/views.py:445
|
#: intervention/views.py:451
|
||||||
msgid "Share link invalid"
|
msgid "Share link invalid"
|
||||||
msgstr "Freigabelink ungültig"
|
msgstr "Freigabelink ungültig"
|
||||||
|
|
||||||
#: compensation/views/eco_account.py:839 ema/views.py:663
|
#: compensation/views/eco_account.py:839 ema/views.py:663
|
||||||
#: intervention/views.py:468
|
#: intervention/views.py:474
|
||||||
msgid "Share settings updated"
|
msgid "Share settings updated"
|
||||||
msgstr "Freigabe Einstellungen aktualisiert"
|
msgstr "Freigabe Einstellungen aktualisiert"
|
||||||
|
|
||||||
@ -1292,14 +1292,14 @@ msgid "Intervention handler detail"
|
|||||||
msgstr "Detailangabe zum Eingriffsverursacher"
|
msgstr "Detailangabe zum Eingriffsverursacher"
|
||||||
|
|
||||||
#: intervention/forms/forms.py:173
|
#: intervention/forms/forms.py:173
|
||||||
#: intervention/templates/intervention/detail/view.html:96
|
#: intervention/templates/intervention/detail/view.html:101
|
||||||
#: intervention/templates/intervention/report/report.html:79
|
#: intervention/templates/intervention/report/report.html:79
|
||||||
#: intervention/utils/quality.py:73
|
#: intervention/utils/quality.py:73
|
||||||
msgid "Registration date"
|
msgid "Registration date"
|
||||||
msgstr "Datum Zulassung bzw. Satzungsbeschluss"
|
msgstr "Datum Zulassung bzw. Satzungsbeschluss"
|
||||||
|
|
||||||
#: intervention/forms/forms.py:185
|
#: intervention/forms/forms.py:185
|
||||||
#: intervention/templates/intervention/detail/view.html:100
|
#: intervention/templates/intervention/detail/view.html:105
|
||||||
#: intervention/templates/intervention/report/report.html:83
|
#: intervention/templates/intervention/report/report.html:83
|
||||||
msgid "Binding on"
|
msgid "Binding on"
|
||||||
msgstr "Datum Bestandskraft bzw. Rechtskraft"
|
msgstr "Datum Bestandskraft bzw. Rechtskraft"
|
||||||
@ -1471,7 +1471,7 @@ msgid "Remove payment"
|
|||||||
msgstr "Zahlung entfernen"
|
msgstr "Zahlung entfernen"
|
||||||
|
|
||||||
#: intervention/templates/intervention/detail/includes/revocation.html:8
|
#: intervention/templates/intervention/detail/includes/revocation.html:8
|
||||||
#: intervention/templates/intervention/detail/view.html:104
|
#: intervention/templates/intervention/detail/view.html:109
|
||||||
msgid "Revocations"
|
msgid "Revocations"
|
||||||
msgstr "Widersprüche"
|
msgstr "Widersprüche"
|
||||||
|
|
||||||
@ -1493,7 +1493,7 @@ msgstr "Widerspruch entfernen"
|
|||||||
msgid "Intervention handler"
|
msgid "Intervention handler"
|
||||||
msgstr "Eingriffsverursacher"
|
msgstr "Eingriffsverursacher"
|
||||||
|
|
||||||
#: intervention/templates/intervention/detail/view.html:103
|
#: intervention/templates/intervention/detail/view.html:108
|
||||||
msgid "Exists"
|
msgid "Exists"
|
||||||
msgstr "vorhanden"
|
msgstr "vorhanden"
|
||||||
|
|
||||||
@ -1532,19 +1532,19 @@ msgstr "Eingriffe - Übersicht"
|
|||||||
msgid "Intervention {} added"
|
msgid "Intervention {} added"
|
||||||
msgstr "Eingriff {} hinzugefügt"
|
msgstr "Eingriff {} hinzugefügt"
|
||||||
|
|
||||||
#: intervention/views.py:320
|
#: intervention/views.py:326
|
||||||
msgid "Intervention {} edited"
|
msgid "Intervention {} edited"
|
||||||
msgstr "Eingriff {} bearbeitet"
|
msgstr "Eingriff {} bearbeitet"
|
||||||
|
|
||||||
#: intervention/views.py:356
|
#: intervention/views.py:362
|
||||||
msgid "{} removed"
|
msgid "{} removed"
|
||||||
msgstr "{} entfernt"
|
msgstr "{} entfernt"
|
||||||
|
|
||||||
#: intervention/views.py:489
|
#: intervention/views.py:495
|
||||||
msgid "Check performed"
|
msgid "Check performed"
|
||||||
msgstr "Prüfung durchgeführt"
|
msgstr "Prüfung durchgeführt"
|
||||||
|
|
||||||
#: intervention/views.py:640
|
#: intervention/views.py:646
|
||||||
msgid "There are errors on this intervention:"
|
msgid "There are errors on this intervention:"
|
||||||
msgstr "Es liegen Fehler in diesem Eingriff vor:"
|
msgstr "Es liegen Fehler in diesem Eingriff vor:"
|
||||||
|
|
||||||
@ -2058,7 +2058,8 @@ msgstr "Am {} von {} geprüft worden"
|
|||||||
|
|
||||||
#: konova/utils/message_templates.py:87
|
#: konova/utils/message_templates.py:87
|
||||||
msgid "Data has changed since last check on {} by {}"
|
msgid "Data has changed since last check on {} by {}"
|
||||||
msgstr "Daten wurden nach der letzten Prüfung geändert. Letzte Prüfung am {} durch {}"
|
msgstr ""
|
||||||
|
"Daten wurden nach der letzten Prüfung geändert. Letzte Prüfung am {} durch {}"
|
||||||
|
|
||||||
#: konova/utils/message_templates.py:88
|
#: konova/utils/message_templates.py:88
|
||||||
msgid "Current data not checked yet"
|
msgid "Current data not checked yet"
|
||||||
@ -2547,11 +2548,11 @@ msgstr "Neuen Token generieren"
|
|||||||
msgid "A new token needs to be validated by an administrator!"
|
msgid "A new token needs to be validated by an administrator!"
|
||||||
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
|
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
|
||||||
|
|
||||||
#: user/forms.py:168 user/forms.py:172 user/forms.py:332 user/forms.py:337
|
#: user/forms.py:168 user/forms.py:172 user/forms.py:351 user/forms.py:356
|
||||||
msgid "Team name"
|
msgid "Team name"
|
||||||
msgstr "Team Name"
|
msgstr "Team Name"
|
||||||
|
|
||||||
#: user/forms.py:179 user/forms.py:345 user/templates/user/team/index.html:30
|
#: user/forms.py:179 user/forms.py:364 user/templates/user/team/index.html:30
|
||||||
msgid "Description"
|
msgid "Description"
|
||||||
msgstr "Beschreibung"
|
msgstr "Beschreibung"
|
||||||
|
|
||||||
@ -2579,43 +2580,61 @@ msgstr ""
|
|||||||
"Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich "
|
"Sie werden standardmäßig der Administrator dieses Teams. Sie müssen sich "
|
||||||
"selbst nicht zur Liste der Mitglieder hinzufügen."
|
"selbst nicht zur Liste der Mitglieder hinzufügen."
|
||||||
|
|
||||||
#: user/forms.py:218 user/forms.py:279
|
#: user/forms.py:218 user/forms.py:296
|
||||||
msgid "Name already taken. Try another."
|
msgid "Name already taken. Try another."
|
||||||
msgstr "Name bereits vergeben. Probieren Sie einen anderen."
|
msgstr "Name bereits vergeben. Probieren Sie einen anderen."
|
||||||
|
|
||||||
#: user/forms.py:249
|
#: user/forms.py:248
|
||||||
msgid "Admin"
|
msgid "Admins"
|
||||||
msgstr "Administrator"
|
msgstr "Administratoren"
|
||||||
|
|
||||||
#: user/forms.py:250
|
#: user/forms.py:250
|
||||||
msgid "Administrators manage team details and members"
|
msgid "Administrators manage team details and members"
|
||||||
msgstr "Administratoren verwalten die Teamdaten und Mitglieder"
|
msgstr "Administratoren verwalten die Teamdaten und Mitglieder"
|
||||||
|
|
||||||
#: user/forms.py:263
|
#: user/forms.py:273
|
||||||
msgid "Selected admin ({}) needs to be a member of this team."
|
msgid "Selected admins need to be members of this team."
|
||||||
msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein."
|
msgstr "Gewählte Administratoren müssen Teammitglieder sein."
|
||||||
|
|
||||||
#: user/forms.py:291 user/templates/user/team/index.html:54
|
#: user/forms.py:280
|
||||||
|
msgid "There must be at least one admin on this team."
|
||||||
|
msgstr "Es muss mindestens einen Administrator für das Team geben."
|
||||||
|
|
||||||
|
#: user/forms.py:308 user/templates/user/team/index.html:60
|
||||||
msgid "Edit team"
|
msgid "Edit team"
|
||||||
msgstr "Team bearbeiten"
|
msgstr "Team bearbeiten"
|
||||||
|
|
||||||
#: user/forms.py:323 user/templates/user/team/index.html:50
|
#: user/forms.py:336
|
||||||
|
msgid ""
|
||||||
|
"ATTENTION!\n"
|
||||||
|
"\n"
|
||||||
|
"Removing the team means all members will lose their access to data, based on "
|
||||||
|
"this team! \n"
|
||||||
|
"\n"
|
||||||
|
"Are you sure to remove this team?"
|
||||||
|
msgstr ""
|
||||||
|
"ACHTUNG!\n\n"
|
||||||
|
"Wenn dieses Team gelöscht wird, verlieren alle Teammitglieder den Zugriff auf die Daten, die nur über dieses Team freigegeben sind!\n"
|
||||||
|
"\n"
|
||||||
|
"Sind Sie sicher, dass Sie dieses Team löschen möchten?"
|
||||||
|
|
||||||
|
#: user/forms.py:342 user/templates/user/team/index.html:56
|
||||||
msgid "Leave team"
|
msgid "Leave team"
|
||||||
msgstr "Team verlassen"
|
msgstr "Team verlassen"
|
||||||
|
|
||||||
#: user/forms.py:356
|
#: user/forms.py:375
|
||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Team"
|
msgstr "Team"
|
||||||
|
|
||||||
#: user/models/user_action.py:22
|
#: user/models/user_action.py:23
|
||||||
msgid "Unrecorded"
|
msgid "Unrecorded"
|
||||||
msgstr "Entzeichnet"
|
msgstr "Entzeichnet"
|
||||||
|
|
||||||
#: user/models/user_action.py:24
|
#: user/models/user_action.py:25
|
||||||
msgid "Edited"
|
msgid "Edited"
|
||||||
msgstr "Bearbeitet"
|
msgstr "Bearbeitet"
|
||||||
|
|
||||||
#: user/models/user_action.py:25
|
#: user/models/user_action.py:26
|
||||||
msgid "Deleted"
|
msgid "Deleted"
|
||||||
msgstr "Gelöscht"
|
msgstr "Gelöscht"
|
||||||
|
|
||||||
@ -2632,8 +2651,8 @@ msgid "Name"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: user/templates/user/index.html:21
|
#: user/templates/user/index.html:21
|
||||||
msgid "Groups"
|
msgid "Permissions"
|
||||||
msgstr "Gruppen"
|
msgstr "Berechtigungen"
|
||||||
|
|
||||||
#: user/templates/user/index.html:34
|
#: user/templates/user/index.html:34
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -2689,7 +2708,11 @@ msgstr "Neues Team hinzufügen"
|
|||||||
msgid "Members"
|
msgid "Members"
|
||||||
msgstr "Mitglieder"
|
msgstr "Mitglieder"
|
||||||
|
|
||||||
#: user/templates/user/team/index.html:57
|
#: user/templates/user/team/index.html:32
|
||||||
|
msgid "Administrator"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: user/templates/user/team/index.html:63
|
||||||
msgid "Remove team"
|
msgid "Remove team"
|
||||||
msgstr "Team entfernen"
|
msgstr "Team entfernen"
|
||||||
|
|
||||||
@ -2741,19 +2764,19 @@ msgstr "API Nutzer Token"
|
|||||||
msgid "New team added"
|
msgid "New team added"
|
||||||
msgstr "Neues Team hinzugefügt"
|
msgstr "Neues Team hinzugefügt"
|
||||||
|
|
||||||
#: user/views.py:191
|
#: user/views.py:192
|
||||||
msgid "Team edited"
|
msgid "Team edited"
|
||||||
msgstr "Team bearbeitet"
|
msgstr "Team bearbeitet"
|
||||||
|
|
||||||
#: user/views.py:204
|
#: user/views.py:206
|
||||||
msgid "Team removed"
|
msgid "Team removed"
|
||||||
msgstr "Team gelöscht"
|
msgstr "Team gelöscht"
|
||||||
|
|
||||||
#: user/views.py:218
|
#: user/views.py:220
|
||||||
msgid "You are not a member of this team"
|
msgid "You are not a member of this team"
|
||||||
msgstr "Sie sind kein Mitglied dieses Teams"
|
msgstr "Sie sind kein Mitglied dieses Teams"
|
||||||
|
|
||||||
#: user/views.py:225
|
#: user/views.py:227
|
||||||
msgid "Left Team"
|
msgid "Left Team"
|
||||||
msgstr "Team verlassen"
|
msgstr "Team verlassen"
|
||||||
|
|
||||||
@ -4256,6 +4279,9 @@ msgstr ""
|
|||||||
msgid "Unable to connect to qpid with SASL mechanism %s"
|
msgid "Unable to connect to qpid with SASL mechanism %s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#~ msgid "Groups"
|
||||||
|
#~ msgstr "Gruppen"
|
||||||
|
|
||||||
#~ msgid "Show more..."
|
#~ msgid "Show more..."
|
||||||
#~ msgstr "Mehr anzeigen..."
|
#~ msgstr "Mehr anzeigen..."
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</h4>
|
</h4>
|
||||||
{% if form.form_caption is not None %}
|
{% if form.form_caption is not None %}
|
||||||
<small>
|
<small>
|
||||||
{{ form.form_caption }}
|
{{ form.form_caption|linebreaks }}
|
||||||
</small>
|
</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<form method="post" action="{{ form.action_url }}" {% for attr_key, attr_val in form.form_attrs.items %} {{attr_key}}="{{attr_val}}"{% endfor %}>
|
<form method="post" action="{{ form.action_url }}" {% for attr_key, attr_val in form.form_attrs.items %} {{attr_key}}="{{attr_val}}"{% endfor %}>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<article>
|
<article>
|
||||||
{{ form.form_caption }}
|
{{ form.form_caption|linebreaks }}
|
||||||
</article>
|
</article>
|
||||||
{% include 'form/table/generic_table_form_body.html' %}
|
{% include 'form/table/generic_table_form_body.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,22 +68,16 @@ class TeamAdmin(admin.ModelAdmin):
|
|||||||
list_display = [
|
list_display = [
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"admin",
|
|
||||||
]
|
]
|
||||||
search_fields = [
|
search_fields = [
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
]
|
]
|
||||||
filter_horizontal = [
|
filter_horizontal = [
|
||||||
"users"
|
"users",
|
||||||
|
"admins",
|
||||||
]
|
]
|
||||||
|
|
||||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
|
||||||
if db_field.name == "admin":
|
|
||||||
team_id = request.resolver_match.kwargs.get("object_id", None)
|
|
||||||
kwargs["queryset"] = User.objects.filter(teams__id__in=[team_id])
|
|
||||||
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(Team, TeamAdmin)
|
admin.site.register(Team, TeamAdmin)
|
||||||
|
@ -230,7 +230,7 @@ class NewTeamModalForm(BaseModalForm):
|
|||||||
team = Team.objects.create(
|
team = Team.objects.create(
|
||||||
name=self.cleaned_data.get("name", None),
|
name=self.cleaned_data.get("name", None),
|
||||||
description=self.cleaned_data.get("description", None),
|
description=self.cleaned_data.get("description", None),
|
||||||
admin=self.user,
|
admins__in=[self.user],
|
||||||
)
|
)
|
||||||
members = self.cleaned_data.get("members", User.objects.none())
|
members = self.cleaned_data.get("members", User.objects.none())
|
||||||
if self.user.id not in members:
|
if self.user.id not in members:
|
||||||
@ -244,23 +244,40 @@ class NewTeamModalForm(BaseModalForm):
|
|||||||
|
|
||||||
|
|
||||||
class EditTeamModalForm(NewTeamModalForm):
|
class EditTeamModalForm(NewTeamModalForm):
|
||||||
admin = forms.ModelChoiceField(
|
admins = forms.ModelMultipleChoiceField(
|
||||||
|
label=_("Admins"),
|
||||||
label_suffix="",
|
label_suffix="",
|
||||||
label=_("Admin"),
|
|
||||||
help_text=_("Administrators manage team details and members"),
|
help_text=_("Administrators manage team details and members"),
|
||||||
queryset=User.objects.none(),
|
required=True,
|
||||||
empty_label=None,
|
queryset=User.objects.all(),
|
||||||
|
widget=autocomplete.ModelSelect2Multiple(
|
||||||
|
url="team-admin-autocomplete",
|
||||||
|
forward=[
|
||||||
|
"members",
|
||||||
|
"admins",
|
||||||
|
],
|
||||||
|
attrs={
|
||||||
|
"data-placeholder": _("Click for selection"),
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def __is_admin_valid(self):
|
def __is_admins_valid(self):
|
||||||
admin = self.cleaned_data.get("admin", None)
|
admins = set(self.cleaned_data.get("admins", {}))
|
||||||
members = self.cleaned_data.get("members", None)
|
members = set(self.cleaned_data.get("members", {}))
|
||||||
_is_valid = admin in members
|
_is_valid = admins.issubset(members)
|
||||||
|
|
||||||
if not _is_valid:
|
if not _is_valid:
|
||||||
self.add_error(
|
self.add_error(
|
||||||
"members",
|
"admins",
|
||||||
_("Selected admin ({}) needs to be a member of this team.").format(admin.username)
|
_("Selected admins need to be members of this team.")
|
||||||
|
)
|
||||||
|
|
||||||
|
_is_admin_length_valid = len(admins) > 0
|
||||||
|
if not _is_admin_length_valid:
|
||||||
|
self.add_error(
|
||||||
|
"admins",
|
||||||
|
_("There must be at least one admin on this team.")
|
||||||
)
|
)
|
||||||
|
|
||||||
return _is_valid
|
return _is_valid
|
||||||
@ -283,7 +300,7 @@ class EditTeamModalForm(NewTeamModalForm):
|
|||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
super_valid = super().is_valid()
|
super_valid = super().is_valid()
|
||||||
admin_valid = self.__is_admin_valid()
|
admin_valid = self.__is_admins_valid()
|
||||||
return super_valid and admin_valid
|
return super_valid and admin_valid
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -293,13 +310,13 @@ class EditTeamModalForm(NewTeamModalForm):
|
|||||||
self.cancel_redirect = reverse("user:team-index")
|
self.cancel_redirect = reverse("user:team-index")
|
||||||
|
|
||||||
members = self.instance.users.all()
|
members = self.instance.users.all()
|
||||||
self.fields["admin"].queryset = members
|
#self.fields["admins"].queryset = members
|
||||||
|
|
||||||
form_data = {
|
form_data = {
|
||||||
"members": members,
|
"members": members,
|
||||||
"name": self.instance.name,
|
"name": self.instance.name,
|
||||||
"description": self.instance.description,
|
"description": self.instance.description,
|
||||||
"admin": self.instance.admin,
|
"admins": self.instance.admins.all(),
|
||||||
}
|
}
|
||||||
self.load_initial_data(form_data)
|
self.load_initial_data(form_data)
|
||||||
|
|
||||||
@ -307,14 +324,16 @@ class EditTeamModalForm(NewTeamModalForm):
|
|||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
self.instance.name = self.cleaned_data.get("name", None)
|
self.instance.name = self.cleaned_data.get("name", None)
|
||||||
self.instance.description = self.cleaned_data.get("description", None)
|
self.instance.description = self.cleaned_data.get("description", None)
|
||||||
self.instance.admin = self.cleaned_data.get("admin", None)
|
|
||||||
self.instance.save()
|
self.instance.save()
|
||||||
self.instance.users.set(self.cleaned_data.get("members", []))
|
self.instance.users.set(self.cleaned_data.get("members", []))
|
||||||
|
self.instance.admins.set(self.cleaned_data.get("admins", []))
|
||||||
return self.instance
|
return self.instance
|
||||||
|
|
||||||
|
|
||||||
class RemoveTeamModalForm(RemoveModalForm):
|
class RemoveTeamModalForm(RemoveModalForm):
|
||||||
pass
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.form_caption = _("ATTENTION!\n\nRemoving the team means all members will lose their access to data, based on this team! \n\nAre you sure to remove this team?")
|
||||||
|
|
||||||
|
|
||||||
class LeaveTeamModalForm(RemoveModalForm):
|
class LeaveTeamModalForm(RemoveModalForm):
|
||||||
|
35
user/migrations/0004_auto_20220530_1105.py
Normal file
35
user/migrations/0004_auto_20220530_1105.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Generated by Django 3.1.3 on 2022-05-30 09:05
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_fkey_admin_to_m2m(apps, schema_editor):
|
||||||
|
Team = apps.get_model('user', 'Team')
|
||||||
|
all_teams = Team.objects.all()
|
||||||
|
for team in all_teams:
|
||||||
|
admin = team.admin
|
||||||
|
if admin is None:
|
||||||
|
continue
|
||||||
|
team.admins.add(admin)
|
||||||
|
team.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('user', '0003_team'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='team',
|
||||||
|
name='admins',
|
||||||
|
field=models.ManyToManyField(blank=True, related_name='_team_admins_+', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.RunPython(migrate_fkey_admin_to_m2m),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='team',
|
||||||
|
name='admin',
|
||||||
|
),
|
||||||
|
]
|
@ -11,7 +11,7 @@ class Team(UuidModel):
|
|||||||
name = models.CharField(max_length=500, null=True, blank=True)
|
name = models.CharField(max_length=500, null=True, blank=True)
|
||||||
description = models.TextField(null=True, blank=True)
|
description = models.TextField(null=True, blank=True)
|
||||||
users = models.ManyToManyField("user.User", blank=True, related_name="teams")
|
users = models.ManyToManyField("user.User", blank=True, related_name="teams")
|
||||||
admin = models.ForeignKey("user.User", blank=True, null=True, related_name="+", on_delete=models.SET_NULL)
|
admins = models.ManyToManyField("user.User", blank=True, related_name="+")
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
@ -104,6 +104,19 @@ class Team(UuidModel):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
self.users.remove(user)
|
self.users.remove(user)
|
||||||
if self.admin == user:
|
self.admins.remove(user)
|
||||||
self.admin = self.users.first()
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
|
def is_user_admin(self, user) -> bool:
|
||||||
|
""" Returns whether a given user is an admin of the team
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (User): The user
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
user_is_admin (bool): Whether the user is an admin or not
|
||||||
|
"""
|
||||||
|
user_is_admin = self.admins.filter(
|
||||||
|
id=user.id
|
||||||
|
).exists()
|
||||||
|
return user_is_admin
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<td>{{user.email}}</td>
|
<td>{{user.email}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans 'Groups' %}</th>
|
<th scope="row">{% trans 'Permissions' %}</th>
|
||||||
<td>
|
<td>
|
||||||
{% for group in user.groups.all %}
|
{% for group in user.groups.all %}
|
||||||
<span class="badge badge-pill rlp-r">{% trans group.name %}</span>
|
<span class="badge badge-pill rlp-r">{% trans group.name %}</span>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
<th scope="col" class="align-middle">{% trans 'Name' %}</th>
|
<th scope="col" class="align-middle">{% trans 'Name' %}</th>
|
||||||
<th scope="col" class="align-middle w-20">{% trans 'Description' %}</th>
|
<th scope="col" class="align-middle w-20">{% trans 'Description' %}</th>
|
||||||
<th scope="col" class="align-middle">{% trans 'Members' %}</th>
|
<th scope="col" class="align-middle">{% trans 'Members' %}</th>
|
||||||
|
<th scope="col" class="align-middle">{% trans 'Administrator' %}</th>
|
||||||
<th scope="col" class="align-middle">{% trans 'Action' %}</th>
|
<th scope="col" class="align-middle">{% trans 'Action' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -45,11 +46,16 @@
|
|||||||
<span class="badge badge-pill rlp-r">{{member.username}}</span>
|
<span class="badge badge-pill rlp-r">{{member.username}}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{% for admin in team.admins.all %}
|
||||||
|
<span class="badge badge-pill rlp-r">{{admin.username}}</span>
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-leave' team.id %}" title="{% trans 'Leave team' %}">
|
<button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-leave' team.id %}" title="{% trans 'Leave team' %}">
|
||||||
{% fa5_icon 'sign-out-alt' %}
|
{% fa5_icon 'sign-out-alt' %}
|
||||||
</button>
|
</button>
|
||||||
{% if team.admin == user %}
|
{% if user in team.admins.all %}
|
||||||
<button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-edit' team.id %}" title="{% trans 'Edit team' %}">
|
<button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-edit' team.id %}" title="{% trans 'Edit team' %}">
|
||||||
{% fa5_icon 'edit' %}
|
{% fa5_icon 'edit' %}
|
||||||
</button>
|
</button>
|
||||||
|
@ -183,7 +183,8 @@ def new_team_view(request: HttpRequest):
|
|||||||
@login_required
|
@login_required
|
||||||
def edit_team_view(request: HttpRequest, id: str):
|
def edit_team_view(request: HttpRequest, id: str):
|
||||||
team = get_object_or_404(Team, id=id)
|
team = get_object_or_404(Team, id=id)
|
||||||
if request.user != team.admin:
|
user_is_admin = team.is_user_admin(request.user)
|
||||||
|
if not user_is_admin:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
form = EditTeamModalForm(request.POST or None, instance=team, request=request)
|
form = EditTeamModalForm(request.POST or None, instance=team, request=request)
|
||||||
return form.process_request(
|
return form.process_request(
|
||||||
@ -196,7 +197,8 @@ def edit_team_view(request: HttpRequest, id: str):
|
|||||||
@login_required
|
@login_required
|
||||||
def remove_team_view(request: HttpRequest, id: str):
|
def remove_team_view(request: HttpRequest, id: str):
|
||||||
team = get_object_or_404(Team, id=id)
|
team = get_object_or_404(Team, id=id)
|
||||||
if request.user != team.admin:
|
user_is_admin = team.is_user_admin(request.user)
|
||||||
|
if not user_is_admin:
|
||||||
raise Http404()
|
raise Http404()
|
||||||
form = RemoveTeamModalForm(request.POST or None, instance=team, request=request)
|
form = RemoveTeamModalForm(request.POST or None, instance=team, request=request)
|
||||||
return form.process_request(
|
return form.process_request(
|
||||||
|
Loading…
Reference in New Issue
Block a user