Projet

Général

Profil

0004-agendas-refresh-an-exception-source-29209.patch

Lauréline Guérin, 13 décembre 2019 14:46

Télécharger (10,8 ko)

Voir les différences:

Subject: [PATCH 4/4] agendas: refresh an exception source (#29209)

 chrono/manager/forms.py                       | 17 +++-
 .../chrono/manager_import_exceptions.html     |  2 +-
 .../chrono/manager_refresh_exceptions.html    | 28 +++++++
 chrono/manager/urls.py                        |  2 +
 chrono/manager/views.py                       | 33 +++++++-
 tests/test_manager.py                         | 83 +++++++++++++++++++
 6 files changed, 162 insertions(+), 3 deletions(-)
 create mode 100644 chrono/manager/templates/chrono/manager_refresh_exceptions.html
chrono/manager/forms.py
27 27
from django.utils.translation import ugettext_lazy as _
28 28

  
29 29
from chrono.agendas.models import (Agenda, Event, MeetingType, TimePeriod, Desk,
30
                                   TimePeriodException, WEEKDAYS_LIST)
30
                                   TimePeriodException, TimePeriodExceptionSource, WEEKDAYS_LIST)
31 31

  
32 32
from . import widgets
33 33

  
......
263 263
            raise forms.ValidationError(_('Please provide an ICS File or an URL.'))
264 264

  
265 265

  
266
class TimePeriodExceptionSourceRefreshForm(forms.ModelForm):
267
    ics_file = forms.FileField(
268
        label=_('ICS File'), required=False,
269
        help_text=_('ICS file containing events which will be considered as exceptions.'))
270

  
271
    class Meta:
272
        model = TimePeriodExceptionSource
273
        fields = []
274

  
275
    def __init__(self, *args, **kwargs):
276
        super().__init__(*args, **kwargs)
277
        if self.instance.ics_filename is None:
278
            del self.fields['ics_file']
279

  
280

  
266 281
class AgendasImportForm(forms.Form):
267 282
    agendas_json = forms.FileField(label=_('Agendas Export File'))
chrono/manager/templates/chrono/manager_import_exceptions.html
31 31
          </span>
32 32
        </td>
33 33
        <td>
34
          <a rel="popup" href="">
34
          <a rel="popup" href="{% url 'chrono-manager-time-period-exception-source-refresh' object.pk %}">
35 35
            {% if object.ics_filename %}{% trans "replace" %}{% else %}{% trans "refresh" %}{% endif %}
36 36
          </a>
37 37
        </td>
chrono/manager/templates/chrono/manager_refresh_exceptions.html
1
{% extends "chrono/manager_import_exceptions.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
<h2>{% if form.instance.ics_filename %}{% trans "Replace exceptions" %}{% else %}{% trans "Refresh exceptions" %}{% endif %}</h2>
6
{% endblock %}
7

  
8
{% block content %}
9
<form method="post" enctype="multipart/form-data">
10
  {% if form.instance.ics_filename %}
11
    <p class="notice">{% trans "To replace existing exceptions, please upload a new file." %}</p>
12
  {% else %}
13
  <p class="notice">
14
    {% trans 'Press the button "Refresh" to refresh existing exceptions from:' %}
15
    <br />
16
    <a href="{{ form.instance.ics_url }}">{{ form.instance.ics_url }}</a>
17
  </p>
18
  {% endif %}
19
  {% csrf_token %}
20
  {{ form.as_p }}
21
  <p>
22
  </p>
23
  <div class="buttons">
24
    <button>{% if form.instance.ics_filename %}{% trans "Replace" %}{% else %}{% trans "Refresh" %}{% endif %}</button>
25
    <a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=agenda.id %}">{% trans 'Cancel' %}</a>
26
  </div>
27
</form>
28
{% endblock %}
chrono/manager/urls.py
82 82
            name='chrono-manager-time-period-exception-list'),
83 83
        url(r'^time-period-exceptions-source/(?P<pk>\d+)/delete$', views.time_period_exception_source_delete,
84 84
            name='chrono-manager-time-period-exception-source-delete'),
85
        url(r'^time-period-exceptions-source/(?P<pk>\d+)/refresh$', views.time_period_exception_source_refresh,
86
            name='chrono-manager-time-period-exception-source-refresh'),
85 87

  
86 88
        url(r'^agendas/events.csv$', views.agenda_import_events_sample_csv,
87 89
            name='chrono-manager-sample-events-csv'),
chrono/manager/views.py
38 38

  
39 39
from .forms import (AgendaAddForm, AgendaEditForm, NewEventForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
40 40
                    TimePeriodForm, ImportEventsForm, NewDeskForm, DeskForm, TimePeriodExceptionForm,
41
                    ExceptionsImportForm, AgendasImportForm, TimePeriodAddForm)
41
                    ExceptionsImportForm, TimePeriodExceptionSourceRefreshForm, AgendasImportForm, TimePeriodAddForm)
42 42
from .utils import import_site
43 43

  
44 44

  
......
840 840
time_period_exception_source_delete = TimePeriodExceptionSourceDeleteView.as_view()
841 841

  
842 842

  
843
class TimePeriodExceptionSourceRefreshView(ManagedDeskSubobjectMixin, UpdateView):
844
    model = TimePeriodExceptionSource
845
    form_class = TimePeriodExceptionSourceRefreshForm
846
    template_name = 'chrono/manager_refresh_exceptions.html'
847

  
848
    def form_valid(self, form):
849
        exceptions = None
850
        try:
851
            if form.instance.ics_filename is not None:
