create()   B
last analyzed

Complexity

Conditions 6

Size

Total Lines 80
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 29
CRAP Score 6.1144

Importance

Changes 0
Metric Value
eloc 56
dl 0
loc 80
rs 7.5066
c 0
b 0
f 0
cc 6
nop 0
ccs 29
cts 34
cp 0.8529
crap 6.1144

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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