From 90aa5833f4ff86cfe2104ba266522757eae3eaac Mon Sep 17 00:00:00 2001 From: Tom Teichler <tom.teichler@teckids.org> Date: Wed, 23 Sep 2020 19:59:36 +0100 Subject: [PATCH] Clean up code --- .gitignore | 4 +- aleksis/apps/ticdesk/forms.py | 45 +---- aleksis/apps/ticdesk/models.py | 96 ++--------- aleksis/apps/ticdesk/preferences.py | 32 +--- .../edit.html | 0 .../feedback.html | 0 .../list.html | 0 .../manage.html | 0 .../register.html | 0 .../register_additional.html | 0 aleksis/apps/ticdesk/views.py | 155 +++++------------- poetry.lock | 14 +- pyproject.toml | 1 + 13 files changed, 78 insertions(+), 269 deletions(-) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/edit.html (100%) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/feedback.html (100%) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/list.html (100%) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/manage.html (100%) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/register.html (100%) rename aleksis/apps/ticdesk/templates/ticdesk/{teckids_project => teckids_event}/register_additional.html (100%) diff --git a/.gitignore b/.gitignore index 4fd8861..dfb3016 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ local_settings.py env/ venv/ ENV/ +.tox/ # Editors *~ @@ -50,6 +51,3 @@ DEADJOE # Database db.sqlite3 - -# Compiled CSS files -*.css diff --git a/aleksis/apps/ticdesk/forms.py b/aleksis/apps/ticdesk/forms.py index bae09c7..4258080 100644 --- a/aleksis/apps/ticdesk/forms.py +++ b/aleksis/apps/ticdesk/forms.py @@ -44,14 +44,6 @@ LICENCE_CHOICES = [ ), ] -DISALLOWED_UIDS = get_site_preferences()["ticdesk__disallowed_uids"].split(",") - -DISALLOWED_LOCAL_PARTS = get_site_preferences()[ - "ticdesk__disallowed_local_parts" -].split(",") + get_site_preferences()["ticdesk__disallowed_uids"].split(",") - -MAIL_DOMAINS = tuple(get_site_preferences()["ticdesk__mail_domains"].split(",")) - NEWSLETTER_CHOICES = get_site_preferences()["ticdesk__newsletter_choices"].split(",") @@ -204,44 +196,13 @@ class EditEventForm(forms.ModelForm): """Form to create or edit an event.""" layout = Layout( - Fieldset(_("Base data"), Row("short_name", "display_name"), "description",), - Fieldset(_("Persons"), Row("members", "owners"),), - Fieldset(_("Feedback aspects"), "feedback_aspects",), - Fieldset( - _("Event settings"), - Row("date_event", "date_registration", "date_retraction"), - Row("cost", "max_participants"), - "place", - "published", - ), + Fieldset(_("Base data"), Row("group", "description", Row("place"), "published"), + Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction"), + Fieldset(_("Feedback aspects"), "feedback_aspects"), ) class Meta: model = TeckidsEvent - exclude = ["gid_number"] - widgets = { - "owners": ModelSelect2MultipleWidget( - search_fields=[ - "first_name__icontains", - "last_name__icontains", - "short_name__icontains", - ] - ), - } - - -MAIL_LOCAL_REGEX = r"^[a-z][a-z0-9._-]{1,29}$" -MAIL_LOCAL_MESSAGE = _( - "The local part of the email address may only consist of lowercase letters, numbers," - "periods, hyphens and underscores and must begin with a letter!" -) - - -def is_mail_taken(mail): - return ( - bool(Person.objects.filter(email=mail)) - or mail.split("@")[0] in DISALLOWED_LOCAL_PARTS - ) class EditVoucherForm(forms.ModelForm): diff --git a/aleksis/apps/ticdesk/models.py b/aleksis/apps/ticdesk/models.py index 53f85f2..b54c4c0 100644 --- a/aleksis/apps/ticdesk/models.py +++ b/aleksis/apps/ticdesk/models.py @@ -2,6 +2,8 @@ from django.db import models from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from django_iban.fields import IBANField + from aleksis.core.mixins import ExtensibleModel, PureDjangoModel from aleksis.core.models import Person @@ -57,27 +59,18 @@ class TeckidsEvent(ExtensibleModel): verbose_name = _("Teckids event") verbose_name_plural = _("Teckids events") - # Group name details - short_name = models.CharField(max_length=50) - display_name = models.CharField(max_length=100, verbose_name=_("Display name")) + # Event details + group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name=_("Group"), related_name="event") description = models.CharField(max_length=500, verbose_name=_("Description")) - gid_number = models.IntegerField(verbose_name=_("GID number")) published = models.BooleanField(default=False, verbose_name=_("Publish")) - - # Members of this group - members = models.ManyToManyField( - Person, verbose_name=_("Members"), related_name="member" - ) - owners = models.ManyToManyField( - Person, verbose_name=_("Owners"), related_name="owner" - ) - place = models.CharField(max_length=50, verbose_name="Place") + # Date details date_event = models.DateTimeField(verbose_name=_("Date of event")) date_registration = models.DateTimeField(verbose_name=_("Registration deadline")) date_retraction = models.DateTimeField(verbose_name=_("Retraction deadline")) + # Other details cost = models.IntegerField(verbose_name=_("Cost in €")) max_participants = models.IntegerField(verbose_name=_("Max participants")) @@ -88,18 +81,6 @@ class TeckidsEvent(ExtensibleModel): def __str__(self) -> str: return self.display_name - def clean(self): - if not self.gid_number: - self.gid_number = ( - TeckidsEvent.objects.order_by("-gid_number")[0].gid_number + 1 - ) - - super(TeckidsEvent, self).clean() - - def save(self, *args, **kwargs): - self.clean() - super(TeckidsEvent, self).save(*args, **kwargs) - def can_register(self, request=None): now = timezone.now() @@ -112,7 +93,7 @@ class TeckidsEvent(ExtensibleModel): ): return True - if self.members.count() >= self.max_participants: + if self.group.members.count() >= self.max_participants: return False if self.date_registration: @@ -121,56 +102,15 @@ class TeckidsEvent(ExtensibleModel): @property def booked_percentage(self): - return self.members.count() / self.max_participants * 100 - - def sync_members(self): - # Ensure member_uids are in sync mith members - self.member_uids = [] - for member_dn in self.members: - # Rely on RDN being correctly set, for performance reasons - rdn = member_dn.split(",")[0] - rdn_parts = rdn.split("+") - - # Find the uid part of the RDN - for rdn_part in rdn_parts: - if rdn_part.startswith("uid="): - # Add to uids list and continue with next entry - uid = rdn_part.split("=")[1] - self.member_uids.append(uid) - break - - def add_member(self, person): - # Add person both to groupOfNames and posixGroup part - if person not in self.members.all(): - self.members.add(person) + return self.group.members.count() / self.max_participants * 100 @property def members_persons(self): - return self._get_objects("members", Person) + return self.group.members.all() @property def owners_persons(self): - return self._get_objects("owners", Person) - - -class RegistrationField(ExtensibleModel): - class Meta: - unique_together = ("event", "person", "title") - - event = models.ForeignKey( - TeckidsEvent, - related_name="registration_field", - verbose_name=_("Project"), - on_delete=models.CASCADE, - ) - person = models.ForeignKey( - Person, - related_name="registration_field", - verbose_name=_("Person"), - on_delete=models.CASCADE, - ) - title = models.CharField(max_length=30, verbose_name=_("Title")) - content = models.TextField(verbose_name=_("Content")) + return self.group.owners.all() class Voucher(ExtensibleModel): @@ -223,15 +163,6 @@ class EventRegistration(ExtensibleModel): verbose_name = _("Registration") verbose_name_plural = _("Registrations") - CHANNEL_CHOICES = [ - ("none", _("No information")), - ("internet", _("From internet")), - ("school", _("From school")), - ("friends", _("From friends")), - ("parents", _("From parents")), - ("newsletter", _("From newsletter")), - ] - event = models.ForeignKey( TeckidsEvent, on_delete=models.CASCADE, verbose_name=_("Event") ) @@ -248,7 +179,6 @@ class EventRegistration(ExtensibleModel): channel = models.CharField( verbose_name=_("Channel"), max_length=255, - choices=CHANNEL_CHOICES, blank=True, null=True, ) @@ -264,11 +194,9 @@ class EventRegistration(ExtensibleModel): ) accept_sepa = models.BooleanField(verbose_name=_("SEPA direct debit")) - iban = models.CharField( - max_length=255, + iban = models.IBANField( verbose_name=_("IBAN (for SEPA direct debit)"), - blank=True, - null=True, + enforce_database_constraint=True, ) accept_terms = models.BooleanField( diff --git a/aleksis/apps/ticdesk/preferences.py b/aleksis/apps/ticdesk/preferences.py index de1f87e..cc7feb2 100644 --- a/aleksis/apps/ticdesk/preferences.py +++ b/aleksis/apps/ticdesk/preferences.py @@ -8,15 +8,6 @@ from aleksis.core.registries import site_preferences_registry ticdesk = Section("ticdesk") -@site_preferences_registry.register -class MailDomains(StringPreference): - section = ticdesk - name = "mail_domains" - default = "" - required = False - verbose_name = _("Available mail domains (comma-seperated)") - - @site_preferences_registry.register class NewsletterChoices(StringPreference): section = ticdesk @@ -27,27 +18,18 @@ class NewsletterChoices(StringPreference): @site_preferences_registry.register -class DisallowedUids(StringPreference): - section = ticdesk - name = "disallowed_uids" - default = "" - required = False - verbose_name = _("Disallowed uids (comma-seperated)") - - -@site_preferences_registry.register -class DisallowedLocalParts(StringPreference): +class WWSPostUrl(StringPreference): section = ticdesk - name = "disallowed_local_parts" + name = "wws_post_url" default = "" required = False - verbose_name = _("Disallowed mail local parts (comma-seperated)") + verbose_name = _("POST url for Sympa") @site_preferences_registry.register -class WWSPostUrl(StringPreference): +class ChannelChoices(StringPreference): section = ticdesk - name = "wws_post_url" + name = "channel_choices" default = "" - required = False - verbose_name = _("POST url for Sympa") + requred = False + verbose_name = _("Channel choices") diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/edit.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/edit.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/edit.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/edit.html diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/feedback.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/feedback.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/feedback.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/feedback.html diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/list.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/list.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/list.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/list.html diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/manage.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/manage.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/manage.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/manage.html diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/register.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/register.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/register.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/register.html diff --git a/aleksis/apps/ticdesk/templates/ticdesk/teckids_project/register_additional.html b/aleksis/apps/ticdesk/templates/ticdesk/teckids_event/register_additional.html similarity index 100% rename from aleksis/apps/ticdesk/templates/ticdesk/teckids_project/register_additional.html rename to aleksis/apps/ticdesk/templates/ticdesk/teckids_event/register_additional.html diff --git a/aleksis/apps/ticdesk/views.py b/aleksis/apps/ticdesk/views.py index 054af97..909973c 100644 --- a/aleksis/apps/ticdesk/views.py +++ b/aleksis/apps/ticdesk/views.py @@ -79,39 +79,38 @@ def events(request): return render(request, "ticdesk/teckids_event/list.html", context) - -@login_required +@reversion.register() +@person_required def register_event(request, id_): context = {} # Get current person and event - current_person = Person.objects.get(user__username=request.user.username) event = event.objects.get(id=id_) context["event"] = event initial = { - "person": current_person, + "person": request.user.person, "event": event, - "school": current_person.school, - "school_place": current_person.school_place, - "school_class": current_person.school_class, - "mobile_number": current_person.mobile_number, - "email": current_person.email, - "street": current_person.street, - "place": current_person.place, - "housenumber": current_person.housenumber, - "sex": current_person.sex, - "date_of_birth": current_person.date_of_birth, - "postal_code": current_person.postal_code, + "school": request.user.person.school, + "school_place": request.user.person.school_place, + "school_class": request.user.person.school_class, + "mobile_number": request.user.person.mobile_number, + "email": request.user.person.email, + "street": request.user.person.street, + "place": request.user.person.place, + "housenumber": request.user.person.housenumber, + "sex": request.user.person.sex, + "date_of_birth": request.user.person.date_of_birth, + "postal_code": request.user.person.postal_code, } - if current_person.guardians.first(): + if request.user.person.guardians.first(): initial.update( { - "guardian_first_name": current_person.guardians.first().first_name, - "guardian_last_name": current_person.guardians.first().last_name, - "guardian_mobile_number": current_person.guardians.first().mobile_number, - "guardian_email": current_person.guardians.first().email, + "guardian_first_name": request.user.person.guardians.first().first_name, + "guardian_last_name": request.user.person.guardians.first().last_name, + "guardian_mobile_number": request.user.person.guardians.first().mobile_number, + "guardian_email": request.user.person.guardians.first().email, } ) @@ -123,7 +122,7 @@ def register_event(request, id_): return redirect("events") # Check whether person is already a member of the event - if current_person in event.members.all(): + if request.user.person in event.group.members.all(): messages.success(request, _("You are already registred.")) return redirect("events") @@ -139,18 +138,18 @@ def register_event(request, id_): or "sex" in register_form.changed_data or "date_of_birth" in register_form.changed_data, ): - current_person.school = register_form.cleaned_data["school"] - current_person.school_class = register_form.cleaned_data["school_class"] - current_person.school_place = register_form.cleaned_data["school_place"] - current_person.mobile_number = register_form.cleaned_data[ + request.user.person.school = register_form.cleaned_data["school"] + request.user.person.school_class = register_form.cleaned_data["school_class"] + request.user.person.school_place = register_form.cleaned_data["school_place"] + request.user.person.mobile_number = register_form.cleaned_data[ "mobile_number" ] - current_person.sex = register_form.cleaned_data["sex"] - current_person.date_of_birth = register_form.cleaned_data[ + request.user.person.sex = register_form.cleaned_data["sex"] + request.user.person.date_of_birth = register_form.cleaned_data[ "date_of_birth" ] - with reversion.create_revision(): - current_person.save() + + request.user.person.save() # Store postal address in database if ( @@ -159,11 +158,11 @@ def register_event(request, id_): or "street" in register_form.changed_data ): - current_person.street = register_form.cleaned_data["steet"] - current_person.postal_code = register_form.cleaned_data["postal_code"] - current_person.place = register_form.cleaned_data["place"] - with reversion.create_revision(): - current_person.save() + request.user.person.street = register_form.cleaned_data["steet"] + request.user.person.postal_code = register_form.cleaned_data["postal_code"] + request.user.person.place = register_form.cleaned_data["place"] + + request.user.person.save() if ( "guardian_first_name" in register_form.changed_data @@ -180,17 +179,14 @@ def register_event(request, id_): email=register_form.cleaned_data["guardian_email"], ) - current_person.guardians.add(guardian[0]) - with reversion.create_revision(): - current_person.save() + request.user.person.guardians.add(guardian[0]) + request.user.person.save() # Add the current person to the event - event.add_member(current_person) - with reversion.create_revision(): - event.save() + event.add_member(request.user.person) + event.save() - with reversion.create_revision(): - registration = register_form.save(commit=True) + registration = register_form.save(commit=True) if "voucher_code" in register_form.changed_data: voucher = Voucher.objects.get( code=register_form.cleaned_data["voucher_code"] @@ -204,13 +200,13 @@ def register_event(request, id_): # Produce e-mail message = EmailMessage() - message.reply_to = (current_person.mail,) + message.reply_to = (request.user.person.mail,) message.to = [ "orga@teckids.org", ] message.subject = _("New event:") % (event,) message.extra_headers = { - "X-OTRS-CustomerUser": current_person.user.username, + "X-OTRS-CustomerUser": request.user.person.user.username, } message.body = "" message.body += form_to_text_table(edit_event_form, 78) @@ -240,73 +236,6 @@ def register_event(request, id_): return render(request, "ticdesk/teckids_event/register.html", context) -@login_required -def register_event_additional(request, cn): - context = {} - - # Get current person and event - current_person = Person.objects.get(user__username=request.user.username) - event = event.objects.get(cn=cn) - context["event"] = event - - register_form = EventAdditionalSurveyForm(event) - - # Check whether person is already a member of the event - if current_person not in event.members: - return redirect("events") - messages.error(request, _("You are not registered for this event.")) - - if request.method == "POST": - register_form = EventAdditionalSurveyForm(event, request.POST) - if register_form.is_valid(): - # Store additional registration fields - for field in event.registration_fields: - label, help_text, *choices = field.split("|") - var = re.sub(r"[^A-Za-z0-9]|^(?=\d)", "_", label) - - field = RegistrationField.objects.get_or_create( - event=event, person=current_person, title=label - )[0] - - field.content = register_form.cleaned_data[var] - with reversion.create_revision(): - field.save() - - # Produce e-mail to registration queue - message = EmailMessage() - message.reply_to = (current_person.mail,) - message.to = [ - "anmeldung@teckids.org", - ] - message.subject = _("Additional informaion: %s from %s") % ( - event.display_name, - current_person.cn, - ) - message.extra_headers = { - "X-OTRS-DynamicField-TeckidsEvent": event.display_name, - "X-OTRS-CustomerUser": current_person.user.username, - } - message.body = "" - message.body += form_to_text_table(register_form, 78) - - # Attach raw form data as attachment - message.attach( - "register_form.json", - json.dumps(register_form.cleaned_data, indent=4, default=str), - "application/json", - ) - - # Send message - message.send() - - # Set success - context["success"] = True - - context["register_form"] = register_form - - return render(request, "ticdesk/teckids_event/register_additional.html", context) - - @login_required def feedback_event(request, id_): context = {} @@ -325,7 +254,7 @@ def feedback_event(request, id_): feedback_form = EventFeedbackForm(event, initial=initial) # Check whether person is a member of the event - if current_person not in event.members.all(): + if current_person not in event.group.members.all(): return redirect("events") messages.error(request, _("You did not take part in this event.")) @@ -388,10 +317,8 @@ def edit_event(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse: """View to edit or create an event.""" context = {} - current_person = request.user.person event = objectgetter_optional(event, None, False)(request, id_) context["event"] = event - context["person"] = current_person if id_: # Edit form for existing event diff --git a/poetry.lock b/poetry.lock index 0670b94..311057b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -85,6 +85,7 @@ ldap = ["django-auth-ldap (^2.2)"] reference = "7f1a59aaaef8cde8007afcb0742ac9934f4115b5" type = "git" url = "https://edugit.org/AlekSIS/official/AlekSIS" + [[package]] category = "dev" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." @@ -552,6 +553,14 @@ version = "3.14.1" [package.dependencies] django = ">=1.11" +[[package]] +category = "main" +description = "IBAN field for django with validation and optional postgresql in database constraint checking" +name = "django-iban-field" +optional = false +python-versions = "*" +version = "0.8" + [[package]] category = "main" description = "A reusable app for cropping images easily and non-destructively in Django" @@ -2134,7 +2143,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] -content-hash = "4a2973c045b427cd99b71aa5d77484f4b42cce7c141e6af4f1bac57ecdac22f7" +content-hash = "014c8ff1cf6f39c409543d9a021dfa3514a8fb2f92d32ade9b648b1c81989e92" python-versions = "^3.7" [metadata.files] @@ -2336,6 +2345,9 @@ django-health-check = [ {file = "django-health-check-3.14.1.tar.gz", hash = "sha256:08706f3b7a36b1690381779880b357c8d26d0b05109425eb891febd08993bbf1"}, {file = "django_health_check-3.14.1-py2.py3-none-any.whl", hash = "sha256:19a136e2da4bad473e29e0f12f866f33d80b3d778b959290e09617738539c0bc"}, ] +django-iban-field = [ + {file = "django_iban_field-0.8-py2.py3-none-any.whl", hash = "sha256:9d11eacb49b939702aa169aa0a3c9880970ed087c236279c32c26f86c7e10092"}, +] django-image-cropping = [ {file = "django-image-cropping-1.5.0.tar.gz", hash = "sha256:59744e8df88db7e46e37b526fc715fdde665d9efa345922745f50411a6dadb3f"}, {file = "django_image_cropping-1.5.0-py3-none-any.whl", hash = "sha256:81dbcabb6421c5a1e88fac9d96f336d6109a23dcb8fa6c678329d3688c9973c4"}, diff --git a/pyproject.toml b/pyproject.toml index 174dee5..c1f4034 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,6 +31,7 @@ python-dateutil = "^2.8.1" python-pam = "^1.8.4" python-resize-image = "^1.1.19" redis-collections = "^0.8.0" +django-iban-field = "^0.8" [tool.poetry.dev-dependencies] sphinx = "^3.0" -- GitLab