Passed
Push — main ( 4dce73...0d6f99 )
by Jochen
04:31
created

time_slot_delete()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1.0156

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 1
dl 0
loc 6
ccs 3
cts 4
cp 0.75
crap 1.0156
rs 10
c 0
b 0
f 0
1
"""
2
byceps.blueprints.admin.orga_presence.views
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
5
:Copyright: 2006-2021 Jochen Kupperschmidt
6
:License: Revised BSD (see `LICENSE` file for details)
7
"""
8
9 1
from __future__ import annotations
10 1
from collections import defaultdict
11 1
from datetime import datetime
12 1
from typing import Iterable
13
14 1
from flask import abort, g, request
15
16 1
from ....services.orga_presence import service as orga_presence_service
17 1
from ....services.orga_presence.transfer.models import (
18
    PartyTimeSlot,
19
    PresenceTimeSlot,
20
    TimeSlot,
21
)
22 1
from ....services.party import service as party_service
23 1
from ....services.user.transfer.models import User
24 1
from ....util.datetime.timezone import local_tz_to_utc
25 1
from ....util.framework.blueprint import create_blueprint
26 1
from ....util.framework.templating import templated
27 1
from ....util.views import permission_required, redirect_to, respond_no_content
28
29 1
from .forms import build_presence_create_form
30
31
32 1
blueprint = create_blueprint('orga_presence', __name__)
33
34
35 1
@blueprint.get('/<party_id>')
36 1
@permission_required('orga_presence.view')
37 1
@templated
38
def view(party_id):
39
    """List orga presence and task time slots for that party."""
40
    party = _get_party_or_404(party_id)
41
42
    party_time_slot = PartyTimeSlot.from_party(party)
43
    presences = orga_presence_service.get_presences(party.id)
44
    tasks = orga_presence_service.get_tasks(party.id)
45
46
    presences_by_orga = _group_presences_by_orga(presences)
47
48
    time_slots = [party_time_slot] + presences + tasks
49
    hour_ranges = list(orga_presence_service.get_hour_ranges(time_slots))
50
51
    days_and_hour_totals = list(
52
        orga_presence_service.get_days_and_hour_totals(hour_ranges)
53
    )
54
55
    current_user_presences = [
56
        presence for presence in presences if presence.orga.id == g.user.id
57
    ]
58
59
    return {
60
        'party': party,
61
        'days_and_hour_totals': days_and_hour_totals,
62
        'hour_ranges': hour_ranges,
63
        'party_time_slot': party_time_slot,
64
        'presences_by_orga': presences_by_orga,
65
        'tasks': tasks,
66
        'is_instant_contained_in_time_slots': is_instant_contained_in_time_slots,
67
        'current_user_presences': current_user_presences,
68
    }
69
70
71 1
def _group_presences_by_orga(
72
    presences: Iterable[PresenceTimeSlot],
73
) -> dict[User, set[PresenceTimeSlot]]:
74
    d = defaultdict(set)
75
76
    for presence in presences:
77
        d[presence.orga].add(presence)
78
79
    return d
80
81
82 1
def is_instant_contained_in_time_slots(
83
    instant: datetime, time_slots: Iterable[TimeSlot]
84
) -> bool:
85
    return any(time_slot.range.contains(instant) for time_slot in time_slots)
86
87
88 1
@blueprint.get('/<party_id>/presences/create')
89 1
@permission_required('orga_presence.update')
90 1
@templated
91 1
def create_form(party_id, erroneous_form=None):
92
    """Show form to create a presence for that party."""
93
    party = _get_party_or_404(party_id)
94
95
    party_time_slot = PartyTimeSlot.from_party(party)
96
    valid_range = party_time_slot.range
97
98
    CreateForm = build_presence_create_form(valid_range)
99
    form = erroneous_form if erroneous_form else CreateForm()
100
101
    return {
102
        'party': party,
103
        'valid_range': valid_range,
104
        'form': form,
105
    }
106
107
108 1
@blueprint.post('/<party_id>/presences')
109 1
@permission_required('orga_presence.update')
110
def create(party_id):
111
    """Create a presence for that party."""
112
    party = _get_party_or_404(party_id)
113
114
    party_time_slot = PartyTimeSlot.from_party(party)
115
116
    CreateForm = build_presence_create_form(party_time_slot.range)
117
    form = CreateForm(request.form)
118
119
    if not form.validate():
120
        return create_form(party.id, form)
121
122
    starts_at = local_tz_to_utc(
123
        datetime.combine(form.starts_on.data, form.starts_at.data)
124
    )
125
    ends_at = local_tz_to_utc(
126
        datetime.combine(form.ends_on.data, form.ends_at.data)
127
    )
128
129
    orga_presence_service.create_presence(
130
        party.id,
131
        g.user.id,
132
        starts_at,
133
        ends_at,
134
    )
135
136
    return redirect_to('.view', party_id=party.id)
137
138
139 1
@blueprint.delete('/time_slots/<time_slot_id>')
140 1
@permission_required('orga_presence.update')
141 1
@respond_no_content
142
def time_slot_delete(time_slot_id):
143
    """Delete the time slot."""
144
    orga_presence_service.delete_time_slot(time_slot_id)
145
146
147 1
def _get_party_or_404(party_id):
148
    party = party_service.find_party(party_id)
149
150
    if party is None:
151
        abort(404)
152
153
    return party
154