Passed
Push — master ( 604fab...2b3f0b )
by Jochen
02:09
created

byceps.blueprints.user.creation.views   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 287
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 175
dl 0
loc 287
rs 10
c 0
b 0
f 0
wmc 30

10 Functions

Rating   Name   Duplication   Size   Complexity  
A _find_privacy_policy_consent_subject_id() 0 10 2
D create() 0 119 11
A create_form() 0 39 3
A _find_newsletter_list_for_brand() 0 10 2
A _find_brand_setting_value() 0 5 1
A _adjust_create_form() 0 20 5
A _abort_if_user_account_creation_disabled() 0 4 2
A _is_real_name_required() 0 9 1
A _find_site_setting_value() 0 5 1
A _is_user_account_creation_enabled() 0 6 2
1
"""
2
byceps.blueprints.user.creation.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2019 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9
from datetime import datetime
10
from typing import Optional
11
12
from flask import abort, g, request
13
14
from ....config import get_site_mode
15
from ....services.brand import settings_service as brand_settings_service
16
from ....services.consent.transfer.models import Consent, SubjectID
17
from ....services.newsletter.transfer.models import (
18
    ListID as NewsletterListID,
19
    Subscription as NewsletterSubscription,
20
)
21
from ....services.site import (
22
    settings_service as site_settings_service,
23
    service as site_service,
24
)
25
from ....services.terms import document_service as terms_document_service
26
from ....services.terms import version_service as terms_version_service
27
from ....services.user import creation_service as user_creation_service
28
from ....services.user import service as user_service
29
from ....util.framework.blueprint import create_blueprint
30
from ....util.framework.flash import flash_error, flash_success
31
from ....util.framework.templating import templated
32
from ....util.views import redirect_to
33
34
from .. import signals
35
36
from .forms import UserCreateForm
37
38
39
blueprint = create_blueprint('user_creation', __name__)
40
41
42
@blueprint.route('/create')
43
@templated
44
def create_form(erroneous_form=None):
45
    """Show a form to create a user."""
46
    _abort_if_user_account_creation_disabled()
47
48
    terms_version = terms_version_service.find_current_version_for_brand(
49
        g.brand_id
50
    )
51
52
    privacy_policy_consent_subject_id = (
53
        _find_privacy_policy_consent_subject_id()
54
    )
55
56
    newsletter_list_id = _find_newsletter_list_for_brand()
57
58
    real_name_required = _is_real_name_required()
59
    terms_consent_required = (terms_version is not None)
60
    privacy_policy_consent_required \
61
        = (privacy_policy_consent_subject_id is not None)
62
    newsletter_offered = (newsletter_list_id is not None)
63
64
    if terms_consent_required:
65
        terms_version_id = terms_version.id
66
    else:
67
        terms_version_id = None
68
69
    form = erroneous_form if erroneous_form \
70
        else UserCreateForm(terms_version_id=terms_version_id)
71
72
    _adjust_create_form(
73
        form,
74
        real_name_required,
75
        terms_consent_required,
76
        privacy_policy_consent_required,
77
        newsletter_offered,
78
    )
79
80
    return {'form': form}
81
82
83
@blueprint.route('/', methods=['POST'])
84
def create():
85
    """Create a user."""
86
    _abort_if_user_account_creation_disabled()
87
88
    terms_document_id = terms_document_service.find_document_id_for_brand(
89
        g.brand_id
90
    )
91
92
    privacy_policy_consent_subject_id = (
93
        _find_privacy_policy_consent_subject_id()
94
    )
95
96
    newsletter_list_id = _find_newsletter_list_for_brand()
97
98
    real_name_required = _is_real_name_required()
99
    terms_consent_required = (terms_document_id is not None)
100
    privacy_policy_consent_required \
101
        = (privacy_policy_consent_subject_id is not None)
102
    newsletter_offered = (newsletter_list_id is not None)
103
104
    form = UserCreateForm(request.form)
105
106
    _adjust_create_form(
107
        form,
108
        real_name_required,
109
        terms_consent_required,
110
        privacy_policy_consent_required,
111
        newsletter_offered,
112
    )
113
114
    if not form.validate():
115
        return create_form(form)
116
117
    screen_name = form.screen_name.data.strip()
118
    email_address = form.email_address.data.strip().lower()
119
    password = form.password.data
120
121
    now_utc = datetime.utcnow()
122
123
    if user_service.is_screen_name_already_assigned(screen_name):
124
        flash_error(
125
            'Dieser Benutzername ist bereits einem Benutzerkonto zugeordnet.'
126
        )
127
        return create_form(form)
128
129
    if user_service.is_email_address_already_assigned(email_address):
130
        flash_error(
131
            'Diese E-Mail-Adresse ist bereits einem Benutzerkonto zugeordnet.'
132
        )
133
        return create_form(form)
134
135
    if real_name_required:
136
        first_names = form.first_names.data.strip()
137
        last_name = form.last_name.data.strip()
138
    else:
139
        first_names = None
140
        last_name = None
141
142
    terms_consent = None
143
    if terms_consent_required:
144
        terms_version_id = form.terms_version_id.data
145
        consent_to_terms = form.consent_to_terms.data
146
147
        terms_version = terms_version_service.find_version(terms_version_id)
148
        if terms_version.document_id != terms_document_id:
149
            abort(400, 'Die AGB-Version gehört nicht zu dieser Veranstaltung.')
150
151
        terms_consent = Consent(
152
            user_id=None,  # not available at this point
153
            subject_id=terms_version.consent_subject_id,
154
            expressed_at=now_utc,
155
        )
156
157
    privacy_policy_consent = None
158
    if privacy_policy_consent_required:
159
        privacy_policy_consent = Consent(
160
            user_id=None,  # not available at this point
161
            subject_id=privacy_policy_consent_subject_id,
162
            expressed_at=now_utc,
163
        )
164
165
    newsletter_subscription = None
166
    if newsletter_offered:
167
        subscribe_to_newsletter = form.subscribe_to_newsletter.data
168
        if subscribe_to_newsletter:
169
            newsletter_subscription = NewsletterSubscription(
170
                user_id=None,  # not available at this point
171
                list_id=newsletter_list_id,
172
                expressed_at=now_utc,
173
            )
174
175
    try:
176
        user, event = user_creation_service.create_user(
177
            screen_name,
178
            email_address,
179
            password,
180
            first_names,
181
            last_name,
182
            g.site_id,
183
            terms_consent=terms_consent,
184
            privacy_policy_consent=privacy_policy_consent,
185
            newsletter_subscription=newsletter_subscription,
186
        )
187
    except user_creation_service.UserCreationFailed:
188
        flash_error(
189
            f'Das Benutzerkonto für "{screen_name}" konnte nicht angelegt werden.'
190
        )
191
        return create_form(form)
192
193
    flash_success(
194
        f'Das Benutzerkonto für "{user.screen_name}" wurde angelegt. '
195
        'Bevor du dich damit anmelden kannst, muss zunächst der Link in '
196
        'der an die angegebene Adresse verschickten E-Mail besucht werden.',
197
    )
198
199
    signals.account_created.send(None, event=event)
200
201
    return redirect_to('authentication.login_form')
202
203
204
def _abort_if_user_account_creation_disabled():
205
    if not _is_user_account_creation_enabled():
206
        flash_error('Das Erstellen von Benutzerkonten ist deaktiviert.')
207
        abort(403)
208
209
210
def _is_user_account_creation_enabled():
211
    if get_site_mode().is_admin():
212
        return False
213
214
    site = site_service.get_site(g.site_id)
215
    return site.user_account_creation_enabled
216
217
218
def _adjust_create_form(
219
    form,
220
    real_name_required,
221
    terms_consent_required,
222
    privacy_policy_consent_required,
223
    newsletter_offered,
224
):
225
    if not real_name_required:
226
        del form.first_names
227
        del form.last_name
228
229
    if not terms_consent_required:
230
        del form.terms_version_id
231
        del form.consent_to_terms
232
233
    if not privacy_policy_consent_required:
234
        del form.consent_to_privacy_policy
235
236
    if not newsletter_offered:
237
        del form.subscribe_to_newsletter
238
239
240
def _is_real_name_required() -> bool:
241
    """Return `True` if real name is required.
