Passed
Push — master ( d29cbb...0943a5 )
by Jochen
02:31
created

change_email_address_form()   A

Complexity

Conditions 2

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 9
nop 2
dl 0
loc 12
rs 9.95
c 0
b 0
f 0
1
"""
2
byceps.blueprints.admin.user.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2019 Jochen Kupperschmidt
6
:License: Modified BSD, see LICENSE for details.
7
"""
8
9
from flask import abort, g, redirect, request, url_for
10
11
from ....services.authentication.password import service as password_service
12
from ....services.authorization import service as authorization_service
13
from ....services.orga_team import service as orga_team_service
14
from ....services.shop.order import service as order_service
15
from ....services.shop.shop import service as shop_service
16
from ....services.site import service as site_service
17
from ....services.user import command_service as user_command_service
18
from ....services.user import creation_service as user_creation_service
19
from ....services.user import service as user_service
20
from ....services.user import stats_service as user_stats_service
21
from ....services.user_badge import service as badge_service
22
from ....util.framework.blueprint import create_blueprint
23
from ....util.framework.flash import flash_error, flash_success
24
from ....util.framework.templating import templated
25
from ....util.views import redirect_to, respond_no_content
26
27
from ...authorization.decorators import permission_required
28
from ...authorization.registry import permission_registry
29
from ...user import signals
30
31
from ..authorization.authorization import RolePermission
32
33
from .authorization import UserPermission
34
from .forms import (
35
    ChangeEmailAddressForm,
36
    ChangeScreenNameForm,
37
    CreateAccountForm,
38
    DeleteAccountForm,
39
    SetPasswordForm,
40
    SuspendAccountForm,
41
)
42
from .models import UserStateFilter
43
from . import service
44
45
46
blueprint = create_blueprint('user_admin', __name__)
47
48
49
permission_registry.register_enum(UserPermission)
50
51
52
@blueprint.route('/', defaults={'page': 1})
53
@blueprint.route('/pages/<int:page>')
54
@permission_required(UserPermission.view)
55
@templated
56
def index(page):
57
    """List users."""
58
    per_page = request.args.get('per_page', type=int, default=20)
59
    search_term = request.args.get('search_term', default='').strip()
60
    only = request.args.get('only')
61
62
    user_state_filter = UserStateFilter.__members__.get(
63
        only, UserStateFilter.none
64
    )
65
66
    users = service.get_users_paginated(
67
        page, per_page, search_term=search_term, state_filter=user_state_filter
68
    )
69
70
    total_active = user_stats_service.count_active_users()
71
    total_uninitialized = user_stats_service.count_uninitialized_users()
72
    total_suspended = user_stats_service.count_suspended_users()
73
    total_deleted = user_stats_service.count_deleted_users()
74
    total_overall = user_stats_service.count_users()
75
76
    return {
77
        'users': users,
78
        'total_active': total_active,
79
        'total_uninitialized': total_uninitialized,
80
        'total_suspended': total_suspended,
81
        'total_deleted': total_deleted,
82
        'total_overall': total_overall,
83
        'search_term': search_term,
84
        'only': only,
85
        'UserStateFilter': UserStateFilter,
86
        'user_state_filter': user_state_filter,
87
    }
88
89
90
@blueprint.route('/<uuid:user_id>')
91
@permission_required(UserPermission.view)
92
@templated
93
def view(user_id):
94
    """Show a user's interal profile."""
95
    user = user_service.find_user_with_details(user_id)
96
    if user is None:
97
        abort(404)
98
99
    orga_team_memberships = orga_team_service.get_memberships_for_user(user.id)
100
101
    newsletter_subscriptions = service.get_newsletter_subscriptions(user.id)
102
103
    orders = order_service.get_orders_placed_by_user(user.id)
104
105
    order_shop_ids = {order.shop_id for order in orders}
106
    shops = shop_service.find_shops(order_shop_ids)
107
    shops_by_id = {shop.id: shop for shop in shops}
108
109
    parties_and_tickets = service.get_parties_and_tickets(user.id)
