Passed
Push — main ( 7e9c56...8b0189 )
by Jochen
03:34
created

ms_version_id()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.2559

Importance

Changes 0
Metric Value
cc 2
eloc 6
nop 2
dl 0
loc 6
ccs 3
cts 5
cp 0.6
crap 2.2559
rs 10
c 0
b 0
f 0
1
"""
2
byceps.blueprints.common.user.creation.forms
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9 1
import re
10 1
from typing import Set
11 1
from uuid import UUID
12
13 1
from wtforms import BooleanField, HiddenField, PasswordField, StringField
14 1
from wtforms.validators import InputRequired, Length, ValidationError
15
16 1
from .....services.consent.transfer.models import Subject, SubjectID
17 1
from .....services.user import screen_name_validator
18 1
from .....services.user import service as user_service
19 1
from .....util.l10n import LocalizedForm
20
21
22 1
EMAIL_ADDRESS_PATTERN = re.compile(r'^.+?@.+?\..+?$')
23
24
25 1
class ScreenNameValidator:
26
    """Make sure screen name contains only permitted characters.
27
28
    However, do *not* check the length; use WTForms' `Length` for that.
29
    """
30
31 1
    def __call__(self, form, field):
32 1
        if not screen_name_validator.contains_only_valid_chars(field.data):
33
            special_chars_spaced = ' '.join(screen_name_validator.SPECIAL_CHARS)
34
            raise ValidationError(
35
                'Enthält ungültige Zeichen. Erlaubt sind Buchstaben, '
36
                f' Ziffern und diese Sonderzeichen: {special_chars_spaced}'
37
            )
38
39
40 1
def assemble_user_create_form(
41
    real_name_required: bool,
42
    terms_consent_required: bool,
43
    required_consent_subjects: Set[Subject],
44
    newsletter_offered: bool,
45
):
46 1
    class UserCreateForm(LocalizedForm):
47 1
        screen_name = StringField('Benutzername', [
48
            InputRequired(),
49
            Length(min=screen_name_validator.MIN_LENGTH,
50
                   max=screen_name_validator.MAX_LENGTH),
51
            ScreenNameValidator(),
52
        ])
53 1
        first_names = StringField('Vorname(n)', [InputRequired(), Length(min=2, max=40)])
54 1
        last_name = StringField('Nachname', [InputRequired(), Length(min=2, max=80)])
55 1
        email_address = StringField('E-Mail-Adresse', [InputRequired(), Length(min=6, max=120)])
56 1
        password = PasswordField('Passwort', [InputRequired(), Length(min=8)])
57 1
        is_bot = BooleanField('Bot')
58
59 1
        @staticmethod
60
        def validate_screen_name(form, field):
61 1
            if user_service.is_screen_name_already_assigned(field.data):
62
                raise ValueError('Dieser Benutzername kann nicht verwendet werden.')
63
64 1
        @staticmethod
65
        def validate_email_address(form, field):
66 1
            if EMAIL_ADDRESS_PATTERN.search(field.data) is None:
67
                raise ValueError('Die E-Mail-Adresse ist ungültig.')
68
69 1
            if user_service.is_email_address_already_assigned(field.data):
70
                raise ValueError(
71
                    'Diese E-Mail-Adresse kann nicht verwendet werden.'
72
                )
73
74 1
        @staticmethod
75
        def validate_terms_version_id(form, field):
76 1
            try:
77 1
                UUID(field.data)
78
            except ValueError:
79
                raise ValueError('Ungültige AGB-Version.')
80
81 1
        @staticmethod
82
        def validate_is_bot(form, field):
83 1
            if field.data:
84
                raise ValueError('Bots sind nicht erlaubt.')
85
86 1
        def get_field_for_consent_subject_id(self, subject_id: SubjectID):
87
            name = _generate_consent_subject_field_name(subject_id)
88
            return getattr(self, name)
89
90 1
    if not real_name_required:
91
        del UserCreateForm.first_names
92
        del UserCreateForm.last_name
93
94 1
    if terms_consent_required:
95 1
        terms_version_id = HiddenField('AGB-Version', [InputRequired()])
96 1
        consent_to_terms = BooleanField('AGB', [InputRequired()])
97 1
        setattr(UserCreateForm, 'terms_version_id', terms_version_id)
98 1
        setattr(UserCreateForm, 'consent_to_terms', consent_to_terms)
99
100 1
    for subject in required_consent_subjects:
101 1
        field_name = _generate_consent_subject_field_name(subject.id)
102 1
        field = BooleanField('', [InputRequired()])
103 1
        setattr(UserCreateForm, field_name, field)
104
105 1
    if newsletter_offered:
106 1
        subscribe_to_newsletter = BooleanField('Newsletter')
107 1
        setattr(UserCreateForm, 'subscribe_to_newsletter', subscribe_to_newsletter)
108
109 1
    return UserCreateForm
110
111
112 1
def _generate_consent_subject_field_name(subject_id: SubjectID) -> str:
113
    return f'consent_to_subject_{subject_id}'
114