242
243
    By default, real name is required. It can be disabled by configuring
244
    the string `false` for the site setting `real_name_required`.
245
    """
246
    value = _find_site_setting_value('real_name_required')
247
248
    return value != 'false'
249
250
251
def _find_privacy_policy_consent_subject_id() -> Optional[SubjectID]:
252
    """Return the privacy policy consent subject ID configured for this
253
    brand, or `None` if none is configured.
254
    """
255
    value = _find_brand_setting_value('privacy_policy_consent_subject_id')
256
257
    if not value:
258
        return None
259
260
    return SubjectID(value)
261
262
263
def _find_newsletter_list_for_brand() -> Optional[NewsletterListID]:
264
    """Return the newsletter list configured for this brand, or `None`
265
    if none is configured.
266
    """
267
    value = _find_brand_setting_value('newsletter_list_id')
268
269
    if not value:
270
        return None
271
272
    return NewsletterListID(value)
273
274
275
def _find_brand_setting_value(setting_name: str) -> Optional[str]:
276
    """Return the value configured for this brand and the given setting
277
    name, or `None` if not configured.
278
    """
279
    return brand_settings_service.find_setting_value(g.brand_id, setting_name)
280
281
282
def _find_site_setting_value(setting_name: str) -> Optional[str]:
283
    """Return the value configured for this site and the given setting
284
    name, or `None` if not configured.
285
    """
286
    return site_settings_service.find_setting_value(g.site_id, setting_name)
287