Projet

Général

Profil

0002-manager-add-views-for-virtual-agendas-37123.patch

Emmanuel Cazenave, 16 mars 2020 17:47

Télécharger (29,2 ko)

Voir les différences:

Subject: [PATCH 2/8] manager: add views for virtual agendas (#37123)

 chrono/agendas/models.py                      |  22 ++
 chrono/manager/forms.py                       |  41 +++
 ...manager_confirm_virtual_member_delete.html |  19 ++
 .../manager_virtual_agenda_settings.html      |  64 +++++
 .../chrono/manager_virtual_agenda_view.html   |  26 ++
 .../chrono/manager_virtual_member_form.html   |  28 ++
 chrono/manager/urls.py                        |  10 +
 chrono/manager/views.py                       |  86 ++++++
 tests/test_manager.py                         | 250 ++++++++++++++++++
 9 files changed, 546 insertions(+)
 create mode 100644 chrono/manager/templates/chrono/manager_confirm_virtual_member_delete.html
 create mode 100644 chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
 create mode 100644 chrono/manager/templates/chrono/manager_virtual_agenda_view.html
 create mode 100644 chrono/manager/templates/chrono/manager_virtual_member_form.html
chrono/agendas/models.py
107 107
    class Meta:
108 108
        ordering = ['label']
109 109

  
110
    def __str__(self):
111
        return self.label
112

  
110 113
    def save(self, *args, **kwargs):
111 114
        if not self.slug:
112 115
            self.slug = generate_slug(self)
......
176 179
            return MeetingType.objects.get(id=id_, agenda=self)
177 180
        return MeetingType.objects.get(slug=slug, agenda=self)
178 181

  
182
    def get_virtual_members(self):
183
        return VirtualMember.objects.filter(virtual_agenda=self)
184

  
179 185
    def get_base_meeting_duration(self):
180 186
        durations = [x.duration for x in self.iter_meetingtypes()]
181 187
        if not durations:
......
249 255
        Agenda, on_delete=models.CASCADE, related_name='virtual_members', verbose_name='Agenda'
250 256
    )
251 257

  
258
    def clean(self):
259
        error_msg = _('This agenda does not have the same meetingtypes provided by the virtual agenda.')
260
        virtual_meetingtypes = self.virtual_agenda.iter_meetingtypes()
261
        for meetingtype in virtual_meetingtypes:
262
            try:
263
                MeetingType.objects.get(
264
                    agenda=self.real_agenda,
265
                    label=meetingtype.label,
266
                    slug=meetingtype.slug,
267
                    duration=meetingtype.duration,
268
                )
269
            except MeetingType.DoesNotExist:
270
                raise ValidationError(error_msg)
271
        if len(virtual_meetingtypes) != MeetingType.objects.filter(agenda=self.real_agenda).count():
272
            raise ValidationError(error_msg)
273

  
252 274

  
253 275
WEEKDAYS_LIST = sorted(WEEKDAYS.items(), key=lambda x: x[0])
254 276

  
chrono/manager/forms.py
34 34
    Desk,
35 35
    TimePeriodException,
36 36
    TimePeriodExceptionSource,
37
    VirtualMember,
37 38
    WEEKDAYS_LIST,
38 39
)
39 40

  
......
88 89
        }
89 90
        exclude = ['slug']
90 91

  
92
    def clean(self):
93
        super().clean()
94
        agenda = self.cleaned_data['agenda']
95
        for virtual_agenda in agenda.virtual_agendas.all():
96
            for real_agenda in virtual_agenda.real_agendas.all():
97
                if real_agenda != agenda:
98
                    raise ValidationError(
99
                        _("Can't add a meetingtype to an agenda that is included in a virtual agenda.")
100
                    )
101

  
91 102

  
92 103
class MeetingTypeForm(forms.ModelForm):
93 104
    class Meta:
......
97 108
        }
98 109
        exclude = []
99 110

  
111
    def clean(self):
112
        super().clean()
113
        for virtual_agenda in self.instance.agenda.virtual_agendas.all():
