1
|
|
|
""" |
2
|
|
|
:Copyright: 2006-2019 Jochen Kupperschmidt |
3
|
|
|
:License: Modified BSD, see LICENSE for details. |
4
|
|
|
""" |
5
|
|
|
|
6
|
|
|
from unittest.mock import patch |
7
|
|
|
|
8
|
|
|
from byceps.services.authentication.password.models import Credential |
9
|
|
|
from byceps.services.authentication.session import service as session_service |
10
|
|
|
from byceps.services.authorization.models import Role, UserRole |
11
|
|
|
from byceps.services.brand import settings_service as brand_settings_service |
12
|
|
|
from byceps.services.consent import consent_service, \ |
13
|
|
|
subject_service as consent_subject_service |
14
|
|
|
from byceps.services.email import service as email_service |
15
|
|
|
from byceps.services.newsletter import \ |
16
|
|
|
command_service as newsletter_command_service, service as newsletter_service |
17
|
|
|
from byceps.services.snippet import service as snippet_service |
18
|
|
|
from byceps.services.snippet.transfer.models import Scope |
19
|
|
|
from byceps.services.terms import version_service as terms_version_service |
20
|
|
|
from byceps.services.user import event_service, service as user_service |
21
|
|
|
from byceps.services.user.models.user import User |
22
|
|
|
from byceps.services.verification_token import service as \ |
23
|
|
|
verification_token_service |
24
|
|
|
|
25
|
|
|
from tests.base import AbstractAppTestCase |
26
|
|
|
from tests.helpers import create_brand, create_party, create_site, \ |
27
|
|
|
create_user, http_client |
28
|
|
|
|
29
|
|
|
from testfixtures.authorization import create_role |
30
|
|
|
|
31
|
|
|
|
32
|
|
|
class UserCreateTestCase(AbstractAppTestCase): |
33
|
|
|
|
34
|
|
|
def setUp(self): |
35
|
|
|
super().setUp() |
36
|
|
|
|
37
|
|
|
self.admin = create_user('Admin') |
38
|
|
|
|
39
|
|
|
self.brand = create_brand() |
40
|
|
|
email_service.set_sender_address_for_brand(self.brand.id, |
41
|
|
|
'[email protected]') |
42
|
|
|
self.brand_id = self.brand.id |
43
|
|
|
|
44
|
|
|
party = create_party(brand_id=self.brand.id) |
45
|
|
|
create_site(party.id) |
46
|
|
|
|
47
|
|
|
self.setup_terms() |
48
|
|
|
self.setup_privacy_policy() |
49
|
|
|
self.setup_newsletter_list() |
50
|
|
|
self.setup_roles() |
51
|
|
|
|
52
|
|
|
def setup_terms(self): |
53
|
|
|
scope = Scope.for_brand(self.brand_id) |
54
|
|
|
|
55
|
|
|
snippet = snippet_service.create_fragment( |
56
|
|
|
scope, 'terms_of_service', self.admin.id, |
57
|
|
|
'Don\'t do anything stupid!') |
58
|
|
|
|
59
|
|
|
consent_subject = consent_subject_service.create_subject( |
60
|
|
|
'{}_terms-of-service_v1'.format(self.brand_id), |
61
|
|
|
'Terms of service for {} / v1'.format(self.brand.title), |
62
|
|
|
'terms_of_service') |
63
|
|
|
|
64
|
|
|
terms_version = terms_version_service.create_version( |
65
|
|
|
self.brand_id, '01-Jan-2016', snippet.id, consent_subject.id) |
66
|
|
|
|
67
|
|
|
terms_version_service.set_current_version(self.brand.id, |
68
|
|
|
terms_version.id) |
69
|
|
|
|
70
|
|
|
self.terms_version_id = terms_version.id |
71
|
|
|
self.terms_consent_subject_id = terms_version.consent_subject_id |
72
|
|
|
|
73
|
|
|
def setup_privacy_policy(self): |
74
|
|
|
consent_subject = consent_subject_service.create_subject( |
75
|
|
|
'{}_privacy_policy_v1'.format(self.brand_id), |
76
|
|
|
'Privacy policy for {} / v1'.format(self.brand.title), |
77
|
|
|
'privacy_policy') |
78
|
|
|
|
79
|
|
|
brand_settings_service.create_setting(self.brand.id, |
80
|
|
|
'privacy_policy_consent_subject_id', str(consent_subject.id)) |
81
|
|
|
|
82
|
|
|
self.privacy_policy_consent_subject_id = consent_subject.id |
83
|
|
|
|
84
|
|
|
def setup_newsletter_list(self): |
85
|
|
|
newsletter_command_service.create_list(self.brand.id, self.brand.title) |
86
|
|
|
|
87
|
|
|
def setup_roles(self): |
88
|
|
|
self.board_user_role = create_role('board_user') |
89
|
|
|
self.db.session.add(self.board_user_role) |
90
|
|
|
self.db.session.commit() |
91
|
|
|
|
92
|
|
|
@patch('byceps.email.send') |
93
|
|
|
def test_create(self, send_email_mock): |
94
|
|
|
screen_name = 'Hiro' |
95
|
|
|
|
96
|
|
|
user_count_before = get_user_count() |
97
|
|
|
assert find_user(screen_name) is None |
98
|
|
|
|
99
|
|
|
form_data = { |
100
|
|
|
'screen_name': screen_name, |
101
|
|
|
'first_names': 'Hiroaki', |
102
|
|
|
'last_name': 'Protagonist', |
103
|
|
|
'email_address': '[email protected]', |
104
|
|
|
'password': 'Snow_Crash', |
105
|
|
|
'terms_version_id': self.terms_version_id, |
106
|
|
|
'consent_to_terms': 'y', |
107
|
|
|
'consent_to_privacy_policy': 'y', |
108
|
|
|
'subscribe_to_newsletter': 'y', |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
response = self.send_request(form_data) |
112
|
|
|
assert response.status_code == 302 |
113
|
|
|
|
114
|
|
|
user_count_afterwards = get_user_count() |
115
|
|
|
assert user_count_afterwards == user_count_before + 1 |
116
|
|
|
|
117
|
|
|
user = find_user(screen_name) |
118
|
|
|
assert user is not None |
119
|
|
|
|
120
|
|
|
assert user.created_at is not None |
121
|
|
|
assert user.screen_name == 'Hiro' |
122
|
|
|
assert user.email_address == '[email protected]' |
123
|
|
|
assert not user.enabled |
124
|
|
|
assert not user.deleted |
125
|
|
|
|
126
|
|
|
# events |
127
|
|
|
assert_creation_event_created(user.id) |
128
|
|
|
|
129
|
|
|
# password |
130
|
|
|
assert_password_credentials_created(user.id) |
131
|
|
|
|
132
|
|
|
# Session token should not have been created at this point. |
133
|
|
|
session_token = session_service.find_session_token_for_user(user.id) |
134
|
|
|
assert session_token is None |
135
|
|
|
|
136
|
|
|
# avatar |
137
|
|
|
assert user.avatar is None |
138
|
|
|
|
139
|
|
|
# details |
140
|
|
|
assert user.detail.first_names == 'Hiroaki' |
141
|
|
|
assert user.detail.last_name == 'Protagonist' |
142
|
|
|
|
143
|
|
|
# authorization |
144
|
|
|
board_user_role = Role.query.get('board_user') |
145
|
|
|
actual_roles = get_user_roles(user.id) |
146
|
|
|
assert board_user_role in actual_roles |
147
|
|
|
|
148
|
|
|
# consents |
149
|
|
|
assert_consent(user.id, self.terms_consent_subject_id) |
150
|
|
|
assert_consent(user.id, self.privacy_policy_consent_subject_id) |
151
|
|
|
|
152
|
|
|
# newsletter subscription |
153
|
|
|
assert is_subscribed_to_newsletter(user.id, self.brand_id) |
154
|
|
|
|
155
|
|
|
# confirmation e-mail |
156
|
|
|
|
157
|
|
|
verification_token = find_verification_token(user.id) |
158
|
|
|
assert verification_token is not None |
159
|
|
|
|
160
|
|
|
expected_sender = '[email protected]' |
161
|
|
|
expected_recipients = ['[email protected]'] |
162
|
|
|
expected_subject = 'Hiro, bitte bestätige deine E-Mail-Adresse' |
163
|
|
|
expected_body = ''' |
164
|
|
|
Hallo Hiro, |
165
|
|
|
|
166
|
|
|
bitte bestätige deine E-Mail-Adresse, indem du diese URL abrufst: https://www.example.com/users/email_address/confirmation/{} |
167
|
|
|
'''.strip().format(verification_token.token) |
168
|
|
|
|
169
|
|
|
send_email_mock.assert_called_once_with( |
170
|
|
|
expected_sender, |
171
|
|
|
expected_recipients, |
172
|
|
|
expected_subject, |
173
|
|
|
expected_body) |
174
|
|
|
|
175
|
|
|
@patch('byceps.email.send') |
176
|
|
|
def test_create_without_newsletter_subscription(self, send_email_mock): |
177
|
|
|
screen_name = 'Hiro' |
178
|
|
|
|
179
|
|
|
form_data = { |
180
|
|
|
'screen_name': screen_name, |
181
|
|
|
'first_names': 'Hiroaki', |
182
|
|
|
'last_name': 'Protagonist', |
183
|
|
|
'email_address': '[email protected]', |
184
|
|
|
'password': 'Snow_Crash', |
185
|
|
|
'terms_version_id': self.terms_version_id, |
186
|
|
|
'consent_to_terms': 'y', |
187
|
|
|
'consent_to_privacy_policy': 'y', |
188
|
|
|
'subscribe_to_newsletter': '', |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
response = self.send_request(form_data) |
192
|
|
|
assert response.status_code == 302 |
193
|
|
|
|
194
|
|
|
user = find_user(screen_name) |
195
|
|
|
assert user is not None |
196
|
|
|
|
197
|
|
|
# newsletter subscription |
198
|
|
|
assert not is_subscribed_to_newsletter(user.id, self.brand_id) |
199
|
|
|
|
200
|
|
|
# helpers |
201
|
|
|
|
202
|
|
|
def send_request(self, form_data): |
203
|
|
|
url = '/users/' |
204
|
|
|
|
205
|
|
|
with http_client(self.app) as client: |
206
|
|
|
return client.post(url, data=form_data) |
207
|
|
|
|
208
|
|
|
|
209
|
|
|
def find_user(screen_name): |
210
|
|
|
return user_service.find_user_by_screen_name(screen_name) |
211
|
|
|
|
212
|
|
|
|
213
|
|
|
def get_user_count(): |
214
|
|
|
return User.query.count() |
215
|
|
|
|
216
|
|
|
|
217
|
|
|
def get_user_roles(user_id): |
218
|
|
|
return Role.query \ |
219
|
|
|
.join(UserRole) \ |
220
|
|
|
.filter_by(user_id=user_id) \ |
221
|
|
|
.all() |
222
|
|
|
|
223
|
|
|
|
224
|
|
|
def find_verification_token(user_id): |
225
|
|
|
return verification_token_service \ |
226
|
|
|
.find_for_email_address_confirmation_by_user(user_id) |
227
|
|
|
|
228
|
|
|
|
229
|
|
|
def is_subscribed_to_newsletter(user_id, brand_id): |
230
|
|
|
return newsletter_service.is_subscribed(user_id, brand_id) |
231
|
|
|
|
232
|
|
|
|
233
|
|
|
def assert_creation_event_created(user_id): |
234
|
|
|
events = event_service.get_events_of_type_for_user('user-created', user_id) |
235
|
|
|
assert len(events) == 1 |
236
|
|
|
|
237
|
|
|
first_event = events[0] |
238
|
|
|
assert first_event.event_type == 'user-created' |
239
|
|
|
assert first_event.data == {} |
240
|
|
|
|
241
|
|
|
|
242
|
|
|
def assert_password_credentials_created(user_id): |
243
|
|
|
credential = Credential.query.get(user_id) |
244
|
|
|
|
245
|
|
|
assert credential is not None |
246
|
|
|
assert credential.password_hash.startswith('pbkdf2:sha256:150000$') |
247
|
|
|
assert credential.updated_at is not None |
248
|
|
|
|
249
|
|
|
|
250
|
|
|
def assert_consent(user_id, subject_id): |
251
|
|
|
assert consent_service.has_user_consented_to_subject(user_id, subject_id) |
252
|
|
|
|