diff --git a/konova/management/commands/setup.py b/konova/management/commands/setup.py index 735256c2..831998bd 100644 --- a/konova/management/commands/setup.py +++ b/konova/management/commands/setup.py @@ -11,8 +11,10 @@ from django.contrib.auth.models import User, Group from django.core.management import BaseCommand from django.db import transaction -from konova.management.commands.setup_data import TEST_ORGANISATION_DATA, GROUPS_DATA +from konova.management.commands.setup_data import TEST_ORGANISATION_DATA, GROUPS_DATA, USER_NOTIFICATIONS_NAMES from organisation.models import Organisation +from user.enums import UserNotificationEnum +from user.models import UserNotification CREATED_TEMPLATE = "{} created" @@ -26,6 +28,7 @@ class Command(BaseCommand): self._init_superuser() self._init_test_organisation() self._init_default_groups() + self._init_user_notifications() except KeyboardInterrupt: self._break_line() exit(-1) @@ -38,9 +41,11 @@ class Command(BaseCommand): """ self._write_warning("--- Superuser ---") username = input("Superuser name: ") + if User.objects.filter(username=username).exists(): - self._write_error("Name already taken!") - exit(-1) + self._write_error("Superuser {} exists! Skip.".format(username)) + return + pw = getpass("Password: ") pw_confirm = getpass("Confirm password : ") if pw != pw_confirm: @@ -90,6 +95,23 @@ class Command(BaseCommand): self._break_line() + def _init_user_notifications(self): + """ Creates the default user notification triggers + + Returns: + + """ + self._write_warning("--- User Notifications ---") + choices = UserNotificationEnum.as_choices(drop_empty_choice=True) + for choice in choices: + UserNotification.objects.get_or_create( + id=choice[0], + name=USER_NOTIFICATIONS_NAMES.get(choice[0], None), + ) + self._write_success(CREATED_TEMPLATE.format(choice[0])) + + self._break_line() + def _break_line(self): """ Simply prints a line break diff --git a/konova/management/commands/setup_data.py b/konova/management/commands/setup_data.py index f0c46d8a..659032f1 100644 --- a/konova/management/commands/setup_data.py +++ b/konova/management/commands/setup_data.py @@ -8,6 +8,7 @@ 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 = [ { @@ -34,4 +35,14 @@ GROUPS_DATA = [ { "name": ETS_GROUP, }, - ] \ No newline at end of file + ] + +# Must match with UserNotificationEnum +USER_NOTIFICATIONS_NAMES = { + "NOTIFY_ON_NEW_RELATED_DATA": _("On new related data"), + "NOTIFY_ON_SHARE_LINK_DISABLED": _("On disabled share link"), + "NOTIFY_ON_SHARED_ACCESS_REMOVED": _("On shared access removed"), + "NOTIFY_ON_SHARED_DATA_REGISTERED": _("On shared data registered"), + "NOTIFY_ON_SHARED_DATA_DELETED": _("On shared data deleted"), + "NOTIFY_ON_REGISTERED_DATA_EDITED": _("On registered data edited"), +} \ No newline at end of file diff --git a/konova/static/css/konova.css b/konova/static/css/konova.css index 4275cd0b..0e68e6f7 100644 --- a/konova/static/css/konova.css +++ b/konova/static/css/konova.css @@ -127,5 +127,11 @@ nav{ border-radius: 0; } .btn-default:hover{ + /* color: var(--rlp-gray-light); + color: var(--rlp-red);; + background-color: unset; + border: 1px solid var(--rlp-red); + */ + box-shadow: 1px 1px 3px var(--rlp-gray-dark); } \ No newline at end of file diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index dbf0f6bc..1cafffdf 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 ea02b573..3d58f187 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-07-07 15:50+0200\n" +"POT-Creation-Date: 2021-07-08 17:21+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -185,9 +185,33 @@ msgstr "Entferne" msgid "You are about to remove {} {}" msgstr "Sie sind dabei {} {} zu löschen" +#: konova/management/commands/setup_data.py:42 +msgid "On new related data" +msgstr "Wenn neue Daten für mich angelegt werden" + +#: konova/management/commands/setup_data.py:43 +msgid "On disabled share link" +msgstr "Wenn ein Freigabelink deaktiviert wird" + +#: konova/management/commands/setup_data.py:44 +msgid "On shared access removed" +msgstr "Wenn mir eine Freigabe zu Daten entzogen wird" + +#: konova/management/commands/setup_data.py:45 +msgid "On shared data registered" +msgstr "Wenn meine freigegebenen Daten verzeichnet wurden" + +#: konova/management/commands/setup_data.py:46 +msgid "On shared data deleted" +msgstr "Wenn meine freigegebenen Daten gelöscht wurden" + +#: konova/management/commands/setup_data.py:47 +msgid "On registered data edited" +msgstr "Wenn meine freigegebenen Daten bearbeitet wurden" + #: konova/settings.py:55 msgid "Default" -msgstr "" +msgstr "Standard" #: konova/settings.py:56 msgid "Registration office" @@ -251,7 +275,7 @@ msgstr "" #: templates/footer.html:12 msgid "Contact" -msgstr "" +msgstr "Kontakt" #: templates/generic_table_form.html:37 msgid "Fields with * are required." @@ -297,7 +321,7 @@ msgstr "" msgid "Reports" msgstr "Berichte" -#: templates/navbar.html:56 +#: templates/navbar.html:56 user/templates/user/index.html:31 msgid "Settings" msgstr "Einstellungen" @@ -317,6 +341,67 @@ msgstr "Neu" msgid "Results per page" msgstr "Treffer pro Seite" +#: user/forms.py:23 +msgid "Notifications" +msgstr "Benachrichtigungen" + +#: user/forms.py:25 +msgid "Select the situations when you want to receive a notification" +msgstr "Wann wollen Sie per E-Mail benachrichtigt werden?" + +#: user/forms.py:37 +msgid "Edit notifications" +msgstr "Benachrichtigungen bearbeiten" + +#: user/templates/user/index.html:9 +msgid "Username" +msgstr "Nutzername" + +#: user/templates/user/index.html:13 +msgid "Name" +msgstr "" + +#: user/templates/user/index.html:17 +msgid "E-Mail" +msgstr "" + +#: user/templates/user/index.html:21 +msgid "Groups" +msgstr "Gruppen" + +#: user/templates/user/index.html:34 +msgid "" +"\n" +" Please note: Personal data can only be edited in the " +"login portal. The settings in here are KSP specific.\n" +" " +msgstr "" +"\n" +" Achtung: Allgemeine Nutzerdaten können nur im " +"Loginportal geändert werden. Die folgenden Einstellungen sind KSP " +"spezifisch.\n" +" " + +#: user/templates/user/index.html:42 +msgid "Change default configuration for your KSP map" +msgstr "Karteneinstellungen ändern" + +#: user/templates/user/index.html:45 +msgid "Map settings" +msgstr "Karte" + +#: user/templates/user/index.html:50 +msgid "Change notification configurations" +msgstr "Benachrichtigungseinstellungen ändern" + +#: user/templates/user/index.html:53 +msgid "Notification settings" +msgstr "Benachrichtigungen" + +#: user/views.py:52 +msgid "Notifications edited" +msgstr "Benachrichtigungen bearbeitet" + #: venv/lib/python3.7/site-packages/bootstrap4/components.py:17 #: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/form_errors.html:3 #: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/messages.html:4 @@ -1533,9 +1618,6 @@ msgstr "" #~ msgid "Add new compensation" #~ msgstr "Neue Kompensation hinzufügen" -#~ msgid "Edit compensation" -#~ msgstr "Kompensation bearbeiten" - #~ msgid "Delete compensation" #~ msgstr "Kompensation löschen" @@ -1548,9 +1630,6 @@ msgstr "" #~ msgid "Delete eco account" #~ msgstr "Ökokonto löschen" -#~ msgid "Create share link" -#~ msgstr "Freigabelink erstellen" - #~ msgid "Confirm check on data" #~ msgstr "Datenprüfung bestätigen" @@ -1617,9 +1696,6 @@ msgstr "" #~ msgid "Annual report" #~ msgstr "Jahresbericht" -#~ msgid "User" -#~ msgstr "Nutzer" - #~ msgid "You are currently working as " #~ msgstr "Sie arbeiten gerade als " @@ -1704,9 +1780,6 @@ msgstr "" #~ "Ein Vorgang basiert immer auf einem Eingriff. Bitte geben Sie die " #~ "fehlenden Daten für diesen Eingriff ein" -#~ msgid "Process {} removed" -#~ msgstr "Vorgang {} gelöscht" - #~ msgid "{} status changed from {} to {}" #~ msgstr "{} Status von {} auf {} geändert" diff --git a/templates/base.html b/templates/base.html index 38506216..16aff7ca 100644 --- a/templates/base.html +++ b/templates/base.html @@ -19,6 +19,14 @@ {% endblock %}
+
+ {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} +
+ {% block body %} {% endblock %} diff --git a/user/admin.py b/user/admin.py index 8c38f3f3..fb8a5d68 100644 --- a/user/admin.py +++ b/user/admin.py @@ -1,3 +1,21 @@ from django.contrib import admin -# Register your models here. +from user.models import UserNotification, KonovaUserExtension + + +class UserNotificationAdmin(admin.ModelAdmin): + list_display = [ + "id", + "name", + "is_active", + ] + + +class KonovaUserExtensionAdmin(admin.ModelAdmin): + list_display = [ + "user", + ] + + +admin.site.register(UserNotification, UserNotificationAdmin) +admin.site.register(KonovaUserExtension, KonovaUserExtensionAdmin) diff --git a/user/enums.py b/user/enums.py new file mode 100644 index 00000000..64080749 --- /dev/null +++ b/user/enums.py @@ -0,0 +1,17 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 08.07.21 + +""" +from konova.enums import BaseEnum + + +class UserNotificationEnum(BaseEnum): + NOTIFY_ON_NEW_RELATED_DATA = "NOTIFY_ON_NEW_RELATED_DATA" # notifies in case new data has been added which is related to the user's organisation + NOTIFY_ON_SHARE_LINK_DISABLED = "NOTIFY_ON_SHARE_LINK_DISABLED" # notifies in case share link for data has been disabled + NOTIFY_ON_SHARED_ACCESS_REMOVED = "NOTIFY_ON_SHARED_ACCESS_REMOVED" # notifies in case shared access to data has been removed + NOTIFY_ON_SHARED_DATA_REGISTERED = "NOTIFY_ON_SHARED_DATA_REGISTERED" # notifies in case data has been "verzeichnet" + NOTIFY_ON_SHARED_DATA_DELETED = "NOTIFY_ON_SHARED_DATA_DELETED" # notifies in case data has been deleted + NOTIFY_ON_REGISTERED_DATA_EDITED = "NOTIFY_ON_REGISTERED_DATA_EDITED" # notifies in case registered ("verzeichnet") data has been edited \ No newline at end of file diff --git a/user/forms.py b/user/forms.py new file mode 100644 index 00000000..de2e31f9 --- /dev/null +++ b/user/forms.py @@ -0,0 +1,70 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 08.07.21 + +""" +from django import forms +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ +from django.contrib.auth.models import User + +from konova.forms import BaseForm +from user.models import UserNotification, KonovaUserExtension + + +class UserNotificationForm(BaseForm): + """ Form for changing the notification settings of a user + + """ + notifications = forms.MultipleChoiceField( + label_suffix="", + label=_("Notifications"), + required=False, # allow total disabling of all notifications + help_text=_("Select the situations when you want to receive a notification"), + widget=forms.CheckboxSelectMultiple( + attrs={ + "class": "no-bullets", + } + ), + choices=[] + ) + + def __init__(self, user: User, *args, **kwargs): + super().__init__(*args, **kwargs) + self.user = user + self.form_title = _("Edit notifications") + self.action_url = reverse("user:notifications") + self.cancel_redirect = reverse("user:index") + + # Insert all notifications into form field by creating choices as tuples + notifications = UserNotification.objects.filter( + is_active=True, + ) + choices = [] + for n in notifications: + choices.append( + (n.id, _(n.name)) + ) + self.fields["notifications"].choices = choices + + # Set currently selected notifications as initial + self.konova_extension = KonovaUserExtension.objects.get_or_create( + user=user + )[0] + users_current_notifications = self.konova_extension.notifications.all() + users_current_notifications = [str(n.id) for n in users_current_notifications] + self.fields["notifications"].initial = users_current_notifications + + def save(self): + """ Stores the changes in the user konova_extension + + Returns: + + """ + selected_notification_ids = self.cleaned_data.get("notifications", []) + notifications = UserNotification.objects.filter( + id__in=selected_notification_ids, + ) + self.konova_extension.notifications.set(notifications) diff --git a/user/models.py b/user/models.py index 71a83623..428b4f5b 100644 --- a/user/models.py +++ b/user/models.py @@ -1,3 +1,38 @@ +from django.contrib.auth.models import User from django.db import models -# Create your models here. +from user.enums import UserNotificationEnum + + +class UserNotification(models.Model): + """ Notifications for users + + """ + id = models.CharField( + max_length=500, + null=False, + blank=False, + choices=UserNotificationEnum.as_choices(drop_empty_choice=True), + primary_key=True, + ) + name = models.CharField( + max_length=500, + null=False, + blank=False, + unique=True, + help_text="Human readable name" + ) + is_active = models.BooleanField(default=True, help_text="Can be toggle to enable/disable this notification for all users") + + def __str__(self): + return self.name + + +class KonovaUserExtension(models.Model): + """ Extension model for additional ksp features + + Extends the default user model for some extras + + """ + user = models.OneToOneField(User, on_delete=models.CASCADE) + notifications = models.ManyToManyField(UserNotification, related_name="+") diff --git a/user/templates/user/index.html b/user/templates/user/index.html index 217f18cf..bf8baea4 100644 --- a/user/templates/user/index.html +++ b/user/templates/user/index.html @@ -1,22 +1,60 @@ {% extends 'base.html' %} -{% load i18n %} +{% load i18n fontawesome_5 %} {% block body %}
- + - + + + + + + + + +
{% trans 'Username' %}{% trans 'Username' %} {{user.username}}
{% trans 'Name' %}{% trans 'Name' %} {{user.first_name}} {{user.last_name}}
{% trans 'E-Mail' %}{{user.email}}
{% trans 'Groups' %} + {% for group in user.groups.all %} + {% trans group.name %} + {% endfor %} +
- +

{% trans 'Settings' %}

+
+ + {% blocktrans %} + Please note: Personal data can only be edited in the login portal. The settings in here are KSP specific. + {% endblocktrans %} + +
+
+
{% endblock %} \ No newline at end of file diff --git a/user/templates/user/notifications.html b/user/templates/user/notifications.html new file mode 100644 index 00000000..b50da5d6 --- /dev/null +++ b/user/templates/user/notifications.html @@ -0,0 +1,5 @@ +{% extends 'base.html' %} + +{% block body %} + {% include 'generic_table_form.html' %} +{% endblock %} \ No newline at end of file diff --git a/user/urls.py b/user/urls.py index 4ee04b63..fd5ff27d 100644 --- a/user/urls.py +++ b/user/urls.py @@ -7,9 +7,10 @@ Created on: 08.07.21 """ from django.urls import path -from user.views import index_view +from user.views import * -app_name="user" +app_name = "user" urlpatterns = [ path("", index_view, name="index"), + path("notifications/", notifications_view, name="notifications"), ] \ No newline at end of file diff --git a/user/views.py b/user/views.py index 5eb6f141..13fbfee4 100644 --- a/user/views.py +++ b/user/views.py @@ -1,8 +1,12 @@ +from django.contrib import messages from django.contrib.auth.decorators import login_required from django.http import HttpRequest -from django.shortcuts import render +from django.shortcuts import render, redirect +from django.utils.translation import gettext_lazy as _ from konova.contexts import BaseContext +from user.forms import UserNotificationForm +from user.models import KonovaUserExtension @login_required @@ -21,3 +25,43 @@ def index_view(request: HttpRequest): } context = BaseContext(request, context).context return render(request, template, context) + + +@login_required +def notifications_view(request: HttpRequest): + """ Renders the notifications settings view + + Args: + request (): + + Returns: + + """ + template = "user/notifications.html" + user = request.user + konova_ext = KonovaUserExtension.objects.get_or_create( + user=user + )[0] + + form = UserNotificationForm(user=user, data=request.POST or None) + if request.method == "POST": + if form.is_valid(): + form.save() + messages.success( + request, + _("Notifications edited") + ) + return redirect("user:index") + elif request.method == "GET": + # Implicit + pass + else: + raise NotImplementedError + + context = { + "user": user, + "form": form, + "konova_ext": konova_ext, + } + context = BaseContext(request, context).context + return render(request, template, context)