114
            if virtual_agenda.real_agendas.count() == 1:
115
                continue
116
            for mt in virtual_agenda.iter_meetingtypes():
117
                if (
118
                    mt.label == self.instance.label
119
                    and mt.slug == self.instance.slug
120
                    and mt.duration == self.instance.duration
121
                ):
122
                    raise ValidationError(
123
                        _('This meetingtype is used by a virtual agenda: %s' % virtual_agenda)
124
                    )
125

  
100 126

  
101 127
class TimePeriodAddForm(forms.Form):
102 128
    weekdays = forms.MultipleChoiceField(
......
161 187
        return self.cleaned_data['end_datetime']
162 188

  
163 189

  
190
class VirtualMemberForm(forms.ModelForm):
191
    class Meta:
192
        model = VirtualMember
193
        fields = ['virtual_agenda', 'real_agenda']
194
        widgets = {
195
            'virtual_agenda': forms.HiddenInput(),
196
        }
197

  
198
    def __init__(self, *args, **kwargs):
199
        super(VirtualMemberForm, self).__init__(*args, **kwargs)
200
        self.fields['real_agenda'].queryset = Agenda.objects.filter(kind='meetings').exclude(
201
            virtual_agendas__pk__in=[kwargs['initial']['agenda']]
202
        )
203

  
204

  
164 205
class ImportEventsForm(forms.Form):
165 206
    events_csv_file = forms.FileField(
166 207
        label=_('Events File'),
chrono/manager/templates/chrono/manager_confirm_virtual_member_delete.html
1
{% extends "chrono/manager_home.html" %}
2
{% load i18n %}
3

  
4
{% block appbar %}
5
<h2>{% trans "Exclude Agenda" %}</h2>
6
{% endblock %}
7

  
8
{% block content %}
9
<form method="post">
10
  {% csrf_token %}
11
  <p>
12
  {% blocktrans %}Are you sure you want to exclude this agenda from the virtual agenda ?{% endblocktrans %}
13
  </p>
14
  <div class="buttons">
15
    <button class="delete-button">{% trans 'Exclude' %}</button>
16
    <a class="cancel" href="{% url 'chrono-manager-agenda-settings' agenda.pk %}">{% trans 'Cancel' %}</a>
17
  </div>
18
</form>
19
{% endblock %}
chrono/manager/templates/chrono/manager_virtual_agenda_settings.html
1
{% extends "chrono/manager_agenda_settings.html" %}
2
{% load i18n %}
3

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

  
8
{% block agenda-settings %}
9

  
10
<div class="section">
11
<h3>{% trans 'Included Agendas' %}</h3>
12
<div>
13
{% if virtual_members.count %}
14
  <ul class="objects-list single-links">
15
    {% for virtual_member in virtual_members %}
16
    <li><a href="{% url 'chrono-manager-agenda-settings' pk=virtual_member.real_agenda.id %}">
17
        {{real_agenda.label}}
18
        <span class="identifier">[{% trans "identifier:" %} {{virtual_member.real_agenda.slug}}]</span>
19
        </a>
20
        <a rel="popup" class="delete" href="{% url 'chrono-manager-virtual-member-delete' pk=virtual_member.pk %}">{% trans "remove" %}</a>
21
    </li>
22
    {% endfor %}
23
  </ul>
24
{% else %}
25
<div class="big-msg-info">
26
  {% blocktrans %}
27
  This virtual agenda doesn't include any agenda yet. Click on the "Include Agenda" button in
28
  the top right of the page to include a first one.
29
  {% endblocktrans %}
30
</div>
31
{% endif %}
32
</div>
33
</div>
34

  
35
{% if virtual_members.count %}
36
<div class="section">
37
<h3>{% trans 'Meeting Types' %}</h3>
38
<div>
39
{% if meeting_types %}
40
  <ul class="objects-list single-links">
41
    {% for meeting_type in meeting_types %}
42
    <li><a rel="popup" href="">
43
        {{meeting_type.label}}
44
        <span class="duration">({{meeting_type.duration}} {% trans "minutes" %})</span>
45
        <span class="identifier">[{% trans "identifier:" %} {{meeting_type.slug}}]</span>
46
        </a>
47
    </li>
48
    {% endfor %}
49
  </ul>
50
{% else %}
51
<div class="errornotice">
52
  {% blocktrans %}
53
  This virtual agenda doesn't have any meeting type.
54
  It is probably because its included agendas have incompatible meeting types
55
  and it makes this virtual agenda unusable.
56
  {% endblocktrans %}
57
</div>
58
{% endif %}
59
</div>
60
</div>
61
{% endif %}
62

  
63

  
64
{% endblock %}
chrono/manager/templates/chrono/manager_virtual_agenda_view.html
1
{% extends "chrono/manager_agenda_view.html" %}
2
{% load i18n %}
3

  
4
{% block content %}
5
<div class="section">
6
<h3>{% trans 'Included Agendas' %}</h3>
7
<div>
8
{% if agenda.real_agendas.count %}
9
  <ul class="objects-list single-links">
10
    {% for real_agenda in agenda.real_agendas.all %}
11
    <li><a href="{% url 'chrono-manager-agenda-view' pk=real_agenda.pk %}">
12
        {{real_agenda.label}}
13
        <span class="identifier">[{% trans "identifier:" %} {{real_agenda.slug}}]</span>
14
        </a>
15
    {% endfor %}
16
  </ul>
17
{% else %}
18
<div class="big-msg-info">
19
  {% blocktrans %}
20
  This virtual agenda is empty.
21
  {% endblocktrans %}
22
</div>
23
{% endif %}
24
</div>
25
</div>
26
{% endblock %}
chrono/manager/templates/chrono/manager_virtual_member_form.html
1
{% extends "chrono/manager_agenda_view.html" %}
2
{% load i18n %}
3

  
4
{% block extrascripts %}
5
{{ block.super }}
6
{{ form.media }}
7
{% endblock %}
8

  
9
{% block breadcrumb %}
10
{{ block.super }}
11
<a href="">{% trans "Include Agenda" %}</a>
12
{% endblock %}
13

  
14
{% block appbar %}
15
<h2>{% trans "Include Agenda" %}</h2>
16
{% endblock %}
17

  
18
{% block content %}
19

  
20
<form method="post" enctype="multipart/form-data">
21
  {% csrf_token %}
22
  {{ form.as_p }}
23
  <div class="buttons">
24
    <button class="submit-button">{% trans "Save" %}</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
93 93
        views.desk_import_time_period_exceptions,
94 94
        name='chrono-manager-desk-add-import-time-period-exceptions',
95 95
    ),
96
    url(
97
        r'^agendas/(?P<pk>\d+)/add-virtual-member$',
98
        views.agenda_add_virtual_member,
99
        name='chrono-manager-agenda-add-virtual-member',
100
    ),
101
    url(
102
        r'^virtual-members/(?P<pk>\d+)/delete$',
103
        views.virtual_member_delete,
104
        name='chrono-manager-virtual-member-delete',
105
    ),
96 106
    url(
97 107
        r'^time-period-exceptions/(?P<pk>\d+)/edit$',
98 108
        views.time_period_exception_edit,
chrono/manager/views.py
23 23
from django.forms import ValidationError
24 24
from django.http import Http404, HttpResponse, HttpResponseRedirect
25 25
from django.shortcuts import get_object_or_404
26
from django.template.response import TemplateResponse
26 27
from django.urls import reverse, reverse_lazy
27 28
from django.utils.dates import MONTHS
28 29
from django.utils.timezone import now, make_aware, make_naive
......
53 54
    ICSError,
54 55
    AgendaImportError,
55 56
    TimePeriodExceptionSource,
57
    VirtualMember,
56 58
)
57 59

  
58 60
from .forms import (
......
71 73
    AgendasImportForm,
72 74
    TimePeriodAddForm,
73 75
    TimePeriodExceptionSourceReplaceForm,
76
    VirtualMemberForm,
74 77
)
75 78
from .utils import import_site
76 79

  
......
241 244
class AgendaView(ViewableAgendaMixin, View):
242 245
    def get(self, request, *args, **kwargs):
243 246
        today = datetime.date.today()
247
        if self.agenda.kind == 'virtual':
248
            return TemplateResponse(
249
                request=request,
250
                template='chrono/manager_virtual_agenda_view.html',
251
                context={
252
                    'agenda': self.agenda,
253
                    'object': self.agenda,
254
                    'user_can_manage': self.agenda.can_be_managed(self.request.user),
255
                },
256
            )
257

  
244 258
        if self.agenda.kind == 'meetings':
245 259
            # redirect to today view
246 260
            return HttpResponseRedirect(
......
665 679
class AgendaSettings(ManagedAgendaMixin, DetailView):
666 680
    model = Agenda
667 681

  
682
    def get_context_data(self, **kwargs):
683
        context = super(AgendaSettings, self).get_context_data(**kwargs)
684
        if self.agenda.kind == 'virtual':
685
            context['virtual_members'] = self.object.get_virtual_members()
686
            context['meeting_types'] = self.object.iter_meetingtypes()
687
        return context
688

  
668 689
    def get_events(self):
669 690
        return Event.annotate_queryset(Event.objects.filter(agenda=self.agenda).select_related('agenda'))
670 691

  
......
830 851
    template_name = 'chrono/manager_confirm_delete.html'
831 852
    model = MeetingType
832 853

  
854
    def get_context_data(self, **kwargs):
855
        context = super(MeetingTypeDeleteView, self).get_context_data(**kwargs)
856
        cannot_delete = False
857
        meeting_type = self.get_object()
858
        for virtual_agenda in self.get_object().agenda.virtual_agendas.all():
859
            if virtual_agenda.real_agendas.count() == 1:
860
                continue
861
            for mt in virtual_agenda.iter_meetingtypes():
862
                if (
863
                    meeting_type.slug == mt.slug
864
                    and meeting_type.label == mt.label
865
                    and meeting_type.duration == mt.duration
866
                ):
867
                    cannot_delete = True
868
                    context['cannot_delete_msg'] = _(
869
                        'This cannot be removed as it used by a virtual agenda: %(agenda)s'
870
                        % {'agenda': virtual_agenda}
871
                    )
872
                    break
873
        context['cannot_delete'] = cannot_delete
874
        return context
875

  
876
    def delete(self, request, *args, **kwargs):
877
        self.object = self.get_object()
878
        context = self.get_context_data()
879
        if context['cannot_delete']:
880
            raise PermissionDenied()
881
        return super(MeetingTypeDeleteView, self).delete(request, *args, **kwargs)
882

  
833 883

  
834 884
meeting_type_delete = MeetingTypeDeleteView.as_view()
835 885

  
......
911 961
desk_delete = DeskDeleteView.as_view()
912 962

  
913 963

  
964
class VirtualMemberAddView(ManagedAgendaMixin, CreateView):
965
    template_name = 'chrono/manager_virtual_member_form.html'
966
    form_class = VirtualMemberForm
967
    model = VirtualMember
968

  
969
    def get_form_kwargs(self):
970
        kwargs = super(VirtualMemberAddView, self).get_form_kwargs()
971
        kwargs['initial']['virtual_agenda'] = kwargs['initial']['agenda']
972
        return kwargs
973

  
974

  
975
agenda_add_virtual_member = VirtualMemberAddView.as_view()
976

  
977

  
978
class VirtualMemberDeleteView(DeleteView):
979
    template_name = 'chrono/manager_confirm_virtual_member_delete.html'
980
    model = VirtualMember
981

  
982
    def dispatch(self, request, *args, **kwargs):
983
        self.agenda = self.get_object().virtual_agenda
984
        if not self.agenda.can_be_managed(request.user):
985
            raise PermissionDenied()
986
        return super(VirtualMemberDeleteView, self).dispatch(request, *args, **kwargs)
987

  
988
    def get_context_data(self, **kwargs):
989
        context = super(VirtualMemberDeleteView, self).get_context_data(**kwargs)
990
        context['agenda'] = self.agenda
991
        return context
992

  
993
    def get_success_url(self):
994
        return reverse('chrono-manager-agenda-settings', kwargs={'pk': self.agenda.pk})
995

  
996

  
997
virtual_member_delete = VirtualMemberDeleteView.as_view()
998

  
999

  
914 1000
class AgendaAddTimePeriodExceptionView(ManagedDeskMixin, CreateView):
915 1001
    template_name = 'chrono/manager_time_period_exception_form.html'
916 1002
    model = TimePeriodException
tests/test_manager.py
25 25
    TimePeriod,
26 26
    TimePeriodException,
27 27
    TimePeriodExceptionSource,
28
    VirtualMember,
28 29
)
29 30

  
30 31
pytestmark = pytest.mark.django_db
......
2171 2172
    resp.form['agendas_json'] = Upload('export.json', agenda_export, 'application/json')
2172 2173
    resp = resp.form.submit()
2173 2174
    assert u'Missing &quot;gé1&quot; role' in resp.text
2175

  
2176

  
2177
def test_virtual_agenda_add(app, admin_user):
2178
    app = login(app)
2179
    resp = app.get('/manage/', status=200)
2180
    resp = resp.click('New')
2181
    resp.form['label'] = 'Virtual agenda'
2182
    resp.form['kind'] = 'virtual'
2183
    resp = resp.form.submit()
2184
    agenda = Agenda.objects.get(label='Virtual agenda')
2185
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
2186

  
2187

  
2188
def test_virtual_agenda_baseview_empty(app, admin_user):
2189
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2190
    app = login(app)
2191
    resp = app.get(agenda.get_absolute_url())
2192
    assert 'Settings' in resp.text
2193
    assert 'My Virtual agenda' in resp.text
2194
    assert 'Included Agendas' in resp.text
2195
    assert 'This virtual agenda is empty.' in resp.text
2196
    assert '/manage/agendas/%s/settings' % agenda.pk in resp.text
2197

  
2198

  
2199
def test_virtual_agenda_baseview(app, admin_user):
2200
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2201
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2202
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2203
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2204
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2205

  
2206
    app = login(app)
2207
    resp = app.get(agenda.get_absolute_url())
2208
    assert 'Settings' in resp.text
2209
    assert 'My Virtual agenda' in resp.text
2210
    assert 'Included Agendas' in resp.text
2211
    assert 'This virtual agenda is empty.' not in resp.text
2212
    for real_agenda in [meeting_agenda_1, meeting_agenda_2]:
2213
        assert real_agenda.label in resp.text
2214
        assert real_agenda.slug in resp.text
2215
        assert real_agenda.get_absolute_url() in resp.text
2216

  
2217

  
2218
def test_virtual_agenda_settings_empty(app, admin_user):
2219
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2220
    app = login(app)
2221
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2222
    assert 'Include Agenda' in resp.text
2223
    assert 'Options' in resp.text
2224
    assert 'Export' in resp.text
2225
    assert 'Delete' in resp.text
2226
    assert 'Included Agendas' in resp.text
2227
    assert "This virtual agenda doesn't include any agenda yet" in resp.text
2228
    # No meeting types yet
2229
    assert 'Meeting Types' not in resp.text
2230

  
2231

  
2232
def test_virtual_agenda_settings(app, admin_user):
2233
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2234
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2235
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2236
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2237
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2238
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2239
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2240

  
2241
    app = login(app)
2242
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2243
    assert "This virtual agenda doesn't include any agenda yet" not in resp.text
2244
    for real_agenda in [meeting_agenda_1, meeting_agenda_2]:
2245
        assert real_agenda.slug in resp.text
2246
        assert '/manage/agendas/%s/settings' % real_agenda.pk in resp.text
2247

  
2248
    assert 'Meeting Types' in resp.text
2249
    assert 'MT' in resp.text
2250
    assert 'mt' in resp.text
2251
    assert '10' in resp.text
2252

  
2253
    # Error message when incompatible meeting types
2254
    mt2.delete()
2255
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2256
    assert "This virtual agenda doesn't have any meeting type." in resp.text
2257

  
2258

  
2259
def test_virtual_agenda_settings_include(app, admin_user):
2260
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2261
    Agenda.objects.create(label='Event agenda', kind='events')
2262
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2263
    Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2264

  
2265
    app = login(app)
2266
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2267
    resp = resp.click('Include Agenda')
2268
    # Only meetings agenda are proposed (2) + 1 empty choice = 3
2269
    assert len(resp.form['real_agenda'].options) == 3
2270
    # Include a real agenda
2271
    resp.form['real_agenda'].value = meeting_agenda_1.pk
2272
    resp = resp.form.submit()
2273
    assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id)