110
111
    attended_parties = service.get_attended_parties(user.id)
112
113
    badges_with_awarding_quantity = badge_service.get_badges_for_user(user.id)
114
115
    return {
116
        'user': user,
117
        'orga_team_memberships': orga_team_memberships,
118
        'newsletter_subscriptions': newsletter_subscriptions,
119
        'orders': orders,
120
        'shops_by_id': shops_by_id,
121
        'parties_and_tickets': parties_and_tickets,
122
        'attended_parties': attended_parties,
123
        'badges_with_awarding_quantity': badges_with_awarding_quantity,
124
    }
125
126
127
@blueprint.route('/create')
128
@permission_required(UserPermission.create)
129
@templated
130
def create_account_form(erroneous_form=None):
131
    """Show a form to create a user account."""
132
    form = erroneous_form if erroneous_form else CreateAccountForm()
133
    form.set_site_choices()
134
135
    return {'form': form}
136
137
138
@blueprint.route('/', methods=['POST'])
139
@permission_required(UserPermission.create)
140
def create_account():
141
    """Create a user account."""
142
    form = CreateAccountForm(request.form)
143
    form.set_site_choices()
144
145
    if not form.validate():
146
        return create_account_form(form)
147
148
    screen_name = form.screen_name.data.strip()
149
    first_names = form.first_names.data.strip()
150
    last_name = form.last_name.data.strip()
151
    email_address = form.email_address.data.lower()
152
    password = form.password.data
153
    site_id = form.site_id.data
154
155
    if site_id:
156
        site = site_service.get_site(site_id)
157
    else:
158
        site = None
159
160
    if user_service.is_screen_name_already_assigned(screen_name):
161
        flash_error(
162
            'Dieser Benutzername ist bereits einem Benutzerkonto zugeordnet.'
163
        )
164
        return create_account_form(form)
165
166
    if user_service.is_email_address_already_assigned(email_address):
167
        flash_error(
168
            'Diese E-Mail-Adresse ist bereits einem Benutzerkonto zugeordnet.'
169
        )
170
        return create_account_form(form)
171
172
    initiator_id = g.current_user.id
173
174
    try:
175
        user, event = user_creation_service.create_basic_user(
176
            screen_name,
177
            email_address,
178
            password,
179
            first_names=first_names,
180
            last_name=last_name,
181
            creator_id=initiator_id,
182
        )
183
    except user_creation_service.UserCreationFailed:
184
        flash_error(
185
            f'Das Benutzerkonto für "{screen_name}" '
186
            'konnte nicht angelegt werden.'
187
        )
188
        return create_account_form(form)
189
190
    flash_success(f'Das Benutzerkonto "{user.screen_name}" wurde angelegt.')
191
192
    if site:
193
        user_creation_service.request_email_address_confirmation(
194
            user, email_address, site_id
195
        )
196
        flash_success(
197
            f'Eine E-Mail wurde an die hinterlegte Adresse versendet.',
198
            icon='email',
199
        )
200
201
    signals.account_created.send(None, event=event)
202
203
    return redirect_to('.view', user_id=user.id)
204
205
206
@blueprint.route('/<uuid:user_id>/password')
207
@permission_required(UserPermission.set_password)
208
@templated
209
def set_password_form(user_id, erroneous_form=None):
210
    """Show a form to set a new password for the user."""
211
    user = _get_user_or_404(user_id)
212
213
    form = erroneous_form if erroneous_form else SetPasswordForm()
214
215
    return {
216
        'user': user,
217
        'form': form,
218
    }
219
220
221
@blueprint.route('/<uuid:user_id>/password', methods=['POST'])
222
@permission_required(UserPermission.set_password)
223
def set_password(user_id):
224
    """Set a new password for the user."""
225
    user = _get_user_or_404(user_id)
226
227
    form = SetPasswordForm(request.form)
228
    if not form.validate():
229
        return set_password_form(user.id, form)
230
231
    new_password = form.password.data
232
    initiator_id = g.current_user.id
