Projet

Général

Profil

0001-manager-grab-exceptions-from-unavailability-calendar.patch

Emmanuel Cazenave, 17 novembre 2020 12:21

Télécharger (11,6 ko)

Voir les différences:

Subject: [PATCH] manager: grab exceptions from unavailability calendars
 (#47395)

 chrono/agendas/models.py                      | 14 +++---
 .../manager_meetings_agenda_settings.html     |  4 +-
 .../manager_time_period_exception_list.html   |  4 +-
 chrono/manager/views.py                       |  4 +-
 tests/test_agendas.py                         | 17 +++++++
 tests/test_manager.py                         | 49 ++++++++++++++++++-
 6 files changed, 79 insertions(+), 13 deletions(-)
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
-