1
|
|
|
""" |
2
|
|
|
byceps.blueprints.site.user.creation.views |
3
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4
|
|
|
|
5
|
|
|
:Copyright: 2014-2024 Jochen Kupperschmidt |
6
|
|
|
:License: Revised BSD (see `LICENSE` file for details) |
7
|
|
|
""" |
8
|
|
|
|
9
|
1 |
|
from datetime import datetime |
10
|
|
|
|
11
|
1 |
|
from flask import abort, g, request |
12
|
|
|
from flask_babel import gettext |
13
|
1 |
|
|
14
|
1 |
|
from byceps.services.brand import brand_setting_service |
15
|
|
|
from byceps.services.consent import consent_service, consent_subject_service |
16
|
1 |
|
from byceps.services.consent.models import ConsentSubject |
17
|
1 |
|
from byceps.services.newsletter import ( |
18
|
1 |
|
newsletter_command_service, |
19
|
1 |
|
newsletter_service, |
20
|
|
|
) |
21
|
|
|
from byceps.services.newsletter.models import ( |
22
|
|
|
List as NewsletterList, |
23
|
1 |
|
ListID as NewsletterListID, |
24
|
|
|
) |
25
|
|
|
from byceps.services.site import site_setting_service |
26
|
|
|
from byceps.services.user import user_creation_service |
27
|
1 |
|
from byceps.signals import user as user_signals |
28
|
1 |
|
from byceps.util.framework.blueprint import create_blueprint |
29
|
1 |
|
from byceps.util.framework.flash import flash_error, flash_success |
30
|
1 |
|
from byceps.util.framework.templating import templated |
31
|
1 |
|
from byceps.util.views import redirect_to |
32
|
1 |
|
|
33
|
1 |
|
from .forms import assemble_user_create_form |
34
|
|
|
|
35
|
1 |
|
|
36
|
|
|
blueprint = create_blueprint('user_creation', __name__) |
37
|
|
|
|
38
|
1 |
|
|
39
|
|
|
@blueprint.get('/create') |
40
|
|
|
@templated |
41
|
1 |
|
def create_form(erroneous_form=None): |
42
|
1 |
|
"""Show a form to create a user.""" |
43
|
1 |
|
_abort_if_user_account_creation_disabled() |
44
|
|
|
|
45
|
|
|
required_consent_subjects = _get_required_consent_subjects() |
46
|
|
|
newsletter_list = _find_newsletter_list_for_brand() |
47
|
|
|
|
48
|
|
|
real_name_required = _is_real_name_required() |
49
|
|
|
newsletter_offered = newsletter_list is not None |
50
|
|
|
|
51
|
|
|
if erroneous_form: |
52
|
|
|
form = erroneous_form |
53
|
|
|
else: |
54
|
|
|
UserCreateForm = assemble_user_create_form( |
55
|
|
|
real_name_required=real_name_required, |
56
|
|
|
required_consent_subjects=required_consent_subjects, |
57
|
|
|
newsletter_offered=newsletter_offered, |
58
|
|
|
) |
59
|
|
|
form = UserCreateForm() |
60
|
|
|
|
61
|
|
|
return { |
62
|
|
|
'form': form, |
63
|
|
|
'required_consent_subjects': required_consent_subjects, |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
|
67
|
|
|
@blueprint.post('/') |
68
|
|
|
def create(): |
69
|
1 |
|
"""Create a user.""" |
70
|
1 |
|
_abort_if_user_account_creation_disabled() |
71
|
|
|
|
72
|
1 |
|
required_consent_subjects = _get_required_consent_subjects() |
73
|
|
|
newsletter_list = _find_newsletter_list_for_brand() |
74
|
1 |
|
|
75
|
1 |
|
real_name_required = _is_real_name_required() |
76
|
|
|
newsletter_offered = newsletter_list is not None |
77
|
1 |
|
|
78
|
1 |
|
UserCreateForm = assemble_user_create_form( |
79
|
|
|
real_name_required=real_name_required, |
80
|
1 |
|
required_consent_subjects=required_consent_subjects, |
81
|
|
|
newsletter_offered=newsletter_offered, |
82
|
|
|
) |
83
|
|
|
form = UserCreateForm(request.form) |
84
|
|
|
|
85
|
1 |
|
if not form.validate(): |
86
|
|
|
return create_form(form) |
87
|
1 |
|
|
88
|
|
|
screen_name = form.screen_name.data.strip() |
89
|
|
|
email_address = form.email_address.data.strip().lower() |
90
|
1 |
|
password = form.password.data |
91
|
1 |
|
|
92
|
1 |
|
now_utc = datetime.utcnow() |
93
|
|
|
|
94
|
1 |
|
if real_name_required: |
95
|
|
|
first_name = form.first_name.data.strip() |
96
|
1 |
|
last_name = form.last_name.data.strip() |
97
|
1 |
|
else: |
98
|
1 |
|
first_name = None |
99
|
|
|
last_name = None |
100
|
|
|
|
101
|
|
|
creation_result = user_creation_service.create_user( |
102
|
|
|
screen_name, |
103
|
1 |
|
email_address, |
104
|
|
|
password, |
105
|
|
|
first_name=first_name, |
106
|
|
|
last_name=last_name, |
107
|
|
|
creation_method='site app', |
108
|
|
|
site=g.site, |
109
|
|
|
ip_address=request.remote_addr, |
110
|
|
|
) |
111
|
|
|
if creation_result.is_err(): |
112
|
|
|
flash_error( |
113
|
|
|
gettext( |
114
|
1 |
|
'User "%(screen_name)s" could not be created.', |
115
|
|
|
screen_name=screen_name, |
116
|
|
|
) |
117
|
|
|
) |
118
|
|
|
return create_form(form) |
119
|
|
|
|
120
|
|
|
user, event = creation_result.unwrap() |
121
|
|
|
|
122
|
|
|
user_creation_service.request_email_address_confirmation( |
123
|
1 |
|
user, email_address, g.site_id |
124
|
|
|
).unwrap() |
125
|
1 |
|
|
126
|
|
|
subject_ids = {subject.id for subject in required_consent_subjects} |
127
|
|
|
consent_service.consent_to_subjects(user.id, subject_ids, now_utc) |
128
|
|
|
|
129
|
1 |
|
flash_success( |
130
|
1 |
|
gettext( |
131
|
|
|
'User "%(screen_name)s" has been created. Before you can log in, ' |
132
|
1 |
|
'please visit the link emailed to you to verify your email address.', |
133
|
|
|
screen_name=user.screen_name, |
134
|
|
|
) |
135
|
|
|
) |
136
|
|
|
|
137
|
|
|
user_signals.account_created.send(None, event=event) |
138
|
|
|
|
139
|
|
|
if newsletter_offered: |
140
|
1 |
|
subscribe_to_newsletter = form.subscribe_to_newsletter.data |
141
|
|
|
if subscribe_to_newsletter: |
142
|
1 |
|
newsletter_command_service.subscribe( |
143
|
1 |
|
user, newsletter_list, now_utc |
144
|
1 |
|
).unwrap() |
145
|
1 |
|
|
146
|
|
|
return redirect_to('authn_login.log_in_form') |
147
|
|
|
|
148
|
|
|
|
149
|
1 |
|
def _abort_if_user_account_creation_disabled(): |
150
|
|
|
if not g.site.user_account_creation_enabled: |
151
|
|
|
flash_error(gettext('User account creation is disabled.')) |
152
|
1 |
|
abort(403) |
153
|
1 |
|
|
154
|
|
|
|
155
|
|
|
def _is_real_name_required() -> bool: |
156
|
|
|
"""Return `True` if real name is required. |
157
|
|
|
|
158
|
1 |
|
By default, real name is required. It can be disabled by configuring |
159
|
|
|
the string `false` for the site setting `real_name_required`. |
160
|
|
|
""" |
161
|
|
|
value = _find_site_setting_value('real_name_required') |
162
|
|
|
|
163
|
|
|
return value != 'false' |
164
|
1 |
|
|
165
|
|
|
|
166
|
1 |
|
def _get_required_consent_subjects() -> set[ConsentSubject]: |
167
|
|
|
"""Return the consent subjects required for this brand.""" |
168
|
|
|
return consent_subject_service.get_subjects_required_for_brand(g.brand_id) |
169
|
1 |
|
|
170
|
|
|
|
171
|
1 |
|
def _find_newsletter_list_for_brand() -> NewsletterList | None: |
172
|
|
|
"""Return the newsletter list configured for this brand, or `None` |
173
|
|
|
if none is configured. |
174
|
1 |
|
""" |
175
|
|
|
list_id = _find_brand_setting_value('newsletter_list_id') |
176
|
|
|
|
177
|
|
|
if not list_id: |
178
|
1 |
|
return None |
179
|
|
|
|
180
|
1 |
|
return newsletter_service.get_list(NewsletterListID(list_id)).unwrap() |
181
|
|
|
|
182
|
|
|
|
183
|
1 |
|
def _find_brand_setting_value(setting_name: str) -> str | None: |
184
|
|
|
"""Return the value configured for this brand and the given setting |
185
|
|
|
name, or `None` if not configured. |
186
|
1 |
|
""" |
187
|
|
|
return brand_setting_service.find_setting_value(g.brand_id, setting_name) |
188
|
|
|
|
189
|
|
|
|
190
|
1 |
|
def _find_site_setting_value(setting_name: str) -> str | None: |
191
|
|
|
"""Return the value configured for this site and the given setting |
192
|
|
|
name, or `None` if not configured. |
193
|
1 |
|
""" |
194
|
|
|
return site_setting_service.find_setting_value(g.site_id, setting_name) |
195
|
|
|
|