233
234
    password_service.update_password_hash(user.id, new_password, initiator_id)
235
236
    flash_success(
237
        f"Für Benutzerkonto '{user.screen_name}' wurde "
238
        "ein neues Passwort gesetzt."
239
    )
240
241
    return redirect(url_for('.view', user_id=user.id))
242
243
244
@blueprint.route('/<uuid:user_id>/initialize', methods=['POST'])
245
@permission_required(UserPermission.administrate)
246
@respond_no_content
247
def initialize_account(user_id):
248
    """Initialize the user account."""
249
    user = _get_user_or_404(user_id)
250
251
    initiator_id = g.current_user.id
252
253
    user_command_service.initialize_account(user.id, initiator_id=initiator_id)
254
255
    flash_success(
256
        f"Das Benutzerkonto '{user.screen_name}' wurde initialisiert."
257
    )
258
259
260
@blueprint.route('/<uuid:user_id>/suspend')
261
@permission_required(UserPermission.administrate)
262
@templated
263
def suspend_account_form(user_id, erroneous_form=None):
264
    """Show form to suspend the user account."""
265
    user = _get_user_or_404(user_id)
266
267
    if user.suspended:
268
        flash_error(
269
            f"Das Benutzerkonto '{user.screen_name}' ist bereits gesperrt."
270
        )
271
        return redirect_to('.view', user_id=user.id)
272
273
    form = erroneous_form if erroneous_form else SuspendAccountForm()
274
275
    return {
276
        'user': user,
277
        'form': form,
278
    }
279
280
281
@blueprint.route('/<uuid:user_id>/suspend', methods=['POST'])
282
@permission_required(UserPermission.administrate)
283
def suspend_account(user_id):
284
    """Suspend the user account."""
285
    user = _get_user_or_404(user_id)
286
287
    if user.suspended:
288
        flash_error(
289
            f"Das Benutzerkonto '{user.screen_name}' ist bereits gesperrt."
290
        )
291
        return redirect_to('.view', user_id=user.id)
292
293
    form = SuspendAccountForm(request.form)
294
    if not form.validate():
295
        return suspend_account_form(user.id, form)
296
297
    initiator_id = g.current_user.id
298
    reason = form.reason.data.strip()
299
300
    event = user_command_service.suspend_account(user.id, initiator_id, reason)
301
302
    signals.account_suspended.send(None, event=event)
303
304
    flash_success(f"Das Benutzerkonto '{user.screen_name}' wurde gesperrt.")
305
    return redirect_to('.view', user_id=user.id)
306
307
308
@blueprint.route('/<uuid:user_id>/unsuspend')
309
@permission_required(UserPermission.administrate)
310
@templated
311
def unsuspend_account_form(user_id, erroneous_form=None):
312
    """Show form to unsuspend the user account."""
313
    user = _get_user_or_404(user_id)
314
315
    if not user.suspended:
316
        flash_error(
317
            f"Das Benutzerkonto '{user.screen_name}' ist bereits entsperrt."
318
        )
319
        return redirect_to('.view', user_id=user.id)
320
321
    form = erroneous_form if erroneous_form else SuspendAccountForm()
322
323
    return {
324
        'user': user,
325
        'form': form,
326
    }
327
328
329
@blueprint.route('/<uuid:user_id>/unsuspend', methods=['POST'])
330
@permission_required(UserPermission.administrate)
331
def unsuspend_account(user_id):
332
    """Unsuspend the user account."""
333
    user = _get_user_or_404(user_id)
334
335
    if not user.suspended:
336
        flash_error(
337
            f"Das Benutzerkonto '{user.screen_name}' ist bereits entsperrt."
338
        )
339
        return redirect_to('.view', user_id=user.id)
340
341
    form = SuspendAccountForm(request.form)
342
    if not form.validate():
343
        return unsuspend_account_form(user.id, form)
344
345
    initiator_id = g.current_user.id
346
    reason = form.reason.data.strip()
347
348
    event = user_command_service.unsuspend_account(
349
        user.id, initiator_id, reason
350
    )
