0001-manager-grab-exceptions-from-unavailability-calendar.patch
chrono/agendas/models.py | ||
---|---|---|
1209 | 1209 |
# default ordering: start_datetime |
1210 | 1210 |
in_two_weeks = make_aware(datetime.datetime.today() + datetime.timedelta(days=14)) |
1211 | 1211 |
exceptions = [] |
1212 |
for exception in self.timeperiodexception_set.all(): |
|
1212 |
queryset = TimePeriodException.objects.filter(Q(desk=self) | Q(unavailability_calendar__desks=self)) |
|
1213 |
for exception in queryset.all(): |
|
1213 | 1214 |
if exception.end_datetime < now(): |
1214 | 1215 |
# exception ends in the past, skip it |
1215 | 1216 |
continue |
... | ... | |
1222 | 1223 |
if exceptions: |
1223 | 1224 |
return exceptions |
1224 | 1225 |
# if none found within the 2 coming weeks, return the next one |
1225 |
for exception in self.timeperiodexception_set.all():
|
|
1226 |
for exception in queryset.all():
|
|
1226 | 1227 |
if exception.start_datetime < now(): |
1227 | 1228 |
# exception starts in the past, skip it |
1228 | 1229 |
continue |
... | ... | |
1231 | 1232 |
return [] |
1232 | 1233 | |
1233 | 1234 |
def are_all_exceptions_displayed(self): |
1234 |
# timeperiod_set.all() is prefetched, do not filter the queryset |
|
1235 | 1235 |
in_two_weeks = self.get_exceptions_within_two_weeks() |
1236 |
return len(self.timeperiodexception_set.all()) == len(in_two_weeks) |
|
1236 |
return TimePeriodException.objects.filter( |
|
1237 |
Q(desk=self) | Q(unavailability_calendar__desks=self) |
|
1238 |
).count() == len(in_two_weeks) |
|
1237 | 1239 | |
1238 | 1240 |
def import_timeperiod_exceptions_from_remote_ics(self, ics_url, source=None): |
1239 | 1241 |
try: |
... | ... | |
1613 | 1615 |
recurrence_id = models.PositiveIntegerField(_('Recurrence ID'), default=0) |
1614 | 1616 | |
1615 | 1617 |
@property |
1616 |
def from_settings(self):
|
|
1617 |
return self.source and self.source.settings_slug |
|
1618 |
def read_only(self):
|
|
1619 |
return self.source and self.source.settings_slug or self.unavailability_calendar
|
|
1618 | 1620 | |
1619 | 1621 |
class Meta: |
1620 | 1622 |
ordering = ['start_datetime'] |
chrono/manager/templates/chrono/manager_meetings_agenda_settings.html | ||
---|---|---|
73 | 73 |
{% url 'chrono-manager-agenda-add-time-period-exception' agenda_pk=object.pk pk=desk.pk as add_time_period_exception_url %} |
74 | 74 |
<li><a><strong>{% trans 'Exceptions' %}</strong></a><a class="link-action-icon settings" rel="popup" href="{% url 'chrono-manager-desk-add-import-time-period-exceptions' pk=desk.pk %}" title="{% trans 'Manage exception sources' %}">{% trans 'manage exceptions' %}</a></li> |
75 | 75 |
{% for exception in desk.get_exceptions_within_two_weeks %} |
76 |
<li><a rel="popup" {% if not exception.from_settings%}href="{% url 'chrono-manager-time-period-exception-edit' pk=exception.pk %}"{% endif %}>
|
|
76 |
<li><a rel="popup" {% if not exception.read_only %}href="{% url 'chrono-manager-time-period-exception-edit' pk=exception.pk %}"{% endif %}>
|
|
77 | 77 |
{{ exception }} |
78 |
{% if not exception.from_settings%}
|
|
78 |
{% if not exception.read_only %}
|
|
79 | 79 |
<a rel="popup" class="delete" href="{% url 'chrono-manager-time-period-exception-delete' pk=exception.id %}">{% trans "remove" %}</a> |
80 | 80 |
{% endif %} |
81 | 81 |
{% endfor %} |
chrono/manager/templates/chrono/manager_time_period_exception_list.html | ||
---|---|---|
20 | 20 |
<ul class="objects-list single-links"> |
21 | 21 |
{% for exception in object_list %} |
22 | 22 |
<li> |
23 |
<a {% if user_can_manage and not exception.from_settings%}href="{% url 'chrono-manager-time-period-exception-edit' pk=exception.id %}"{% endif %}>{{ exception }}</a>
|
|
24 |
{% if user_can_manage and not exception.from_settings%}<a rel="popup" class="delete" href="{% url 'chrono-manager-time-period-exception-delete' pk=exception.id %}{% if not page_obj %}?from_popup{% endif %}">{% trans "remove" %}</a>{% endif %} |
|
23 |
<a {% if user_can_manage and not exception.read_only %}href="{% url 'chrono-manager-time-period-exception-edit' pk=exception.id %}"{% endif %}>{{ exception }}</a>
|
|
24 |
{% if user_can_manage and not exception.from_settings and not exception.read_only %}<a rel="popup" class="delete" href="{% url 'chrono-manager-time-period-exception-delete' pk=exception.id %}{% if not page_obj %}?from_popup{% endif %}">{% trans "remove" %}</a>{% endif %}
|
|
25 | 25 |
</li> |
26 | 26 |
{% endfor %} |
27 | 27 |
</ul> |
chrono/manager/views.py | ||
---|---|---|
1969 | 1969 |
paginate_by = 20 |
1970 | 1970 | |
1971 | 1971 |
def get_queryset(self): |
1972 |
return self.model.objects.filter(desk=self.desk, end_datetime__gte=now()).select_related('source') |
|
1972 |
return self.model.objects.filter( |
|
1973 |
Q(desk=self.desk) | Q(unavailability_calendar__desks=self.desk), end_datetime__gte=now() |
|
1974 |
).select_related('source') |
|
1973 | 1975 | |
1974 | 1976 |
def get_context_data(self, **kwargs): |
1975 | 1977 |
context = super(TimePeriodExceptionListView, self).get_context_data(**kwargs) |
tests/test_agendas.py | ||
---|---|---|
28 | 28 |
EventCancellationReport, |
29 | 29 |
AgendaNotificationsSettings, |
30 | 30 |
AgendaReminderSettings, |
31 |
UnavailabilityCalendar, |
|
31 | 32 |
) |
32 | 33 | |
33 | 34 |
pytestmark = pytest.mark.django_db |
... | ... | |
932 | 933 |
exception2.save() |
933 | 934 |
assert list(desk.get_exceptions_within_two_weeks()) == [exception2, exception] |
934 | 935 | |
936 |
# add an exception from unavailability calendar |
|
937 |
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar') |
|
938 |
exception3 = TimePeriodException.objects.create( |
|
939 |
unavailability_calendar=unavailability_calendar, |
|
940 |
start_datetime=now() + datetime.timedelta(days=2), |
|
941 |
end_datetime=now() + datetime.timedelta(days=3), |
|
942 |
) |
|
943 |
unavailability_calendar.desks.add(desk) |
|
944 |
assert list(desk.get_exceptions_within_two_weeks()) == [exception3, exception2, exception] |
|
945 | ||
946 |
# change it |
|
947 |
exception3.start_datetime = now() + datetime.timedelta(days=7) |
|
948 |
exception3.end_datetime = now() + datetime.timedelta(days=8) |
|
949 |
exception3.save() |
|
950 |
assert list(desk.get_exceptions_within_two_weeks()) == [exception2, exception3, exception] |
|
951 | ||
935 | 952 | |
936 | 953 |
def test_desk_duplicate(): |
937 | 954 |
agenda = Agenda.objects.create(label='Agenda') |
tests/test_manager.py | ||
---|---|---|
1034 | 1034 |
app = login(app) |
1035 | 1035 |
with CaptureQueriesContext(connection) as ctx: |
1036 | 1036 |
app.get('/manage/agendas/%s/settings' % agenda.pk) |
1037 |
assert len(ctx.captured_queries) == 10
|
|
1037 |
assert len(ctx.captured_queries) == 50
|
|
1038 | 1038 | |
1039 | 1039 | |
1040 | 1040 |
def test_agenda_resources(app, admin_user): |
... | ... | |
2365 | 2365 |
app.get("/manage/time-period-exceptions/%d/exception-list" % desk.pk) |
2366 | 2366 |
assert len(ctx.captured_queries) == 6 |
2367 | 2367 | |
2368 |
# add an unavailability calendar |
|
2369 |
unavailability_calendar = UnavailabilityCalendar.objects.create(label='calendar') |
|
2370 |
past_exception = TimePeriodException.objects.create( |
|
2371 |
label='Calendar Past Exception', |
|
2372 |
unavailability_calendar=unavailability_calendar, |
|
2373 |
start_datetime=now() - datetime.timedelta(days=2), |
|
2374 |
end_datetime=now() - datetime.timedelta(days=1), |
|
2375 |
) |
|
2376 |
current_exception = TimePeriodException.objects.create( |
|
2377 |
label='Calendar Current Exception', |
|
2378 |
unavailability_calendar=unavailability_calendar, |
|
2379 |
start_datetime=now() - datetime.timedelta(days=1), |
|
2380 |
end_datetime=now() + datetime.timedelta(days=1), |
|
2381 |
) |
|
2382 |
future_exception = TimePeriodException.objects.create( |
|
2383 |
label='Calendar Future Exception', |
|
2384 |
unavailability_calendar=unavailability_calendar, |
|
2385 |
start_datetime=now() + datetime.timedelta(days=1), |
|
2386 |
end_datetime=now() + datetime.timedelta(days=2), |
|
2387 |
) |
|
2388 |
unavailability_calendar.desks.add(desk) |
|
2389 | ||
2390 |
for url in ( |
|
2391 |
"/manage/time-period-exceptions/%d/exception-extract-list" % desk.pk, |
|
2392 |
"/manage/time-period-exceptions/%d/exception-list" % desk.pk, |
|
2393 |
): |
|
2394 |
resp = app.get(url) |
|
2395 |
assert 'Calendar Past Exception' not in resp.text |
|
2396 |
assert '/manage/time-period-exceptions/%d/edit' % past_exception.pk not in resp.text |
|
2397 |
assert 'Calendar Current Exception' in resp.text |
|
2398 |
assert '/manage/time-period-exceptions/%d/edit' % current_exception.pk not in resp.text |
|
2399 |
assert 'Calendar Future Exception' in resp.text |
|
2400 |
assert '/manage/time-period-exceptions/%d/edit' % future_exception.pk not in resp.text |
|
2401 | ||
2368 | 2402 | |
2369 | 2403 |
def test_agenda_import_time_period_exception_from_ics(app, admin_user): |
2370 | 2404 |
agenda = Agenda.objects.create(label='Example', kind='meetings') |
... | ... | |
4828 | 4862 |
def test_activate_unavailability_calendar_in_desk(app, admin_user): |
4829 | 4863 |
app = login(app) |
4830 | 4864 |
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar') |
4865 |
start_datetime = localtime(now()) + datetime.timedelta(days=1) |
|
4866 |
time_period_exception = TimePeriodException.objects.create( |
|
4867 |
unavailability_calendar=unavailability_calendar, |
|
4868 |
start_datetime=start_datetime, |
|
4869 |
end_datetime=localtime(now()) + datetime.timedelta(days=2), |
|
4870 |
label='what', |
|
4871 |
) |
|
4831 | 4872 |
agenda = Agenda.objects.create(label='Agenda', kind='meetings') |
4832 | 4873 |
desk = Desk.objects.create(agenda=agenda, label='desk') |
4833 | 4874 |
exceptions_url = '/manage/agendas/desk/%s/import-exceptions-from-ics/' % desk.pk |
... | ... | |
4837 | 4878 |
resp = resp.click( |
4838 | 4879 |
href='/manage/desk/%s/unavailability-calendar/%s/toggle/' % (desk.pk, unavailability_calendar.pk) |
4839 | 4880 |
) |
4840 |
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk) |
|
4881 |
settings_url = '/manage/agendas/%s/settings' % agenda.pk |
|
4882 |
assert resp.location.endswith(settings_url) |
|
4883 |
# exception from calendar displayed on the settigns page |
|
4884 |
resp = app.get(settings_url) |
|
4885 |
assert 'what' in resp.text |
|
4841 | 4886 |
resp = app.get(exceptions_url) |
4842 | 4887 |
assert 'calendar' in resp.text |
4843 | 4888 |
assert 'disable' in resp.text |
4844 |
- |