Projet

Général

Profil

0002-manager-add-excluded-timeperiods-management-40058.patch

Emmanuel Cazenave, 26 février 2020 18:30

Télécharger (11,9 ko)

Voir les différences:

Subject: [PATCH 2/3] manager: add excluded timeperiods management (#40058)

 chrono/manager/forms.py                       |  9 +++
 .../chrono/manager_time_period_form.html      |  2 +-
 .../manager_virtual_agenda_settings.html      | 16 +++++
 chrono/manager/urls.py                        |  5 ++
 chrono/manager/views.py                       | 69 ++++++++++++++++---
 tests/test_manager.py                         | 65 ++++++++++++++++-
 6 files changed, 154 insertions(+), 12 deletions(-)
chrono/manager/forms.py
138 138
            'start_time': widgets.TimeWidget(),
139 139
            'end_time': widgets.TimeWidget(),
140 140
            'desk': forms.HiddenInput(),
141
            'agenda': forms.HiddenInput(),
141 142
        }
142 143
        exclude = []
143 144

  
145
    def __init__(self, *args, **kwargs):
146
        has_desk = kwargs.pop('has_desk')
147
        super(TimePeriodForm, self).__init__(*args, **kwargs)
148
        if has_desk:
149
            del self.fields['agenda']
150
        else:
151
            del self.fields['desk']
152

  
144 153
    def clean_end_time(self):
145 154
        if self.cleaned_data['end_time'] <= self.cleaned_data['start_time']:
146 155
            raise ValidationError(_('End time must come after start time.'))
chrono/manager/templates/chrono/manager_time_period_form.html
33 33
  {{ form.as_p }}
34 34
  <div class="buttons">
35 35
    <button class="submit-button">{% trans "Save" %}</button>
36
    <a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=desk.agenda.id %}">{% trans 'Cancel' %}</a>
36
    <a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=agenda.id %}">{% trans 'Cancel' %}</a>
37 37
  </div>
38 38
</form>
39 39
{% endblock %}
chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
2 2
{% load i18n %}
3 3

  
4 4
{% block agenda-extra-management-actions %}
5
  <a rel="popup" href="{% url 'chrono-manager-virtual-agenda-add-time-period' pk=object.id %}">{% trans 'Add Excluded Period' %}</a>
5 6
  <a rel="popup" href="{% url 'chrono-manager-agenda-add-virtual-member' pk=object.id %}">{% trans 'Include Agenda' %}</a>
6 7
{% endblock %}
7 8

  
......
60 61
</div>
61 62
{% endif %}
62 63

  
64
{% if agenda.excluded_timeperiods.count %}
65
<div class="section">
66
<h3>{% trans 'Excluded Periods' %}</h3>
67
<div>
68
  <ul class="objects-list single-links">
69
    {% for time_period in agenda.excluded_timeperiods.all %}
70
    <li><a rel="popup" href="{% url 'chrono-manager-time-period-edit' pk=time_period.id %}">
71
        {{time_period.weekday_str}} / {{time_period.start_time}} → {{time_period.end_time}}</a>
72
      <a rel="popup" class="delete" href="{% url 'chrono-manager-time-period-delete' pk=time_period.id %}">{% trans "remove" %}</a>
73
    </li>
74
    {% endfor %}
75
  </ul>
76
</div>
77
</div>
78
{% endif %}
63 79

  
64 80
{% endblock %}
chrono/manager/urls.py
74 74
        views.agenda_add_time_period,
75 75
        name='chrono-manager-agenda-add-time-period',
76 76
    ),
77
    url(
78
        r'^agendas/(?P<pk>\d+)/add-time-period$',
79
        views.virtual_agenda_add_time_period,
80
        name='chrono-manager-virtual-agenda-add-time-period',
81
    ),
77 82
    url(r'^timeperiods/(?P<pk>\d+)/edit$', views.time_period_edit, name='chrono-manager-time-period-edit'),