2274
    assert VirtualMember.objects.get(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2275

  
2276
    resp = resp.follow()
2277
    resp = resp.click('Include Agenda')
2278
    # The previously include agenda is not proposed any more
2279
    assert len(resp.form['real_agenda'].options) == 2
2280

  
2281

  
2282
def test_virtual_agenda_settings_include_incompatible_agenda(app, admin_user):
2283
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2284
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2285
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2286
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2287
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2288
    app = login(app)
2289

  
2290
    # refused because different slug
2291
    mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mtt', duration=10)
2292
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2293
    resp = resp.click('Include Agenda')
2294
    resp.form['real_agenda'].value = meeting_agenda_2.pk
2295
    resp = resp.form.submit()
2296
    assert 'This agenda does not have the same meetingtypes provided by the virtual agenda.' in resp.text
2297
    assert meeting_agenda_2.virtual_agendas.count() == 0
2298
    mt.delete()
2299

  
2300
    # refused because different duration
2301
    mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=15)
2302
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2303
    resp = resp.click('Include Agenda')
2304
    resp.form['real_agenda'].value = meeting_agenda_2.pk
2305
    resp = resp.form.submit()
2306
    assert 'This agenda does not have the same meetingtypes provided by the virtual agenda.' in resp.text
2307
    assert meeting_agenda_2.virtual_agendas.count() == 0