351
352
    signals.account_unsuspended.send(None, event=event)
353
354
    flash_success(f"Das Benutzerkonto '{user.screen_name}' wurde entsperrt.")
355
    return redirect_to('.view', user_id=user.id)
356
357
358
@blueprint.route('/<uuid:user_id>/delete')
359
@permission_required(UserPermission.administrate)
360
@templated
361
def delete_account_form(user_id, erroneous_form=None):
362
    """Show form to delete the user account."""
363
    user = _get_user_or_404(user_id)
364
365
    if user.deleted:
366
        flash_error(
367
            f"Das Benutzerkonto '{user.screen_name}' "
368
            "ist bereits gelöscht worden."
369
        )
370
        return redirect_to('.view', user_id=user.id)
371
372
    form = erroneous_form if erroneous_form else DeleteAccountForm()
373
374
    return {
375
        'user': user,
376
        'form': form,
377
    }
378
379
380
@blueprint.route('/<uuid:user_id>/delete', methods=['POST'])
381
@permission_required(UserPermission.administrate)
382
def delete_account(user_id):
383
    """Delete the user account."""
384
    user = _get_user_or_404(user_id)
385
386
    if user.deleted:
387
        flash_error(
388
            f"Das Benutzerkonto '{user.screen_name}' "
389
            "ist bereits gelöscht worden."
390
        )
391
        return redirect_to('.view', user_id=user.id)
392
393
    form = DeleteAccountForm(request.form)
394
    if not form.validate():
395
        return delete_account_form(user.id, form)
396
397
    initiator_id = g.current_user.id
398
    reason = form.reason.data.strip()
399
400
    event = user_command_service.delete_account(user.id, initiator_id, reason)
401
402
    signals.account_deleted.send(None, event=event)
403
404
    flash_success(f"Das Benutzerkonto '{user.screen_name}' wurde gelöscht.")
405
    return redirect_to('.view', user_id=user.id)
406
407
408
@blueprint.route('/<uuid:user_id>/change_email_address')
409
@permission_required(UserPermission.administrate)
410
@templated
411
def change_email_address_form(user_id, erroneous_form=None):
412
    """Show form to change the user's e-mail address."""
413
    user = _get_user_or_404(user_id)
414
415
    form = erroneous_form if erroneous_form else ChangeEmailAddressForm()
416
417
    return {
418
        'user': user,
419
        'form': form,
420
    }
421
422
423
@blueprint.route('/<uuid:user_id>/change_email_address', methods=['POST'])
424
@permission_required(UserPermission.administrate)
425
def change_email_address(user_id):
426
    """Change the user's e-mail address."""
427
    user = _get_user_or_404(user_id)
428
429
    form = ChangeEmailAddressForm(request.form)
430
    if not form.validate():
431
        return change_email_address_form(user.id, form)
432
433
    old_email_address = user.email_address
434
    new_email_address = form.email_address.data.strip()
435
    initiator_id = g.current_user.id
436
    reason = form.reason.data.strip()
437
438
    event = user_command_service.change_email_address(
439
        user.id, new_email_address, initiator_id, reason=reason
440
    )
441
442
    signals.email_address_changed.send(None, event=event)
443
444
    flash_success(
445
        f"Die E-Mail-Adresse des Benutzerkontos '{user.screen_name}' wurde "
446
        f"geändert."
447
    )
448
    return redirect_to('.view', user_id=user.id)
449
450
451
@blueprint.route('/<uuid:user_id>/change_screen_name')
452
@permission_required(UserPermission.administrate)
453
@templated
454
def change_screen_name_form(user_id, erroneous_form=None):
455
    """Show form to change the user's screen name."""
456
    user = _get_user_or_404(user_id)
457
458
    form = erroneous_form if erroneous_form else ChangeScreenNameForm()
459
460
    return {
461
        'user': user,
462
        'form': form,
463
    }
464
465
466
@blueprint.route('/<uuid:user_id>/change_screen_name', methods=['POST'])
467
@permission_required(UserPermission.administrate)
468
def change_screen_name(user_id):
469
    """Change the user's screen name."""
