0001-agendas-add-date-filter-params-on-datetimes-api-4807.patch
chrono/api/views.py | ||
---|---|---|
64 | 64 |
return localtime(dt).strftime('%Y-%m-%d %H:%M:%S') |
65 | 65 | |
66 | 66 | |
67 |
def get_min_datetime(agenda): |
|
68 |
if agenda.minimal_booking_delay is None: |
|
67 |
def get_min_datetime(agenda, start_datetime=None):
|
|
68 |
if agenda.minimal_booking_delay is None and start_datetime is None:
|
|
69 | 69 |
return None |
70 |
elif agenda.minimal_booking_delay is None: |
|
71 |
return start_datetime |
|
72 | ||
70 | 73 |
min_datetime = now() + datetime.timedelta(days=agenda.minimal_booking_delay) |
71 |
return min_datetime.replace(hour=0, minute=0, second=0, microsecond=0) |
|
74 |
min_datetime = min_datetime.replace(hour=0, minute=0, second=0, microsecond=0) |
|
75 |
if start_datetime is None: |
|
76 |
return min_datetime |
|
77 |
return max(min_datetime, start_datetime) |
|
72 | 78 | |
73 | 79 | |
74 |
def get_max_datetime(agenda): |
|
75 |
if agenda.maximal_booking_delay is None: |
|
80 |
def get_max_datetime(agenda, end_datetime=None):
|
|
81 |
if agenda.maximal_booking_delay is None and end_datetime is None:
|
|
76 | 82 |
return None |
83 |
elif agenda.maximal_booking_delay is None: |
|
84 |
return end_datetime |
|
85 | ||
77 | 86 |
max_datetime = now() + datetime.timedelta(days=agenda.maximal_booking_delay) |
78 | 87 |
max_datetime = max_datetime.replace(hour=0, minute=0, second=0, microsecond=0) |
79 |
return max_datetime |
|
88 |
if end_datetime is None: |
|
89 |
return max_datetime |
|
90 |
return min(max_datetime, end_datetime) |
|
80 | 91 | |
81 | 92 | |
82 | 93 |
TimeSlot = collections.namedtuple('TimeSlot', ['start_datetime', 'end_datetime', 'full', 'desk']) |
83 | 94 | |
84 | 95 | |
85 |
def get_all_slots(base_agenda, meeting_type, resources=None, unique=False): |
|
96 |
def get_all_slots( |
|
97 |
base_agenda, meeting_type, resources=None, unique=False, start_datetime=None, end_datetime=None |
|
98 |
): |
|
86 | 99 |
'''Get all occupation state of all possible slots for the given agenda (of |
87 | 100 |
its real agendas for a virtual agenda) and the given meeting_type. |
88 | 101 | |
... | ... | |
107 | 120 |
# that the base_meeting_duration for the virtual agenda is always the same |
108 | 121 |
# as the base meeting duration of each real agenda. |
109 | 122 |
base_meeting_duration = base_agenda.get_base_meeting_duration() |
110 |
base_min_datetime = get_min_datetime(base_agenda) |
|
111 |
base_max_datetime = get_max_datetime(base_agenda) |
|
123 |
base_min_datetime = get_min_datetime(base_agenda, start_datetime)
|
|
124 |
base_max_datetime = get_max_datetime(base_agenda, end_datetime)
|
|
112 | 125 | |
113 | 126 |
meeting_duration = meeting_type.duration |
114 | 127 |
meeting_duration_td = datetime.timedelta(minutes=meeting_duration) |
... | ... | |
121 | 134 |
agenda_ids_by_min_max_datetimes = collections.defaultdict(set) |
122 | 135 |
agenda_id_min_max_datetime = {} |
123 | 136 |
for agenda in agendas: |
124 |
used_min_datetime = base_min_datetime or get_min_datetime(agenda) |
|
125 |
used_max_datetime = base_max_datetime or get_max_datetime(agenda) |
|
137 |
used_min_datetime = base_min_datetime or get_min_datetime(agenda, start_datetime)
|
|
138 |
used_max_datetime = base_max_datetime or get_max_datetime(agenda, end_datetime)
|
|
126 | 139 |
agenda_ids_by_min_max_datetimes[(used_min_datetime, used_max_datetime)].add(agenda.id) |
127 | 140 |
agenda_id_min_max_datetime[agenda.id] = (used_min_datetime, used_max_datetime) |
128 | 141 | |
... | ... | |
518 | 531 |
except APIError as e: |
519 | 532 |
return e.to_response() |
520 | 533 | |
534 |
start_datetime = None |
|
535 |
if 'date_start' in request.GET: |
|
536 |
start_datetime = make_aware( |
|
537 |
datetime.datetime.combine(parse_date(request.GET['date_start']), datetime.time(0, 0)) |
|
538 |
) |
|
539 | ||
540 |
end_datetime = None |
|
541 |
if 'date_end' in request.GET: |
|
542 |
end_datetime = make_aware( |
|
543 |
datetime.datetime.combine(parse_date(request.GET['date_end']), datetime.time(0, 0)) |
|
544 |
) |
|
545 | ||
521 | 546 |
# Generate an unique slot for each possible meeting [start_datetime, |
522 | 547 |
# end_datetime] range. |
523 | 548 |
# First use get_all_slots() to get each possible meeting by desk and |
... | ... | |
531 | 556 |
# The generator also remove slots starting before the current time. |
532 | 557 |
def unique_slots(): |
533 | 558 |
last_slot = None |
534 |
all_slots = list(get_all_slots(agenda, meeting_type, resources=resources, unique=True)) |
|
559 |
all_slots = list( |
|
560 |
get_all_slots( |
|
561 |
agenda, |
|
562 |
meeting_type, |
|
563 |
resources=resources, |
|
564 |
unique=True, |
|
565 |
start_datetime=start_datetime, |
|
566 |
end_datetime=end_datetime, |
|
567 |
) |
|
568 |
) |
|
535 | 569 |
for slot in sorted(all_slots, key=lambda slot: slot[:3]): |
536 | 570 |
if slot.start_datetime < now_datetime: |
537 | 571 |
continue |
tests/test_api.py | ||
---|---|---|
4451 | 4451 |
resp = app.get(api_url) |
4452 | 4452 |
data = resp.json['data'] |
4453 | 4453 |
assert len(data) == 4 |
4454 | ||
4455 | ||
4456 |
def test_meetings_and_virtual_datetimes_date_filter(app): |
|
4457 |
agenda_foo = Agenda.objects.create( |
|
4458 |
label=u'Agenda Foo', kind='meetings', minimal_booking_delay=1, maximal_booking_delay=7 |
|
4459 |
) |
|
4460 |
meeting_type = MeetingType.objects.create(agenda=agenda_foo, label='Meeting Type', duration=30) |
|
4461 |
desk_foo = Desk.objects.create(agenda=agenda_foo, label='Desk 1') |
|
4462 |
weekday1 = (localtime(now())).weekday() + 1 % 7 |
|
4463 |
weekday2 = (localtime(now())).weekday() + 2 % 7 |
|
4464 |
weekday3 = (localtime(now())).weekday() + 3 % 7 |
|
4465 |
weekday4 = (localtime(now())).weekday() + 4 % 7 |
|
4466 |
weekday5 = (localtime(now())).weekday() + 5 % 7 |
|
4467 |
weekday6 = (localtime(now())).weekday() + 6 % 7 |
|
4468 |
for weekday in (weekday1, weekday2, weekday3, weekday4, weekday5, weekday6): |
|
4469 |
TimePeriod.objects.create( |
|
4470 |
weekday=weekday, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0), desk=desk_foo, |
|
4471 |
) |
|
4472 | ||
4473 |
virtual_agenda = Agenda.objects.create( |
|
4474 |
label=u'Agenda Virtual', kind='virtual', minimal_booking_delay=1, maximal_booking_delay=7 |
|
4475 |
) |
|
4476 |
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=agenda_foo) |
|
4477 | ||
4478 |
# 4 slots each day * 6 days |
|
4479 |
foo_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (agenda_foo.slug, meeting_type.slug) |
|
4480 |
resp = app.get(foo_api_url) |
|
4481 |
assert len(resp.json['data']) == 24 |
|
4482 |
virtual_api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (virtual_agenda.slug, meeting_type.slug) |
|
4483 |
resp = app.get(virtual_api_url) |
|
4484 |
assert len(resp.json['data']) == 24 |
|
4485 | ||
4486 |
# exclude weekday1 through date_start, 4 slots each day * 5 days |
|
4487 |
params = {'date_start': (localtime(now()) + datetime.timedelta(days=2)).date().isoformat()} |
|
4488 |
resp = app.get(foo_api_url, params=params) |
|
4489 |
assert len(resp.json['data']) == 20 |
|
4490 |
resp = app.get(virtual_api_url, params=params) |
|
4491 |
assert len(resp.json['data']) == 20 |
|
4492 | ||
4493 |
# minimal_booking_delay (which exclude weekday1 and wekkday2 ) takes precedence |
|
4494 |
# 4 slots each day * 4 days |
|
4495 |
agenda_foo.minimal_booking_delay = 3 |
|
4496 |
agenda_foo.save() |
|
4497 |
resp = app.get(foo_api_url, params=params) |
|
4498 |
assert len(resp.json['data']) == 16 |
|
4499 |
# also on virtual agenda |
|
4500 |
virtual_agenda.minimal_booking_delay = 3 |
|
4501 |
virtual_agenda.save() |
|
4502 |
resp = app.get(virtual_api_url, params=params) |
|
4503 |
assert len(resp.json['data']) == 16 |
|
4504 | ||
4505 |
# reset |
|
4506 |
agenda_foo.minimal_booking_delay = 1 |
|
4507 |
virtual_agenda.minimal_booking_delay = 1 |
|
4508 |
agenda_foo.save() |
|
4509 |
virtual_agenda.save() |
|
4510 | ||
4511 |
# exclude weekday6 through date_end, 4 slots each day * 5 days |
|
4512 |
params = {'date_end': (localtime(now()) + datetime.timedelta(days=6)).date().isoformat()} |
|
4513 |
resp = app.get(foo_api_url, params=params) |
|
4514 |
assert len(resp.json['data']) == 20 |
|
4515 |
resp = app.get(virtual_api_url, params=params) |
|
4516 |
assert len(resp.json['data']) == 20 |
|
4517 | ||
4518 |
# maximal_booking_delay (which exclude weekday5 and weekday6 ) takes precedence |
|
4519 |
# 4 slots each day * 4 days |
|
4520 |
agenda_foo.maximal_booking_delay = 5 |
|
4521 |
agenda_foo.save() |
|
4522 |
resp = app.get(foo_api_url, params=params) |
|
4523 |
assert len(resp.json['data']) == 16 |
|
4524 |
# also on virtual agenda |
|
4525 |
virtual_agenda.maximal_booking_delay = 5 |
|
4526 |
virtual_agenda.save() |
|
4527 |
resp = app.get(virtual_api_url, params=params) |
|
4528 |
assert len(resp.json['data']) == 16 |
|
4454 |
- |