2308
    mt.delete()
2309

  
2310
    # refused because different label
2311
    mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MTT', slug='mt', duration=10)
2312
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2313
    resp = resp.click('Include Agenda')
2314
    resp.form['real_agenda'].value = meeting_agenda_2.pk
2315
    resp = resp.form.submit()
2316
    assert 'This agenda does not have the same meetingtypes provided by the virtual agenda.' in resp.text
2317
    assert meeting_agenda_2.virtual_agendas.count() == 0
2318
    mt.delete()
2319

  
2320
    # refused because has one more meeting type
2321
    mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2322
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='AA', slug='aa', duration=30)
2323
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2324
    resp = resp.click('Include Agenda')
2325
    resp.form['real_agenda'].value = meeting_agenda_2.pk
2326
    resp = resp.form.submit()
2327
    assert 'This agenda does not have the same meetingtypes provided by the virtual agenda.' in resp.text
2328
    assert meeting_agenda_2.virtual_agendas.count() == 0
2329
    mt.delete()
2330
    mt2.delete()
2331

  
2332
    # refused because has one less meeting type
2333
    mt = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2334
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_1, label='AA', slug='aa', duration=30)
2335
    resp = app.get('/manage/agendas/%s/settings' % agenda.pk)
2336
    resp = resp.click('Include Agenda')
