api: add real agenda info for each slot (#78064)
gitea/chrono/pipeline/head This commit looks good Details

This commit is contained in:
Emmanuel Cazenave 2023-06-01 15:37:46 +02:00
parent 0e84adb3ac
commit a303d359d8
2 changed files with 130 additions and 22 deletions

View File

@ -801,25 +801,55 @@ class MeetingDatetimes(APIView):
# slot from the list if there is still a bookable slot on a desk at the
# same time.
# The generator also remove slots starting before the current time.
def unique_slots():
last_slot = None
all_slots = list(
agenda.get_all_slots(
meeting_type,
resources=resources,
unique=True,
start_datetime=start_datetime,
end_datetime=end_datetime,
user_external_id=booked_user_external_id or excluded_user_external_id,
if agenda.kind == 'meetings':
def unique_slots():
last_slot = None
all_slots = list(
agenda.get_all_slots(
meeting_type,
resources=resources,
unique=True,
start_datetime=start_datetime,
end_datetime=end_datetime,
user_external_id=booked_user_external_id or excluded_user_external_id,
)
)
)
for slot in sorted(all_slots, key=lambda slot: slot[:3]):
if slot.start_datetime < now_datetime:
continue
if last_slot and last_slot[:2] == slot[:2]:
continue
last_slot = slot
yield slot
for slot in sorted(all_slots, key=lambda slot: slot[:3]):
if slot.start_datetime < now_datetime:
continue
if last_slot and last_slot[:2] == slot[:2]:
continue
last_slot = slot
yield slot, None
elif agenda.kind == 'virtual':
def unique_slots():
all_slots = list(
agenda.get_all_slots(
meeting_type,
resources=resources,
unique=False,
start_datetime=start_datetime,
end_datetime=end_datetime,
user_external_id=booked_user_external_id or excluded_user_external_id,
)
)
last_slot, slot_agendas = None, set()
for slot in sorted(all_slots, key=lambda slot: slot[:3]):
if slot.start_datetime < now_datetime:
continue
if last_slot is None:
last_slot = slot
elif last_slot[:2] != slot[:2]:
yield last_slot, slot_agendas
last_slot = slot
slot_agendas = set()
if not slot.full:
slot_agendas.add(slot.desk.agenda)
if last_slot:
yield last_slot, slot_agendas
generator_of_unique_slots = unique_slots()
@ -839,7 +869,7 @@ class MeetingDatetimes(APIView):
bookable_datetimes_number_available = 0
first_bookable_slot = None
data = []
for slot in generator_of_unique_slots:
for slot, slot_agendas in generator_of_unique_slots:
if request.GET.get('hide_disabled') and slot.full:
continue
if minutes and slot.start_datetime.minute not in minutes:
@ -861,6 +891,23 @@ class MeetingDatetimes(APIView):
}
if booked_user_external_id and slot.booked_for_external_user:
slot_data['booked_for_external_user'] = True
if slot_agendas is not None:
slot_data['agendas'] = [
{
'id': agenda.id,
'text': agenda.label,
'slug': agenda.slug,
'api': {
'fillslot_url': request.build_absolute_uri(
reverse(
'api-fillslot',
kwargs={'agenda_identifier': agenda.slug, 'event_identifier': slot_id},
)
)
},
}
for agenda in sorted(slot_agendas, key=lambda a: a.label)
]
data.append(slot_data)
bookable_datetimes_number_total += 1

View File

@ -10,7 +10,6 @@ from chrono.agendas.models import (
Desk,
Event,
MeetingType,
Resource,
TimePeriod,
TimePeriodException,
UnavailabilityCalendar,
@ -18,6 +17,8 @@ from chrono.agendas.models import (
)
from chrono.utils.timezone import localtime, make_aware, now
from ...utils import build_virtual_agenda
pytestmark = pytest.mark.django_db
@ -514,7 +515,7 @@ def test_virtual_agendas_meetings_datetimes_multiple_agendas(app, mock_now):
with CaptureQueriesContext(connection) as ctx:
resp = app.get(api_url)
assert len(resp.json['data']) == 12
assert len(ctx.captured_queries) == 10
assert len(ctx.captured_queries) == 12
# simulate booking
dt = datetime.datetime.strptime(resp.json['data'][2]['id'].split(':')[1], '%Y-%m-%d-%H%M')
@ -643,7 +644,7 @@ def test_virtual_agendas_meetings_datetimes_exclude_slots(app):
'/api/agenda/%s/meetings/%s/datetimes/' % (virt_agenda.slug, meeting_type.slug),
params={'exclude_user_external_id': '42'},
)
assert len(ctx.captured_queries) == 11
assert len(ctx.captured_queries) == 13
assert resp.json['data'][0]['id'] == 'foo-bar:2021-02-26-0900'
assert resp.json['data'][0]['disabled'] is True
assert resp.json['data'][2]['id'] == 'foo-bar:2021-02-26-1000'
@ -1188,3 +1189,63 @@ def test_datetimes_api_meetings_virtual_agenda_date_time_period(app):
assert [x['datetime'] for x in resp.json['data']] == [
'2022-10-24 13:00:00',
]
def test_show_available_agendas(app, user):
agenda = build_virtual_agenda(
agendas={
'Agenda 1': {
'desks': {
'Desk 1': 'monday-sunday 08:00-12:00 14:00-17:00',
'Desk 2': 'monday-sunday 08:00-12:00 14:00-17:00',
},
},
'Agenda 2': {
'desks': {
'Desk 1': 'monday-sunday 08:00-12:00 14:00-17:00',
'Desk 2': 'monday-sunday 08:00-12:00 14:00-17:00',
},
},
},
meeting_types=[30],
)
api_url = '/api/agenda/%s/meetings/mt-30/datetimes/' % agenda.slug
resp = app.get(api_url)
first_slot = resp.json['data'][0]
assert first_slot['disabled'] is False
assert len(first_slot['agendas']) == 2
assert first_slot['agendas'][0]['text'] == 'Agenda 1'
assert first_slot['agendas'][1]['text'] == 'Agenda 2'
## Make a booking directly on agenda 1, and check that nothing changed
app.authorization = ('Basic', ('john.doe', 'password'))
app.post(first_slot['agendas'][0]['api']['fillslot_url'])
resp = app.get(api_url)
first_slot = resp.json['data'][0]
assert first_slot['disabled'] is False
assert len(first_slot['agendas']) == 2
assert first_slot['agendas'][0]['text'] == 'Agenda 1'
assert first_slot['agendas'][1]['text'] == 'Agenda 2'
## Make a second booking directly on agenda 1, agenda 2 should be the only one left available
app.post(first_slot['agendas'][0]['api']['fillslot_url'])
resp = app.get(api_url)
first_slot = resp.json['data'][0]
assert first_slot['disabled'] is False
assert len(first_slot['agendas']) == 1
assert first_slot['agendas'][0]['text'] == 'Agenda 2'
## Make a booking directly on agenda 2, and check that nothing changed
app.post(first_slot['agendas'][0]['api']['fillslot_url'])
resp = app.get(api_url)
first_slot = resp.json['data'][0]
assert first_slot['disabled'] is False
assert len(first_slot['agendas']) == 1
assert first_slot['agendas'][0]['text'] == 'Agenda 2'
## Make a booking directly on agenda 2, the slots is full and no agenda available
app.post(first_slot['agendas'][0]['api']['fillslot_url'])
resp = app.get(api_url)
first_slot = resp.json['data'][0]
assert first_slot['disabled'] is True
assert len(first_slot['agendas']) == 0