Completed
Push — main ( 4a0798...19a6c5 )
by Jochen
04:14
created

teams_for_party()   A

Complexity

Conditions 3

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 6.087

Importance

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