0001-manager-import-export-events-update-event-if-slug-ex.patch
chrono/manager/forms.py | ||
---|---|---|
27 | 27 |
from django.utils.encoding import force_text |
28 | 28 |
from django.utils.six import StringIO |
29 | 29 |
from django.utils.timezone import make_aware |
30 |
from django.utils.timezone import now |
|
30 | 31 |
from django.utils.translation import ugettext_lazy as _ |
31 | 32 | |
32 | 33 |
from chrono.agendas.models import ( |
... | ... | |
44 | 45 |
AgendaNotificationsSettings, |
45 | 46 |
AgendaReminderSettings, |
46 | 47 |
WEEKDAYS_LIST, |
48 |
generate_slug, |
|
47 | 49 |
) |
48 | 50 | |
49 | 51 |
from . import widgets |
... | ... | |
365 | 367 |
dialect = None |
366 | 368 | |
367 | 369 |
events = [] |
368 |
slugs = set() |
|
370 |
warnings = {} |
|
371 |
events_by_slug = {e.slug: e for e in Event.objects.filter(agenda=self.agenda_pk)} |
|
372 |
event_ids_with_bookings = set( |
|
373 |
Booking.objects.filter( |
|
374 |
event__agenda=self.agenda_pk, cancellation_datetime__isnull=True |
|
375 |
).values_list('event_id', flat=True) |
|
376 |
) |
|
377 |
seen_slugs = set(events_by_slug.keys()) |
|
369 | 378 |
for i, csvline in enumerate(csv.reader(StringIO(content), dialect=dialect)): |
370 | 379 |
if not csvline: |
371 | 380 |
continue |
... | ... | |
373 | 382 |
raise ValidationError(_('Invalid file format. (line %d)') % (i + 1)) |
374 | 383 |
if i == 0 and csvline[0].strip('#') in ('date', 'Date', _('date'), _('Date')): |
375 | 384 |
continue |
376 |
event = Event() |
|
377 |
event.agenda_id = self.agenda_pk |
|
385 | ||
386 |
# label needed to generate a slug |
|
387 |
label = None |
|
388 |
if len(csvline) >= 5: |
|
389 |
label = force_text(csvline[4]) |
|
390 | ||
391 |
# get or create event |
|
392 |
event = None |
|
393 |
slug = None |
|
394 |
if len(csvline) >= 6: |
|
395 |
slug = force_text(csvline[5]) if csvline[5] else None |
|
396 |
# get existing event if relevant |
|
397 |
if slug and slug in seen_slugs: |
|
398 |
event = events_by_slug[slug] |
|
399 |
# update label |
|
400 |
event.label = label |
|
401 |
if event is None: |
|
402 |
# new event |
|
403 |
event = Event(agenda_id=self.agenda_pk, label=label) |
|
404 |
# generate a slug if not provided |
|
405 |
event.slug = slug or generate_slug(event, seen_slugs=seen_slugs, agenda=self.agenda_pk) |
|
406 |
# maintain caches |
|
407 |
seen_slugs.add(event.slug) |
|
408 |
events_by_slug[event.slug] = event |
|
409 | ||
378 | 410 |
for datetime_fmt in ( |
379 | 411 |
'%Y-%m-%d %H:%M', |
380 | 412 |
'%d/%m/%Y %H:%M', |
... | ... | |
383 | 415 |
'%d/%m/%Y %H:%M:%S', |
384 | 416 |
): |
385 | 417 |
try: |
386 |
event_datetime = datetime.datetime.strptime('%s %s' % tuple(csvline[:2]), datetime_fmt) |
|
418 |
event_datetime = make_aware( |
|
419 |
datetime.datetime.strptime('%s %s' % tuple(csvline[:2]), datetime_fmt) |
|
420 |
) |
|
387 | 421 |
except ValueError: |
388 | 422 |
continue |
389 |
event.start_datetime = make_aware(event_datetime) |
|
423 |
if ( |
|
424 |
event.pk is not None |
|
425 |
and event.start_datetime != event_datetime |
|
426 |
and event.start_datetime > now() |
|
427 |
and event.pk in event_ids_with_bookings |
|
428 |
and event.pk not in warnings |
|
429 |
): |
|
430 |
# event start datetime has changed, event is not past and has not cancelled bookings |
|
431 |
# => warn the user |
|
432 |
warnings[event.pk] = event |
|
433 |
event.start_datetime = event_datetime |
|
390 | 434 |
break |
391 | 435 |
else: |
392 | 436 |
raise ValidationError(_('Invalid file format. (date/time format, line %d)') % (i + 1)) |
... | ... | |
401 | 445 |
raise ValidationError( |
402 | 446 |
_('Invalid file format. (number of places in waiting list, line %d)') % (i + 1) |
403 | 447 |
) |
404 |
if len(csvline) >= 5: |
|
405 |
event.label = force_text(csvline[4]) |
|
406 |
exclude = ['desk', 'meeting_type'] |
|
407 |
if len(csvline) >= 6: |
|
408 |
event.slug = force_text(csvline[5]) if csvline[5] else None |
|
409 |
if event.slug and event.slug in slugs: |
|
410 |
raise ValidationError(_('File contains duplicated event identifiers: %s') % event.slug) |
|
411 |
else: |
|
412 |
slugs.add(event.slug) |
|
413 |
else: |
|
414 |
exclude += ['slug'] |
|
448 | ||
415 | 449 |
column_index = 7 |
416 | 450 |
for more_attr in ('description', 'pricing', 'url'): |
417 | 451 |
if len(csvline) >= column_index: |
... | ... | |
435 | 469 |
raise ValidationError(_('Invalid file format. (duration, line %d)') % (i + 1)) |
436 | 470 | |
437 | 471 |
try: |
438 |
event.full_clean(exclude=exclude)
|
|
472 |
event.full_clean(exclude=['desk', 'meeting_type'])
|
|
439 | 473 |
except ValidationError as e: |
440 | 474 |
errors = [_('Invalid file format:\n')] |
441 | 475 |
for label, field_errors in e.message_dict.items(): |
... | ... | |
449 | 483 |
raise ValidationError(errors) |
450 | 484 |
events.append(event) |
451 | 485 |
self.events = events |
486 |
self.warnings = warnings |
|
452 | 487 | |
453 | 488 |
@staticmethod |
454 | 489 |
def get_verbose_name(field_name): |
chrono/manager/templates/chrono/manager_agenda_settings.html | ||
---|---|---|
21 | 21 |
<ul class="extra-actions-menu"> |
22 | 22 |
<li><a rel="popup" href="{% url 'chrono-manager-agenda-edit' pk=object.id %}">{% trans 'Options' %}</a></li> |
23 | 23 |
<li><a rel="popup" class="action-duplicate" href="{% url 'chrono-manager-agenda-duplicate' pk=object.pk %}">{% trans 'Duplicate' %}</a></li> |
24 |
<li><a download href="{% url 'chrono-manager-agenda-export' pk=object.id %}">{% trans 'Export' %}</a></li> |
|
24 |
<li><a download href="{% url 'chrono-manager-agenda-export' pk=object.id %}">{% trans 'Export Configuration (JSON)' %}</a></li> |
|
25 |
{% if object.kind == 'events' %} |
|
26 |
<li><a download href="{% url 'chrono-manager-agenda-export-events' pk=object.pk %}">{% trans 'Export Events (CSV)' %}</a></li> |
|
27 |
{% endif %} |
|
25 | 28 |
{% if user.is_staff %} |
26 | 29 |
<li><a rel="popup" href="{% url 'chrono-manager-agenda-delete' pk=object.id %}">{% trans 'Delete' %}</a></li> |
27 | 30 |
{% endif %} |
chrono/manager/urls.py | ||
---|---|---|
73 | 73 |
views.agenda_import_events, |
74 | 74 |
name='chrono-manager-agenda-import-events', |
75 | 75 |
), |
76 |
url( |
|
77 |
r'^agendas/(?P<pk>\d+)/export-events$', |
|
78 |
views.agenda_export_events, |
|
79 |
name='chrono-manager-agenda-export-events', |
|
80 |
), |
|
76 | 81 |
url( |
77 | 82 |
r'^agendas/(?P<pk>\d+)/notifications$', |
78 | 83 |
views.agenda_notifications_settings, |
chrono/manager/views.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU Affero General Public License |
15 | 15 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
import csv |
|
17 | 18 |
import datetime |
18 | 19 |
import itertools |
19 | 20 |
import json |
... | ... | |
1330 | 1331 |
template_name = 'chrono/manager_import_events.html' |
1331 | 1332 |
agenda = None |
1332 | 1333 | |
1334 |
def set_agenda(self, **kwargs): |
|
1335 |
self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events') |
|
1336 | ||
1333 | 1337 |
def get_form_kwargs(self): |
1334 | 1338 |
kwargs = super(AgendaImportEventsView, self).get_form_kwargs() |
1335 | 1339 |
kwargs['agenda_pk'] = self.kwargs['pk'] |
... | ... | |
1338 | 1342 |
def form_valid(self, form): |
1339 | 1343 |
if form.events: |
1340 | 1344 |
# existing event slugs for this agenda |
1341 |
seen_slugs = set(self.agenda.event_set.values_list('slug', flat=True)) |
|
1342 | 1345 |
for event in form.events: |
1343 |
event.agenda_id = self.kwargs['pk']
|
|
1344 |
event.save(seen_slugs=seen_slugs) # optimization: seen_slugs
|
|
1346 |
event.agenda = self.agenda
|
|
1347 |
event.save()
|
|
1345 | 1348 |
messages.info(self.request, _('%d events have been imported.') % len(form.events)) |
1349 |
for event in form.warnings.values(): |
|
1350 |
messages.warning( |
|
1351 |
self.request, |
|
1352 |
_('Event "%s" start date has changed. Do not forget to notify the registrants.') |
|
1353 |
% (event.label or event.slug), |
|
1354 |
) |
|
1346 | 1355 |
return super(AgendaImportEventsView, self).form_valid(form) |
1347 | 1356 | |
1348 | 1357 | |
1349 | 1358 |
agenda_import_events = AgendaImportEventsView.as_view() |
1350 | 1359 | |
1351 | 1360 | |
1361 |
class AgendaExportEventsView(ManagedAgendaMixin, View): |
|
1362 |
template_name = 'chrono/manager_export_events.html' |
|
1363 |
agenda = None |
|
1364 | ||
1365 |
def set_agenda(self, **kwargs): |
|
1366 |
self.agenda = get_object_or_404(Agenda, pk=kwargs.get('pk'), kind='events') |
|
1367 | ||
1368 |
def get(self, request, *args, **kwargs): |
|
1369 |
response = HttpResponse(content_type='text/csv') |
|
1370 |
today = datetime.date.today() |
|
1371 |
response['Content-Disposition'] = 'attachment; filename="export_agenda_events_{}_{}.csv"'.format( |
|
1372 |
self.agenda.slug, today.strftime('%Y%m%d') |
|
1373 |
) |
|
1374 |
writer = csv.writer(response) |
|
1375 |
# headers |
|
1376 |
writer.writerow( |
|
1377 |
[ |
|
1378 |
_('date'), |
|
1379 |
_('time'), |
|
1380 |
_('number of places'), |
|
1381 |
_('number of places in waiting list'), |
|
1382 |
_('label'), |
|
1383 |
_('identifier'), |
|
1384 |
_('description'), |
|
1385 |
_('pricing'), |
|
1386 |
_('URL'), |
|
1387 |
_('publication date'), |
|
1388 |
_('duration'), |
|
1389 |
] |
|
1390 |
) |
|
1391 |
for event in self.agenda.event_set.all(): |
|
1392 |
start_datetime = localtime(event.start_datetime) |
|
1393 |
writer.writerow( |
|
1394 |
[ |
|
1395 |
start_datetime.strftime('%Y-%m-%d'), |
|
1396 |
start_datetime.strftime('%H:%M'), |
|
1397 |
event.places, |
|
1398 |
event.waiting_list_places, |
|
1399 |
event.label, |
|
1400 |
event.slug, |
|
1401 |
event.description, |
|
1402 |
event.pricing, |
|
1403 |
event.url, |
|
1404 |
event.publication_date.strftime('%Y-%m-%d') if event.publication_date else '', |
|
1405 |
event.duration, |
|
1406 |
] |
|
1407 |
) |
|
1408 |
return response |
|
1409 | ||
1410 | ||
1411 |
agenda_export_events = AgendaExportEventsView.as_view() |
|
1412 | ||
1413 | ||
1352 | 1414 |
class AgendaNotificationsSettingsView(ManagedAgendaMixin, UpdateView): |
1353 | 1415 |
template_name = 'chrono/manager_agenda_notifications_form.html' |
1354 | 1416 |
model = AgendaNotificationsSettings |
tests/test_manager.py | ||
---|---|---|
1404 | 1404 |
assert Event.objects.count() == 0 |
1405 | 1405 | |
1406 | 1406 | |
1407 |
def test_export_events(app, admin_user): |
|
1408 |
agenda = Agenda.objects.create(label=u'Foo bar') |
|
1409 | ||
1410 |
app = login(app) |
|
1411 |
resp = app.get('/manage/agendas/%s/export-events' % agenda.id) |
|
1412 |
csv_export = resp.text |
|
1413 |
assert ( |
|
1414 |
csv_export |
|
1415 |
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n' |
|
1416 |
) |
|
1417 | ||
1418 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id) |
|
1419 |
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,00:30,10', 'text/csv') |
|
1420 |
resp.form.submit(status=302) |
|
1421 | ||
1422 |
resp = app.get('/manage/agendas/%s/export-events' % agenda.id) |
|
1423 |
csv_export = resp.text |
|
1424 |
assert ( |
|
1425 |
csv_export |
|
1426 |
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n' |
|
1427 |
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n' |
|
1428 |
) |
|
1429 | ||
1430 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id) |
|
1431 |
resp.form['events_csv_file'] = Upload( |
|
1432 |
't.csv', |
|
1433 |
b'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90', |
|
1434 |
'text/csv', |
|
1435 |
) |
|
1436 |
resp.form.submit(status=302) |
|
1437 |
resp = app.get('/manage/agendas/%s/export-events' % agenda.id) |
|
1438 |
csv_export = resp.text |
|
1439 |
assert ( |
|
1440 |
csv_export |
|
1441 |
== 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n' |
|
1442 |
'2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n' |
|
1443 |
'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90\r\n' |
|
1444 |
) |
|
1445 | ||
1446 | ||
1447 |
def test_export_events_wrong_kind(app, admin_user): |
|
1448 |
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings') |
|
1449 | ||
1450 |
app = login(app) |
|
1451 |
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404) |
|
1452 |
agenda.kind = 'virtual' |
|
1453 |
agenda.save() |
|
1454 |
app.get('/manage/agendas/%s/export-events' % agenda.id, status=404) |
|
1455 | ||
1456 | ||
1407 | 1457 |
def test_import_events(app, admin_user): |
1408 | 1458 |
agenda = Agenda(label=u'Foo bar') |
1409 | 1459 |
agenda.save() |
... | ... | |
1549 | 1599 |
assert event.slug == 'slug' |
1550 | 1600 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
1551 | 1601 |
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv') |
1552 |
resp = resp.form.submit(status=200) |
|
1553 |
assert 'Event with this Agenda and Identifier already exists.' in resp.text |
|
1554 |
assert '__all__' not in resp.text |
|
1602 |
resp = resp.form.submit(status=302) |
|
1603 |
assert Event.objects.count() == 1 |
|
1604 |
event = Event.objects.latest('pk') |
|
1605 |
assert event.slug == 'slug' |
|
1555 | 1606 | |
1556 | 1607 |
# additional optional attributes |
1557 | 1608 |
Event.objects.all().delete() |
... | ... | |
1602 | 1653 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
1603 | 1654 |
resp.form['events_csv_file'] = Upload( |
1604 | 1655 |
't.csv', |
1605 |
b'2016-09-16,18:00,10,5,labela,,,pricing,\n' |
|
1606 |
b'2016-09-17,18:00,10,5,labela,,,pricing,\n' |
|
1607 |
b'2016-09-18,18:00,10,5,labela,,,pricing,\n' |
|
1656 |
b'2016-09-16,18:00,10,5,labela,labelb,,pricing,\n'
|
|
1657 |
b'2016-09-17,18:00,10,5,labela,labelb-1,,pricing,\n'
|
|
1658 |
b'2016-09-18,18:00,10,5,labela,labelb-2,,pricing,\n'
|
|
1608 | 1659 |
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n' |
1609 | 1660 |
b'2016-09-18,18:00,10,5,labelb,,,pricing,\n', |
1610 | 1661 |
'text/csv', |
1611 | 1662 |
) |
1612 | 1663 |
with CaptureQueriesContext(connection) as ctx: |
1613 | 1664 |
resp = resp.form.submit(status=302) |
1614 |
assert len(ctx.captured_queries) == 24
|
|
1665 |
assert len(ctx.captured_queries) == 22
|
|
1615 | 1666 |
assert Event.objects.count() == 5 |
1667 |
assert set(Event.objects.values_list('slug', flat=True)) == set( |
|
1668 |
['labelb', 'labelb-1', 'labelb-2', 'labelb-3', 'labelb-4'] |
|
1669 |
) |
|
1616 | 1670 | |
1617 | 1671 |
# forbidden numerical slug |
1618 | 1672 |
Event.objects.all().delete() |
... | ... | |
1622 | 1676 |
assert 'value cannot be a number' in resp.text |
1623 | 1677 |
assert 'Identifier:' in resp.text # verbose_name is shown, not field name ('slug:') |
1624 | 1678 | |
1625 |
# handle duplicated slug |
|
1626 |
Event.objects.all().delete() |
|
1679 | ||
1680 |
def test_import_events_existing_event(app, admin_user, freezer): |
|
1681 |
agenda = Agenda.objects.create(label=u'Foo bar') |
|
1682 | ||
1683 |
app = login(app) |
|
1627 | 1684 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
1628 | 1685 |
resp.form['events_csv_file'] = Upload( |
1629 |
't.csv', b'2016-09-16,18:00,10,5,label,slug\n' b'2016-09-16,18:00,10,5,label,slug\n', 'text/csv',
|
|
1686 |
't.csv', b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,18:00,10,5,label,slug\n', 'text/csv', |
|
1630 | 1687 |
) |
1631 |
resp = resp.form.submit(status=200) |
|
1632 |
assert 'duplicated event identifiers' in resp.text |
|
1688 |
resp.form.submit(status=302) |
|
1689 |
assert agenda.event_set.count() == 1 |
|
1690 |
event = Event.objects.latest('pk') |
|
1691 | ||
1692 |
def check_import(date, time, with_alert): |
|
1693 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
|
1694 |
resp.form['events_csv_file'] = Upload( |
|
1695 |
't.csv', b'%s,%s,10,5,label,slug\n' % (date.encode(), time.encode()), 'text/csv', |
|
1696 |
) |
|
1697 |
resp = resp.form.submit(status=302).follow() |
|
1698 |
assert agenda.event_set.count() == 1 |
|
1699 |
event.refresh_from_db() |
|
1700 |
if with_alert: |
|
1701 |
assert ( |
|
1702 |
'<li class="warning">Event "label" start date has changed. Do not forget to notify the registrants.</li>' |
|
1703 |
in resp.text |
|
1704 |
) |
|
1705 |
else: |
|
1706 |
assert ( |
|
1707 |
'<li class="warning">Event "label" start date has changed. Do not forget to notify the registrants.</li>' |
|
1708 |
not in resp.text |
|
1709 |
) |
|
1710 |
assert event.start_datetime == make_aware( |
|
1711 |
datetime.datetime(*[int(v) for v in date.split('-')], *[int(v) for v in time.split(':')]) |
|
1712 |
) |
|
1713 | ||
1714 |
# change date or time |
|
1715 |
# event in the past, no alert, with or without booking |
|
1716 |
Booking.objects.create( |
|
1717 |
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30)) |
|
1718 |
) |
|
1719 |
check_import('2016-09-15', '18:00', False) # change date |
|
1720 |
check_import('2016-09-15', '17:00', False) # change time |
|
1721 |
# available booking |
|
1722 |
Booking.objects.create(event=event) |
|
1723 |
check_import('2016-09-14', '17:00', False) # change date |
|
1724 |
check_import('2016-09-14', '16:00', False) # change time |
|
1725 | ||
1726 |
# date in the future |
|
1727 |
freezer.move_to('2016-09-01') |
|
1728 |
# warn if available booking only |
|
1729 |
check_import('2016-09-13', '16:00', True) # change date |
|
1730 |
check_import('2016-09-13', '15:00', True) # change time |
|
1731 |
# no available booking |
|
1732 |
Booking.objects.all().delete() |
|
1733 |
Booking.objects.create( |
|
1734 |
event=event, cancellation_datetime=make_aware(datetime.datetime(2017, 5, 20, 10, 30)) |
|
1735 |
) |
|
1736 |
check_import('2016-09-12', '15:00', False) # change date |
|
1737 |
check_import('2016-09-12', '14:00', False) # change time |
|
1738 | ||
1739 |
# check there is a message per changed event |
|
1740 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
|
1741 |
resp.form['events_csv_file'] = Upload( |
|
1742 |
't.csv', b'2016-09-16,18:00,10,5,label,slug\n2016-09-16,19:00,10,5,label,other_slug\n', 'text/csv', |
|
1743 |
) |
|
1744 |
resp.form.submit(status=302) |
|
1745 |
assert agenda.event_set.count() == 2 |
|
1746 |
event2 = Event.objects.latest('pk') |
|
1747 |
Booking.objects.create(event=event) |
|
1748 |
Booking.objects.create(event=event2) |
|
1749 | ||
1750 |
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200) |
|
1751 |
resp.form['events_csv_file'] = Upload( |
|
1752 |
't.csv', |
|
1753 |
b'2016-09-17,18:00,10,5,label,slug\n2016-09-17,19:00,10,5,,other_slug\n2016-09-17,20:00,10,5,,other_slug\n', |
|
1754 |
'text/csv', |
|
1755 |
) |
|
1756 |
resp = resp.form.submit(status=302).follow() |
|
1757 |
assert agenda.event_set.count() == 2 |
|
1758 |
assert ( |
|
1759 |
resp.text.count( |
|
1760 |
'Event "label" start date has changed. Do not forget to notify the registrants.' |
|
1761 |
) |
|
1762 |
== 1 |
|
1763 |
) |
|
1764 |
assert ( |
|
1765 |
resp.text.count( |
|
1766 |
'Event "other_slug" start date has changed. Do not forget to notify the registrants.' |
|
1767 |
) |
|
1768 |
== 1 |
|
1769 |
) |
|
1770 | ||
1771 | ||
1772 |
def test_import_events_wrong_kind(app, admin_user): |
|
1773 |
agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings') |
|
1774 | ||
1775 |
app = login(app) |
|
1776 |
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404) |
|
1777 |
agenda.kind = 'virtual' |
|
1778 |
agenda.save() |
|
1779 |
app.get('/manage/agendas/%s/import-events' % agenda.id, status=404) |
|
1633 | 1780 | |
1634 | 1781 | |
1635 | 1782 |
def test_add_meetings_agenda(app, admin_user): |
... | ... | |
3321 | 3468 |
agenda.save() |
3322 | 3469 | |
3323 | 3470 |
app = login(app) |
3324 |
resp = app.get('/manage/agendas/%s/settings' % agenda.id) |
|
3325 | 3471 |
with freezegun.freeze_time('2020-06-15'): |
3326 |
resp = resp.click('Export')
|
|
3472 |
resp = app.get('/manage/agendas/%s/export' % agenda.id)
|
|
3327 | 3473 |
assert resp.headers['content-type'] == 'application/json' |
3328 | 3474 |
assert resp.headers['content-disposition'] == 'attachment; filename="export_agenda_foo-bar_20200615.json"' |
3329 | 3475 |
agenda_export = resp.text |
3330 |
- |