470
    user = _get_user_or_404(user_id)
471
472
    form = ChangeScreenNameForm(request.form)
473
    if not form.validate():
474
        return change_screen_name_form(user.id, form)
475
476
    old_screen_name = user.screen_name
477
    new_screen_name = form.screen_name.data.strip()
478
    initiator_id = g.current_user.id
479
    reason = form.reason.data.strip()
480
481
    event = user_command_service.change_screen_name(
482
        user.id, new_screen_name, initiator_id, reason=reason
483
    )
484
485
    signals.screen_name_changed.send(None, event=event)
486
487
    flash_success(
488
        f"Das Benutzerkonto '{old_screen_name}' wurde "
489
        f"umbenannt in '{new_screen_name}'."
490
    )
491
    return redirect_to('.view', user_id=user.id)
492
493
494
@blueprint.route('/<uuid:user_id>/permissions')
495
@permission_required(UserPermission.view)
496
@templated
497
def view_permissions(user_id):
498
    """Show user's permissions."""
499
    user = _get_user_or_404(user_id)
500
501
    permissions_by_role = authorization_service.get_permissions_by_roles_for_user_with_titles(
502
        user.id
503
    )
504
505
    return {
506
        'user': user,
507
        'permissions_by_role': permissions_by_role,
508
    }
509
510
511
@blueprint.route('/<uuid:user_id>/roles/assignment')
512
@permission_required(RolePermission.assign)
513
@templated
514
def manage_roles(user_id):
515
    """Manage what roles are assigned to the user."""
516
    user = _get_user_or_404(user_id)
517
518
    permissions_by_role = (
519
        authorization_service.get_permissions_by_roles_with_titles()
520
    )
521
522
    user_role_ids = authorization_service.find_role_ids_for_user(user.id)
523
524
    return {
525
        'user': user,
526
        'permissions_by_role': permissions_by_role,
527
        'user_role_ids': user_role_ids,
528
    }
529
530
531
@blueprint.route('/<uuid:user_id>/roles/<role_id>', methods=['POST'])
532
@permission_required(RolePermission.assign)
533
@respond_no_content
534
def role_assign(user_id, role_id):
535
    """Assign the role to the user."""
536
    user = _get_user_or_404(user_id)
537
    role = _get_role_or_404(role_id)
538
    initiator_id = g.current_user.id
539
540
    authorization_service.assign_role_to_user(
541
        role.id, user.id, initiator_id=initiator_id
542
    )
543
544
    flash_success(
545
        f'{user.screen_name} wurde die Rolle "{role.title}" zugewiesen.'
546
    )
547
548
549
@blueprint.route('/<uuid:user_id>/roles/<role_id>', methods=['DELETE'])
550
@permission_required(RolePermission.assign)
551
@respond_no_content
552
def role_deassign(user_id, role_id):
553
    """Deassign the role from the user."""
554
    user = _get_user_or_404(user_id)
555
    role = _get_role_or_404(role_id)
556
    initiator_id = g.current_user.id
557
558
    authorization_service.deassign_role_from_user(
559
        role.id, user.id, initiator_id=initiator_id
560
    )
561
562
    flash_success(
563
        f'{user.screen_name} wurde die Rolle "{role.title}" genommen.'
564
    )
565
566
567
@blueprint.route('/<uuid:user_id>/events')
568
@permission_required(UserPermission.view)
569
@templated
570
def view_events(user_id):
571
    """Show user's events."""
572
    user = _get_user_or_404(user_id)
573
574
    events = service.get_events(user.id)
575
576
    return {
577
        'user': user,
578
        'events': events,
579
    }
580
581
582
def _get_user_or_404(user_id):
583
    user = user_service.find_user_with_details(user_id)
584
585
    if user is None:
586
        abort(404)
587
588
    return user
589
590
591
def _get_role_or_404(role_id):
592
    role = authorization_service.find_role(role_id)
593
594
    if role is None:
595
        abort(404)
596
597
    return role
598