2337
    resp.form['real_agenda'].value = meeting_agenda_2.pk
2338
    resp = resp.form.submit()
2339
    assert 'This agenda does not have the same meetingtypes provided by the virtual agenda.' in resp.text
2340
    assert meeting_agenda_2.virtual_agendas.count() == 0
2341
    mt.delete()
2342
    mt2.delete()
2343

  
2344

  
2345
def test_cant_delete_meetingtype_used_by_virtual_agenda(app, admin_user):
2346
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2347
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2348
    mt1 = MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2349
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2350

  
2351
    # ok because there is only one agenda in the virtual agenda
2352
    app = login(app)
2353
    resp = app.get('/manage/agendas/%s/settings' % meeting_agenda_1.pk)
2354
    resp = resp.click('MT')
2355
    resp = resp.click('Delete')
2356
    resp = resp.form.submit()
2357
    assert not meeting_agenda_1.iter_meetingtypes()
2358
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2359

  
2360
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2361
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2362
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2363

  
2364
    resp = app.get('/manage/agendas/%s/settings' % meeting_agenda_2.pk)
2365
    resp = resp.click('MT')
2366
    resp = resp.click('Delete')
2367
    assert 'This cannot be removed as it used by a virtual agenda' in resp.text
2368
    assert 'disabled' in resp.text
