diff --git a/aleksis/apps/paweljong/forms.py b/aleksis/apps/paweljong/forms.py
index 0fe993f2361a43f25f3dd454b35496bbb893ffca..11d385cae110f94ebeab6e21109cd9b5d77b6f34 100644
--- a/aleksis/apps/paweljong/forms.py
+++ b/aleksis/apps/paweljong/forms.py
@@ -1,18 +1,15 @@
-import re
-from collections import OrderedDict
-
 from django import forms
+from django.forms import fields
 from django.utils.translation import ugettext_lazy as _
 
-import phonenumbers
+from allauth.account.views import SignupForm
 from django_select2.forms import ModelSelect2MultipleWidget, ModelSelect2Widget
 from django_starfield import Stars
 from material import Fieldset, Layout, Row
+from phonenumber_field.formfields import PhoneNumberField
 
-from aleksis.core.forms import AccountRegisterForm
 from aleksis.core.mixins import ExtensibleForm
 from aleksis.core.models import Group, Person
-from aleksis.core.util.core_helpers import get_site_preferences
 
 from .models import Event, EventRegistration, FeedbackAspect, Voucher
 
@@ -33,84 +30,12 @@ LICENCE_CHOICES = [
     (
         "CC-BY-SA-4.0+",
         _(
-            "Creative Commons with attribution and distribution only"
+            "Creative Commons with attribution and distribution only "
             "under the same conditions, 4.0 or later"
         ),
     ),
 ]
 
-NEWSLETTER_CHOICES = get_site_preferences()["paweljong__newsletter_choices"].split(",")
-
-
-def is_phonenumber(number):
-    try:
-        phonenumbers.parse(number, "DE")
-    except BaseException:
-        raise forms.ValidationError(_("%s is not a valid phone number") % number)
-
-
-def is_valid_voucher_for(event_cn):
-    def _is_valid_voucher(code):
-        if Voucher.objects.filter(code=code, event_cn=event_cn, used=False).count() == 0:
-            raise forms.ValidationError(_("The voucher is invalid!"))
-
-    return _is_valid_voucher
-
-
-def clean_phonenumber(field):
-    def _clean_phonenumber(obj):
-        value = obj.cleaned_data[field]
-
-        if value:
-            pn = phonenumbers.parse(value, "DE")
-            value = phonenumbers.format_number(pn, phonenumbers.PhoneNumberFormat.E164)
-
-        return value
-
-    return _clean_phonenumber
-
-
-class EventAdditionalSurveyForm(forms.Form):
-    def __init__(self, event, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.add_fields_from_ldap(event)
-
-    def add_fields_from_ldap(self, event, before=None):
-        new_fields = OrderedDict()
-
-        for field in event.registration_fields:
-            label, help_text, *choices = field.split("|")
-            var = re.sub(r"[^A-Za-z0-9]|^(?=\d)", "_", label)
-
-            if choices:
-                choices_map = [
-                    (re.sub(r"[^A-Za-z0-9]|^(?=\d)", "_", choice), choice) for choice in choices
-                ]
-                field_attr = forms.ChoiceField(
-                    label=label,
-                    help_text=help_text,
-                    choices=choices_map,
-                    required=False,
-                )
-            else:
-                field_attr = forms.CharField(label=label, help_text=help_text, required=False)
-
-            new_fields[var] = field_attr
-
-        if before:
-            before_field_index = list(self.fields.keys()).index(before)
-            field_names = list(self.fields.keys())
-            new_field_order = (
-                field_names[: before_field_index - 1]
-                + list(new_fields.keys())
-                + field_names[before_field_index - 1 :]
-            )
-
-        self.fields.update(new_fields)
-
-        if before:
-            self.order_fields(new_field_order)
-
 
 class EventFeedbackForm(ExtensibleForm):
     class Meta:
@@ -135,7 +60,7 @@ class EventFeedbackForm(ExtensibleForm):
         required=False,
         label=_("Comment for the team"),
         help_text=_(
-            "This comment is for the team only. You can write down everything you"
+            "This comment is for the team only. You can write down everything you "
             "would like to give us as feedback here."
         ),
         widget=forms.Textarea,
@@ -145,8 +70,8 @@ class EventFeedbackForm(ExtensibleForm):
         required=False,
         label=_("Comment for the website"),
         help_text=_(
-            "This comment is for the report on our website. Tell in detail about what"
-            "you experienced, what you liked, what you learned and everything else"
+            "This comment is for the report on our website. Tell in detail about what "
+            "you experienced, what you liked, what you learned and everything else "
             "you can think of."
         ),
         widget=forms.Textarea,
@@ -163,7 +88,7 @@ class EventFeedbackForm(ExtensibleForm):
         widget=forms.ClearableFileInput(attrs={"multiple": True}),
         required=False,
         help_text=_(
-            "If you want to contribute photos to the report, you can upload them here. You can"
+            "If you want to contribute photos to the report, you can upload them here. You can "
             "select multiple files in most file selection dialogs with CTRL + click."
         ),
     )
@@ -175,7 +100,7 @@ class EventFeedbackForm(ExtensibleForm):
         help_text=_("If you upload photos, choose a license here."),
     )
 
-    def __init__(self, event, *args, **kwargs):
+    def __init__(self, event, request, *args, **kwargs):
         super(EventFeedbackForm, self).__init__(*args, **kwargs)
         self._event = event
 
@@ -189,27 +114,40 @@ class EventFeedbackForm(ExtensibleForm):
             self.add_node_to_layout(node)
 
 
-class EditEventForm(forms.ModelForm):
+class EditEventForm(ExtensibleForm):
     """Form to create or edit an event."""
 
     layout = Layout(
         Fieldset(
             _("Base data"),
-            "group",
+            "linked_group",
             Row("display_name", "description"),
             Row("place", "published"),
             Fieldset(_("Date data"), Row("date_event", "date_registration", "date_retraction")),
-            Fieldset(_("Event details"), Row("cost", "max_participants")),
+            Fieldset(_("Event details"), Row("cost", "max_participants"), "information"),
             Fieldset(_("Feedback aspects"), "feedback_aspects"),
         ),
     )
 
     class Meta:
         model = Event
