Completed
Branch master (4d0d43)
by Jochen
03:26 queued 01:02
created

_get_newsletter_subscription()   A

Complexity

Conditions 3

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
nop 4
dl 0
loc 14
rs 9.85
c 0
b 0
f 0
1
"""
2
byceps.blueprints.user.creation.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2020 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
    )
63
    newsletter_offered = newsletter_list_id is not None
64
65
    if terms_consent_required:
66
        terms_version_id = terms_version.id
67
    else:
68
        terms_version_id = None
69
70
    form = (
71
        erroneous_form
72
        if erroneous_form
73
        else UserCreateForm(terms_version_id=terms_version_id)
74
    )
75
76
    _adjust_create_form(
77
        form,
78
        real_name_required,
79
        terms_consent_required,
80
        privacy_policy_consent_required,
81
        newsletter_offered,
82
    )
83
84
    return {'form': form}
85
86
87
@blueprint.route('/', methods=['POST'])
88
def create():
89
    """Create a user."""
90
    _abort_if_user_account_creation_disabled()
91
92
    terms_document_id = terms_document_service.find_document_id_for_brand(
93
        g.brand_id
94
    )
95
96
    privacy_policy_consent_subject_id = (
97
        _find_privacy_policy_consent_subject_id()
98
    )
99
100
    newsletter_list_id = _find_newsletter_list_for_brand()
101
102
    real_name_required = _is_real_name_required()
103
    terms_consent_required = terms_document_id is not None
104
    privacy_policy_consent_required = (
105
        privacy_policy_consent_subject_id is not None
106
    )
107
    newsletter_offered = newsletter_list_id is not None
108
109
    form = UserCreateForm(request.form)
110
111
    _adjust_create_form(
112
        form,
113
        real_name_required,
114
        terms_consent_required,
115
        privacy_policy_consent_required,
116
        newsletter_offered,
117
    )
118
119
    if not form.validate():
120
        return create_form(form)
121
122
    screen_name = form.screen_name.data.strip()
123
    email_address = form.email_address.data.strip().lower()
124
    password = form.password.data
125
126
    now_utc = datetime.utcnow()
127
128
    if user_service.is_screen_name_already_assigned(screen_name):
129
        flash_error(
130
            'Dieser Benutzername ist bereits einem Benutzerkonto zugeordnet.'
131
        )
132
        return create_form(form)
133
134
    if user_service.is_email_address_already_assigned(email_address):
135
        flash_error(
136
            'Diese E-Mail-Adresse ist bereits einem Benutzerkonto zugeordnet.'
137
        )
138
        return create_form(form)
139
140
    if real_name_required:
141
        first_names = form.first_names.data.strip()
142
        last_name = form.last_name.data.strip()
143
    else:
144
        first_names = None
145
        last_name = None
146
147
    terms_consent = None
148
    if terms_consent_required:
149
        terms_version_id = form.terms_version_id.data
150
        consent_to_terms = form.consent_to_terms.data
151
152
        terms_version = terms_version_service.find_version(terms_version_id)
153
        if terms_version.document_id != terms_document_id:
154
            abort(400, 'Die AGB-Version gehört nicht zu dieser Veranstaltung.')
155
156
        terms_consent = _assemble_privacy_policy_consent(
157
            terms_version.consent_subject_id, now_utc
158
        )
159
160
    privacy_policy_consent = _get_privacy_policy_consent(
161
        privacy_policy_consent_required,
162
        privacy_policy_consent_subject_id,
163
        now_utc,
164
    )
165
166
    newsletter_subscription = _get_newsletter_subscription(
167
        newsletter_offered, form, newsletter_list_id, now_utc
168
    )
169
170
    try:
171
        user, event = user_creation_service.create_user(
172
            screen_name,
173
            email_address,
174
            password,
175
            first_names,
176
            last_name,
177
            g.site_id,
178
            terms_consent=terms_consent,
179
            privacy_policy_consent=privacy_policy_consent,
180
            newsletter_subscription=newsletter_subscription,
181
        )
182
    except user_creation_service.UserCreationFailed:
183
        flash_error(
184
            f'Das Benutzerkonto für "{screen_name}" konnte nicht angelegt werden.'
185
        )
186
        return create_form(form)
187
188
    flash_success(
189
        f'Das Benutzerkonto für "{user.screen_name}" wurde angelegt. '
190
        'Bevor du dich damit anmelden kannst, muss zunächst der Link in '
191
        'der an die angegebene Adresse verschickten E-Mail besucht werden.'
192
    )
193
194
    signals.account_created.send(None, event=event)
195
196
    return redirect_to('authentication.login_form')
197
198
199
def _abort_if_user_account_creation_disabled():
200
    if not _is_user_account_creation_enabled():
201
        flash_error('Das Erstellen von Benutzerkonten ist deaktiviert.')
202
        abort(403)
203
204
205
def _is_user_account_creation_enabled():
206
    if get_site_mode().is_admin():
207
        return False
208
209
    site = site_service.get_site(g.site_id)
210
    return site.user_account_creation_enabled
211
212
213
def _adjust_create_form(
214
    form,
215
    real_name_required,
216
    terms_consent_required,
217
    privacy_policy_consent_required,
218
    newsletter_offered,
219
):
220
    if not real_name_required:
221
        del form.first_names
222
        del form.last_name
223
224
    if not terms_consent_required:
225
        del form.terms_version_id
226
        del form.consent_to_terms
227
228
    if not privacy_policy_consent_required:
229
        del form.consent_to_privacy_policy
230
231
    if not newsletter_offered:
232
        del form.subscribe_to_newsletter
233
234
235
def _is_real_name_required() -> bool:
236
    """Return `True` if real name is required.
