diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2449b5d35de313e28a857415e993bce7258b59cd..b69711b1dc3f7b2543a9f618d346cc3f7738ce33 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -12,6 +12,9 @@ Unreleased Fixed ~~~~~ +* No person was created and linked to the PersonInvitation object when invite by e-mail is used +* No valid data in the second e-mail field of the signup form when it was disabled +* Invitation options were displayed even when the feature was disabled * Inviting newly created persons for registration failed * [Docker] Do not clear cache in migration container die to session invalidation issues * Notification email about user changes was broken diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py index 87071a8fd13c8c01de700ad8c1e82db9aa063edb..ef4184812f73d22bb1dcfa1ff84f74f722c3c774 100644 --- a/aleksis/core/forms.py +++ b/aleksis/core/forms.py @@ -18,6 +18,7 @@ from dj_cleavejs import CleaveWidget from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget, Select2Widget from dynamic_preferences.forms import PreferenceForm from guardian.shortcuts import assign_perm +from invitations.forms import InviteForm from material import Fieldset, Layout, Row from .mixins import ExtensibleForm, SchoolTermRelatedExtensibleForm @@ -29,6 +30,7 @@ from .models import ( GroupType, OAuthApplication, Person, + PersonInvitation, SchoolTerm, ) from .registries import ( @@ -410,6 +412,31 @@ class InvitationCodeForm(forms.Form): self.fields["code"].widget = CleaveWidget(blocks=blocks, delimiter="-", uppercase=True) +class PersonCreateInviteForm(InviteForm): + """Custom form to create a person and invite them.""" + + first_name = forms.CharField(label=_("First name"), required=True) + last_name = forms.CharField(label=_("Last name"), required=True) + + layout = Layout( + Row("first_name", "last_name"), + Row("email"), + ) + + def clean_email(self): + if Person.objects.filter(email=self.cleaned_data["email"]).exists(): + raise ValidationError(_("A person is using this e-mail address")) + return super().clean_email() + + def save(self, email): + person = Person.objects.create( + first_name=self.cleaned_data["first_name"], + last_name=self.cleaned_data["last_name"], + email=email, + ) + return PersonInvitation.create(email=email, person=person) + + class SelectPermissionForm(forms.Form): """Select a permission to assign.""" diff --git a/aleksis/core/models.py b/aleksis/core/models.py index c0f03d34707c26e24ca6826cf5c9d4e7d87b10d5..812a9d254ca4bff2e9372ed7969d0cb2b811c176 100644 --- a/aleksis/core/models.py +++ b/aleksis/core/models.py @@ -1156,7 +1156,7 @@ class PersonInvitation(AbstractBaseInvitation, PureDjangoModel): packet_size = get_site_preferences()["auth__invite_code_packet_size"] code = generate_random_code(length, packet_size) - instance = cls._default_manager.create(email=email, inviter=inviter, key=code, **kwargs) + instance = cls.objects.create(email=email, inviter=inviter, key=code, **kwargs) return instance key_expired = Invitation.key_expired diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index aaf341ef69d5618254053856f3d4b179db1e90c1..4bcdab6d4c473a868aff178b0841e564d97b8e77 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -371,6 +371,8 @@ INVITATIONS_INVITATION_EXPIRY = _settings.get("auth.invitation.expiry", 3) INVITATIONS_EMAIL_SUBJECT_PREFIX = ACCOUNT_EMAIL_SUBJECT_PREFIX # Use custom invitation model INVITATIONS_INVITATION_MODEL = "core.PersonInvitation" +# Use custom invitation form +INVITATIONS_INVITE_FORM = "aleksis.core.forms.PersonCreateInviteForm" # Display error message if invitation code is invalid INVITATIONS_GONE_ON_ACCEPT_ERROR = False # Mark invitation as accepted after signup