-        exclude = []
+        fields = [
+            "linked_group",
+            "display_name",
+            "description",
+            "place",
+            "published",
+            "date_event",
+            "date_registration",
+            "date_retraction",
+            "cost",
+            "max_participants",
+            "feedback_aspects",
+            "information",
+        ]
         widgets = {
-            "group": ModelSelect2Widget(
-                search_fields=["name__icontains", "short_name__icontains"],
+            "linked_group": ModelSelect2Widget(
+                search_fields=["name__icontains"],
                 attrs={"data-minimum-input-length": 0, "class": "browser-default"},
             ),
             "feedback_aspects": ModelSelect2MultipleWidget(
@@ -225,6 +163,16 @@ class EditVoucherForm(forms.ModelForm):
     class Meta:
         model = Voucher
         exclude = ["code", "used_person_uid", "used", "deleted"]
+        widgets = {
+            "event": ModelSelect2Widget(
+                search_fields=["display_name__icontains"],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+            ),
+            "person": ModelSelect2Widget(
+                search_fields=["first_name__icontains", "last_name__icontains"],
+                attrs={"data-minimum-input-length": 0, "class": "browser-default"},
+            ),
+        }
         help_texts = {
             "event": _("Event the voucher is valid for."),
             "person": _("Person the voucher is valid for."),
@@ -250,30 +198,16 @@ class GenerateListForm(forms.Form):
     landscape = forms.BooleanField(
         label=_("Landscape"),
         help_text=_("Select if output should be in landscape."),
+        required=False,
     )
 
 
-class RegisterEventForm(forms.ModelForm):
-    """Form to register for an event."""
+class RegisterEventGuardians(ExtensibleForm):
+    class Meta:
+        model = EventRegistration
+        fields = []
 
     layout = Layout(
-        Fieldset(
-            _("Address data"),
-            Row("street", "housenumber"),
-            Row("postal_code", "place"),
-        ),
-        Fieldset(
-            _("Contact details"),
-            Row("mobile_number", "email"),
-        ),
-        Fieldset(
-            _("Personal data"),
-            Row("date_of_birth", "sex"),
-        ),
-        Fieldset(
-            _("School details"),
-            Row("school", "school_place", "school_class"),
-        ),
         Fieldset(
             _("Guardians personal data"),
             Row("guardian_first_name", "guardian_last_name"),
@@ -282,73 +216,12 @@ class RegisterEventForm(forms.ModelForm):
             _("Guardians contact details"),
             Row("guardian_email", "guardian_mobile_number"),
         ),
-        Fieldset(
-            _("General event information"),
-            Row("event", "person"),
-            Row("comment", "channel"),
-        ),
-        Fieldset(
-            _("Financial data"),
-            "voucher_code",
-            Row("iban", "donation", "accept_sepa"),
-        ),
-        Fieldset(
-            _("Declaration of consent"),
-            Row("accept_terms", "accept_data", "accept_general_terms"),
-        ),
     )
 
-    class Meta:
-        model = EventRegistration
-        exclude = ["date_registred", "voucher"]
-        help_texts = {
-            "voucher": _(
-                "If you have a voucher for the event, enter the code here."
-                "It will be charged automatically."
-            ),
-            "donation": (
-                "Our association would like to offer all children and young"
-                "people the opportunity to participate in our events. Often,"
-                "however, the family fee cannot be paid. We therefore have a"
-                "budget from which we can promote participation after we have"
-                "carefully examined the necessity and eligibility. We rely on"
-                "donations for this budget. If you would like to donate a voluntary"
-                "additional amount for this budget, please indicate this here. We do"
-                "not permanently save whether and if so in what amount donations are"
-                "made and also not within the association, e.g. passed on to leisure supervisors."
-            ),
-            "accept_sepa": _(
-                "Parents: I authorize the creditor  e.V., Rochusstr. 2-4, 53123 Bonn with"
-                "creditor ID DE70FZT00001497650, to collect the participant fee from my account"
-                "once using the SEPA core direct debit. At the same time, I instruct my bank to"
-                "redeem the SEPA core direct debit withdrawn from my account by  e.V."
-            ),
-            "iban": _(
-                "If your parents want to pay by SEPA direct debit,"
-                "please let them fill out this field."
-            ),
-            "accept_terms": _(
-                "Parents: My child filled out the registration form together with me, but myself,"
-                "and I agree to the participation, the terms of use and the terms and conditions."
-                "I am aware that the registration is binding and that withdrawal is only possible"
-                "in exceptional cases with a valid reason. In addition, I agree to pay the"
-                "participation fee in advance and agree to the reimbursement guidelines"
-                "mentioned above."
-            ),
-            "accept_data": _(
-                "I consent to the processing of my data as stated in the"
-                "terms of use and all the data provided is correct. If I am under the"
-                "age of 16, my parents also agree to this and I can prove this on request"
-                "(e.g. by making contact with my parents)."
-            ),
-            "accept_general_terms": _("I agree with the" "AGB and have read them."),
-            "channel": _("How did you find out about the event?"),
-        }
-
     guardian_first_name = forms.CharField(
         label=_("Guardians first name"),
         help_text=_(
-            "Please enter the first name of the legal guardian who will fill in the registration"
+            "Please enter the first name of the legal guardian who will fill in the registration "
             "with you and who can be reached during the event in an emergency."
         ),
     )
@@ -356,15 +229,15 @@ class RegisterEventForm(forms.ModelForm):
     guardian_last_name = forms.CharField(
         label=_("Guardians last name"),
         help_text=_(
-            "Please enter the last name of the legal guardian who will fill in the registration"
+            "Please enter the last name of the legal guardian who will fill in the registration "
             "with you and who can be reached during the event in an emergency."
         ),
     )
 
-    guardian_mobile_number = forms.CharField(
+    guardian_mobile_number = PhoneNumberField(
         label=_("Guardians mobile number"),
         help_text=_(
-            "We need the mobile phone number for emergencies if we"
+            "We need the mobile phone number for emergencies if we "
             "urgently need to reach your parents during the event."
         ),
     )
@@ -373,12 +246,49 @@ class RegisterEventForm(forms.ModelForm):
         label=_("Guardians email address"),
     )
 
-    voucher_code = forms.CharField(
-        label=_("Voucher code"),
-        help_text=_("If you have a voucher code, type it in here."),
+
+class RegisterEventContactDetails(ExtensibleForm):
+    class Meta:
+        model = EventRegistration
+        fields = []
+
+    layout = Layout(
+        Fieldset(
+            _("Personal data"),
+            Row("first_name", "additional_name", "last_name"),
+            Row("date_of_birth", "sex"),
+        ),
+        Fieldset(
+            _("Address data"),
+            Row("street", "housenumber"),
+            Row("postal_code", "place"),
+        ),
+        Fieldset(
+            _("Contact details"),
+            Row("mobile_number", "email"),
+        ),
+        Fieldset(
+            _("School details"),
+            Row("school", "school_place", "school_class"),
+        ),
+    )
+
+    first_name = forms.CharField(
+        label=_("First name"),
+        disabled=True,
+    )
+
+    additional_name = forms.CharField(
+        label=_("Additional names"),
+        help_text=_("Please enter any additional names."),
         required=False,
     )
 
+    last_name = forms.CharField(
+        label=_("Last name"),
+        disabled=True,
+    )
+
     street = forms.CharField(
         label=_("Street"),
     )
@@ -395,15 +305,14 @@ class RegisterEventForm(forms.ModelForm):
         label=_("Place"),
     )
 
-    mobile_number = forms.CharField(
+    mobile_number = PhoneNumberField(
         label=_("Mobile number"),
         required=False,
         help_text=_(
-            "Your mobile number helps us to reach you in an emergency during the event, e.g."
-            "if you are alone with your group at a conference or similar. If you don't have a"
+            "Your mobile number helps us to reach you in an emergency during the event, e.g. "
+            "if you are alone with your group at a conference or similar. If you don't have a "
             "cell phone, you can leave the field blank."
         ),
-        validators=[is_phonenumber],
     )
 
     date_of_birth = forms.DateField(
@@ -413,9 +322,10 @@ class RegisterEventForm(forms.ModelForm):
     sex = forms.ChoiceField(
         label=_("Sex"),
         help_text=_(
-            "For various reasons, e.g. because we have to keep gender segregation during the night"
-            "for legal reasons, we need to know if you are a boy or a girl. With some names this is"
-            "not always immediately recognizable, so we ask you to indicate it here."
+            "For various reasons, e.g. because we have to keep gender segregation during the night "
+            "for legal reasons, we need to know if you are a boy or a girl. "
+            " With some names this is not always immediately recognizable, so we ask you to "
+            "indicate it here."
         ),
         choices=Person.SEX_CHOICES,
         initial=None,
@@ -423,6 +333,11 @@ class RegisterEventForm(forms.ModelForm):
 
     email = forms.EmailField(
         label=_("Email address"),
+        help_text=_(
+            "If you don't have an email address, leave this field empty. You can "
+            "register an email address in the next step."
+        ),
+        required=False,
     )
 
     school = forms.CharField(
@@ -440,14 +355,114 @@ class RegisterEventForm(forms.ModelForm):
         help_text=_("Please enter the class you are going to (e.g. 8a)."),
     )
 
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
 
-        self.fields["event"].disabled = True
-        self.fields["person"].disabled = True
-        self.fields["accept_terms"].required = True
-        self.fields["accept_general_terms"].required = True
-        self.fields["accept_data"].required = True
+class RegisterEventAdditional(ExtensibleForm):
+
+    layout = Layout(
+        Fieldset(
+            _("Medical information / intolerances"),
+            Row("medical_information"),
+        ),
+        Fieldset(
+            _("Other remarks"),
+            Row("comment"),
+        ),
+    )
+
+    class Meta:
+        model = EventRegistration
+        fields = ["medical_information", "comment"]
+
+    def __init__(self, event, *args, **kwargs):
+        super(RegisterEventAdditional, self).__init__(*args, **kwargs)
+
+        for _field in event.linked_group.additional_fields.all():
+            field = getattr(fields, _field.field_type)(
+                required=False,
+            )
+            self.fields[_field.title] = field
+            node = Fieldset(f"{_field.title}", f"{_field.title}")
+            self.add_node_to_layout(node)
+
+
+class RegisterEventFinancial(ExtensibleForm):
+    """Form to register for an event."""
+
+    layout = Layout(
+        Fieldset(
+            _("Financial data"),
+            "voucher_code",
+            Row("iban", "donation", "accept_sepa"),
+        ),
+    )
+
+    voucher_code = forms.CharField(
+        label=_("Voucher code"),
+        help_text=_("If you have a voucher code, type it in here."),
+        required=False,
+    )
+
+    class Meta:
+        model = EventRegistration
+        fields = ["voucher_code", "iban", "donation", "accept_sepa"]
+        help_texts = {
+            "voucher": _(
+                "If you have a voucher for the event, enter the code here. "
+                "It will be charged automatically."
+            ),
+            "donation": (
+                "Our association would like to offer all children and young "
+                "people the opportunity to participate in our events. Often, "
+                "however, the family fee cannot be paid. We therefore have a "
+                "budget from which we can promote participation after we have "
+                "carefully examined the necessity and eligibility. We rely on "
+                "donations for this budget. If you would like to donate a voluntary "
+                "additional amount for this budget, please indicate this here. We do "
+                "not permanently save whether and if so in what amount donations are "
+                "made and also not within the association, e.g. passed on to leisure supervisors."
+            ),
+            "accept_sepa": _(
+                "Parents: I authorize the creditor  e.V., Rochusstr. 2-4, 53123 Bonn with "
+                "creditor ID DE70FZT00001497650, to collect the participant fee from my account "
+                "once using the SEPA core direct debit. At the same time, I instruct my bank to "
+                "redeem the SEPA core direct debit withdrawn from my account by  e.V."
+            ),
+            "iban": _(
+                "If your parents want to pay by SEPA direct debit, "
+                "please let them fill out this field."
+            ),
+        }
+
+
+class RegisterEventConsent(ExtensibleForm):
+
+    layout = Layout(
+        Fieldset(
+            _("Declaration of consent"),
+            Row("accept_terms", "accept_data", "accept_general_terms"),
+        ),
+    )
+
+    class Meta:
+        model = EventRegistration
+        fields = ["accept_terms", "accept_data", "accept_general_terms"]
+        help_texts = {
+            "accept_terms": _(
+                "Parents: My child filled out the registration form together with me, but myself, "
+                "and I agree to the participation, the terms of use and the terms and conditions. "
+                "I am aware that the registration is binding and that withdrawal is only possible "
+                "in exceptional cases with a valid reason. In addition, I agree to pay the "
+                "participation fee in advance and agree to the reimbursement guidelines "
+                "mentioned above."
+            ),
+            "accept_data": _(
+                "I consent to the processing of my data as stated in the "
+                "terms of use and all the data provided is correct. If I am under the "
+                "age of 16, my parents also agree to this and I can prove this on request "
+                "(e.g. by making contact with my parents)."
+            ),
+            "accept_general_terms": _("I agree with the AGB and have read them."),
+        }
 
 
 class EditEventRegistrationForm(forms.ModelForm):
@@ -456,7 +471,7 @@ class EditEventRegistrationForm(forms.ModelForm):
         Fieldset(
             _("General event information"),
             Row("event", "person"),
-            Row("comment", "channel"),
+            Row("comment"),
         ),
         Fieldset(
             _("Financial data"),
@@ -477,42 +492,41 @@ class EditEventRegistrationForm(forms.ModelForm):
                 "It will be charged automatically."
             ),
             "donation": (
-                "Our association would like to offer all children and young"
-                "people the opportunity to participate in our events. Often,"
-                "however, the family fee cannot be paid. We therefore have a"
-                "budget from which we can promote participation after we have"
-                "carefully examined the necessity and eligibility. We rely on"
-                "donations for this budget. If you would like to donate a voluntary"
-                "additional amount for this budget, please indicate this here. We do not"
-                "permanently save whether and if so in what amount donations are made"
-                "and also not within the association, e.g. passed on to leisure supervisors."
+                "Our association would like to offer all children and young "
+                "people the opportunity to participate in our events. Often, "
+                "however, the family fee cannot be paid. We therefore have a "
+                "budget from which we can promote participation after we have "
+                "carefully examined the necessity and eligibility. We rely on "
+                "donations for this budget. If you would like to donate a voluntary "
+                "additional amount for this budget, please indicate this here. We do not "
+                "permanently save whether and if so in what amount donations are made "
+                "and also not within the association, e.g. passed on to leisure supervisors. "
             ),
             "accept_sepa": _(
-                "Parents: I authorize the creditor  e.V., Rochusstr. 2-4, 53123 Bonn with"
-                "creditor ID DE70FZT00001497650, to collect the participant fee from my account"
-                "once using the SEPA core direct debit. At the same time, I instruct my bank"
+                "Parents: I authorize the creditor  e.V., Rochusstr. 2-4, 53123 Bonn with "
+                "creditor ID DE70FZT00001497650, to collect the participant fee from my account "
+                "once using the SEPA core direct debit. At the same time, I instruct my bank "
                 "to redeem the SEPA core direct debit withdrawn from my account by  e.V."
             ),
             "iban": _(
-                "If your parents want to pay by SEPA direct debit,"
+                "If your parents want to pay by SEPA direct debit, "
                 "please let them fill out this field."
             ),
             "accept_terms": _(
-                "Parents: My child filled out the registration form together with me, but myself,"
-                "and I agree to the participation, the terms of use and the terms and conditions."
-                "I am aware that the registration is binding and that withdrawal is only possible"
-                "in exceptional cases with a valid reason. In addition, I agree to pay the"
-                "participation fee in advance and agree to the reimbursement"
+                "Parents: My child filled out the registration form together with me, but myself, "
+                "and I agree to the participation, the terms of use and the terms and conditions. "
+                "I am aware that the registration is binding and that withdrawal is only possible "
+                "in exceptional cases with a valid reason. In addition, I agree to pay the "
+                "participation fee in advance and agree to the reimbursement "
                 "guidelines mentioned above."
             ),
             "accept_data": _(
-                "I consent to the processing of my data as stated in the"
-                "terms of use and all the data provided is correct. If I am under"
-                "the age of 16, my parents also agree to this and I can prove this on"
+                "I consent to the processing of my data as stated in the "
+                "terms of use and all the data provided is correct. If I am under "
+                "the age of 16, my parents also agree to this and I can prove this on "
                 "request (e.g. by making contact with my parents)."
             ),
             "accept_general_terms": _("I agree with the" "AGB and have read them."),
-            "channel": _("How did you find out about the event?"),
         }
         exclude = []
 
@@ -523,6 +537,35 @@ class EditFeedbackAspectForm(forms.ModelForm):
         exclude = []
 
 
-date_of_birth = forms.DateField(label=_("Date of birth"))
-extend_register_form = Fieldset(date_of_birth)
-AccountRegisterForm.add_node_to_layout(extend_register_form)
+class RegisterEventAccount(SignupForm, ExtensibleForm):
+    """Form to register new user accounts."""
+
+    class Meta:
+        model = Person
+        fields = []
+
+    layout = Layout(
+        Fieldset(
+            _("Base data"),
+            Row("first_name", "last_name"),
+        ),
+        Fieldset(
+            _("Account data"),
+            "username",
+            Row("email", "email2"),
+            Row("password1", "password2"),
+        ),
+    )
+
+    first_name = forms.CharField(label=_("First name"))
+    last_name = forms.CharField(label=_("Last name"))
+    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
+    password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)
+
+    def save(self, request):
+        adapter = get_adapter(request)
+        user = adapter.new_user(request)
+        adapter.save_user(request, user, self)
+        self.custom_signup(request, user)
+        setup_user_email(request, user, [])
+        return user
diff --git a/aleksis/apps/paweljong/urls.py b/aleksis/apps/paweljong/urls.py
index bad236b36099dfbf3807df0486a4a61104e21f92..fa52e0152e3a16bd499a5a0a0b7cef3275385da0 100644
--- a/aleksis/apps/paweljong/urls.py
+++ b/aleksis/apps/paweljong/urls.py
@@ -1,41 +1,80 @@
 from django.urls import path
 
+from aleksis.apps.postbuero.forms import MailAddForm
+
 from . import views
+from .forms import (
+    RegisterEventAccount,
+    RegisterEventAdditional,
+    RegisterEventConsent,
+    RegisterEventContactDetails,
+    RegisterEventFinancial,
+    RegisterEventGuardians,
+)
+
+register_forms = [
+    ("email", MailAddForm),
+    ("register", RegisterEventAccount),
+    ("contact_details", RegisterEventContactDetails),
+    ("guardians", RegisterEventGuardians),
+    ("additional", RegisterEventAdditional),
+    ("financial", RegisterEventFinancial),
+    ("consent", RegisterEventConsent),
+]
+condition_dict = {
+    "email": views.is_email_needed,
+    "register": views.is_person_anonymous,
+}
 
 urlpatterns = [
-    path("event/<int:id_>/edit", views.edit_event, name="edit_event_by_id"),
-    path("event/<int:id_>/feedback", views.feedback_event, name="feedback_event_by_id"),
-    path("event/<int:id_>/register", views.register_event, name="register_event_by_id"),
-    path("events/create", views.edit_event, name="create_event"),
-    path("events/manage", views.ManageEvents.as_view(), name="manage_events"),
-    path("events/", views.events, name="events"),
-    path("vouchers/create", views.edit_voucher, name="create_vouchers"),
-    path("vouchers/<int:id_>/delete", views.delete_voucher, name="delete_voucher_by_id"),
-    path("vouchers/<int:id_>/edit", views.edit_voucher, name="edit_voucher_by_id"),
-    path("vouchers/<int:id_>/print", views.print_voucher, name="print_voucher_by_id"),
+    path("event/<int:pk>/edit", views.EditEventView.as_view(), name="edit_event_by_pk"),
+    path("event/<int:pk>/feedback", views.feedback_event, name="feedback_event_by_pk"),
+    path(
+        "event/<int:pk>/register",
+        views.RegisterEventWizardView.as_view(register_forms, condition_dict=condition_dict),
+        name="register_event_by_id",
+    ),
+    path("event/<slug:slug>", views.EventFullView.as_view(), name="event_by_name"),
+    path("misc/set_email_needed/<int:pk>", views.set_email_needed, name="set_email_needed"),
+    path("events/create", views.CreateEventView.as_view(), name="create_event"),
+    path("events/manage", views.manage_events, name="manage_events"),
+    path("vouchers/create", views.VoucherCreateView.as_view(), name="create_vouchers"),
+    path(
+        "vouchers/<int:pk>/delete", views.VoucherDeleteView.as_view(), name="delete_voucher_by_pk"
+    ),
+    path("vouchers/<int:pk>/edit", views.VoucherEditView.as_view(), name="edit_voucher_by_pk"),
+    path("vouchers/<int:pk>/print", views.print_voucher, name="print_voucher_by_pk"),
     path("vouchers/", views.vouchers, name="vouchers"),
     path("event/lists/generate", views.generate_lists, name="generate_lists"),
     path("event/registrations/list", views.registrations, name="registrations"),
-    path("event/registrations/<int:id_>", views.registration, name="registration_by_id"),
     path(
-        "event/registrations/<int:id_>/edit",
-        views.edit_registration,
-        name="edit_registration_by_id",
+        "event/registrations/<int:pk>",
+        views.EventRegistrationDetailView.as_view(),
+        name="registration_by_pk",
+    ),
+    path(
+        "event/registrations/<int:pk>/edit",
+        views.EventRegistrationEditView.as_view(),
+        name="edit_registration_by_pk",
+    ),
+    path(
+        "event/registrations/<int:pk>/delete",
+        views.EventRegistrationDeleteView.as_view(),
+        name="delete_registration_by_pk",
     ),
     path(
-        "event/registrations/<int:id_>/delete",
-        views.delete_registration,
-        name="delete_registration_by_id",
+        "event/feedback_aspects/list",
+        views.FeedbackAspectListView.as_view(),
+        name="feedback_aspects",
     ),
-    path("event/feedback_aspects/list", views.feedback_aspects, name="feedback_aspects"),
     path(
         "event/feedback_aspects/create",
-        views.edit_feedback_aspect,
+        views.FeedbackAspectCreateView.as_view(),
         name="create_feedback_aspect",
     ),
     path(
-        "event/feedback_aspects/<int:id_>/edit",
-        views.edit_feedback_aspect,
-        name="edit_feedback_aspect_by_id",
+        "event/feedback_aspects/<int:pk>/edit",
+        views.FeedbackAspectEditView.as_view(),
+        name="edit_feedback_aspect_by_pk",
     ),
 ]
diff --git a/aleksis/apps/paweljong/views.py b/aleksis/apps/paweljong/views.py
index 515bef9f933133b5afcdd4554493e5eb6045ae17..45e007da9616523a23b9b497f1f2d6e7fde9e244 100644
--- a/aleksis/apps/paweljong/views.py
+++ b/aleksis/apps/paweljong/views.py
@@ -1,23 +1,31 @@
-from typing import Optional
-
+from django.conf import settings
+from django.contrib.auth import get_user_model
 from django.contrib.auth.decorators import login_required
 from django.http import HttpRequest, HttpResponse
 from django.shortcuts import redirect, render
+from django.urls import reverse_lazy
 from django.utils import timezone
+from django.utils.decorators import method_decorator
+from django.utils.text import slugify
 from django.utils.translation import ugettext as _
-from django.views.generic.list import ListView
+from django.views.decorators.cache import never_cache
+from django.views.generic.detail import DetailView
 
 import reversion
 from django_tables2 import RequestConfig
-from reversion.views import create_revision
+from django_tables2.views import SingleTableView
+from formtools.wizard.views import SessionWizardView
+from reversion.views import RevisionMixin
 from rules.contrib.views import PermissionRequiredMixin, permission_required
 from templated_email import send_templated_mail
 
+from aleksis.apps.postbuero.models import MailAddress
+from aleksis.core.mixins import AdvancedCreateView, AdvancedDeleteView, AdvancedEditView
 from aleksis.core.models import Activity, Person
 from aleksis.core.util import messages
 from aleksis.core.util.core_helpers import lazy_preference, objectgetter_optional
 
-from .filters import EventRegistrationFilter, FeedbackAspectsFilter, VoucherFilter
+from .filters import EventFilter, EventRegistrationFilter, VoucherFilter
 from .forms import (
     EditEventForm,
     EditEventRegistrationForm,
@@ -25,199 +33,20 @@ from .forms import (
     EditVoucherForm,
     EventFeedbackForm,
     GenerateListForm,
-    RegisterEventForm,
 )
 from .models import Event, EventRegistration, FeedbackAspect, Voucher
-from .tables import (
-    EventRegistrationsTable,
-    EventsTable,
-    FeedbackAspectsTable,
-    ParticipatedEventsTable,
-    VouchersTable,
-)
-from .util import generate_code
-
-
-def events(request):
-    context = {}
-
-    # Get all upcoming events
-    now = timezone.datetime.today()
-    events = Event.objects.filter(date_event__gte=now, published=True)
-
-    # Build table
-    events_table = EventsTable(events)
-    RequestConfig(request).configure(events_table)
-    context["events_table"] = events_table
-
-    if request.user.is_authenticated:
-        # Get all events the person participated in.
-        current_person = Person.objects.get(user__username=request.user.username)
-        participated_events = Event.objects.filter(group__members=current_person)
-
-        # Build table
-        participated_events_table = ParticipatedEventsTable(participated_events)
-        RequestConfig(request).configure(participated_events_table)
-        context["participated_events_table"] = participated_events_table
-
-    return render(request, "paweljong/_event/list.html", context)
-
-
-@create_revision
-@login_required
-def register_event(request, id_):
-    context = {}
-
-    # Get current person and event
-    event = Event.objects.get(id=id_)
-    context["event"] = event
-
-    initial = {
-        "person": request.user.person,
-        "event": event,
-        "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 request.user.person.guardians.first():
-        initial.update(
-            {
-                "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,
-            }
-        )
-
-    register_form = RegisterEventForm(initial=initial)
-
-    # Produce error if registration is not possible
-    if not event.can_register(request):
-        messages.error(request, _("Registration is no longer possible"))
-        return redirect("events")
-
-    # Check whether person is already a member of the event
-    if request.user.person in event.group.members.all():
-        messages.success(request, _("You are already registred."))
-        return redirect("events")
-
-    if request.method == "POST":
-        register_form = RegisterEventForm(request.POST, initial=initial)
-        if register_form.is_valid():
-            # Update person information if changed
-            if (
-                "school" in register_form.changed_data
-                or "school_class" in register_form.changed_data
-                or "school_place" in register_form.changed_data
-                or "mobile" in register_form.changed_data
-                or "sex" in register_form.changed_data
-                or "date_of_birth" in register_form.changed_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"]
-                request.user.person.sex = register_form.cleaned_data["sex"]
-                request.user.person.date_of_birth = register_form.cleaned_data["date_of_birth"]
-
-                request.user.person.save()
-
-            # Store postal address in database
-            if (
-                "postal_code" in register_form.changed_data
-                or "place" in register_form.changed_data
-                or "street" in register_form.changed_data
-            ):
-
-                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
-                or "guardian_last_name" in register_form.changed_data
-                or "guardian_mobile_number" in register_form.changed_data
-                or "guardian_email" in register_form.changed_data
-            ):
-                guardian = Person.objects.get_or_create(
-                    defaults={
-                        "first_name": register_form.cleaned_data["guardian_first_name"],
-                        "last_name": register_form.cleaned_data["guardian_last_name"],
-                        "mobile_number": register_form.cleaned_data["guardian_mobile_number"],
-                    },
-                    email=register_form.cleaned_data["guardian_email"],
-                )
-
-                request.user.person.guardians.add(guardian[0])
-                request.user.person.save()
-
-            # Add the current person to the event
-            event.add_member(request.user.person)
-            event.save()
-
-            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"])
-                if voucher:
-                    registration.voucher = voucher
-                    with reversion.create_revision():
-                        registration.save()
-                else:
-                    messages.error(request, _("You entered an invalid voucher code!"))
-
-            send_templated_mail(
-                template_name="event_registred",
-                from_email=lazy_preference("mail", "address"),
-                recipient_list=["orga@.org"],
-                headers={
-                    "reply_to": [
-                        request.person.email,
-                        request.person.guardians.first().email,
-                    ],
-                },
-                context=context,
-            )
+from .tables import EventRegistrationsTable, FeedbackAspectsTable, ManageEventsTable, VouchersTable
 
-            messages.success(
-                request,
-                _(
-                    "You have successfully registered for the event. Please give us"
-                    "up to two days to process your registration. You will then"
-                    "receive an email from us."
-                ),
-            )
-
-            act = Activity(
-                title=_("You registred for an event"),
-                description=_("You registred for the event %s" % event.display_name),
-                app="TIC-Desk",
-                user=request.user.person,
-            )
-            act.save()
-
-    context["register_form"] = register_form
-
-    return render(request, "paweljong/_event/register.html", context)
+User = get_user_model()
 
 
 @login_required
-def feedback_event(request, id_):
+def feedback_event(request, pk):
     context = {}
 
     # Get current person and event
     current_person = Person.objects.get(user__username=request.user.username)
-    event = Event.objects.get(id=id_)
+    event = Event.objects.get(id=pk)
     context["event"] = event
 
     # Prepare the form
@@ -229,8 +58,8 @@ 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.group.members.all():
-        return redirect("events")
+    if current_person not in event.linked_group.members.all():
+        return redirect("index")
         messages.error(request, _("You did not take part in this event."))
 
     if request.method == "POST":
@@ -242,7 +71,7 @@ def feedback_event(request, id_):
             send_templated_mail(
                 template_name="event_feedback",
                 from_email=lazy_preference("mail", "address"),
-                recipient_list=["verein@.org"],
+                recipient_list=["verein@teckids.org"],
                 headers={
                     "reply_to": [
                         request.person.email,
@@ -253,7 +82,7 @@ def feedback_event(request, id_):
 
             # Set success
             messages.success(request, _("Feedback successfully submitted."))
-            return redirect("events")
+            return redirect("index")
 
             act = Activity(
                 title=_("You submitted feedback"),
@@ -265,55 +94,49 @@ def feedback_event(request, id_):
 
     context["feedback_form"] = feedback_form
 
-    return render(request, "paweljong/_event/feedback.html", context)
+    return render(request, "paweljong/event/feedback.html", context)
 
 
-@permission_required("paweljong.change_event", fn=objectgetter_optional(Event, None, False))
-def edit_event(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """View to edit or create an event."""
-    context = {}
+@method_decorator(never_cache, name="dispatch")
+class CreateEventView(PermissionRequiredMixin, AdvancedCreateView):
+    form_class = EditEventForm
+    model = Event
+    permission_required = "paweljong.change_event"
+    template_name = "paweljong/event/create.html"
+    success_url = reverse_lazy("mange_events")
+    success_message = _("The event has been saved.")
 
-    event = objectgetter_optional(Event, None, False)(request, id_)
-    context["event"] = event
-
-    if event:
-        # Edit form for existing event
-        edit_event_form = EditEventForm(request.POST or None, instance=event)
-    else:
-        # Empty form to create a new event
-        edit_event_form = EditEventForm(request.POST or None)
 
-    if request.method == "POST":
-        if edit_event_form.is_valid():
-            with reversion.create_revision():
-                new_event = edit_event_form.save()
-                context["new_event"] = new_event
-                context["person"] = request.user.person
-                send_templated_mail(
-                    template_name="event_created",
-                    from_email=lazy_preference("mail", "address"),
-                    recipient_list=["orga@.org"],
-                    context=context,
-                )
-            messages.success(request, _("The event has been saved."))
+@method_decorator(never_cache, name="dispatch")
+class EditEventView(PermissionRequiredMixin, RevisionMixin, AdvancedEditView):
+    form_class = EditEventForm
+    model = Event
+    permission_required = "paweljong.change_event"
+    context_object_name = "manage_events"
+    template_name = "paweljong/event/edit.html"
+    success_url = reverse_lazy("manage_events")
+    success_message = _("The event has been saved.")
 
-            return redirect("events")
 
-    context["edit_event_form"] = edit_event_form
-
-    return render(request, "paweljong/_event/edit.html", context)
+@permission_required("paweljong.change_events")
+def manage_events(request: HttpRequest) -> HttpResponse:
+    """List view listing all registrations."""
+    context = {}
 
+    # Get all registrations
+    now = timezone.datetime.today()
+    events = Event.objects.filter(date_event__gte=now)
 
-class ManageEvents(ListView, PermissionRequiredMixin):
-    """View listing upcoming events."""
+    # Get filter
+    events_filter = EventFilter(request.GET, queryset=events)
+    context["events_filter"] = events_filter
 
-    template_name = "paweljong/_event/manage.html"
-    permission_required = "paweljong.change_events"
-    context = {}
+    # Build table
+    events_table = ManageEventsTable(events_filter.qs)
+    RequestConfig(request).configure(events_table)
+    context["events_table"] = events_table
 
-    def get_queryset(self):
-        now = timezone.datetime.today()
-        return Event.objects.filter(date_event__gte=now)
+    return render(request, "paweljong/event/manage.html", context)
 
 
 @permission_required("paweljong.view_vouchers")
@@ -335,70 +158,6 @@ def vouchers(request):
     return render(request, "paweljong/voucher/list.html", context)
 
 
-@permission_required("paweljong.delete_voucher")
-def delete_voucher(request, id_):
-    context = {}
-
-    current_voucher = Voucher.objects.get(id=id_)
-    current_voucher.deleted = True
-    with reversion.create_revision():
-        current_voucher.save()
-
-    act = Activity(
-        title=_("You deleted a voucher!"),
-        description=_("You deleted the voucher with ID %s" % current_voucher.id),
-        app="TIC-Desk",
-        user=request.user.person,
-    )
-    act.save()
-
-    messages.success(request, _("The voucher was successfully deleted."))
-
-    return redirect("vouchers")
-
-
-@permission_required("paweljong.change_voucher", fn=objectgetter_optional(Voucher, None, False))
-def edit_voucher(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """View to edit or create a voucher."""
-    context = {}
-
-    voucher = objectgetter_optional(Voucher, None, False)(request, id_)
-    context["voucher"] = voucher
-
-    if id_:
-        # Edit form for existing voucher
-        edit_voucher_form = EditVoucherForm(request.POST or None, instance=voucher)
-    else:
-        # Empty form to create a new voucher
-        edit_voucher_form = EditVoucherForm(request.POST or None)
-
-    if request.method == "POST":
-        if edit_voucher_form.is_valid():
-            voucher = edit_voucher_form.save(commit=True)
-            if not voucher.code:
-                voucher.code = generate_code()
-            with reversion.create_revision():
-                voucher.save()
-
-            act = Activity(
-                title=_("You have created a voucher."),
-                description=_(
-                    "You have created a voucher for %s for %s" % (voucher.person, voucher.event)
-                ),
-                app="TIC-Desk",
-                user=request.user.person,
-            )
-            act.save()
-
-            messages.success(request, _("The voucher has been saved."))
-
-            return redirect("vouchers")
-
-    context["edit_voucher_form"] = edit_voucher_form
-
-    return render(request, "paweljong/voucher/edit.html", context)
-
-
 @permission_required("paweljong.generate_lists")
 def generate_lists(request: HttpRequest) -> HttpResponse:
     context = {}
@@ -439,51 +198,38 @@ def registrations(request: HttpRequest) -> HttpResponse:
     return render(request, "paweljong/event_registration/list.html", context)
 
 
-@permission_required(
-    "paweljong.view_registration",
-    fn=objectgetter_optional(EventRegistration, "request.user.person", True),
-)
-def registration(request: HttpRequest, id_) -> HttpResponse:
-    context = {}
-
-    registration = objectgetter_optional(EventRegistration, "request.user.person", True)(
-        request, id_
-    )
-
-    context["registration"] = registration
-
-    return render(request, "paweljong/event_registration/full.html", context)
-
+@method_decorator(never_cache, name="dispatch")
+class EventRegistrationCreateView(PermissionRequiredMixin, AdvancedCreateView):
+    """Create view for event registrations."""
 
-@permission_required(
-    "paweljong.delete_registrations",
-    fn=objectgetter_optional(EventRegistration, None, False),
-)
-def delete_registration(request: HttpRequest, id_) -> HttpResponse:
-    context = {}
+    model = EventRegistration
+    form_class = EditEventRegistrationForm
+    permission_required = "paweljong.manage_registration"
+    template_name = "paweljong/event_registration/create.html"
+    success_url = reverse_lazy("event_registrations")
+    success_message = _("The event registration has been created.")
 
-    registration = EventRegistration.objects.get(id=id_)
 
-    person = registration.person
+@method_decorator(never_cache, name="dispatch")
+class EventRegistrationEditView(PermissionRequiredMixin, AdvancedEditView):
+    """Edit view for event registrations."""
 
-    registration.event.remove_member(registration.person)
-    registration.event.save()
-
-    registration.delete()
-
-    messages.success(request, _("Registration was successfully deleted."))
-
-    return redirect("registrations")
+    model = EventRegistration
+    form_class = EditEventRegistrationForm
+    permission_required = "paweljong.manage_eventregistration"
+    template_name = "paweljong/event_registration/edit.html"
+    success_url = reverse_lazy("event_registrations")
+    success_message = _("The event registration has been saved.")
 
 
 @permission_required(
     "paweljong.manage_registrations",
     fn=objectgetter_optional(EventRegistration, None, False),
 )
-def edit_registration(request: HttpRequest, id_) -> HttpResponse:
+def edit_registration(request: HttpRequest, pk) -> HttpResponse:
     context = {}
 
-    registration = objectgetter_optional(EventRegistration, None, False)(request, id_)
+    registration = objectgetter_optional(EventRegistration, None, False)(request, pk)
 
     edit_event_registration_form = EditEventRegistrationForm(
         request.POST or None, instance=registration
@@ -504,72 +250,422 @@ def edit_registration(request: HttpRequest, id_) -> HttpResponse:
 
 
 @permission_required("paweljong.is_own_voucher", fn=objectgetter_optional(Voucher, None, False))
-def print_voucher(request: HttpRequest, id_) -> HttpResponse:
+def print_voucher(request: HttpRequest, pk) -> HttpResponse:
     context = {}
 
-    voucher = Voucher.objects.get(id=id_)
+    voucher = Voucher.objects.get(id=pk)
     context["voucher"] = voucher
 
     return render(request, "paweljong/print/voucher.html", context)
 
 
-@permission_required("paweljong.view_feedback_aspects")
-def feedback_aspects(request: HttpRequest) -> HttpResponse:
-    """List view listing all feedback_aspects."""
-    context = {}
+class FeedbackAspectListView(PermissionRequiredMixin, SingleTableView):
+    """Table of all feedback aspects."""
 
-    # Get all feedback_aspects
-    feedback_aspects = FeedbackAspect.objects.all()
+    model = FeedbackAspect
+    table_class = FeedbackAspectsTable
+    permission_required = "paweljong.view_feedback_aspects"
+    template_name = "paweljong/feedback_aspect/list.html"
 
-    # Get filter
-    feedback_aspects_filter = FeedbackAspectsFilter(request.GET, queryset=feedback_aspects)
-    context["feedback_aspects_filter"] = feedback_aspects_filter
 
-    # Build table
-    feedback_aspects_table = FeedbackAspectsTable(feedback_aspects_filter.qs)
-    RequestConfig(request).configure(feedback_aspects_table)
-    context["feedback_aspects_table"] = feedback_aspects_table
+@method_decorator(never_cache, name="dispatch")
+class FeedbackAspectCreateView(PermissionRequiredMixin, AdvancedCreateView):
+    """Create view for feedback aspects."""
 
-    return render(request, "paweljong/feedback_aspect/list.html", context)
+    model = FeedbackAspect
+    form_class = EditFeedbackAspectForm
+    permission_required = "paweljong.add_feedback_aspects"
+    template_name = "paweljong/feedback_aspect/create.html"
+    success_url = reverse_lazy("feedback_aspects")
+    success_message = _("The feedback aspect has been created.")
 
 
-@permission_required(
-    "paweljong.change_feedback_aspect",
-    fn=objectgetter_optional(FeedbackAspect, None, False),
-)
-def edit_feedback_aspect(request: HttpRequest, id_: Optional[int] = None) -> HttpResponse:
-    """View to edit or create an feedback_aspect."""
-    context = {}
+@method_decorator(never_cache, name="dispatch")
+class FeedbackAspectEditView(PermissionRequiredMixin, AdvancedEditView):
+    """Edit view for feedback aspects."""
 
-    feedback_aspect = objectgetter_optional(FeedbackAspect, None, False)(request, id_)
-    context["feedback_aspect"] = feedback_aspect
+    model = FeedbackAspect
+    form_class = EditFeedbackAspectForm
+    permission_required = "paweljong.edit_feedback_aspects"
+    template_name = "paweljong/feedback_aspect/edit.html"
+    success_url = reverse_lazy("feedback_aspects")
+    success_message = _("The feedback aspect has been saved.")
 
-    if id_:
-        # Edit form for existing feedback_aspect
-        edit_feedback_aspect_form = EditFeedbackAspectForm(
-            request.POST or None, instance=feedback_aspect
-        )
-    else:
-        # Empty form to create a new feedback_aspect
-        edit_feedback_aspect_form = EditFeedbackAspectForm(request.POST or None)
 
-    if request.method == "POST":
-        if edit_feedback_aspect_form.is_valid():
-            with reversion.create_revision():
-                aspect = edit_feedback_aspect_form.save(commit=True)
+class EventRegistrationDetailView(PermissionRequiredMixin, DetailView):
+    """Detail view for an application instance."""
+
+    context_object_name = "registration"
+    permission_required = "paweljong.view_registration"
+    template_name = "paweljong/event_registration/full.html"
+
+    def get_queryset(self):
+        return EventRegistration.objects.all()
+
+
+class FeedbackAspectDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
+    """Delete view for dashboard widgets."""
+
+    model = FeedbackAspect
+    permission_required = "paweljong.delete_feedbackaspect"
+    template_name = "core/pages/delete.html"
+    success_url = reverse_lazy("feedback_aspects")
+    success_message = _("The feedback aspect has been deleted.")
+
+
+class EventRegistrationDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
+    """Delete view for registrations."""
+
+    model = EventRegistration
+    permission_required = "paweljong.delete_eventregistration"
+    template_name = "core/pages/delete.html"
+    success_url = reverse_lazy("registrations")
+    success_message = _("The registration has been deleted.")
+
+
+@method_decorator(never_cache, name="dispatch")
+class VoucherCreateView(PermissionRequiredMixin, AdvancedCreateView):
+    """Create view for vouchers."""
+
+    model = Voucher
+    form_class = EditVoucherForm
+    permission_required = "paweljong.add_voucher"
+    template_name = "paweljong/voucher/create.html"
+    success_url = reverse_lazy("vouchers")
+    success_message = _("The voucher has been created.")
+
+
+@method_decorator(never_cache, name="dispatch")
+class VoucherEditView(PermissionRequiredMixin, AdvancedEditView):
+    """Edit view for vouchers."""
+
+    model = Voucher
+    form_class = EditVoucherForm
+    permission_required = "paweljong.edit_voucher"
+    template_name = "paweljong/voucher/edit.html"
+    success_url = reverse_lazy("vouchers")
+    success_message = _("The voucher has been saved.")
+
+
+class VoucherDeleteView(PermissionRequiredMixin, AdvancedDeleteView):
+    """Delete view for vouchers."""
+
+    model = Voucher
+    permission_required = "paweljong.delete_voucher"
+    template_name = "core/pages/delete.html"
+    success_url = reverse_lazy("vouchers")
+    success_message = _("The voucher has been deleted.")
+
+
+def is_person_anonymous(wizard):
+    return wizard.request.user.is_anonymous
+
+
+def set_email_needed(request, pk):
+    request.session["email_needed"] = "true"
+
+    return redirect("register_event_by_id", pk)
+
+
+def is_email_needed(wizard):
+    if wizard.request.session.get("email_needed"):
+        wizard.request.session.pop("email_needed")
+        return True
+
+
+class RegisterEventWizardView(SessionWizardView):
+    template_name = "paweljong/event/register_wizard.html"
+    file_storage = settings.DEFAULT_FILE_STORAGE
+
+    def get_context_data(self, form, **kwargs):
+        context = super().get_context_data(form, **kwargs)
+        context["event"] = Event.objects.get(id=self.kwargs["pk"])
+
+        if self.steps.current == "email":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "register":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "contact_details":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "guardians":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "additional":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "financial":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+        elif self.steps.current == "consent":
+            context["page_title"] = ""
+            context["browser_title"] = ""
+            context["info_title"] = "foobar"
+            context["info_text"] = "barfoo"
+
+        return context
+
+    def get_form_kwargs(self, step):
+        kwargs = super().get_form_kwargs()
+        if step == "email":
+            kwargs["request"] = self.request
+        if step == "additional":
+            event = Event.objects.get(id=self.kwargs["pk"])
+            kwargs["event"] = event
+        return kwargs
+
+    def get_form_initial(self, step):
+
+        initial = self.initial_dict.get(step, {})
+
+        if step == "register":
+            cleaned_data_email = self.get_cleaned_data_for_step("email")
+            if cleaned_data_email:
+                domain = cleaned_data_email["domain"]
+                email = f"{cleaned_data_email['local_part']}@{domain.domain}"
+                initial.update(
+                    {
+                        "email": email,
+                        "email2": email,
+                    }
+                )
 
-                act = Activity(
-                    title=_("You have create a feedback aspect."),
-                    description=_("You have created the feedback aspect: %s" % aspect),
-                    app="TIC-Desk",
-                    user=request.user.person,
+        if step == "guardians":
+            if hasattr(self.request.user, "person"):
+                person = self.request.user.person
+                if person.guardians.first():
+                    initial.update(
+                        {
+                            "guardian_first_name": person.guardians.first().first_name,
+                            "guardian_last_name": person.guardians.first().last_name,
+                            "guardian_mobile_number": person.guardians.first().mobile_number,
+                            "guardian_email": person.guardians.first().email,
+                        }
+                    )
+
+        if step == "contact_details":
+            if hasattr(self.request.user, "person"):
+                person = self.request.user.person
+                initial.update(
+                    {
+                        "first_name": person.first_name,
+                        "additional_name": person.additional_name,
+                        "last_name": person.last_name,
+                        "school": person.school,
+                        "school_place": person.school_place,
+                        "school_class": person.school_class,
+                        "mobile_number": person.mobile_number,
+                        "email": person.email,
+                        "street": person.street,
+                        "place": person.place,
+                        "housenumber": person.housenumber,
+                        "sex": person.sex,
+                        "date_of_birth": person.date_of_birth,
+                        "postal_code": person.postal_code,
+                    }
                 )
-                act.save()
 
-            messages.success(request, _("The feedback aspect has been saved."))
+            else:
+                cleaned_data_register = self.get_cleaned_data_for_step("register")
+                if cleaned_data_register:
+                    initial.update(
+                        {
+                            "first_name": cleaned_data_register["first_name"],
+                            "last_name": cleaned_data_register["last_name"],
+                        }
+                    )
+
+        return self.initial_dict.get(step, initial)
+
+    def done(self, form_list, **kwargs):
+
+        event = Event.objects.get(id=self.kwargs["pk"])
+        cleaned_data_email = self.get_cleaned_data_for_step("email")
+        cleaned_data_contact_details = self.get_cleaned_data_for_step("cotact_details")
+        cleaned_data_guardians = self.get_cleaned_data_for_step("guardians")
+        cleaned_data_register = self.get_cleaned_data_for_step("register")
+        cleaned_data_additional = self.get_cleaned_data_for_step("additional")
+        cleaned_data_financial = self.get_cleaned_data_for_step("financial")
+        cleaned_data_consent = self.get_cleaned_data_for_step("consent")
+
+        # Create email address
+        if cleaned_data_email:
+            _email = MailAddress.objects.create(
+                local_part=cleaned_data_email["local_part"],
+                domain=cleaned_data_email["domain"],
+            )
+
+        # Create user
+        if cleaned_data_register:
+            user = User.objects.create(
+                username=cleaned_data_register["username"],
+                email=cleaned_data_register["email"],
+            )
+            user.set_password(cleaned_data_register["password1"])
+            user.save()
+
+            # Create Person
+            person = Person.objects.create(
+                user=user,
+                email=cleaned_data_contact_detailts["email"],
+                short_name=cleaned_data_contact_detailts["short_name"],
+                first_name=cleaned_data_contact_detailts["first_name"],
+                additional_name=cleaned_data_contact_detailts["additional_name"],
+                last_name=cleaned_data_contact_detailts["last_name"],
+                street=cleaned_data_contact_detailts["street"],
+                housenumber=cleaned_data_contact_detailts["housenumber"],
+                postal_code=cleaned_data_contact_detailts["postal_code"],
+                place=cleaned_data_contact_detailts["place"],
+                mobile_number=cleaned_data_contact_detailts["mobile_number"],
+                phone_number=cleaned_data_contact_detailts["phone_number"],
+                date_of_birth=cleaned_data_contact_detailts["date_of_birth"],
+                place_of_birth=cleaned_data_contact_detailts["place_of_birth"],
+                sex=cleaned_data_contact_detailts["sex"],
+                photo=cleaned_data_contact_detailts["photo"],
+                description=cleaned_data_contact_detailts["description"],
+            )
+
+        if (
+            "school" in cleaned_data_contact_details
+            or "school_class" in cleaned_data_contact_details
+            or "school_place" in cleaned_data_contact_details
+            or "mobile" in cleaned_data_contact_details
+            or "sex" in cleaned_data_contact_details
+            or "date_of_birth" in cleaned_data_contact_details
+        ):
+            person = Person.objects.get(email=cleaned_data_contact_details["email"])
+            person.school = cleaned_data_contact_details["school"]
+            person.school_class = cleaned_data_contact_details["school_class"]
+            person.school_place = cleaned_data_contact_details["school_place"]
+            person.mobile_number = cleaned_data_contact_details["mobile_number"]
+            person.sex = cleaned_data_contact_details["sex"]
+            person.date_of_birth = cleaned_data_contact_details["date_of_birth"]
+
+            person.save()
+
+        # Store postal address in database
+        if (
+            "postal_code" in cleaned_data_contact_details
+            or "place" in cleaned_data_contact_details
+            or "street" in cleaned_data_contact_details
+        ):
+
+            person.street = cleaned_data_contact_details["street"]
+            person.postal_code = cleaned_data_contact_details["postal_code"]
+            person.place = cleaned_data_contact_details["place"]
+
+            person.save()
+
+        if (
+            "guardian_first_name" in cleaned_data_guardians
+            or "guardian_last_name" in cleaned_data_guardians
+            or "guardian_mobile_number" in cleaned_data_guardians
+            or "guardian_email" in cleaned_data_guardians
+        ):
+            guardian = Person.objects.get_or_create(
+                defaults={
+                    "first_name": cleaned_data_guardians["guardian_first_name"],
+                    "last_name": cleaned_data_guardians["guardian_last_name"],
+                    "mobile_number": cleaned_data_guardians["guardian_mobile_number"],
+                },
+                email=cleaned_data_guardians["guardian_email"],
+            )
+
+            person.guardians.add(guardian[0])
+            person.save()
+
+        if cleaned_data_email:
+            _email.person = person
+            _email.save()
+
+        # Add the current person to the event
+        event.linked_group.members.add(person)
+
+        registration = EventRegistration.objects.create(
+            event=event,
+            person=person,
+            medical_information=cleaned_data_additional["medical_information"],
+            donation=cleaned_data_financial["donation"],
+            accept_sepa=cleaned_data_financial["accept_sepa"],
+            iban=cleaned_data_financial["iban"],
+            accept_terms=cleaned_data_consent["accept_terms"],
+            accept_data=cleaned_data_consent["accept_data"],
+            accept_general_terms=cleaned_data_consent["accept_general_terms"],
+        )
+        for field in event.linked_group.additional_fields.all():
+            registration.extended_data[
+                slugify(field.title).replace("-", "_")
+            ] = cleaned_data_additional[field.title]
+        registration.save()
+
+        if cleaned_data_financial["voucher_code"] != "":
+            voucher = Voucher.objects.get(code=cleaned_data_financial["voucher_code"])
+            if voucher:
+                registration.voucher = voucher
+                with reversion.create_revision():
+                    registration.save()
+            else:
+                messages.error(self.request, _("You entered an invalid voucher code!"))
+
+        context = {}
+        context["registration"] = registration
+
+        send_templated_mail(
+            template_name="event_registred",
+            from_email=lazy_preference("mail", "address"),
+            recipient_list=["orga@teckids.org"],
+            headers={
+                "reply_to": [
+                    person.email,
+                    person.guardians.first().email,
+                ],
+            },
+            context=context,
+        )
+
+        messages.success(
+            self.request,
+            _(
+                "You have successfully registered for the event. Please give us "
+                "up to two days to process your registration. You will then "
+                "receive an email from us."
+            ),
+        )
+
+        act = Activity(
+            title=_("You registred for an event"),
+            description=_("You registred for the event %s" % event.display_name),
+            app="TIC-Desk",
+            user=person,
+        )
+        act.save()
+
+        return redirect("index")
+
+
+class EventFullView(DetailView):
 
-            return redirect("feedback_aspects")
+    model = Event
+    slug_field = "linked_group__name"
+    template_name = "paweljong/event/full.html"
+    object_context_name = "event"
 
-    context["edit_feedback_aspect_form"] = edit_feedback_aspect_form
+    def get_context_data(self, **kwargs):
+        context = super(EventFullView, self).get_context_data(**kwargs)
 
-    return render(request, "paweljong/feedback_aspect/edit.html", context)
+        context["can_register"] = context["event"].can_register(request=self.request)
+        return context