byceps.blueprints.admin.orga_team.views   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 391
Duplicated Lines 0 %

Test Coverage

Coverage 90.53%

Importance

Changes 0
Metric Value
eloc 233
dl 0
loc 391
rs 9.76
c 0
b 0
f 0
ccs 153
cts 169
cp 0.9053
wmc 33

14 Functions

Rating   Name   Duplication   Size   Complexity  
A team_create_form() 0 12 2
A membership_update_form() 0 26 2
A _get_membership_or_404() 0 7 2
A _get_team_or_404() 0 7 2
A _get_party_or_404() 0 7 2
A membership_update() 0 30 2
A teams_for_party() 0 25 3
A team_create() 0 22 2
B teams_copy_form() 0 41 5
A membership_remove() 0 17 1
A teams_copy() 0 39 3
A membership_create_form() 0 30 3
A membership_create() 0 27 2
A team_delete() 0 21 2
1
"""
2
byceps.blueprints.admin.orga_team.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2014-2024 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from flask import abort, request
10 1
from flask_babel import gettext
11
12 1
from byceps.services.orga_team import orga_team_service
13 1
from byceps.services.party import party_service
14 1
from byceps.services.user import user_service
15 1
from byceps.util.framework.blueprint import create_blueprint
16 1
from byceps.util.framework.flash import flash_error, flash_success
17 1
from byceps.util.framework.templating import templated
18 1
from byceps.util.views import (
19
    permission_required,
20
    redirect_to,
21
    respond_no_content,
22
)
23
24 1
from .forms import (
25
    MembershipCreateForm,
26
    MembershipUpdateForm,
27
    OrgaTeamCreateForm,
28
    OrgaTeamsCopyForm,
29
)
30
31
32 1
blueprint = create_blueprint('orga_team_admin', __name__)
33
34
35
# -------------------------------------------------------------------- #
36
# teams
37
38
39 1
@blueprint.get('/teams/<party_id>')
40 1
@permission_required('orga_team.view')
41 1
@templated
42 1
def teams_for_party(party_id):
43
    """List organizer teams for that party."""
44 1
    party = _get_party_or_404(party_id)
45
46 1
    teams_and_members = orga_team_service.get_teams_and_members_for_party(
47
        party.id
48
    )
49
50 1
    def sort_members(members):
51
        return sorted(
52
            members,
53
            key=lambda m: user_service.get_sort_key_for_screen_name(m.user),
54
        )
55
56 1
    teams_and_members = sorted(teams_and_members, key=lambda tam: tam[0].title)
57 1
    teams_and_members = [
58
        (teams, sort_members(members)) for teams, members in teams_and_members
59
    ]
60
61 1
    return {
62
        'party': party,
63
        'teams_and_members': teams_and_members,
64
    }
65
66
67 1
@blueprint.get('/teams/<party_id>/create')
68 1
@permission_required('orga_team.create')
69 1
@templated
70 1
def team_create_form(party_id, erroneous_form=None):
71
    """Show form to create an organizer team for a party."""
72 1
    party = _get_party_or_404(party_id)
73
74 1
    form = erroneous_form if erroneous_form else OrgaTeamCreateForm()
75
76 1
    return {
77
        'party': party,
78
        'form': form,
79
    }
80
81
82 1
@blueprint.post('/teams/<party_id>')
83 1
@permission_required('orga_team.create')
84 1
def team_create(party_id):
85
    """Create an organizer team for a party."""
86 1
    party = _get_party_or_404(party_id)
87
88 1
    form = OrgaTeamCreateForm(request.form)
89 1
    if not form.validate():
90
        return team_create_form(party.id, form)
91
92 1
    title = form.title.data.strip()
93
94 1
    team = orga_team_service.create_team(party.id, title)
95
96 1
    flash_success(
97
        gettext(
98
            'Team "%(team_title)s" for party "%(party_title)s" has been created.',
99
            team_title=team.title,
100
            party_title=party.title,
101
        )
102
    )
103 1
    return redirect_to('.teams_for_party', party_id=party.id)
104
105
106 1
@blueprint.delete('/teams/<uuid:team_id>')
107 1
@permission_required('orga_team.delete')
108 1
@respond_no_content
109 1
def team_delete(team_id):
110
    """Delete the team."""
111 1
    team = _get_team_or_404(team_id)
112
113 1
    if orga_team_service.has_team_memberships(team.id):
114
        flash_error(
115
            gettext(
116
                'Team "%(team_title)s" cannot be deleted because it has members.',
117
                team_title=team.title,
118
            )
119
        )
120
        return
121
122 1
    title = team.title
123
124 1
    orga_team_service.delete_team(team.id)
125
126 1
    flash_success(gettext('Team "%(title)s" has been deleted.', title=title))
127
128
129 1
@blueprint.get('/teams/<target_party_id>/copy')
130 1
@permission_required('orga_team.create')
131 1
@templated
132 1
def teams_copy_form(target_party_id, erroneous_form=None):
133
    """Show form to copy all organizer teams from another party."""
134 1
    target_party = _get_party_or_404(target_party_id)
135
136 1
    team_count = orga_team_service.count_teams_for_party(target_party.id)
137 1
    if team_count:
138 1
        flash_error(
139
            gettext(
140
                'This party already has teams. No additional teams can be copied to it.'
141
            )
142
        )
143 1
        return redirect_to('.teams_for_party', party_id=target_party.id)
144
145 1
    parties = party_service.get_parties_for_brand(target_party.brand_id)
146
147
    # Do not offer to copy teams from target party.
148 1
    parties = [p for p in parties if p.id != target_party.id]
149
150 1
    party_ids = {party.id for party in parties}
151 1
    team_count_per_party = orga_team_service.count_teams_for_parties(party_ids)
152
153
    # Exclude parties without orga teams.
154 1
    parties = [p for p in parties if team_count_per_party.get(p.id, 0)]
155
156 1
    if not parties:
157 1
        flash_error(
158
            gettext('No other parties exist from which teams could be copied.')
159
        )
160 1
        return redirect_to('.teams_for_party', party_id=target_party.id)
161
162 1
    parties.sort(key=lambda p: p.starts_at, reverse=True)
163
164 1
    form = erroneous_form if erroneous_form else OrgaTeamsCopyForm()
165 1
    form.set_party_choices(parties, team_count_per_party)
166
167 1
    return {
168
        'party': target_party,
169
        'form': form,
170
    }
171
172
173 1
@blueprint.post('/teams/<target_party_id>/copy')
174 1
@permission_required('orga_team.create')
175 1
def teams_copy(target_party_id):
176
    """Copy all organizer teams from another party."""
177 1
    target_party = _get_party_or_404(target_party_id)
178
179 1
    target_team_count = orga_team_service.count_teams_for_party(target_party.id)
180 1
    if target_team_count:
181
        flash_error(
182
            gettext(
183
                'This party already has teams. No additional teams can be copied to it.'
184
            )
185
        )
186
        return redirect_to('.teams_for_party', party_id=target_party.id)
187
188 1
    parties = party_service.get_parties_for_brand(target_party.brand_id)
189
190 1
    form = OrgaTeamsCopyForm(request.form)
191 1
    form.set_party_choices(parties)
192 1
    if not form.validate():
193
        return teams_copy_form(target_party.id, form)
194
195 1
    source_party = party_service.get_party(form.party_id.data)
196
197 1
    copied_teams_count = orga_team_service.copy_teams_and_memberships(
198
        source_party.id, target_party.id
199
    )
200
201 1
    flash_success(
202
        gettext(
203
            '%(copied_teams_count)s team(s) has/have been copied from party '
204
            '"%(source_party_title)s" to party "%(target_party_title)s".',
205
            copied_teams_count=copied_teams_count,
206
            source_party_title=source_party.title,
207
            target_party_title=target_party.title,
208
        )
209
    )
210
211 1
    return redirect_to('.teams_for_party', party_id=target_party.id)
212
213
214
# -------------------------------------------------------------------- #
215
# memberships
216
217
218 1
@blueprint.get('/teams/<uuid:team_id>/memberships/create')
219 1
@permission_required('orga_team.administrate_memberships')
220 1
@templated
221 1
def membership_create_form(team_id, erroneous_form=None):
222
    """Show form to assign an organizer to that team."""
223 1
    team = _get_team_or_404(team_id)
224
225 1
    party = party_service.get_party(team.party_id)
226
227 1
    unassigned_orgas = orga_team_service.get_unassigned_orgas_for_team(team)
228
229 1
    if not unassigned_orgas:
230 1
        return {
231
            'team': team,
232
            'party': party,
233
            'unassigned_orgas_available': False,
234
        }
235
236
    unassigned_orgas = sorted(
237
        unassigned_orgas, key=user_service.get_sort_key_for_screen_name
238
    )
239
240
    form = erroneous_form if erroneous_form else MembershipCreateForm()
241
    form.set_user_choices(unassigned_orgas)
242
243
    return {
244
        'form': form,
245
        'team': team,
246
        'party': party,
247
        'unassigned_orgas_available': True,
248
    }
249
250
251 1
@blueprint.post('/teams/<uuid:team_id>/memberships')
252 1
@permission_required('orga_team.administrate_memberships')
253 1
def membership_create(team_id):
254
    """Assign an organizer to that team."""
255 1
    team = _get_team_or_404(team_id)
256
257 1
    unassigned_orgas = orga_team_service.get_unassigned_orgas_for_team(team)
258
259 1
    form = MembershipCreateForm(request.form)
260 1
    form.set_user_choices(unassigned_orgas)
261
262 1
    if not form.validate():
263
        return membership_create_form(team.id, form)
264
265 1
    user = user_service.get_user(form.user_id.data)
266 1
    duties = form.duties.data.strip()
267
268 1
    orga_team_service.create_membership(team.id, user.id, duties)
269
270 1
    flash_success(
271
        gettext(
272
            '%(screen_name)s has been added to team "%(team_title)s".',
273
            screen_name=user.screen_name,
274
            team_title=team.title,
275
        )
276
    )
277 1
    return redirect_to('.teams_for_party', party_id=team.party_id)
278
279
280 1
@blueprint.get('/memberships/<uuid:membership_id>/update')
281 1
@permission_required('orga_team.administrate_memberships')
282 1
@templated
283 1
def membership_update_form(membership_id, erroneous_form=None):
284
    """Show form to update a membership."""
285 1
    membership = _get_membership_or_404(membership_id)
286
287 1
    user = user_service.get_user(membership.user_id)
288 1
    team = orga_team_service.find_team(membership.orga_team_id)
289 1
    party = party_service.get_party(team.party_id)
290
291 1
    teams = orga_team_service.get_teams_for_party(team.party_id)
292
293 1
    form = (
294
        erroneous_form
295
        if erroneous_form
296
        else MembershipUpdateForm(obj=membership)
297
    )
298 1
    form.set_orga_team_choices(teams)
299
300 1
    return {
301
        'form': form,
302
        'membership': membership,
303
        'user': user,
304
        'team': team,
305
        'party': party,
306
    }
307
308
309 1
@blueprint.post('/memberships/<uuid:membership_id>')
310 1
@permission_required('orga_team.administrate_memberships')
311 1
def membership_update(membership_id):
312
    """Update a membership."""
313 1
    membership = _get_membership_or_404(membership_id)
314
315 1
    user = user_service.get_user(membership.user_id)
316 1
    team = orga_team_service.find_team(membership.orga_team_id)
317
318 1
    teams = orga_team_service.get_teams_for_party(team.party_id)
319
320 1
    form = MembershipUpdateForm(request.form)
321 1
    form.set_orga_team_choices(teams)
322
323 1
    if not form.validate():
324
        return membership_update_form(membership.id, form)
325
326 1
    team_id = form.orga_team_id.data
327 1
    team = orga_team_service.find_team(team_id)
328 1
    duties = form.duties.data.strip() or None
329
330 1
    orga_team_service.update_membership(membership.id, team.id, duties)
331
332 1
    flash_success(
333
        gettext(
334
            'Membership of %(screen_name)s has been updated.',
335
            screen_name=user.screen_name,
336
        )
337
    )
338 1
    return redirect_to('.teams_for_party', party_id=team.party_id)
339
340
341 1
@blueprint.delete('/memberships/<uuid:membership_id>')
342 1
@permission_required('orga_team.administrate_memberships')
343 1
@respond_no_content
344 1
def membership_remove(membership_id):
345
    """Remove an organizer from a team."""
346 1
    membership = _get_membership_or_404(membership_id)
347
348 1
    user = user_service.get_user(membership.user_id)
349 1
    team = orga_team_service.find_team(membership.orga_team_id)
350
351 1
    orga_team_service.delete_membership(membership.id)
352
353 1
    flash_success(
354
        gettext(
355
            '%(screen_name)s has been removed from team "%(team_title)s".',
356
            screen_name=user.screen_name,
357
            team_title=team.title,
358
        )
359
    )
360
361
362
# -------------------------------------------------------------------- #
363
# helpers
364
365
366 1
def _get_party_or_404(party_id):
367 1
    party = party_service.find_party(party_id)
368
369 1
    if party is None:
370
        abort(404)
371
372 1
    return party
373
374
375 1
def _get_team_or_404(team_id):
376 1
    team = orga_team_service.find_team(team_id)
377
378 1
    if team is None:
379
        abort(404)
380
381 1
    return team
382
383
384 1
def _get_membership_or_404(membership_id):
385 1
    membership = orga_team_service.find_membership(membership_id)
386
387 1
    if membership is None:
388
        abort(404)
389
390
    return membership
391