Completed
Push — master ( 0943a5...c65a32 )
by Jochen
04:29
created

_assemble_newsletter_subscription()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
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
    )
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 = None
161
    if privacy_policy_consent_required:
162
        privacy_policy_consent = _assemble_privacy_policy_consent(
163
            privacy_policy_consent_subject_id, now_utc
164
        )
165
166
    newsletter_subscription = None
167
    if newsletter_offered:
168
        subscribe_to_newsletter = form.subscribe_to_newsletter.data
169
        if subscribe_to_newsletter:
170
            newsletter_subscription = _assemble_newsletter_subscription(
171
                newsletter_list_id, now_utc
172
            )
173
174
    try:
175
        user, event = user_creation_service.create_user(
176
            screen_name,
177
            email_address,
178
            password,
179
            first_names,
180
            last_name,
181
            g.site_id,
182
            terms_consent=terms_consent,
183
            privacy_policy_consent=privacy_policy_consent,
184
            newsletter_subscription=newsletter_subscription,
185
        )
186
    except user_creation_service.UserCreationFailed:
187
        flash_error(
188
            f'Das Benutzerkonto für "{screen_name}" konnte nicht angelegt werden.'
189
        )
190
        return create_form(form)
191
192
    flash_success(
193
        f'Das Benutzerkonto für "{user.screen_name}" wurde angelegt. '
194
        'Bevor du dich damit anmelden kannst, muss zunächst der Link in '
195
        'der an die angegebene Adresse verschickten E-Mail besucht werden.'
196
    )
197
198
    signals.account_created.send(None, event=event)
199
200
    return redirect_to('authentication.login_form')
201
202
203
def _abort_if_user_account_creation_disabled():
204
    if not _is_user_account_creation_enabled():
205
        flash_error('Das Erstellen von Benutzerkonten ist deaktiviert.')
206
        abort(403)
207
208
209
def _is_user_account_creation_enabled():
210
    if get_site_mode().is_admin():
211
        return False
212
213
    site = site_service.get_site(g.site_id)
214
    return site.user_account_creation_enabled
215
216
217
def _adjust_create_form(
218
    form,
219
    real_name_required,
220
    terms_consent_required,
221
    privacy_policy_consent_required,
222
    newsletter_offered,
223
):
224
    if not real_name_required:
225
        del form.first_names
226
        del form.last_name
227
228
    if not terms_consent_required:
229
        del form.terms_version_id
230
        del form.consent_to_terms
231
232
    if not privacy_policy_consent_required:
233
        del form.consent_to_privacy_policy
234
235
    if not newsletter_offered:
236
        del form.subscribe_to_newsletter
237
238
239
def _is_real_name_required() -> bool:
240
    """Return `True` if real name is required.
241
242
    By default, real name is required. It can be disabled by configuring
243
    the string `false` for the site setting `real_name_required`.
244
    """
245
    value = _find_site_setting_value('real_name_required')
246
247
    return value != 'false'
248
249
250
def _find_privacy_policy_consent_subject_id() -> Optional[SubjectID]:
251
    """Return the privacy policy consent subject ID configured for this
252
    brand, or `None` if none is configured.
253
    """
254
    value = _find_brand_setting_value('privacy_policy_consent_subject_id')
255
256
    if not value:
257
        return None
258
259
    return SubjectID(value)
260
261
262
def _find_newsletter_list_for_brand() -> Optional[NewsletterListID]:
263
    """Return the newsletter list configured for this brand, or `None`
264
    if none is configured.
265
    """
266
    value = _find_brand_setting_value('newsletter_list_id')
267
268
    if not value:
269
        return None
270
271
    return NewsletterListID(value)
272
273
274
def _find_brand_setting_value(setting_name: str) -> Optional[str]:
275
    """Return the value configured for this brand and the given setting
276
    name, or `None` if not configured.
277
    """
278
    return brand_settings_service.find_setting_value(g.brand_id, setting_name)
279
280
281
def _find_site_setting_value(setting_name: str) -> Optional[str]:
282
    """Return the value configured for this site and the given setting
283
    name, or `None` if not configured.
284
    """
285
    return site_settings_service.find_setting_value(g.site_id, setting_name)
286
287
288
def _assemble_privacy_policy_consent(
289
    subject_id: SubjectID, now_utc: datetime
290
) -> Consent:
291
    return Consent(
292
        user_id=None,  # not available at this point
293
        subject_id=subject_id,
294
        expressed_at=now_utc,
295
    )
296
297
298
def _assemble_newsletter_subscription(
299
    newsletter_list_id: NewsletterListID, now_utc: datetime
300
) -> NewsletterSubscription:
301
    return NewsletterSubscription(
302
        user_id=None,  # not available at this point
303
        list_id=newsletter_list_id,
304
        expressed_at=now_utc,
305
    )
306