78 83
    url(
79 84
        r'^timeperiods/(?P<pk>\d+)/delete$',
chrono/manager/views.py
644 644
        return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda.id})
645 645

  
646 646

  
647
class ManagedTimePeriodMixin(object):
648
    agenda = None
649

  
650
    def dispatch(self, request, *args, **kwargs):
651
        self.time_period = self.get_object()
652
        self.agenda = self.time_period.agenda
653
        self.has_desk = False
654
        if self.time_period.desk:
655
            self.agenda = self.time_period.desk.agenda
656
            self.has_desk = True
657

  
658
        if not self.agenda.can_be_managed(request.user):
659
            raise PermissionDenied()
660
        return super(ManagedTimePeriodMixin, self).dispatch(request, *args, **kwargs)
661

  
662
    def get_context_data(self, **kwargs):
663
        context = super(ManagedTimePeriodMixin, self).get_context_data(**kwargs)
664
        context['agenda'] = self.agenda
665
        return context
666

  
667
    def get_success_url(self):
668
        return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.agenda.id})
669

  
670

  
647 671
class AgendaSettings(ManagedAgendaMixin, DetailView):
648 672
    model = Agenda
649 673

  
......
846 870
meeting_type_delete = MeetingTypeDeleteView.as_view()
847 871

  
848 872

  
873
def process_time_period_add_form(form, desk=None, agenda=None):
874
    assert desk or agenda, "a time period requires a desk or a agenda"
875
    for weekday in form.cleaned_data.get('weekdays'):
876
        period = TimePeriod(
877
            weekday=weekday,
878
            start_time=form.cleaned_data['start_time'],
879
            end_time=form.cleaned_data['end_time'],
880
        )
881
        if desk:
882
            period.desk = desk
883
        elif agenda:
884
            period.agenda = agenda
885
        period.save()
886

  
887

  
849 888
class AgendaAddTimePeriodView(ManagedDeskMixin, FormView):
850 889
    template_name = 'chrono/manager_time_period_form.html'
851 890
    form_class = TimePeriodAddForm
852 891

  
853 892
    def form_valid(self, form):
854
        for weekday in form.cleaned_data.get('weekdays'):
855
            period = TimePeriod(
856
                weekday=weekday,
857
                start_time=form.cleaned_data['start_time'],
858
                end_time=form.cleaned_data['end_time'],
859
                desk=self.desk,
860
            )
861
            period.save()
893
        process_time_period_add_form(form, desk=self.desk)
862 894
        return super(AgendaAddTimePeriodView, self).form_valid(form)
863 895

  
864 896

  
865 897
agenda_add_time_period = AgendaAddTimePeriodView.as_view()
866 898

  
867 899

  
868
class TimePeriodEditView(ManagedDeskSubobjectMixin, UpdateView):
900
class VirtualAgendaAddTimePeriodView(ManagedAgendaMixin, FormView):
901
    template_name = 'chrono/manager_time_period_form.html'
902
    form_class = TimePeriodAddForm
903

  
904
    def form_valid(self, form):
905
        process_time_period_add_form(form, agenda=self.agenda)
906
        return super(VirtualAgendaAddTimePeriodView, self).form_valid(form)
907

  
908

  
909
virtual_agenda_add_time_period = VirtualAgendaAddTimePeriodView.as_view()
910

  
911

  
912
class TimePeriodEditView(ManagedTimePeriodMixin, UpdateView):
869 913
    template_name = 'chrono/manager_time_period_form.html'
870 914
    model = TimePeriod
871 915
    form_class = TimePeriodForm
872 916

  
917
    def get_form_kwargs(self):
918
        kwargs = super(TimePeriodEditView, self).get_form_kwargs()
919
        kwargs['has_desk'] = self.has_desk
920
        return kwargs