852
                exceptions = form.instance.desk.import_timeperiod_exceptions_from_ics_file(
853
                    form.cleaned_data['ics_file'],
854
                    source=form.instance)
855
            else:
856
                exceptions = form.instance.desk.import_timeperiod_exceptions_from_remote_ics(
857
                    form.instance.ics_url,
858
                    source=form.instance)
859
        except ICSError as e:
860
            form.add_error(None, force_text(e))
861
            return self.form_invalid(form)
862

  
863
        if exceptions is not None:
864
            message = ungettext('An exception has been imported.',
865
                                '%(count)d exceptions have been imported.', exceptions)
866
            message = message % {'count': exceptions}
867
            messages.info(self.request, message)
868
        return super(TimePeriodExceptionSourceRefreshView, self).form_valid(form)
869

  
870

  
871
time_period_exception_source_refresh = TimePeriodExceptionSourceRefreshView.as_view()
872

  
873

  
843 874
def menu_json(request):
844 875
    label = _('Agendas')
845 876
    json_str = json.dumps([{'label': force_text(label),
tests/test_manager.py
1470 1470
    assert TimePeriodExceptionSource.objects.filter(pk=source1.pk).exists() is False
1471 1471

  
1472 1472

  
1473
@mock.patch('chrono.agendas.models.requests.get')
1474
def test_meetings_agenda_refresh_time_period_exception_source(mocked_get, app, admin_user):
1475
    agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
1476
    desk = Desk.objects.create(agenda=agenda, label='Desk A')
1477
    MeetingType(agenda=agenda, label='Blah').save()
1478
    TimePeriod.objects.create(
1479
        weekday=1, desk=desk, start_time=datetime.time(10, 0), end_time=datetime.time(12, 0)
1480
    )
1481
    ics_file_content = b"""BEGIN:VCALENDAR
1482
VERSION:2.0
1483
PRODID:-//foo.bar//EN
1484
BEGIN:VEVENT
1485
DTSTART:20180101
1486
DTEND:20180101
1487
SUMMARY:New Year's Eve
1488
RRULE:FREQ=YEARLY
1489
END:VEVENT
1490
END:VCALENDAR"""
1491

  
1492
    login(app)
1493
    # import a source from a file
1494
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1495
    resp = resp.click('Settings')
1496
    resp = resp.click('upload')
1497
    resp.form['ics_file'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
1498
    resp = resp.form.submit(status=302).follow()
1499
    assert TimePeriodException.objects.filter(desk=desk).count() == 2
1500
    source1 = TimePeriodExceptionSource.objects.latest('pk')
1501
    assert source1.timeperiodexception_set.count() == 2
1502
    exceptions1 = list(source1.timeperiodexception_set.order_by('pk'))
1503

  
1504
    # refresh the source
1505
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1506
    resp = resp.click('Settings')
1507
    resp = resp.click('upload')
1508
    resp = resp.click(href='/manage/time-period-exceptions-source/%d/refresh' % source1.pk)
1509
    resp.form['ics_file'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
1510
    resp = resp.form.submit().follow()
1511
    assert TimePeriodException.objects.count() == 2
1512
    assert source1.timeperiodexception_set.count() == 2
1513
    new_exceptions1 = list(source1.timeperiodexception_set.order_by('pk'))
1514
    assert exceptions1[0].pk != new_exceptions1[0].pk
1515
    assert exceptions1[1].pk != new_exceptions1[1].pk
1516

  
1517
    ics_url_content = """BEGIN:VCALENDAR
1518
VERSION:2.0
1519
PRODID:-//foo.bar//EN
1520
BEGIN:VEVENT
1521
DTSTART:20180101
1522
DTEND:20180101
1523
SUMMARY:New Year's Eve
1524
END:VEVENT
1525
END:VCALENDAR"""
1526

  
1527
    # import a source from an url
1528
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1529
    resp = resp.click('Settings')
1530
    resp = resp.click('upload')
1531
    resp.form['ics_url'] = 'http://example.com/foo.ics'
1532
    mocked_response = mock.Mock()
1533
    mocked_response.text = ics_url_content
1534
    mocked_get.return_value = mocked_response
1535
    resp = resp.form.submit(status=302).follow()
1536
    assert TimePeriodException.objects.filter(desk=desk).count() == 3
1537
    source2 = TimePeriodExceptionSource.objects.latest('pk')
1538
    assert source2.timeperiodexception_set.count() == 1
1539
    exceptions2 = list(source2.timeperiodexception_set.order_by('pk'))
1540

  
1541
    # refresh the source
1542
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1543
    resp = resp.click('Settings')
1544
    resp = resp.click('upload')
1545
    resp = resp.click(href='/manage/time-period-exceptions-source/%d/refresh' % source2.pk)
1546
    mocked_response = mock.Mock()
1547
    mocked_response.text = ics_url_content
1548
    mocked_get.return_value = mocked_response
1549
    resp = resp.form.submit(status=302).follow()
1550
    assert TimePeriodException.objects.count() == 3
1551
    assert source2.timeperiodexception_set.count() == 1
1552
    new_exceptions2 = list(source2.timeperiodexception_set.order_by('pk'))
1553
    assert exceptions2[0].pk != new_exceptions2[0].pk
1554

  
1555

  
1473 1556
def test_agenda_day_view(app, admin_user, manager_user, api_user):
1474 1557
    agenda = Agenda.objects.create(label='New Example', kind='meetings')
1475 1558
    desk = Desk.objects.create(agenda=agenda, label='New Desk')
1476
-