0004-agendas-add-resource-to-agenda-38942.patch
chrono/manager/forms.py | ||
---|---|---|
102 | 102 |
exclude = ['full', 'meeting_type', 'desk', 'resources'] |
103 | 103 | |
104 | 104 | |
105 |
class AgendaResourceForm(forms.Form): |
|
106 |
resource = forms.ModelChoiceField(label=_('Resource'), queryset=Resource.objects.none()) |
|
107 | ||
108 |
def __init__(self, *args, **kwargs): |
|
109 |
super().__init__(*args, **kwargs) |
|
110 |
self.fields['resource'].queryset = Resource.objects.exclude(agenda=self.initial['agenda']) |
|
111 | ||
112 | ||
105 | 113 |
class NewMeetingTypeForm(forms.ModelForm): |
106 | 114 |
class Meta: |
107 | 115 |
model = MeetingType |
chrono/manager/templates/chrono/manager_agenda_resource_form.html | ||
---|---|---|
1 |
{% extends "chrono/manager_agenda_view.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block breadcrumb %} |
|
5 |
{{ block.super }} |
|
6 |
<a href="">{% trans "Add resource" %}</a> |
|
7 |
{% endblock %} |
|
8 | ||
9 |
{% block appbar %} |
|
10 |
<h2>{% trans "Add resource" %}</h2> |
|
11 |
{% endblock %} |
|
12 | ||
13 |
{% block content %} |
|
14 | ||
15 |
<form method="post" enctype="multipart/form-data"> |
|
16 |
{% csrf_token %} |
|
17 |
{{ form.as_p }} |
|
18 |
<div class="buttons"> |
|
19 |
<button class="submit-button">{% trans "Save" %}</button> |
|
20 |
<a class="cancel" href="{% url 'chrono-manager-agenda-settings' pk=agenda.pk %}">{% trans 'Cancel' %}</a> |
|
21 |
</div> |
|
22 |
</form> |
|
23 |
{% endblock %} |
chrono/manager/templates/chrono/manager_meetings_agenda_settings.html | ||
---|---|---|
13 | 13 |
{% endblock %} |
14 | 14 | |
15 | 15 |
{% block agenda-extra-management-actions %} |
16 |
{% if has_resources %}<a rel="popup" href="{% url 'chrono-manager-agenda-add-resource' pk=object.pk %}">{% trans 'Add resource' %}</a>{% endif %} |
|
16 | 17 |
<a rel="popup" href="{% url 'chrono-manager-agenda-add-meeting-type' pk=object.id %}">{% trans 'New Meeting Type' %}</a> |
17 | 18 |
<a rel="popup" href="{% url 'chrono-manager-agenda-add-desk' pk=object.id %}">{% trans 'New Desk' %}</a> |
18 | 19 |
{% endblock %} |
... | ... | |
97 | 98 |
</div> |
98 | 99 |
</div> |
99 | 100 | |
101 |
{% with object.resources.all as agenda_resources %} |
|
102 |
{% if has_resources %} |
|
103 |
<div class="section"> |
|
104 |
<h3>{% trans 'Resources' %}</h3> |
|
105 |
<div> |
|
106 |
{% if agenda_resources %} |
|
107 |
<ul class="objects-list single-links"> |
|
108 |
{% for resource in agenda_resources %} |
|
109 |
<li> |
|
110 |
<a href="{% url 'chrono-manager-resource-view' pk=resource.pk %}"> |
|
111 |
{{ resource.label }} |
|
112 |
<span class="identifier">[{% trans "identifier:" %} {{ resource.slug }}]</span> |
|
113 |
</a> |
|
114 |
<a rel="popup" class="delete" href="{% url 'chrono-manager-agenda-delete-resource' pk=object.pk resource_pk=resource.pk %}">{% trans "remove" %}</a> |
|
115 |
</li> |
|
116 |
{% endfor %} |
|
117 |
</ul> |
|
118 |
{% else %} |
|
119 |
<div class="big-msg-info"> |
|
120 |
{% blocktrans %} |
|
121 |
This agenda doesn't have any resource yet. Click on the "Add resource" button in |
|
122 |
the top right of the page to add a first one. |
|
123 |
{% endblocktrans %} |
|
124 |
</div> |
|
125 |
{% endif %} |
|
126 |
</div> |
|
127 |
</div> |
|
128 |
{% endif %} |
|
129 |
{% endwith %} |
|
130 | ||
100 | 131 |
{% endblock %} |
chrono/manager/templates/chrono/manager_resource_detail.html | ||
---|---|---|
17 | 17 |
<a rel="popup" href="{% url 'chrono-manager-resource-delete' pk=object.pk %}">{% trans 'Delete' %}</a> |
18 | 18 |
</span> |
19 | 19 |
{% endblock %} |
20 | ||
21 |
{% block content %} |
|
22 | ||
23 |
<div class="section"> |
|
24 |
<h3>{% trans 'Used in meetings agendas' %}</h3> |
|
25 |
<div> |
|
26 |
{% with object.agenda_set.all as agendas %} |
|
27 |
{% if agendas %} |
|
28 |
<ul class="objects-list single-links"> |
|
29 |
{% for agenda in agendas %} |
|
30 |
<li> |
|
31 |
<a href="{% url 'chrono-manager-agenda-settings' pk=agenda.pk %}"> |
|
32 |
{{ agenda.label }} |
|
33 |
</a> |
|
34 |
</li> |
|
35 |
{% endfor %} |
|
36 |
</ul> |
|
37 |
{% else %} |
|
38 |
<div class="big-msg-info"> |
|
39 |
{% blocktrans %} |
|
40 |
This resource is not used yet. |
|
41 |
{% endblocktrans %} |
|
42 |
</div> |
|
43 |
{% endif %} |
|
44 |
{% endwith %} |
|
45 |
</div> |
|
46 |
</div> |
|
47 | ||
48 |
{% endblock %} |
chrono/manager/urls.py | ||
---|---|---|
63 | 63 |
views.event_delete, |
64 | 64 |
name='chrono-manager-event-delete', |
65 | 65 |
), |
66 |
url( |
|
67 |
r'^agendas/(?P<pk>\d+)/add-resource/$', |
|
68 |
views.agenda_add_resource, |
|
69 |
name='chrono-manager-agenda-add-resource', |
|
70 |
), |
|
71 |
url( |
|
72 |
r'^agendas/(?P<pk>\d+)/resource/(?P<resource_pk>\d+)/delete/$', |
|
73 |
views.agenda_delete_resource, |
|
74 |
name='chrono-manager-agenda-delete-resource', |
|
75 |
), |
|
66 | 76 |
url( |
67 | 77 |
r'^agendas/(?P<pk>\d+)/add-meeting-type$', |
68 | 78 |
views.agenda_add_meeting_type, |
chrono/manager/views.py | ||
---|---|---|
79 | 79 |
VirtualMemberForm, |
80 | 80 |
ResourceAddForm, |
81 | 81 |
ResourceEditForm, |
82 |
AgendaResourceForm, |
|
82 | 83 |
) |
83 | 84 |
from .utils import import_site |
84 | 85 | |
... | ... | |
787 | 788 |
for virtual_member in self.object.get_virtual_members() |
788 | 789 |
] |
789 | 790 |
context['meeting_types'] = self.object.iter_meetingtypes() |
791 |
if self.agenda.kind == 'meetings': |
|
792 |
context['has_resources'] = Resource.objects.exists() |
|
790 | 793 |
return context |
791 | 794 | |
792 | 795 |
def get_events(self): |
... | ... | |
933 | 936 |
event_delete = EventDeleteView.as_view() |
934 | 937 | |
935 | 938 | |
939 |
class AgendaAddResourceView(ManagedAgendaMixin, FormView): |
|
940 |
template_name = 'chrono/manager_agenda_resource_form.html' |
|
941 |
model = Event |
|
942 |
form_class = AgendaResourceForm |
|
943 | ||
944 |
def set_agenda(self, **kwargs): |
|
945 |
self.agenda = get_object_or_404(Agenda, id=kwargs.get('pk'), kind='meetings') |
|
946 | ||
947 |
def form_valid(self, form): |
|
948 |
self.agenda.resources.add(form.cleaned_data['resource']) |
|
949 |
return super().form_valid(form) |
|
950 | ||
951 | ||
952 |
agenda_add_resource = AgendaAddResourceView.as_view() |
|
953 | ||
954 | ||
955 |
class AgendaResourceDeleteView(ManagedAgendaMixin, DeleteView): |
|
956 |
template_name = 'chrono/manager_confirm_delete.html' |
|
957 |
model = Resource |
|
958 |
pk_url_kwarg = 'resource_pk' |
|
959 | ||
960 |
def set_agenda(self, **kwargs): |
|
961 |
self.agenda = get_object_or_404(Agenda, id=kwargs.get('pk'), kind='meetings') |
|
962 | ||
963 |
def delete(self, request, *args, **kwargs): |
|
964 |
self.object = self.get_object() |
|
965 |
self.agenda.resources.remove(self.object) |
|
966 |
return HttpResponseRedirect(self.get_success_url()) |
|
967 | ||
968 | ||
969 |
agenda_delete_resource = AgendaResourceDeleteView.as_view() |
|
970 | ||
971 | ||
936 | 972 |
class AgendaAddMeetingTypeView(ManagedAgendaMixin, CreateView): |
937 | 973 |
template_name = 'chrono/manager_meeting_type_form.html' |
938 | 974 |
model = Event |
tests/test_manager.py | ||
---|---|---|
193 | 193 |
assert resource.slug == 'foo-bar' |
194 | 194 | |
195 | 195 | |
196 |
def test_view_resource(app, admin_user): |
|
197 |
agenda = Agenda.objects.create(label=u'Foo Bar', kind='meetings') |
|
198 |
resource = Resource.objects.create(label='Resource 1') |
|
199 | ||
200 |
app = login(app) |
|
201 |
resp = app.get('/manage/resource/%s/' % resource.pk, status=200) |
|
202 |
assert '/manage/agendas/%s/settings' % agenda.pk not in resp.text |
|
203 | ||
204 |
agenda.resources.add(resource) |
|
205 |
resp = app.get('/manage/resource/%s/' % resource.pk, status=200) |
|
206 |
assert '/manage/agendas/%s/settings' % agenda.pk in resp.text |
|
207 | ||
208 | ||
196 | 209 |
def test_edit_resource(app, admin_user): |
197 | 210 |
resource = Resource.objects.create(label='Foo bar') |
198 | 211 | |
... | ... | |
259 | 272 |
resp = resp.form.submit() |
260 | 273 |
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.id) |
261 | 274 |
resp = resp.follow() |
275 |
assert 'has_resources' not in resp.context |
|
262 | 276 |
assert 'Foo baz' in resp.text |
263 | 277 |
assert '<h2>Settings' in resp.text |
264 | 278 | |
... | ... | |
322 | 336 |
assert '<h2>Settings' in resp.text |
323 | 337 | |
324 | 338 | |
339 |
def test_agenda_resources(app, admin_user): |
|
340 |
agenda = Agenda.objects.create(label=u'Foo bar', kind='events') |
|
341 |
resource = Resource.objects.create(label='Resource 1') |
|
342 |
app = login(app) |
|
343 |
# not for events agenda |
|
344 |
app.get('/manage/agendas/%s/add-resource/' % agenda.pk, status=404) |
|
345 |
app.get('/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk), status=404) |
|
346 | ||
347 | ||
348 |
def test_meetings_agenda_resources(app, admin_user): |
|
349 |
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings') |
|
350 |
app = login(app) |
|
351 |
resp = app.get('/manage/agendas/%s/settings' % agenda.pk) |
|
352 |
assert 'has_resources' in resp.context |
|
353 |
assert resp.context['has_resources'] is False |
|
354 |
assert 'Add resource' not in resp.text |
|
355 | ||
356 |
resource = Resource.objects.create(label='Resource 1') |
|
357 |
resp = app.get('/manage/agendas/%s/settings' % agenda.pk) |
|
358 |
assert 'has_resources' in resp.context |
|
359 |
assert resp.context['has_resources'] is True |
|
360 |
assert '/manage/resource/%s/' % resource.pk not in resp.text |
|
361 |
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) not in resp.text |
|
362 |
resp = resp.click('Add resource') |
|
363 |
assert list(resp.context['form'].fields['resource'].queryset) == [resource] |
|
364 |
resp.form['resource'] = resource.pk |
|
365 |
resp = resp.form.submit() |
|
366 |
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk) |
|
367 |
assert list(agenda.resources.all()) == [resource] |
|
368 |
resp = resp.follow() |
|
369 |
assert '/manage/resource/%s/' % resource.pk in resp.text |
|
370 |
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) in resp.text |
|
371 |
resp = resp.click('Add resource') |
|
372 |
assert list(resp.context['form'].fields['resource'].queryset) == [] |
|
373 | ||
374 |
resp = app.get('/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk)) |
|
375 |
resp = resp.form.submit() |
|
376 |
assert resp.location.endswith('/manage/agendas/%s/settings' % agenda.pk) |
|
377 |
assert list(agenda.resources.all()) == [] |
|
378 |
resp = resp.follow() |
|
379 |
assert '/manage/resource/%s/' % resource.pk not in resp.text |
|
380 |
assert '/manage/agendas/%s/resource/%s/delete/' % (agenda.pk, resource.pk) not in resp.text |
|
381 | ||
382 | ||
325 | 383 |
def test_delete_agenda(app, admin_user): |
326 | 384 |
agenda = Agenda(label=u'Foo bar') |
327 | 385 |
agenda.save() |
328 |
- |