Projet

Général

Profil

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

Emmanuel Cazenave, 16 mars 2020 19:21

Télécharger (11,9 ko)

Voir les différences:

Subject: [PATCH 7/8] 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
150 150
            'start_time': widgets.TimeWidget(),
151 151
            'end_time': widgets.TimeWidget(),
152 152
            'desk': forms.HiddenInput(),
153
            'agenda': forms.HiddenInput(),
153 154
        }
154 155
        exclude = []
155 156

  
157
    def __init__(self, *args, **kwargs):
158
        has_desk = kwargs.pop('has_desk')
159
        super(TimePeriodForm, self).__init__(*args, **kwargs)
160
        if has_desk:
161
            del self.fields['agenda']
162
        else:
163
            del self.fields['desk']
164

  
156 165
    def clean_end_time(self):
157 166
        if self.cleaned_data['end_time'] <= self.cleaned_data['start_time']:
158 167
            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
676 676
        return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda.id})
677 677

  
678 678

  
679
class ManagedTimePeriodMixin(object):
680
    agenda = None
681

  
682
    def dispatch(self, request, *args, **kwargs):
683
        self.time_period = self.get_object()
684
        self.agenda = self.time_period.agenda
685
        self.has_desk = False
686
        if self.time_period.desk:
687
            self.agenda = self.time_period.desk.agenda
688
            self.has_desk = True
689

  
690
        if not self.agenda.can_be_managed(request.user):
691
            raise PermissionDenied()
692
        return super(ManagedTimePeriodMixin, self).dispatch(request, *args, **kwargs)
693

  
694
    def get_context_data(self, **kwargs):
695
        context = super(ManagedTimePeriodMixin, self).get_context_data(**kwargs)
696
        context['agenda'] = self.agenda
697
        return context
698

  
699
    def get_success_url(self):
700
        return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.agenda.id})
701

  
702

  
679 703
class AgendaSettings(ManagedAgendaMixin, DetailView):
680 704
    model = Agenda
681 705

  
......
884 908
meeting_type_delete = MeetingTypeDeleteView.as_view()
885 909

  
886 910

  
911
def process_time_period_add_form(form, desk=None, agenda=None):
912
    assert desk or agenda, "a time period requires a desk or a agenda"
913
    for weekday in form.cleaned_data.get('weekdays'):
914
        period = TimePeriod(
915
            weekday=weekday,
916
            start_time=form.cleaned_data['start_time'],
917
            end_time=form.cleaned_data['end_time'],
918
        )
919
        if desk:
920
            period.desk = desk
921
        elif agenda:
922
            period.agenda = agenda
923
        period.save()
924

  
925

  
887 926
class AgendaAddTimePeriodView(ManagedDeskMixin, FormView):
888 927
    template_name = 'chrono/manager_time_period_form.html'
889 928
    form_class = TimePeriodAddForm
890 929

  
891 930
    def form_valid(self, form):
892
        for weekday in form.cleaned_data.get('weekdays'):
893
            period = TimePeriod(
894
                weekday=weekday,
895
                start_time=form.cleaned_data['start_time'],
896
                end_time=form.cleaned_data['end_time'],
897
                desk=self.desk,
898
            )
899
            period.save()
931
        process_time_period_add_form(form, desk=self.desk)
900 932
        return super(AgendaAddTimePeriodView, self).form_valid(form)
901 933

  
902 934

  
903 935
agenda_add_time_period = AgendaAddTimePeriodView.as_view()
904 936

  
905 937

  
906
class TimePeriodEditView(ManagedDeskSubobjectMixin, UpdateView):
938
class VirtualAgendaAddTimePeriodView(ManagedAgendaMixin, FormView):
939
    template_name = 'chrono/manager_time_period_form.html'
940
    form_class = TimePeriodAddForm
941

  
942
    def form_valid(self, form):
943
        process_time_period_add_form(form, agenda=self.agenda)
944
        return super(VirtualAgendaAddTimePeriodView, self).form_valid(form)
945

  
946

  
947
virtual_agenda_add_time_period = VirtualAgendaAddTimePeriodView.as_view()
948

  
949

  
950
class TimePeriodEditView(ManagedTimePeriodMixin, UpdateView):
907 951
    template_name = 'chrono/manager_time_period_form.html'