2369
    resp = app.post('/manage/meetingtypes/%s/delete' % mt2.pk, status=403)
2370

  
2371

  
2372
def test_cant_modify_meetingtype_used_by_virtual_agenda(app, admin_user):
2373
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2374
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2375
    mt1 = MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2376
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2377
    app = login(app)
2378

  
2379
    # ok because there is only one agenda in the virtual agenda
2380
    resp = app.get('/manage/meetingtypes/%s/edit' % mt1.pk)
2381
    resp.form['label'].value = 'MTT'
2382
    resp = resp.form.submit()
2383
    assert MeetingType.objects.get(agenda=meeting_agenda_1, label='MTT', slug='mt', duration=10)
2384

  
2385
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2386
    mt2 = MeetingType.objects.create(agenda=meeting_agenda_2, label='MTT', slug='mt', duration=10)
2387
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2388

  
2389
    app = login(app)
2390
    resp = app.get('/manage/meetingtypes/%s/edit' % mt2.pk)
2391
    resp.form['label'].value = 'Oho'
2392
    resp = resp.form.submit()
2393
    assert 'This meetingtype is used by a virtual agenda' in resp.text
2394
    mt = MeetingType.objects.get(pk=mt2.pk)
2395
    assert mt.label == 'MTT'
2396

  
2397

  
2398
def test_cant_add_meetingtype_if_virtual_agenda(app, admin_user):
2399
    agenda = Agenda.objects.create(label='My Virtual agenda', kind='virtual')
