0001-manager-add-site-export-48100.patch
chrono/manager/forms.py | ||
---|---|---|
596 | 596 |
if cleaned_data['days'] and not (cleaned_data['send_email'] or cleaned_data.get('send_sms')): |
597 | 597 |
raise ValidationError(_('Select at least one notification medium.')) |
598 | 598 |
return cleaned_data |
599 | ||
600 | ||
601 |
class AgendasExportForm(forms.Form): |
|
602 |
agendas = forms.BooleanField(label=_('Agendas'), required=False, initial=True) |
|
603 |
unavailability_calendars = forms.BooleanField( |
|
604 |
label=_('Unavailability calendars'), required=False, initial=True |
|
605 |
) |
chrono/manager/templates/chrono/agendas_export.html | ||
---|---|---|
1 |
{% extends "chrono/manager_home.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block breadcrumb %} |
|
5 |
{{ block.super }} |
|
6 |
<a href="{% url 'chrono-manager-agendas-import' %}">{% trans 'Export' %}</a> |
|
7 |
{% endblock %} |
|
8 | ||
9 |
{% block appbar %} |
|
10 |
<h2>{% trans "Export" %}</h2> |
|
11 |
{% endblock %} |
|
12 | ||
13 |
{% block content %} |
|
14 |
<form method="post" enctype="multipart/form-data"> |
|
15 |
{% csrf_token %} |
|
16 |
{{ form.as_p }} |
|
17 |
<div class="buttons"> |
|
18 |
<button class="submit-button">{% trans "Export" %}</button> |
|
19 |
<a class="cancel" href="{% url 'chrono-manager-homepage' %}">{% trans 'Cancel' %}</a> |
|
20 |
</div> |
|
21 |
</form> |
|
22 |
{% endblock %} |
chrono/manager/templates/chrono/manager_home.html | ||
---|---|---|
5 | 5 |
<h2>{% trans 'Agendas' %}</h2> |
6 | 6 |
<span class="actions"> |
7 | 7 |
{% if user.is_staff %} |
8 |
<a class="extra-actions-menu-opener"></a> |
|
9 |
<ul class="extra-actions-menu"> |
|
10 |
<li><a rel="popup" href="{% url 'chrono-manager-agendas-import' %}">{% trans 'Import' %}</a></li> |
|
11 |
<li><a rel="popup" href="{% url 'chrono-manager-agendas-export' %}">{% trans 'Export' %}</a></li> |
|
12 |
</ul> |
|
8 | 13 |
<a href="{% url 'chrono-manager-category-list' %}">{% trans 'Categories' %}</a> |
9 | 14 |
{% endif %} |
10 | 15 |
<a href="{% url 'chrono-manager-unavailability-calendar-list' %}">{% trans 'Unavailability calendars' %}</a> |
11 | 16 |
{% if user.is_staff %} |
12 | 17 |
<a href="{% url 'chrono-manager-resource-list' %}">{% trans 'Resources' %}</a> |
13 |
<a rel="popup" href="{% url 'chrono-manager-agendas-import' %}">{% trans 'Import' %}</a> |
|
14 | 18 |
<a rel="popup" href="{% url 'chrono-manager-agenda-add' %}">{% trans 'New' %}</a> |
15 | 19 |
{% endif %} |
16 | 20 |
</span> |
chrono/manager/urls.py | ||
---|---|---|
81 | 81 |
url(r'^category/(?P<pk>\d+)/delete/$', views.category_delete, name='chrono-manager-category-delete'), |
82 | 82 |
url(r'^agendas/add/$', views.agenda_add, name='chrono-manager-agenda-add'), |
83 | 83 |
url(r'^agendas/import/$', views.agendas_import, name='chrono-manager-agendas-import'), |
84 |
url(r'^agendas/export/$', views.agendas_export, name='chrono-manager-agendas-export'), |
|
84 | 85 |
url(r'^agendas/(?P<pk>\d+)/$', views.agenda_view, name='chrono-manager-agenda-view'), |
85 | 86 |
url( |
86 | 87 |
r'^agendas/(?P<pk>\d+)/month/$', |
chrono/manager/utils.py | ||
---|---|---|
24 | 24 |
from chrono.agendas.models import Agenda, AgendaImportError, UnavailabilityCalendar |
25 | 25 | |
26 | 26 | |
27 |
def export_site(): |
|
27 |
def export_site(agendas=True, unavailability_calendars=True):
|
|
28 | 28 |
'''Dump site objects to JSON-dumpable dictionnary''' |
29 | 29 |
data = collections.OrderedDict() |
30 |
data['unavailability_calendars'] = [x.export_json() for x in UnavailabilityCalendar.objects.all()] |
|
31 |
qs1 = Agenda.objects.filter(~Q(kind='virtual')) |
|
32 |
qs2 = Agenda.objects.filter(kind='virtual') |
|
33 |
data['agendas'] = [x.export_json() for x in itertools.chain(qs1, qs2)] |
|
30 |
if unavailability_calendars: |
|
31 |
data['unavailability_calendars'] = [x.export_json() for x in UnavailabilityCalendar.objects.all()] |
|
32 |
if agendas: |
|
33 |
qs1 = Agenda.objects.filter(~Q(kind='virtual')) |
|
34 |
qs2 = Agenda.objects.filter(kind='virtual') |
|
35 |
data['agendas'] = [x.export_json() for x in itertools.chain(qs1, qs2)] |
|
34 | 36 |
return data |
35 | 37 | |
36 | 38 |
chrono/manager/views.py | ||
---|---|---|
98 | 98 |
AgendaReminderForm, |
99 | 99 |
UnavailabilityCalendarAddForm, |
100 | 100 |
UnavailabilityCalendarEditForm, |
101 |
AgendasExportForm, |
|
101 | 102 |
) |
102 |
from .utils import import_site |
|
103 |
from .utils import import_site, export_site
|
|
103 | 104 | |
104 | 105 |
FUTURE_BOOKING_ERROR_MSG = _('This cannot be removed as there are bookings for a future date.') |
105 | 106 | |
... | ... | |
119 | 120 |
homepage = HomepageView.as_view() |
120 | 121 | |
121 | 122 | |
123 |
class AgendasExportView(FormView): |
|
124 |
form_class = AgendasExportForm |
|
125 |
template_name = 'chrono/agendas_export.html' |
|
126 | ||
127 |
def dispatch(self, request, *args, **kwargs): |
|
128 |
if not request.user.is_staff: |
|
129 |
raise PermissionDenied() |
|
130 |
return super().dispatch(request, *args, **kwargs) |
|
131 | ||
132 |
def form_valid(self, form): |
|
133 |
response = HttpResponse(content_type='application/json') |
|
134 |
today = datetime.date.today() |
|
135 |
response['Content-Disposition'] = 'attachment; filename="export_agendas_{}.json"'.format( |
|
136 |
today.strftime('%Y%m%d') |
|
137 |
) |
|
138 |
json.dump(export_site(**form.cleaned_data), response, indent=2) |
|
139 |
return response |
|
140 | ||
141 | ||
142 |
agendas_export = AgendasExportView.as_view() |
|
143 | ||
144 | ||
122 | 145 |
class ResourceListView(ListView): |
123 | 146 |
template_name = 'chrono/manager_resource_list.html' |
124 | 147 |
model = Resource |
tests/test_manager.py | ||
---|---|---|
5072 | 5072 |
unavailability_calendar.edit_role = group |
5073 | 5073 |
unavailability_calendar.save() |
5074 | 5074 |
app.get(url) |
5075 | ||
5076 | ||
5077 |
def test_export_site(app, admin_user): |
|
5078 |
login(app) |
|
5079 |
resp = app.get('/manage/') |
|
5080 |
resp = resp.click('Export') |
|
5081 | ||
5082 |
with freezegun.freeze_time('2020-06-15'): |
|
5083 |
resp = resp.form.submit() |
|
5084 |
assert resp.headers['content-type'] == 'application/json' |
|
5085 |
assert resp.headers['content-disposition'] == 'attachment; filename="export_agendas_20200615.json"' |
|
5086 | ||
5087 |
site_json = json.loads(resp.text) |
|
5088 |
assert site_json == {'unavailability_calendars': [], 'agendas': []} |
|
5089 | ||
5090 |
agenda = Agenda.objects.create(label=u'Foo Bar', kind='events') |
|
5091 |
unavailability_calendar = UnavailabilityCalendar.objects.create(label='Calendar 1') |
|
5092 |
resp = app.get('/manage/agendas/export/') |
|
5093 |
resp = resp.form.submit() |
|
5094 | ||
5095 |
site_json = json.loads(resp.text) |
|
5096 |
assert len(site_json['agendas']) == 1 |
|
5097 |
assert len(site_json['unavailability_calendars']) == 1 |
|
5098 | ||
5099 |
resp = app.get('/manage/agendas/export/') |
|
5100 |
resp.form['agendas'] = False |
|
5101 |
resp = resp.form.submit() |
|
5102 | ||
5103 |
site_json = json.loads(resp.text) |
|
5104 |
assert 'agendas' not in site_json |
|
5105 |
assert 'unavailability_calendars' in site_json |
|
5075 |
- |