Projet

Général

Profil

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

Lauréline Guérin, 12 décembre 2019 10:57

Télécharger (10,9 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
28 28
from django.utils.translation import ugettext_lazy as _
29 29

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

  
33 33
from . import widgets
34 34

  
......
266 266
            help_text=_('URL to remote calendar which will be synchronised hourly.'))
267 267

  
268 268

  
269
class TimePeriodExceptionSourceRefreshForm(forms.ModelForm):
270
    class Meta:
271
        model = TimePeriodExceptionSource
272
        fields = []
273

  
274
    ics_file = forms.FileField(
275
        label=_('ICS File'), required=False,
276
        help_text=_('ICS file containing events which will be considered as exceptions.'))
277

  
278
    def __init__(self, *args, **kwargs):
279
        super(TimePeriodExceptionSourceRefreshForm, self).__init__(*args, **kwargs)
280
        if self.instance.ics_filename is None:
281
            del self.fields['ics_file']
282

  
283

  
269 284
class AgendasImportForm(forms.Form):
270 285
    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

  
......
843 843
time_period_exception_source_delete = TimePeriodExceptionSourceDeleteView.as_view()
844 844

  
845 845

  
846
class TimePeriodExceptionSourceRefreshView(ManagedDeskSubobjectMixin, UpdateView):
847
    model = TimePeriodExceptionSource
848
    form_class = TimePeriodExceptionSourceRefreshForm
849
    template_name = 'chrono/manager_refresh_exceptions.html'
850

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

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

  
873

  
874
time_period_exception_source_refresh = TimePeriodExceptionSourceRefreshView.as_view()
875

  
876

  
846 877
def menu_json(request):
847 878
    label = _('Agendas')
848 879
    json_str = json.dumps([{'label': force_text(label),
tests/test_manager.py
1455 1455
    assert TimePeriodExceptionSource.objects.filter(pk=source1.pk).exists() is False
1456 1456

  
1457 1457

  
1458
@mock.patch('chrono.agendas.models.requests.get')
1459
def test_meetings_agenda_refresh_time_period_exception_source(mocked_get, app, admin_user):
1460
    agenda = Agenda.objects.create(label='Foo bar', kind='meetings')
1461
    desk = Desk.objects.create(agenda=agenda, label='Desk A')
1462
    MeetingType(agenda=agenda, label='Blah').save()
1463
    TimePeriod.objects.create(weekday=1, desk=desk,
1464
                              start_time=datetime.time(10, 0), end_time=datetime.time(12, 0))
1465
    ics_file_content = b"""BEGIN:VCALENDAR
1466
VERSION:2.0
1467
PRODID:-//foo.bar//EN
1468
BEGIN:VEVENT
1469
DTSTART:20180101
1470
DTEND:20180101
1471
SUMMARY:New Year's Eve
1472
RRULE:FREQ=YEARLY
1473
END:VEVENT
1474
END:VCALENDAR"""
1475

  
1476
    login(app)
1477
    # import a source from a file
1478
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1479
    resp = resp.click('Settings')
1480
    resp = resp.click('upload')
1481
    resp.form['ics_file'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
1482
    resp = resp.form.submit(status=302).follow()
1483
    assert TimePeriodException.objects.filter(desk=desk).count() == 2
1484
    source1 = TimePeriodExceptionSource.objects.latest('pk')
1485
    assert source1.timeperiodexception_set.count() == 2
1486
    exceptions1 = list(source1.timeperiodexception_set.order_by('pk'))
1487

  
1488
    # refresh the source
1489
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1490
    resp = resp.click('Settings')
1491
    resp = resp.click('upload')
1492
    resp = resp.click(href='/manage/time-period-exceptions-source/%d/refresh' % source1.pk)
1493
    resp.form['ics_file'] = Upload('exceptions.ics', ics_file_content, 'text/calendar')
1494
    resp = resp.form.submit().follow()
1495
    assert TimePeriodException.objects.count() == 2
1496
    assert source1.timeperiodexception_set.count() == 2
1497
    new_exceptions1 = list(source1.timeperiodexception_set.order_by('pk'))
1498
    assert exceptions1[0].pk != new_exceptions1[0].pk
1499
    assert exceptions1[1].pk != new_exceptions1[1].pk
1500

  
1501
    ics_url_content = """BEGIN:VCALENDAR
1502
VERSION:2.0
1503
PRODID:-//foo.bar//EN
1504
BEGIN:VEVENT
1505
UID:random-event-id
1506
DTSTART:20180101
1507
DTEND:20180101
1508
SUMMARY:New Year's Eve
1509
END:VEVENT
1510
END:VCALENDAR"""
1511

  
1512
    # import a source from an url
1513
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1514
    resp = resp.click('Settings')
1515
    resp = resp.click('upload')
1516
    resp.form['ics_url'] = 'http://example.com/foo.ics'
1517
    mocked_response = mock.Mock()
1518
    mocked_response.text = ics_url_content
1519
    mocked_get.return_value = mocked_response
1520
    resp = resp.form.submit(status=302).follow()
1521
    assert TimePeriodException.objects.filter(desk=desk).count() == 3
1522
    source2 = TimePeriodExceptionSource.objects.latest('pk')
1523
    assert source2.timeperiodexception_set.count() == 1
1524
    exceptions2 = list(source2.timeperiodexception_set.order_by('pk'))
1525

  
1526
    # refresh the source
1527
    resp = app.get('/manage/agendas/%d/' % agenda.pk).follow()
1528
    resp = resp.click('Settings')
1529
    resp = resp.click('upload')
1530
    resp = resp.click(href='/manage/time-period-exceptions-source/%d/refresh' % source2.pk)
1531
    mocked_response = mock.Mock()
1532
    mocked_response.text = ics_url_content
1533
    mocked_get.return_value = mocked_response
1534
    resp = resp.form.submit(status=302).follow()
1535
    assert TimePeriodException.objects.count() == 3
1536
    assert source2.timeperiodexception_set.count() == 1
1537
    new_exceptions2 = list(source2.timeperiodexception_set.order_by('pk'))
1538
    assert exceptions2[0].pk != new_exceptions2[0].pk
1539

  
1540

  
1458 1541
def test_agenda_day_view(app, admin_user, manager_user, api_user):
1459 1542
    agenda = Agenda.objects.create(label='New Example', kind='meetings')
1460 1543
    desk = Desk.objects.create(agenda=agenda, label='New Desk')
1461
-