0004-manager-add-opened-events-view-for-event-agenda-4445.patch
chrono/agendas/models.py | ||
---|---|---|
405 | 405 |
for weektime_interval in IntervalSet.simple(*time_period_interval) - closed_hours_by_days: |
406 | 406 |
yield SharedTimePeriod.from_weektime_interval(weektime_interval, desks=desks) |
407 | 407 | |
408 |
def get_opened_events(self):
|
|
408 |
def get_open_events(self): |
|
409 | 409 |
assert self.kind == 'events' |
410 | 410 | |
411 | 411 |
entries = self.event_set.all() |
chrono/api/views.py | ||
---|---|---|
294 | 294 |
) |
295 | 295 |
} |
296 | 296 |
if check_events: |
297 |
agenda_detail['opened_events_available'] = agenda.get_opened_events().filter(full=False).exists()
|
|
297 |
agenda_detail['opened_events_available'] = agenda.get_open_events().filter(full=False).exists() |
|
298 | 298 |
elif agenda.accept_meetings(): |
299 | 299 |
agenda_detail['api'] = { |
300 | 300 |
'meetings_url': request.build_absolute_uri( |
... | ... | |
393 | 393 |
if agenda.kind != 'events': |
394 | 394 |
raise Http404('agenda found, but it was not an events agenda') |
395 | 395 | |
396 |
entries = agenda.get_opened_events()
|
|
396 |
entries = agenda.get_open_events() |
|
397 | 397 | |
398 | 398 |
if 'date_start' in request.GET: |
399 | 399 |
entries = entries.filter( |
chrono/manager/static/css/style.scss | ||
---|---|---|
95 | 95 |
min-width: 16ex; |
96 | 96 |
} |
97 | 97 | |
98 |
.openevents .section h4:first-child { |
|
99 |
margin-top: 0; |
|
100 |
} |
|
101 | ||
98 | 102 |
.agenda-table thead th { |
99 | 103 |
width: 14vw; |
100 | 104 |
padding-bottom: 1ex; |
chrono/manager/templates/chrono/manager_agenda_open_events.html | ||
---|---|---|
1 |
{% extends "chrono/manager_agenda_view.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block bodyargs %}class="openevents"{% endblock %} |
|
5 | ||
6 |
{% block breadcrumb %} |
|
7 |
{{ block.super }} |
|
8 |
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans "Open events" %}</a> |
|
9 |
{% endblock %} |
|
10 | ||
11 |
{% block extra-actions %} |
|
12 |
<a href="{% url 'chrono-manager-agenda-month-redirect-view' pk=agenda.pk %}">{% trans 'Month view' %}</a> |
|
13 |
{% endblock %} |
|
14 | ||
15 |
{% block content %} |
|
16 |
<div class="section"> |
|
17 |
<h3>{% trans "Open events" %}</h3> |
|
18 |
<div> |
|
19 |
{% if open_events %} |
|
20 |
{% for event in open_events %} |
|
21 |
{% ifchanged event.start_datetime.month event.start_datetime.year %} |
|
22 |
<h4>{{ event.start_datetime|date:'YEAR_MONTH_FORMAT'|capfirst }}</h4> |
|
23 |
<ul class="objects-list single-links"> |
|
24 |
{% endifchanged %} |
|
25 |
{% include 'chrono/manager_agenda_event_fragment.html' %} |
|
26 |
{% if forloop.last %}</ul>{% endif %} |
|
27 |
{% endfor %} |
|
28 |
{% else %} |
|
29 |
<div class="big-msg-info"> |
|
30 |
{% blocktrans %} |
|
31 |
This agenda doesn't have any open event configured. |
|
32 |
{% endblocktrans %} |
|
33 |
</div> |
|
34 |
{% endif %} |
|
35 |
</div> |
|
36 |
</div> |
|
37 |
{% endblock %} |
chrono/manager/templates/chrono/manager_agenda_view.html | ||
---|---|---|
9 | 9 |
<h2>{{ object.label }}</h2> |
10 | 10 |
{% if user_can_manage %} |
11 | 11 |
<span class="actions"> |
12 |
<a href="{% url 'chrono-manager-agenda-settings' pk=object.id %}">{% trans 'Settings' %}</a> |
|
12 |
<a href="{% url 'chrono-manager-agenda-settings' pk=object.id %}">{% trans 'Settings' %}</a> |
|
13 |
{% block extra-actions %}{% endblock %} |
|
13 | 14 |
</span> |
14 | 15 |
{% endif %} |
15 | 16 |
{% endblock %} |
chrono/manager/templates/chrono/manager_events_agenda_month_view.html | ||
---|---|---|
1 | 1 |
{% extends "chrono/manager_agenda_month_view.html" %} |
2 | 2 |
{% load i18n %} |
3 | 3 | |
4 |
{% block extra-actions %} |
|
5 |
<a href="{% url 'chrono-manager-agenda-open-events-view' pk=agenda.pk %}">{% trans 'Open events' %}</a> |
|
6 |
{% endblock %} |
|
7 | ||
4 | 8 |
{% block content %} |
5 | 9 |
<div class="section"> |
6 | 10 |
<h3>{% trans "Events" %}</h3> |
chrono/manager/urls.py | ||
---|---|---|
53 | 53 |
views.agenda_day_view, |
54 | 54 |
name='chrono-manager-agenda-day-view', |
55 | 55 |
), |
56 |
url( |
|
57 |
r'^agendas/(?P<pk>\d+)/events/open/$', |
|
58 |
views.agenda_open_events_view, |
|
59 |
name='chrono-manager-agenda-open-events-view', |
|
60 |
), |
|
56 | 61 |
url(r'^agendas/(?P<pk>\d+)/settings$', views.agenda_settings, name='chrono-manager-agenda-settings'), |
57 | 62 |
url(r'^agendas/(?P<pk>\d+)/edit$', views.agenda_edit, name='chrono-manager-agenda-edit'), |
58 | 63 |
url(r'^agendas/(?P<pk>\d+)/delete$', views.agenda_delete, name='chrono-manager-agenda-delete'), |
chrono/manager/views.py | ||
---|---|---|
1019 | 1019 |
agenda_monthly_view = AgendaMonthView.as_view() |
1020 | 1020 | |
1021 | 1021 | |
1022 |
class AgendaOpenEventsView(ManagedAgendaMixin, DetailView): |
|
1023 |
model = Agenda |
|
1024 |
template_name = 'chrono/manager_agenda_open_events.html' |
|
1025 | ||
1026 |
def set_agenda(self, **kwargs): |
|
1027 |
self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events') |
|
1028 | ||
1029 |
def get_object(self, **kwargs): |
|
1030 |
return self.agenda |
|
1031 | ||
1032 |
def get_context_data(self, **kwargs): |
|
1033 |
context = super().get_context_data(**kwargs) |
|
1034 |
context['user_can_manage'] = self.agenda.can_be_managed(self.request.user) |
|
1035 |
context['open_events'] = Event.annotate_queryset(self.agenda.get_open_events()) |
|
1036 |
return context |
|
1037 | ||
1038 | ||
1039 |
agenda_open_events_view = AgendaOpenEventsView.as_view() |
|
1040 | ||
1041 | ||
1022 | 1042 |
class ManagedAgendaSubobjectMixin(object): |
1023 | 1043 |
agenda = None |
1024 | 1044 |
tests/test_api.py | ||
---|---|---|
2419 | 2419 |
agenda.minimal_booking_delay = 10 |
2420 | 2420 |
agenda.save() |
2421 | 2421 |
resp = app.get('/api/agenda/%s/' % agenda.slug) |
2422 |
assert list(agenda.get_opened_events()) == [event2, event3]
|
|
2422 |
assert list(agenda.get_open_events()) == [event2, event3] |
|
2423 | 2423 |
assert resp.json['data']['opened_events_available'] is False |
2424 | 2424 | |
2425 | 2425 |
# event3 is not full but too late |
... | ... | |
2427 | 2427 |
agenda.maximal_booking_delay = 12 |
2428 | 2428 |
agenda.save() |
2429 | 2429 |
resp = app.get('/api/agenda/%s/' % agenda.slug) |
2430 |
assert list(agenda.get_opened_events()) == [event2]
|
|
2430 |
assert list(agenda.get_open_events()) == [event2] |
|
2431 | 2431 |
assert resp.json['data']['opened_events_available'] is False |
2432 | 2432 | |
2433 | 2433 |
# events are not full but not published |
2434 | 2434 |
Event.objects.update(full=False) |
2435 | 2435 |
agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20)) |
2436 | 2436 |
resp = app.get('/api/agenda/%s/' % agenda.slug) |
2437 |
assert list(agenda.get_opened_events()) == []
|
|
2437 |
assert list(agenda.get_open_events()) == [] |
|
2438 | 2438 |
assert resp.json['data']['opened_events_available'] is False |
2439 | 2439 | |
2440 | 2440 |
# unknown |
tests/test_manager.py | ||
---|---|---|
2499 | 2499 |
assert "This month doesn't have any event configured." in resp.text |
2500 | 2500 | |
2501 | 2501 | |
2502 |
def test_agenda_open_events_view(app, admin_user): |
|
2503 |
agenda = Agenda.objects.create( |
|
2504 |
label='Events', kind='events', minimal_booking_delay=2, maximal_booking_delay=5 |
|
2505 |
) |
|
2506 |
today = datetime.date.today() |
|
2507 | ||
2508 |
login(app) |
|
2509 |
resp = app.get('/manage/agendas/%s/%s/%s/' % (agenda.pk, today.year, today.month)) |
|
2510 |
assert 'Open events' in resp.text |
|
2511 | ||
2512 |
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk) |
|
2513 |
assert 'Month view' in resp.text |
|
2514 |
assert "This agenda doesn't have any open event configured." in resp.text |
|
2515 | ||
2516 |
# create some events |
|
2517 |
# past event |
|
2518 |
Event.objects.create( |
|
2519 |
agenda=agenda, label='event A', start_datetime=now() - datetime.timedelta(days=1), places=42 |
|
2520 |
) |
|
2521 |
# too late |
|
2522 |
Event.objects.create( |
|
2523 |
agenda=agenda, label='event B', start_datetime=now() + datetime.timedelta(days=1), places=42 |
|
2524 |
) |
|
2525 |
# too soon |
|
2526 |
Event.objects.create( |
|
2527 |
agenda=agenda, label='event C', start_datetime=now() + datetime.timedelta(days=6), places=42 |
|
2528 |
) |
|
2529 |
# in range |
|
2530 |
Event.objects.create( |
|
2531 |
agenda=agenda, label='event D', start_datetime=now() + datetime.timedelta(days=3), places=42 |
|
2532 |
) |
|
2533 |
# publication date in future |
|
2534 |
Event.objects.create( |
|
2535 |
agenda=agenda, |
|
2536 |
label='event E', |
|
2537 |
start_datetime=now() + datetime.timedelta(days=3), |
|
2538 |
publication_date=today + datetime.timedelta(days=1), |
|
2539 |
places=42, |
|
2540 |
) |
|
2541 |
# publication date in past |
|
2542 |
Event.objects.create( |
|
2543 |
agenda=agenda, |
|
2544 |
label='event F', |
|
2545 |
start_datetime=now() + datetime.timedelta(days=3), |
|
2546 |
publication_date=today - datetime.timedelta(days=1), |
|
2547 |
places=42, |
|
2548 |
) |
|
2549 |
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk) |
|
2550 |
assert 'event A' not in resp.text |
|
2551 |
assert 'event B' not in resp.text |
|
2552 |
assert 'event C' not in resp.text |
|
2553 |
assert 'event D' in resp.text |
|
2554 |
assert 'event E' not in resp.text |
|
2555 |
assert 'event F' in resp.text |
|
2556 | ||
2557 |
# wrong kind |
|
2558 |
agenda.kind = 'meetings' |
|
2559 |
agenda.save() |
|
2560 |
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk, status=404) |
|
2561 |
agenda.kind = 'virtual' |
|
2562 |
agenda.save() |
|
2563 |
resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk, status=404) |
|
2564 | ||
2565 | ||
2502 | 2566 |
def test_agenda_month_view(app, admin_user, manager_user, api_user): |
2503 | 2567 |
agenda = Agenda.objects.create(label='Passeports', kind='meetings') |
2504 | 2568 |
desk = Desk.objects.create(agenda=agenda, label='Desk A') |
2505 |
- |