908 952
    model = TimePeriod
909 953
    form_class = TimePeriodForm
910 954

  
955
    def get_form_kwargs(self):
956
        kwargs = super(TimePeriodEditView, self).get_form_kwargs()
957
        kwargs['has_desk'] = self.has_desk
958
        return kwargs
959

  
911 960

  
912 961
time_period_edit = TimePeriodEditView.as_view()
913 962

  
914 963

  
915
class TimePeriodDeleteView(ManagedDeskSubobjectMixin, DeleteView):
964
class TimePeriodDeleteView(ManagedTimePeriodMixin, DeleteView):
916 965
    template_name = 'chrono/manager_confirm_delete.html'
917 966
    model = TimePeriod
918 967

  
tests/test_manager.py
2252 2252
    assert 'Export' in resp.text
2253 2253
    assert 'Delete' in resp.text
2254 2254
    assert 'Included Agendas' in resp.text
2255
    assert 'Add Excluded Period' in resp.text
2255 2256
    assert "This virtual agenda doesn't include any agenda yet" in resp.text
2256 2257
    # No meeting types yet
2257 2258
    assert 'Meeting Types' not in resp.text
2259
    # No absence yet
2260
    assert 'Excluded Periods' not in resp.text
2258 2261

  
2259 2262

  
2260 2263
def test_virtual_agenda_settings(app, admin_user):
......
2265 2268
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2266 2269
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2267 2270
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2268

  
2271
    TimePeriod.objects.create(
2272
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2273
    )
2269 2274
    app = login(app)
2270 2275
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2271 2276
    assert "This virtual agenda doesn't include any agenda yet" not in resp.text
......
2278 2283
    assert 'mt' in resp.text
2279 2284
    assert '10' in resp.text
2280 2285

  
2286
    assert 'Excluded Periods' in resp.text
2287
    assert 'Monday' in resp.text
2288

  
2281 2289
    # Error message when incompatible meeting types
2282 2290
    mt2.delete()
2283 2291
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
......
2307 2315
    assert len(resp.form['real_agenda'].options) == 2
2308 2316

  
2309 2317

  
2318
def test_virtual_agenda_settings_add_excluded_period(app, admin_user):
2319
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2320

  
2321
    app = login(app)
2322
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2323
    resp = resp.click('Add Excluded Period')
2324

  
2325
    resp.form['weekdays-0'].checked = True
2326
    resp.form['start_time'] = '10:00'
2327
    resp.form['end_time'] = '17:00'
2328
    resp = resp.form.submit()
2329
    tp = TimePeriod.objects.get(agenda=agenda)
2330
    assert tp.weekday == 0
2331
    assert tp.start_time.hour == 10
2332
    assert tp.start_time.minute == 0
2333
    assert tp.end_time.hour == 17
2334
    assert tp.end_time.minute == 0
2335

  
2336
    resp = resp.follow()
2337
    assert u'Monday / 10 a.m. → 5 p.m.' in resp.text
2338

  
2339

  
2340
def test_virtual_agenda_settings_edit_excluded_period(app, admin_user):
2341
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2342
    tp = TimePeriod.objects.create(
2343
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2344
    )
2345
    app = login(app)
2346
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2347
    url = '/manage/timeperiods/%s/edit' % tp.pk
2348
    resp = resp.click(href=url)
2349
    resp.form['start_time'] = '11:00'
2350
    resp = resp.form.submit()
2351
    tp = TimePeriod.objects.get(agenda=agenda)
2352
    assert tp.weekday == 0
2353
    assert tp.start_time.hour == 11
2354
    assert tp.start_time.minute == 0
2355
    assert tp.end_time.hour == 18
2356
    assert tp.end_time.minute == 0
2357

  
2358

  
2359
def test_virtual_agenda_settings_delete_excluded_period(app, admin_user):
2360
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2361
    tp = TimePeriod.objects.create(
2362
        agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
2363
    )
2364
    app = login(app)
2365
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2366
    url = '/manage/timeperiods/%s/delete' % tp.pk
2367
    resp = resp.click(href=url)
2368
    resp = resp.form.submit()
2369
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
2370
    assert TimePeriod.objects.count() == 0
2371

  
2372

  
2310 2373
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
2311 2374
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2312 2375
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2313
-