""" Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de Created on: 08.07.21 """ from dal import autocomplete from django import forms from django.db import IntegrityError, transaction from django.urls import reverse, reverse_lazy from django.utils.translation import gettext_lazy as _ from api.models import APIUserToken from intervention.inputs import GenerateInput from user.models import User, UserNotification, Team from konova.forms import BaseForm, BaseModalForm, RemoveModalForm 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": "list-unstyled", } ), choices=[] ) def __init__(self, user: User, *args, **kwargs): super().__init__(*args, **kwargs) self.user = user self.form_title = _("Edit notifications") self.form_caption = _("") 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 users_current_notifications = self.user.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.user.notifications.set(notifications) class UserContactForm(BaseModalForm): name = forms.CharField( label=_("Username"), label_suffix="", required=False, widget=forms.TextInput( attrs={ "readonly": True, "class": "form-control", } ), ) person_name = forms.CharField( label=_("Person name"), label_suffix="", required=False, widget=forms.TextInput( attrs={ "readonly": True, "class": "form-control", } ), ) mail = forms.EmailField( label=_("E-Mail"), label_suffix="", required=False, widget=forms.TextInput( attrs={ "readonly": True, "class": "form-control", } ), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.render_submit = False self.form_title = _("User contact data") self.form_caption = "" self.initialize_form_field("name", self.instance.username) self.initialize_form_field("person_name", "{} {}".format(self.instance.first_name, self.instance.last_name)) self.initialize_form_field("mail", self.instance.email) class UserAPITokenForm(BaseForm): token = forms.CharField( label=_("Token"), label_suffix="", max_length=255, required=True, help_text=_("Generated automatically"), widget=GenerateInput( attrs={ "class": "form-control", "url": reverse_lazy("api:generate-new-token"), } ) ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_title = _("Create new token") self.form_caption = _("A new token needs to be validated by an administrator!") self.action_url = reverse("user:api-token") self.cancel_redirect = reverse("user:index") # Make direct token editing by user impossible. Instead set the proper url for generating a new token self.initialize_form_field("token", None) self.fields["token"].widget.attrs["readonly"] = True def save(self): """ Saves the form data Returns: api_token (APIUserToken) """ user = self.instance new_token = self.cleaned_data["token"] if user.api_token is not None: user.api_token.delete() new_token = APIUserToken.objects.create( token=new_token ) user.api_token = new_token user.save() return new_token class NewTeamModalForm(BaseModalForm): name = forms.CharField( label_suffix="", label=_("Team name"), max_length=500, widget=forms.TextInput( attrs={ "placeholder": _("Team name"), "class": "form-control", } ) ) description = forms.CharField( label_suffix="", label=_("Description"), widget=forms.Textarea( attrs={ "rows": 5, "class": "form-control" } ) ) members = forms.ModelMultipleChoiceField( label=_("Manage team members"), label_suffix="", help_text=_("Multiple selection possible - You can only select users which are not already a team member. Enter the full username or e-mail."), required=True, queryset=User.objects.all(), widget=autocomplete.ModelSelect2Multiple( url="share-user-autocomplete", attrs={ "data-placeholder": _("Click for selection"), "data-minimum-input-length": 3, }, ), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_title = _("Create new team") self.form_caption = _("You will become the administrator for this group by default. You do not need to add yourself to the list of members.") self.action_url = reverse("user:team-new") self.cancel_redirect = reverse("user:team-index") def _is_name_valid(self): name = self.cleaned_data.get("name", None) teams_with_same_name = Team.objects.filter( name=name ) name_valid = not teams_with_same_name.exists() if not name_valid: self.add_error( "name", _("Name already taken. Try another.") ) return name_valid def is_valid(self): super_valid = super().is_valid() name_valid = self._is_name_valid() return super_valid and name_valid def save(self): with transaction.atomic(): team = Team.objects.create( name=self.cleaned_data.get("name", None), description=self.cleaned_data.get("description", None), admin=self.user, ) members = self.cleaned_data.get("members", User.objects.none()) if self.user.id not in members: members = members.union( User.objects.filter( id=self.user.id ) ) team.users.set(members) return team class EditTeamModalForm(NewTeamModalForm): admin = forms.ModelChoiceField( label_suffix="", label=_("Admin"), help_text=_("Administrators manage team details and members"), queryset=User.objects.none(), empty_label=None, ) def __is_admin_valid(self): admin = self.cleaned_data.get("admin", None) members = self.cleaned_data.get("members", None) _is_valid = admin in members if not _is_valid: self.add_error( "members", _("Selected admin ({}) needs to be a member of this team.").format(admin.username) ) return _is_valid def _is_name_valid(self): name = self.cleaned_data.get("name", None) teams_with_same_name = Team.objects.filter( name=name ).exclude( id=self.instance.id ) name_valid = not teams_with_same_name.exists() if not name_valid: self.add_error( "name", _("Name already taken. Try another.") ) return name_valid def is_valid(self): super_valid = super().is_valid() admin_valid = self.__is_admin_valid() return super_valid and admin_valid def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_title = _("Edit team") self.action_url = reverse("user:team-edit", args=(self.instance.id,)) self.cancel_redirect = reverse("user:team-index") members = self.instance.users.all() self.fields["admin"].queryset = members form_data = { "members": members, "name": self.instance.name, "description": self.instance.description, "admin": self.instance.admin, } self.load_initial_data(form_data) def save(self): with transaction.atomic(): self.instance.name = self.cleaned_data.get("name", None) self.instance.description = self.cleaned_data.get("description", None) self.instance.admin = self.cleaned_data.get("admin", None) self.instance.save() self.instance.users.set(self.cleaned_data.get("members", [])) return self.instance class RemoveTeamModalForm(RemoveModalForm): pass class TeamDataForm(BaseModalForm): name = forms.CharField( label_suffix="", label=_("Team name"), max_length=500, required=False, widget=forms.TextInput( attrs={ "placeholder": _("Team name"), "class": "form-control", } ) ) description = forms.CharField( label_suffix="", required=False, label=_("Description"), widget=forms.Textarea( attrs={ "rows": 5, "class": "form-control" } ) ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form_title = _("Team") self.form_caption = "" self.render_submit = False form_data = { "name": self.instance.name, "description": self.instance.description, } self.load_initial_data( form_data, [ "name", "description" ] )