diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py
index 43c84132..32fe2497 100644
--- a/chrono/manager/forms.py
+++ b/chrono/manager/forms.py
@@ -150,9 +150,18 @@ class TimePeriodForm(forms.ModelForm):
'start_time': widgets.TimeWidget(),
'end_time': widgets.TimeWidget(),
'desk': forms.HiddenInput(),
+ 'agenda': forms.HiddenInput(),
}
exclude = []
+ def __init__(self, *args, **kwargs):
+ has_desk = kwargs.pop('has_desk')
+ super(TimePeriodForm, self).__init__(*args, **kwargs)
+ if has_desk:
+ del self.fields['agenda']
+ else:
+ del self.fields['desk']
+
def clean_end_time(self):
if self.cleaned_data['end_time'] <= self.cleaned_data['start_time']:
raise ValidationError(_('End time must come after start time.'))
diff --git a/chrono/manager/templates/chrono/manager_time_period_form.html b/chrono/manager/templates/chrono/manager_time_period_form.html
index 7b809338..da2ba2b5 100644
--- a/chrono/manager/templates/chrono/manager_time_period_form.html
+++ b/chrono/manager/templates/chrono/manager_time_period_form.html
@@ -33,7 +33,7 @@
{{ form.as_p }}
{% endblock %}
diff --git a/chrono/manager/templates/chrono/manager_virtual_agenda_settings.html b/chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
index d0b594a6..8cd930a6 100644
--- a/chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
+++ b/chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
@@ -2,6 +2,7 @@
{% load i18n %}
{% block agenda-extra-management-actions %}
+ {% trans 'Add Excluded Period' %}
{% trans 'Include Agenda' %}
{% endblock %}
@@ -59,5 +60,20 @@
{% endif %}
+{% if agenda.excluded_timeperiods.count %}
+
+
{% trans 'Excluded Periods' %}
+
+
+{% endif %}
{% endblock %}
diff --git a/chrono/manager/urls.py b/chrono/manager/urls.py
index 382a5c19..56b2b9f0 100644
--- a/chrono/manager/urls.py
+++ b/chrono/manager/urls.py
@@ -74,6 +74,11 @@ urlpatterns = [
views.agenda_add_time_period,
name='chrono-manager-agenda-add-time-period',
),
+ url(
+ r'^agendas/(?P\d+)/add-time-period$',
+ views.virtual_agenda_add_time_period,
+ name='chrono-manager-virtual-agenda-add-time-period',
+ ),
url(r'^timeperiods/(?P\d+)/edit$', views.time_period_edit, name='chrono-manager-time-period-edit'),
url(
r'^timeperiods/(?P\d+)/delete$',
diff --git a/chrono/manager/views.py b/chrono/manager/views.py
index 9bd751fd..1be8a407 100644
--- a/chrono/manager/views.py
+++ b/chrono/manager/views.py
@@ -680,6 +680,30 @@ class ManagedDeskSubobjectMixin(object):
return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.desk.agenda.id})
+class ManagedTimePeriodMixin(object):
+ agenda = None
+
+ def dispatch(self, request, *args, **kwargs):
+ self.time_period = self.get_object()
+ self.agenda = self.time_period.agenda
+ self.has_desk = False
+ if self.time_period.desk:
+ self.agenda = self.time_period.desk.agenda
+ self.has_desk = True
+
+ if not self.agenda.can_be_managed(request.user):
+ raise PermissionDenied()
+ return super(ManagedTimePeriodMixin, self).dispatch(request, *args, **kwargs)
+
+ def get_context_data(self, **kwargs):
+ context = super(ManagedTimePeriodMixin, self).get_context_data(**kwargs)
+ context['agenda'] = self.agenda
+ return context
+
+ def get_success_url(self):
+ return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.agenda.id})
+
+
class AgendaSettings(ManagedAgendaMixin, DetailView):
model = Agenda
@@ -891,35 +915,60 @@ class MeetingTypeDeleteView(ManagedAgendaSubobjectMixin, DeleteView):
meeting_type_delete = MeetingTypeDeleteView.as_view()
+def process_time_period_add_form(form, desk=None, agenda=None):
+ assert desk or agenda, "a time period requires a desk or a agenda"
+ for weekday in form.cleaned_data.get('weekdays'):
+ period = TimePeriod(
+ weekday=weekday,
+ start_time=form.cleaned_data['start_time'],
+ end_time=form.cleaned_data['end_time'],
+ )
+ if desk:
+ period.desk = desk
+ elif agenda:
+ period.agenda = agenda
+ period.save()
+
+
class AgendaAddTimePeriodView(ManagedDeskMixin, FormView):
template_name = 'chrono/manager_time_period_form.html'
form_class = TimePeriodAddForm
def form_valid(self, form):
- for weekday in form.cleaned_data.get('weekdays'):
- period = TimePeriod(
- weekday=weekday,
- start_time=form.cleaned_data['start_time'],
- end_time=form.cleaned_data['end_time'],
- desk=self.desk,
- )
- period.save()
+ process_time_period_add_form(form, desk=self.desk)
return super(AgendaAddTimePeriodView, self).form_valid(form)
agenda_add_time_period = AgendaAddTimePeriodView.as_view()
-class TimePeriodEditView(ManagedDeskSubobjectMixin, UpdateView):
+class VirtualAgendaAddTimePeriodView(ManagedAgendaMixin, FormView):
+ template_name = 'chrono/manager_time_period_form.html'
+ form_class = TimePeriodAddForm
+
+ def form_valid(self, form):
+ process_time_period_add_form(form, agenda=self.agenda)
+ return super(VirtualAgendaAddTimePeriodView, self).form_valid(form)
+
+
+virtual_agenda_add_time_period = VirtualAgendaAddTimePeriodView.as_view()
+
+
+class TimePeriodEditView(ManagedTimePeriodMixin, UpdateView):
template_name = 'chrono/manager_time_period_form.html'
model = TimePeriod
form_class = TimePeriodForm
+ def get_form_kwargs(self):
+ kwargs = super(TimePeriodEditView, self).get_form_kwargs()
+ kwargs['has_desk'] = self.has_desk
+ return kwargs
+
time_period_edit = TimePeriodEditView.as_view()
-class TimePeriodDeleteView(ManagedDeskSubobjectMixin, DeleteView):
+class TimePeriodDeleteView(ManagedTimePeriodMixin, DeleteView):
template_name = 'chrono/manager_confirm_delete.html'
model = TimePeriod
diff --git a/tests/test_manager.py b/tests/test_manager.py
index b7bee820..73d1a1c4 100644
--- a/tests/test_manager.py
+++ b/tests/test_manager.py
@@ -2251,9 +2251,12 @@ def test_virtual_agenda_settings_empty(app, admin_user):
assert 'Export' in resp.text
assert 'Delete' in resp.text
assert 'Included Agendas' in resp.text
+ assert 'Add Excluded Period' in resp.text
assert "This virtual agenda doesn't include any agenda yet" in resp.text
# No meeting types yet
assert 'Meeting Types' not in resp.text
+ # No absence yet
+ assert 'Excluded Periods' not in resp.text
def test_virtual_agenda_settings(app, admin_user):
@@ -2264,7 +2267,9 @@ def test_virtual_agenda_settings(app, admin_user):
VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
-
+ TimePeriod.objects.create(
+ agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
+ )
app = login(app)
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
assert "This virtual agenda doesn't include any agenda yet" not in resp.text
@@ -2277,6 +2282,9 @@ def test_virtual_agenda_settings(app, admin_user):
assert 'mt' in resp.text
assert '10' in resp.text
+ assert 'Excluded Periods' in resp.text
+ assert 'Monday' in resp.text
+
# Error message when incompatible meeting types
mt2.delete()
resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
@@ -2307,6 +2315,61 @@ def test_virtual_agenda_settings_include(app, admin_user):
assert len(resp.form['real_agenda'].options) == 2
+def test_virtual_agenda_settings_add_excluded_period(app, admin_user):
+ agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
+
+ app = login(app)
+ resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
+ resp = resp.click('Add Excluded Period')
+
+ resp.form['weekdays-0'].checked = True
+ resp.form['start_time'] = '10:00'
+ resp.form['end_time'] = '17:00'
+ resp = resp.form.submit()
+ tp = TimePeriod.objects.get(agenda=agenda)
+ assert tp.weekday == 0
+ assert tp.start_time.hour == 10
+ assert tp.start_time.minute == 0
+ assert tp.end_time.hour == 17
+ assert tp.end_time.minute == 0
+
+ resp = resp.follow()
+ assert u'Monday / 10 a.m. → 5 p.m.' in resp.text
+
+
+def test_virtual_agenda_settings_edit_excluded_period(app, admin_user):
+ agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
+ tp = TimePeriod.objects.create(
+ agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
+ )
+ app = login(app)
+ resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
+ url = '/manage/timeperiods/%s/edit' % tp.pk
+ resp = resp.click(href=url)
+ resp.form['start_time'] = '11:00'
+ resp = resp.form.submit()
+ tp = TimePeriod.objects.get(agenda=agenda)
+ assert tp.weekday == 0
+ assert tp.start_time.hour == 11
+ assert tp.start_time.minute == 0
+ assert tp.end_time.hour == 18
+ assert tp.end_time.minute == 0
+
+
+def test_virtual_agenda_settings_delete_excluded_period(app, admin_user):
+ agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
+ tp = TimePeriod.objects.create(
+ agenda=agenda, weekday=0, start_time=datetime.time(10, 0), end_time=datetime.time(18, 0)
+ )
+ app = login(app)
+ resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
+ url = '/manage/timeperiods/%s/delete' % tp.pk
+ resp = resp.click(href=url)
+ resp = resp.form.submit()
+ assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
+ assert TimePeriod.objects.count() == 0
+
+
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')