921

  
873 922

  
874 923
time_period_edit = TimePeriodEditView.as_view()
875 924

  
876 925

  
877
class TimePeriodDeleteView(ManagedDeskSubobjectMixin, DeleteView):
926
class TimePeriodDeleteView(ManagedTimePeriodMixin, DeleteView):
878 927
    template_name = 'chrono/manager_confirm_delete.html'
879 928
    model = TimePeriod
880 929

  
tests/test_manager.py
2195 2195
    assert 'Export' in resp.text
2196 2196
    assert 'Delete' in resp.text
2197 2197
    assert 'Included Agendas' in resp.text
2198
    assert 'Add Excluded Period' in resp.text
2198 2199
    assert "This virtual agenda doesn't include any agenda yet" in resp.text
2199 2200
    # No meeting types yet
2200 2201
    assert 'Meeting Types' not in resp.text
2202
    # No absence yet
2203
    assert 'Excluded Periods' not in resp.text
2201 2204

  
2202 2205

  
2203 2206
def test_virtual_agenda_settings(app, admin_user):
......
2208 2211
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2209 2212
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2210 2213
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2211

  
2214
    TimePeriod.objects.create(
2215
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2216
    )
2212 2217
    app = login(app)
2213 2218
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2214 2219
    assert "This virtual agenda doesn't include any agenda yet" not in resp.text
......
2221 2226
    assert 'mt' in resp.text
2222 2227
    assert '10' in resp.text
2223 2228

  
2229
    assert 'Excluded Periods' in resp.text
2230
    assert 'Monday' in resp.text
2231

  
2224 2232
    # Error message when incompatible meeting types
2225 2233
    mt2.delete()
2226 2234
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
......
2250 2258
    assert len(resp.form['real_agenda'].options) == 2
2251 2259

  
2252 2260

  
2261
def test_virtual_agenda_settings_add_excluded_period(app, admin_user):
2262
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2263

  
2264
    app = login(app)
2265
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2266
    resp = resp.click('Add Excluded Period')
2267

  
2268
    resp.form['weekdays-0'].checked = True
2269
    resp.form['start_time'] = '10:00'
2270
    resp.form['end_time'] = '17:00'
2271
    resp = resp.form.submit()
2272
    tp = TimePeriod.objects.get(agenda=agenda)
2273
    assert tp.weekday == 0
2274
    assert tp.start_time.hour == 10
2275
    assert tp.start_time.minute == 0
2276
    assert tp.end_time.hour == 17
2277
    assert tp.end_time.minute == 0
2278

  
2279
    resp = resp.follow()
2280
    assert u'Monday / 10 a.m. → 5 p.m.' in resp.text
2281

  
2282

  
2283
def test_virtual_agenda_settings_edit_excluded_period(app, admin_user):
2284
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2285
    tp = TimePeriod.objects.create(
2286
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2287
    )
2288
    app = login(app)
2289
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2290
    url = '/manage/timeperiods/%s/edit' % tp.pk
2291
    resp = resp.click(href=url)
2292
    resp.form['start_time'] = '11:00'
2293
    resp = resp.form.submit()
2294
    tp = TimePeriod.objects.get(agenda=agenda)
2295
    assert tp.weekday == 0
2296
    assert tp.start_time.hour == 11
2297
    assert tp.start_time.minute == 0
2298
    assert tp.end_time.hour == 18
2299
    assert tp.end_time.minute == 0
2300

  
2301

  
2302
def test_virtual_agenda_settings_delete_excluded_period(app, admin_user):
2303
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2304
    tp = TimePeriod.objects.create(
2305
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2306
    )
2307
    app = login(app)
2308
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2309
    url = '/manage/timeperiods/%s/delete' % tp.pk
2310
    resp = resp.click(href=url)
2311
    resp = resp.form.submit()
2312
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
2313
    assert TimePeriod.objects.count() == 0
2314

  
2315

  
2253 2316
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
2254 2317
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2255 2318
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2256
-