2400
    meeting_agenda_1 = Agenda.objects.create(label='Meeting agenda 1', kind='meetings')
2401
    MeetingType.objects.create(agenda=meeting_agenda_1, label='MT', slug='mt', duration=10)
2402
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_1)
2403
    app = login(app)
2404

  
2405
    # ok because there is only one agenda in the virtual agenda
2406
    resp = app.get('/manage/agendas/%s/add-meeting-type' % meeting_agenda_1.pk)
2407
    resp.form['duration'].value = '12'
2408
    resp.form['label'].value = 'Oho'
2409
    resp = resp.form.submit()
2410
    assert MeetingType.objects.filter(agenda=meeting_agenda_1).count() == 2
2411
    MeetingType.objects.get(agenda=meeting_agenda_1, label='Oho').delete()
2412

  
2413
    meeting_agenda_2 = Agenda.objects.create(label='Meeting agenda 2', kind='meetings')
2414
    VirtualMember.objects.create(virtual_agenda=agenda, real_agenda=meeting_agenda_2)
2415
    MeetingType.objects.create(agenda=meeting_agenda_2, label='MT', slug='mt', duration=10)
2416

  
2417
    app = login(app)
2418
    resp = app.get('/manage/agendas/%s/add-meeting-type' % meeting_agenda_1.pk)
2419
    resp.form['duration'].value = '12'
2420
    resp.form['label'].value = 'Oho'
2421
    resp = resp.form.submit()
2422
    assert 'Can&#39;t add a meetingtype to an agenda that is included in a virtual agenda.' in resp.text
2423
    assert MeetingType.objects.filter(agenda=meeting_agenda_1).count() == 1
2174
-