237
238
    By default, real name is required. It can be disabled by configuring
239
    the string `false` for the site setting `real_name_required`.
240
    """
241
    value = _find_site_setting_value('real_name_required')
242
243
    return value != 'false'
244
245
246
def _find_privacy_policy_consent_subject_id() -> Optional[SubjectID]:
247
    """Return the privacy policy consent subject ID configured for this
248
    brand, or `None` if none is configured.
249
    """
250
    value = _find_brand_setting_value('privacy_policy_consent_subject_id')
251
252
    if not value:
253
        return None
254
255
    return SubjectID(value)
256
257
258
def _find_newsletter_list_for_brand() -> Optional[NewsletterListID]:
259
    """Return the newsletter list configured for this brand, or `None`
260
    if none is configured.
261
    """
262
    value = _find_brand_setting_value('newsletter_list_id')
263
264
    if not value:
265
        return None
266
267
    return NewsletterListID(value)
268
269
270
def _find_brand_setting_value(setting_name: str) -> Optional[str]:
271
    """Return the value configured for this brand and the given setting
272
    name, or `None` if not configured.
273
    """
274
    return brand_settings_service.find_setting_value(g.brand_id, setting_name)
275
276
277
def _find_site_setting_value(setting_name: str) -> Optional[str]:
278
    """Return the value configured for this site and the given setting
279
    name, or `None` if not configured.
280
    """
281
    return site_settings_service.find_setting_value(g.site_id, setting_name)
282
283
284
def _get_privacy_policy_consent(
285
    privacy_policy_consent_required: bool,
286
    privacy_policy_consent_subject_id: SubjectID,
287
    expressed_at: datetime,
288
) -> Optional[Consent]:
289
    if not privacy_policy_consent_required:
290
        return None
291
292
    return _assemble_privacy_policy_consent(
293
        privacy_policy_consent_subject_id, expressed_at
294
    )
295
296
297
def _assemble_privacy_policy_consent(
298
    subject_id: SubjectID, expressed_at: datetime
299
) -> Consent:
300
    return Consent(
301
        user_id=None,  # not available at this point
302
        subject_id=subject_id,
303
        expressed_at=expressed_at,
304
    )
305
306
307
def _get_newsletter_subscription(
308
    newsletter_offered: bool,
309
    form: UserCreateForm,
310
    newsletter_list_id: NewsletterListID,
311
    expressed_at: datetime,
312
) -> Optional[NewsletterSubscription]:
313
    if not newsletter_offered:
314
        return None
315
316
    subscribe_to_newsletter = form.subscribe_to_newsletter.data
317
    if not subscribe_to_newsletter:
318
        return None
319
320
    return _assemble_newsletter_subscription(newsletter_list_id, expressed_at)
321
322
323
def _assemble_newsletter_subscription(
324
    newsletter_list_id: NewsletterListID, expressed_at: datetime
325
) -> NewsletterSubscription:
326
    return NewsletterSubscription(
327
        user_id=None,  # not available at this point
328
        list_id=newsletter_list_id,
329
        expressed_at=expressed_at,
330
    )
331