combo/tests/test_applification_api.py

1687 lines
65 KiB
Python

import datetime
import io
import json
import os
import re
import tarfile
import uuid
from unittest import mock
import pytest
from django.apps import apps
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.files import File
from django.core.files.storage import default_storage
from requests.exceptions import ConnectionError
from requests.models import Response
from combo.apps.export_import.models import Application, ApplicationAsyncJob, ApplicationElement
from combo.apps.family.models import WeeklyAgendaCell
from combo.apps.lingo.models import CreditsCell, InvoicesCell, PaymentBackend, PaymentsCell, Regie
from combo.apps.search.models import SearchCell
from combo.apps.wcs.models import WcsCardCell, WcsCategoryCell, WcsFormCell
from combo.data.models import LinkCell, LinkListCell, Page, PageSnapshot, TextCell
from .wcs.utils import MockedRequestResponse, mocked_requests_send
pytestmark = pytest.mark.django_db
def test_object_types(settings, app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
resp = app.get('/api/export-import/')
assert resp.json == {
'data': [
{
'id': 'pages',
'text': 'Pages',
'singular': 'Page',
'urls': {'list': 'http://testserver/api/export-import/pages/'},
},
{
'id': 'roles',
'text': 'Roles',
'singular': 'Role',
'urls': {'list': 'http://testserver/api/export-import/roles/'},
'minor': True,
},
]
}
with mock.patch('combo.apps.export_import.api_views.is_portal_agent') as is_portal_agent:
is_portal_agent.return_value = True
resp = app.get('/api/export-import/')
assert resp.json == {
'data': [
{
'id': 'portal-agent-pages',
'text': 'Pages (agent portal)',
'singular': 'Page (agent portal)',
'urls': {'list': 'http://testserver/api/export-import/pages/'},
},
{
'id': 'roles',
'text': 'Roles',
'singular': 'Role',
'urls': {'list': 'http://testserver/api/export-import/roles/'},
'minor': True,
},
]
}
def test_list(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
Page.objects.all().delete()
page = Page(title='Test', slug='test', template_name='standard')
page.save()
page2 = Page(title='Child', slug='child', template_name='standard', parent=page)
page2.save()
group = Group.objects.create(name='group1')
resp = app.get('/api/export-import/pages/')
assert resp.json == {
'data': [
{
'id': f'{page.uuid}',
'text': 'Test',
'type': 'pages',
'indent': 0,
'order': 0,
'urls': {
'export': f'http://testserver/api/export-import/pages/{page.uuid}/',
'dependencies': f'http://testserver/api/export-import/pages/{page.uuid}/dependencies/',
'redirect': f'http://testserver/api/export-import/pages/{page.uuid}/redirect/',
},
},
{
'id': f'{page2.uuid}',
'text': 'Child',
'type': 'pages',
'indent': 1,
'order': 1,
'urls': {
'export': f'http://testserver/api/export-import/pages/{page2.uuid}/',
'dependencies': f'http://testserver/api/export-import/pages/{page2.uuid}/dependencies/',
'redirect': f'http://testserver/api/export-import/pages/{page2.uuid}/redirect/',
},
},
]
}
resp = app.get('/api/export-import/roles/')
assert resp.json == {
'data': [{'id': group.pk, 'text': 'group1', 'type': 'roles', 'urls': {}, 'uuid': None}]
}
def test_export_page(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
Page.objects.all().delete()
page = Page(title='Test', slug='test', template_name='standard')
page.save()
resp = app.get(f'/api/export-import/pages/{page.uuid}/')
assert resp.json['data']['fields']['title'] == 'Test'
app.get('/api/export-import/pages/%s/' % uuid.uuid4(), status=404)
def test_export_page_with_role(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
group = Group(name='plop')
group.save()
Page.objects.all().delete()
page = Page(title='Test', slug='test', template_name='standard')
page.save()
page.groups.set([group])
resp = app.get(f'/api/export-import/pages/{page.uuid}/')
assert resp.json['data']['fields']['groups'] == ['plop']
def test_page_dependencies(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
page = Page.objects.create(title='Test', slug='test', template_name='standard')
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/')
assert resp.json == {'data': [], 'err': 0}
app.get('/api/export-import/pages/%s/dependencies/' % uuid.uuid4(), status=404)
def test_page_dependencies_groups(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
group1 = Group(name='plop1')
group1.save()
group2 = Group(name='plop2')
group2.save()
Page.objects.all().delete()
page = Page(title='Test', slug='test', template_name='standard')
page.save()
page.groups.set([group1])
cell = TextCell(page=page, placeholder='content', text='Foobar', order=0)
cell.save()
cell.groups.set([group2])
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/')
# note: with hobo.agent.common installed, 'groups' will contain group slugs,
# not group id
assert resp.json == {
'data': [
{'id': group1.id, 'text': group1.name, 'type': 'roles', 'urls': {}, 'uuid': None},
{'id': group2.id, 'text': group2.name, 'type': 'roles', 'urls': {}, 'uuid': None},
],
'err': 0,
}
def test_page_dependencies_children(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
page = Page(title='Test', slug='test', template_name='standard')
page.save()
page2 = Page(title='Child', slug='child', template_name='standard', parent=page)
page2.save()
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/')
assert resp.json == {
'data': [
{
'id': f'{page2.uuid}',
'indent': 0,
'order': 0,
'text': 'Child',
'type': 'pages',
'urls': {
'dependencies': f'http://testserver/api/export-import/pages/{page2.uuid}/dependencies/',
'export': f'http://testserver/api/export-import/pages/{page2.uuid}/',
'redirect': f'http://testserver/api/export-import/pages/{page2.uuid}/redirect/',
},
},
],
'err': 0,
}
def test_page_redirect(app):
page = Page(title='Test', slug='test', template_name='standard')
page.save()
redirect_url = f'/api/export-import/pages/{page.uuid}/redirect/'
resp = app.get(redirect_url, status=302)
assert resp.location == f'/manage/pages/{page.pk}/'
resp = app.get(redirect_url + '?compare', status=302)
assert resp.location == f'/manage/pages/{page.pk}/'
resp = app.get(redirect_url + '?compare&version1=bar&version2=bar&application=foo', status=302)
assert (
resp.location == f'/manage/pages/{page.pk}/history/compare/?version1=bar&version2=bar&application=foo'
)
app.get('/api/export-import/pages/%s/redirect/' % uuid.uuid4(), status=404)
def create_bundle(elements, *args, **kwargs):
visible = kwargs.get('visible', True)
version_number = kwargs.get('version_number', '42.0')
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
manifest_json = {
'application': 'Test',
'slug': 'test',
'icon': 'foo.png',
'description': 'Foo Bar',
'documentation_url': 'http://foo.bar',
'visible': visible,
'version_number': version_number,
'version_notes': 'foo bar blah',
'elements': elements,
}
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode())
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
icon_fd = io.BytesIO(
b'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVQI12NoAAAAggCB3UNq9AAAAABJRU5ErkJggg=='
)
tarinfo = tarfile.TarInfo('foo.png')
tarinfo.size = len(icon_fd.getvalue())
tar.addfile(tarinfo, fileobj=icon_fd)
for path, obj in args:
tarinfo = tarfile.TarInfo(path)
if not hasattr(obj, 'get_serialized_page'):
continue
export_fd = io.BytesIO(json.dumps({'data': obj.get_serialized_page()}).encode())
tarinfo.size = len(export_fd.getvalue())
tar.addfile(tarinfo, fileobj=export_fd)
return tar_io.getvalue()
@pytest.fixture
def bundle(app, admin_user):
page, dummy = Page.objects.get_or_create(
slug='test', defaults={'title': 'Test Page', 'template_name': 'standard'}
)
return create_bundle(
[
{'type': 'pages', 'slug': f'{page.uuid}', 'name': 'Test Page', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
(f'pages/{page.uuid}', page),
)
def test_bundle_import(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
bundles = []
for version_number in ['42.0', '42.1']:
page, dummy = Page.objects.get_or_create(
slug='test', defaults={'title': 'Test Page', 'template_name': 'standard'}
)
bundle = create_bundle(
[
{'type': 'pages', 'slug': f'{page.uuid}', 'name': 'Test Page', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
(f'pages/{page.uuid}', page),
version_number=version_number,
)
bundles.append(bundle)
resp = app.put('/api/export-import/bundle-import/', bundles[0])
assert Page.objects.all().count() == 1
assert resp.json['err'] == 0
assert Application.objects.count() == 1
application = Application.objects.latest('pk')
assert application.slug == 'test'
assert application.name == 'Test'
assert application.description == 'Foo Bar'
assert application.documentation_url == 'http://foo.bar'
assert application.version_number == '42.0'
assert application.version_notes == 'foo bar blah'
assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name)
assert application.editable is False
assert application.visible is True
assert ApplicationElement.objects.count() == 1
for page in Page.objects.all():
last_snapshot = PageSnapshot.objects.filter(page=page).latest('pk')
assert last_snapshot.comment == 'Application (Test)'
assert last_snapshot.application_slug == 'test'
assert last_snapshot.application_version == '42.0'
# check editable flag is kept on install
application.editable = True
application.save()
# create link to element not present in manifest: it should be unlinked
last_page = Page.objects.latest('pk')
ApplicationElement.objects.create(
application=application,
content_type=ContentType.objects.get_for_model(Page),
object_id=last_page.pk + 1,
)
# check update
resp = app.put('/api/export-import/bundle-import/', bundles[1])
job_url = resp.json['url']
resp = app.get(job_url)
assert resp.json['data']['status'] == 'completed'
assert resp.json['data']['completion_status'] == '1/1 (100%)'
assert Page.objects.all().count() == 1
assert resp.json['err'] == 0
assert Application.objects.count() == 1
application = Application.objects.latest('pk')
assert application.editable is False
assert ApplicationElement.objects.count() == 1
assert (
ApplicationElement.objects.filter(
application=application,
content_type=ContentType.objects.get_for_model(Page),
object_id=last_page.pk + 1,
).exists()
is False
)
for page in Page.objects.all():
last_snapshot = PageSnapshot.objects.filter(page=page).latest('pk')
assert last_snapshot.comment == 'Application (Test)'
assert last_snapshot.application_slug == 'test'
assert last_snapshot.application_version == '42.1'
# bad file format
resp = app.put('/api/export-import/bundle-import/', b'garbage', status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
# missing manifest
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
foo_fd = io.BytesIO(json.dumps({'foo': 'bar'}, indent=2).encode())
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue(), status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
# missing component
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
manifest_json = {
'application': 'Test',
'slug': 'test',
'elements': [{'type': 'pages', 'slug': str(uuid.uuid4()), 'name': 'foo'}],
}
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode())
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
resp = app.put('/api/export-import/bundle-import/', tar_io.getvalue())
job_url = resp.json['url']
resp = app.get(job_url)
assert resp.json['data']['status'] == 'failed'
job = ApplicationAsyncJob.objects.get(uuid=job_url.split('/')[-3])
assert job.status == 'failed'
assert (
job.exception
== 'Invalid tar file, missing component pages/%s.' % manifest_json['elements'][0]['slug']
)
def test_bundle_import_pages_position(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
page1 = Page.objects.create(
slug='test1',
title='Test Page 1',
template_name='standard',
)
page11 = Page.objects.create(
slug='test11',
title='Test Page 11',
template_name='standard',
parent=page1,
)
page12 = Page.objects.create(
slug='test12',
title='Test Page 12',
template_name='standard',
parent=page1,
)
page121 = Page.objects.create(
slug='test121',
title='Test Page 121',
template_name='standard',
parent=page12,
)
page13 = Page.objects.create(
slug='test13',
title='Test Page 13',
template_name='standard',
parent=page1,
)
page2 = Page.objects.create(
slug='test2',
title='Test Page 2',
template_name='standard',
)
bundle = create_bundle(
[
{'type': 'pages', 'slug': f'{page1.uuid}', 'name': 'Test Page 1', 'auto-dependency': False},
{'type': 'pages', 'slug': f'{page11.uuid}', 'name': 'Test Page 11', 'auto-dependency': False},
{'type': 'pages', 'slug': f'{page12.uuid}', 'name': 'Test Page 12', 'auto-dependency': False},
{'type': 'pages', 'slug': f'{page121.uuid}', 'name': 'Test Page 121', 'auto-dependency': False},
{'type': 'pages', 'slug': f'{page13.uuid}', 'name': 'Test Page 13', 'auto-dependency': False},
{'type': 'pages', 'slug': f'{page2.uuid}', 'name': 'Test Page 2', 'auto-dependency': False},
],
(f'pages/{page1.uuid}', page1),
(f'pages/{page11.uuid}', page11),
(f'pages/{page12.uuid}', page12),
(f'pages/{page121.uuid}', page121),
(f'pages/{page13.uuid}', page13),
(f'pages/{page2.uuid}', page2),
)
# delete pages
Page.objects.all().delete()
# and create other pages
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# pages from application are placed at the end
assert Page.objects.all().count() == 9
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page4.uuid).order == 2
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 3
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page1.uuid).order == 4
assert Page.objects.get(uuid=page1.uuid).parent is None
assert Page.objects.get(uuid=page11.uuid).order == 5
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page12.uuid).order == 6
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page121.uuid).order == 7
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 8
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 9
assert Page.objects.get(uuid=page2.uuid).parent is None
# delete pages
Page.objects.all().delete()
# create only page2, page3, page4, page41 in this order
page2 = Page.objects.create(slug='test2', title='Test Page 2', template_name='standard', uuid=page2.uuid)
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# pages from application are placed before page3
assert Page.objects.all().count() == 9
assert Page.objects.get(uuid=page1.uuid).order == 1
assert Page.objects.get(uuid=page1.uuid).parent is None
assert Page.objects.get(uuid=page11.uuid).order == 2
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page12.uuid).order == 3
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page121.uuid).order == 4
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 5
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 6
assert Page.objects.get(uuid=page2.uuid).parent is None
assert Page.objects.get(uuid=page3.uuid).order == 7
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page4.uuid).order == 8
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 9
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
# delete pages
Page.objects.all().delete()
# create only page3, page2, page4, page41 in this order
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page2 = Page.objects.create(slug='test2', title='Test Page 2', template_name='standard', uuid=page2.uuid)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# pages from application are placed between page3 and page4
assert Page.objects.all().count() == 9
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent is None
assert Page.objects.get(uuid=page11.uuid).order == 3
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page12.uuid).order == 4
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page121.uuid).order == 5
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 6
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 7
assert Page.objects.get(uuid=page2.uuid).parent is None
assert Page.objects.get(uuid=page4.uuid).order == 8
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 9
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
# delete pages
Page.objects.all().delete()
# create only page3, page4, page41, page2 in this order
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
page2 = Page.objects.create(slug='test2', title='Test Page 2', template_name='standard', uuid=page2.uuid)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# pages from application are placed after page4
assert Page.objects.all().count() == 9
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page4.uuid).order == 2
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 3
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page1.uuid).order == 4
assert Page.objects.get(uuid=page1.uuid).parent is None
assert Page.objects.get(uuid=page11.uuid).order == 5
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page12.uuid).order == 6
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page121.uuid).order == 7
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 8
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 9
assert Page.objects.get(uuid=page2.uuid).parent is None
# delete pages
Page.objects.all().delete()
# create page3, page4, page41, page42 and place page2 under page3
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page2 = Page.objects.create(
slug='test2',
title='Test Page 2',
template_name='standard',
uuid=page2.uuid,
parent=page3,
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
page42 = Page.objects.create(
slug='test42',
title='Test Page 42',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# pages from application are placed under page3
assert Page.objects.all().count() == 10
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page11.uuid).order == 3
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page12.uuid).order == 4
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page121.uuid).order == 5
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 6
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 7
assert Page.objects.get(uuid=page2.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page4.uuid).order == 8
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 9
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page42.uuid).order == 10
assert Page.objects.get(uuid=page42.uuid).parent.uuid == page4.uuid
# delete pages
Page.objects.all().delete()
# create page3, page4, page41, page42 and place page2 under page3, and page12 between page41 and page42
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page2 = Page.objects.create(
slug='test2',
title='Test Page 2',
template_name='standard',
uuid=page2.uuid,
parent=page3,
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
page12 = Page.objects.create(
slug='test12',
title='Test Page 12',
template_name='standard',
uuid=page12.uuid,
parent=page4,
)
page42 = Page.objects.create(
slug='test42',
title='Test Page 42',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# page1 is placed under page3, pages 11, 12, 121, 13 are placed between page41 and page42
assert Page.objects.all().count() == 10
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page2.uuid).order == 3
assert Page.objects.get(uuid=page2.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page4.uuid).order == 4
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 5
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page11.uuid).order == 6
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page12.uuid).order == 7
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page121.uuid).order == 8
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 9
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page42.uuid).order == 10
assert Page.objects.get(uuid=page42.uuid).parent.uuid == page4.uuid
# again, import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# no changes
assert Page.objects.all().count() == 10
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page2.uuid).order == 3
assert Page.objects.get(uuid=page2.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page4.uuid).order == 4
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 5
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page11.uuid).order == 6
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page12.uuid).order == 7
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page121.uuid).order == 8
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page13.uuid).order == 9
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page42.uuid).order == 10
assert Page.objects.get(uuid=page42.uuid).parent.uuid == page4.uuid
# delete pages
Page.objects.all().delete()
# create page3, page4, page41, page42 and place page2 under page3, page11 between page41 and page42 and page121 under page2
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page2 = Page.objects.create(
slug='test2',
title='Test Page 2',
template_name='standard',
uuid=page2.uuid,
parent=page3,
)
page121 = Page.objects.create(
slug='test121',
title='Test Page 121',
template_name='standard',
uuid=page121.uuid,
parent=page2,
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page41 = Page.objects.create(
slug='test41',
title='Test Page 41',
template_name='standard',
parent=page4,
)
page11 = Page.objects.create(
slug='test11',
title='Test Page 11',
template_name='standard',
uuid=page11.uuid,
parent=page4,
)
page42 = Page.objects.create(
slug='test42',
title='Test Page 42',
template_name='standard',
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# page1 is placed under page3, pages 11, 12, 13 are placed between page41 and page42, page 121 stays under page2
assert Page.objects.all().count() == 10
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page2.uuid).order == 3
assert Page.objects.get(uuid=page2.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page121.uuid).order == 4
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page2.uuid
assert Page.objects.get(uuid=page4.uuid).order == 5
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 6
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page11.uuid).order == 7
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page12.uuid).order == 8
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page13.uuid).order == 9
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page42.uuid).order == 10
assert Page.objects.get(uuid=page42.uuid).parent.uuid == page4.uuid
# again, import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# no changes
assert Page.objects.all().count() == 10
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page1.uuid).order == 2
assert Page.objects.get(uuid=page1.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page2.uuid).order == 3
assert Page.objects.get(uuid=page2.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page121.uuid).order == 4
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page2.uuid
assert Page.objects.get(uuid=page4.uuid).order == 5
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page41.uuid).order == 6
assert Page.objects.get(uuid=page41.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page11.uuid).order == 7
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page12.uuid).order == 8
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page13.uuid).order == 9
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page42.uuid).order == 10
assert Page.objects.get(uuid=page42.uuid).parent.uuid == page4.uuid
# delete pages
Page.objects.all().delete()
# create page3, page4, place page12 under page3, page11 under page4
page3 = Page.objects.create(
slug='test3',
title='Test Page 3',
template_name='standard',
)
page12 = Page.objects.create(
slug='test12',
title='Test Page 12',
template_name='standard',
uuid=page12.uuid,
parent=page3,
)
page4 = Page.objects.create(
slug='test4',
title='Test Page 4',
template_name='standard',
)
page11 = Page.objects.create(
slug='test11',
title='Test Page 11',
template_name='standard',
uuid=page11.uuid,
parent=page4,
)
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundle)
assert resp.json['err'] == 0
# page1 and page2 are placed after page4, but can not decide if page13 should be place next to page11 or page12.
assert Page.objects.all().count() == 8
assert Page.objects.get(uuid=page3.uuid).order == 1
assert Page.objects.get(uuid=page3.uuid).parent is None
assert Page.objects.get(uuid=page12.uuid).order == 2
assert Page.objects.get(uuid=page12.uuid).parent.uuid == page3.uuid
assert Page.objects.get(uuid=page121.uuid).order == 3
assert Page.objects.get(uuid=page121.uuid).parent.uuid == page12.uuid
assert Page.objects.get(uuid=page4.uuid).order == 4
assert Page.objects.get(uuid=page4.uuid).parent is None
assert Page.objects.get(uuid=page11.uuid).order == 5
assert Page.objects.get(uuid=page11.uuid).parent.uuid == page4.uuid
assert Page.objects.get(uuid=page1.uuid).order == 6
assert Page.objects.get(uuid=page1.uuid).parent is None
assert Page.objects.get(uuid=page13.uuid).order == 7
assert Page.objects.get(uuid=page13.uuid).parent.uuid == page1.uuid
assert Page.objects.get(uuid=page2.uuid).order == 8
assert Page.objects.get(uuid=page2.uuid).parent is None
def test_bundle_declare(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
page, dummy = Page.objects.get_or_create(
slug='test', defaults={'title': 'Test Page', 'template_name': 'standard'}
)
bundle = create_bundle(
[
{'type': 'pages', 'slug': f'{page.uuid}', 'name': 'Test Page', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
(f'pages/{page.uuid}', page),
visible=False,
)
resp = app.put('/api/export-import/bundle-declare/', bundle)
job_url = resp.json['url']
resp = app.get(job_url)
assert resp.json['data']['status'] == 'completed'
assert resp.json['data']['completion_status'] == '1/1 (100%)'
assert Page.objects.all().count() == 1
assert resp.json['err'] == 0
assert Application.objects.count() == 1
application = Application.objects.latest('pk')
assert application.slug == 'test'
assert application.name == 'Test'
assert application.description == 'Foo Bar'
assert application.documentation_url == 'http://foo.bar'
assert application.version_number == '42.0'
assert application.version_notes == 'foo bar blah'
assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name)
assert application.editable is True
assert application.visible is False
assert ApplicationElement.objects.count() == 1
page, dummy = Page.objects.get_or_create(
slug='test', defaults={'title': 'Test Page', 'template_name': 'standard'}
)
bundle = create_bundle(
[
{'type': 'pages', 'slug': f'{page.uuid}', 'name': 'Test Page', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
(f'pages/{page.uuid}', page),
visible=True,
)
# create link to element not present in manifest: it should be unlinked
last_page = Page.objects.latest('pk')
ApplicationElement.objects.create(
application=application,
content_type=ContentType.objects.get_for_model(Page),
object_id=last_page.pk + 1,
)
# and remove a page to have an unkown reference in manifest
Page.objects.all().delete()
resp = app.put('/api/export-import/bundle-declare/', bundle)
assert Application.objects.count() == 1
application = Application.objects.latest('pk')
assert application.visible is True
assert ApplicationElement.objects.count() == 0
# bad file format
resp = app.put('/api/export-import/bundle-declare/', b'garbage', status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
# missing manifest
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
foo_fd = io.BytesIO(json.dumps({'foo': 'bar'}, indent=2).encode())
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue(), status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
# missing component
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
manifest_json = {
'application': 'Test',
'slug': 'test',
'elements': [{'type': 'pages', 'slug': str(uuid.uuid4()), 'name': 'foo'}],
}
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode())
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
resp = app.put('/api/export-import/bundle-declare/', tar_io.getvalue())
job_url = resp.json['url']
resp = app.get(job_url)
assert resp.json['data']['status'] == 'failed'
job = ApplicationAsyncJob.objects.get(uuid=job_url.split('/')[-3])
assert job.status == 'failed'
assert (
job.exception
== 'Invalid tar file, missing component pages/%s.' % manifest_json['elements'][0]['slug']
)
def test_bundle_unlink(app, admin_user, bundle):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
application = Application.objects.create(
name='Test',
slug='test',
version_number='42.0',
)
other_application = Application.objects.create(
name='Other Test',
slug='other-test',
version_number='42.0',
)
page = Page.objects.latest('pk')
ApplicationElement.objects.create(
application=application,
content_object=page,
)
ApplicationElement.objects.create(
application=application,
content_type=ContentType.objects.get_for_model(Page),
object_id=page.pk + 1,
)
ApplicationElement.objects.create(
application=other_application,
content_object=page,
)
ApplicationElement.objects.create(
application=other_application,
content_type=ContentType.objects.get_for_model(Page),
object_id=page.pk + 1,
)
assert Application.objects.count() == 2
assert ApplicationElement.objects.count() == 4
app.post('/api/export-import/unlink/', {'application': 'test'})
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 2
assert ApplicationElement.objects.filter(
application=other_application,
content_type=ContentType.objects.get_for_model(Page),
object_id=page.pk,
).exists()
assert ApplicationElement.objects.filter(
application=other_application,
content_type=ContentType.objects.get_for_model(Page),
object_id=page.pk + 1,
).exists()
# again
app.post('/api/export-import/unlink/', {'application': 'test'})
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 2
def test_bundle_check(app, admin_user):
app.authorization = ('Basic', (admin_user.username, admin_user.username))
bundles = []
for version_number in ['1.0', '2.0']:
page, dummy = Page.objects.get_or_create(
slug='test', defaults={'title': 'Test Page', 'template_name': 'standard'}
)
bundle = create_bundle(
[
{'type': 'pages', 'slug': f'{page.uuid}', 'name': 'Test Page', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
(f'pages/{page.uuid}', page),
version_number=version_number,
)
bundles.append(bundle)
page_uuid = str(Page.objects.last().uuid)
Page.objects.all().delete()
PageSnapshot.objects.all().delete()
incomplete_bundles = []
for manifest_json in [{'slug': 'test'}, {'version_number': '1.0'}]:
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode())
tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue())
tar.addfile(tarinfo, fileobj=manifest_fd)
incomplete_bundles.append(tar_io.getvalue())
# incorrect bundles, missing information
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[0])
assert resp.json == {'data': {}}
resp = app.put('/api/export-import/bundle-check/', incomplete_bundles[1])
assert resp.json == {'data': {}}
# not yet imported
resp = app.put('/api/export-import/bundle-check/', bundles[0])
assert resp.json == {
'data': {
'differences': [],
'no_history_elements': [],
'unknown_elements': [
{'slug': page_uuid, 'type': 'pages'},
],
'legacy_elements': [],
}
}
# import bundle
resp = app.put('/api/export-import/bundle-import/', bundles[0])
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 1
# remove application links
Application.objects.all().delete()
resp = app.put('/api/export-import/bundle-check/', bundles[0])
assert resp.json == {
'data': {
'differences': [],
'no_history_elements': [],
'unknown_elements': [],
'legacy_elements': [
{
'slug': page_uuid,
'text': 'Test Page',
'type': 'pages',
'url': 'http://testserver/api/export-import/pages/%s/redirect/' % page_uuid,
}
],
}
}
# import bundle again, recreate links
resp = app.put('/api/export-import/bundle-import/', bundles[0])
assert Application.objects.count() == 1
assert ApplicationElement.objects.count() == 1
# no changes since last import
resp = app.put('/api/export-import/bundle-check/', bundles[0])
assert resp.json == {
'data': {
'differences': [],
'unknown_elements': [],
'no_history_elements': [],
'legacy_elements': [],
}
}
# add local changes
snapshots = {}
for page in Page.objects.all():
old_snapshot = PageSnapshot.objects.filter(page=page).latest('pk')
PageSnapshot.take(page=page, comment='local changes')
new_snapshot = PageSnapshot.objects.filter(page=page).latest('pk')
assert new_snapshot.pk > old_snapshot.pk
snapshots['page:%s' % page.slug] = (old_snapshot.pk, new_snapshot.pk)
# and check
resp = app.put('/api/export-import/bundle-check/', bundles[0])
assert resp.json == {
'data': {
'differences': [
{
'slug': page_uuid,
'type': 'pages',
'url': 'http://testserver/manage/pages/%s/history/compare/?version1=%s&version2=%s'
% (page.pk, *snapshots['page:test']),
}
],
'unknown_elements': [],
'no_history_elements': [],
'legacy_elements': [],
}
}
# update bundle
resp = app.put('/api/export-import/bundle-import/', bundles[1])
# and check
resp = app.put('/api/export-import/bundle-check/', bundles[1])
assert resp.json == {
'data': {
'differences': [],
'unknown_elements': [],
'no_history_elements': [],
'legacy_elements': [],
}
}
# snapshots without application info
PageSnapshot.objects.update(application_slug=None, application_version=None)
resp = app.put('/api/export-import/bundle-check/', bundles[1])
assert resp.json == {
'data': {
'differences': [],
'unknown_elements': [],
'no_history_elements': [
{'slug': page_uuid, 'type': 'pages'},
],
'legacy_elements': [],
}
}
# bad file format
resp = app.put('/api/export-import/bundle-check/', b'garbage', status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file'
# missing manifest
tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar:
foo_fd = io.BytesIO(json.dumps({'foo': 'bar'}, indent=2).encode())
tarinfo = tarfile.TarInfo('foo.json')
tarinfo.size = len(foo_fd.getvalue())
tar.addfile(tarinfo, fileobj=foo_fd)
resp = app.put('/api/export-import/bundle-check/', tar_io.getvalue(), status=400)
assert resp.json['err']
assert resp.json['err_desc'] == 'Invalid tar file, missing manifest'
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_card_models(mock_send, app, admin_user):
page = Page.objects.create(
title='Test',
slug='test',
template_name='standard',
extra_variables={'var1': '{{ cards|objects:"card_model_1"|getlist:"id"|list }}'},
)
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
app.authorization = ('Basic', (admin_user.username, admin_user.username))
with mock.patch('requests.Session.get') as requests_get:
requests_get.side_effect = ConnectionError()
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/', status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Unable to get WCS service (request-error)'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 500
requests_get.return_value = mock_resp
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/', status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Unable to get WCS service (request-error-status-500)'
with mock.patch('requests.Session.get') as requests_get:
mock_resp = Response()
mock_resp.status_code = 404
requests_get.return_value = mock_resp
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/', status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Unable to get WCS service (request-error-status-404)'
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'}))
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/', status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Unable to get WCS data'
data = {'data': []}
with mock.patch('requests.Session.get') as requests_get:
requests_get.return_value = MockedRequestResponse(content=json.dumps(data))
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/', status=400)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == 'Unable to get WCS data'
page.extra_variables = {}
page.sub_slug = 'foo'
page.save()
assert card_dep not in page.get_dependencies()
page.sub_slug = 'card_model_1_id'
page.save()
assert card_dep in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_cell_card_models(mock_send):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
cell = TextCell.objects.create(
page=page,
placeholder='content',
text='Foobar',
order=0,
condition='cards|objects:"card_model_1"|getlist:"id"|list',
)
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
def test_page_dependencies_link_cell():
page1 = Page.objects.create(title='Test', slug='test', template_name='standard')
page2 = Page.objects.create(title='Other page', slug='other', template_name='standard')
cell = LinkCell.objects.create(page=page1, placeholder='content', link_page=page2, order=0)
assert page2 in page1.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page1.get_dependencies()
def test_page_dependencies_linkslist_cell():
page1 = Page.objects.create(title='Test', slug='test', template_name='standard')
page2 = Page.objects.create(title='Other page', slug='other', template_name='standard')
links = LinkListCell.objects.create(order=1, page=page1, placeholder='content')
cell = LinkCell.objects.create(page=page1, placeholder=links.link_placeholder, link_page=page2, order=0)
assert page2 in page1.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page1.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_form_cell(mock_send, app, admin_user):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
cell = WcsFormCell(page=page, placeholder='content', order=0, formdef_reference='default:form-title')
cell.save()
assert {
'type': 'forms',
'id': 'form-title',
'text': cell.cached_title,
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/forms/form-title/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/forms/form-title/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/forms/form-title/redirect/',
},
} in page.get_dependencies()
app.authorization = ('Basic', (admin_user.username, admin_user.username))
resp = app.get(f'/api/export-import/pages/{page.uuid}/dependencies/')
assert resp.json['data'][0]['type'] == 'forms'
cell.mark_as_invalid(reason_code='foobar')
assert {
'type': 'forms',
'id': 'form-title',
'text': cell.cached_title,
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/forms/form-title/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/forms/form-title/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/forms/form-title/redirect/',
},
} not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_card_cell(mock_send):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
cell = WcsCardCell(page=page, placeholder='content', order=0, carddef_reference='default:card_model_1')
cell.save()
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.carddef_reference = 'default:card_model_1:custom_view'
cell.save()
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
cell.mark_as_valid()
cell.carddef_reference = 'default:card_model_2'
cell.card_ids = '{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}'
cell.save()
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
cell.mark_as_valid()
cell.card_ids = ''
cell.custom_schema = {
'cells': [
{'varname': '@custom@', 'template': '{{ cards|objects:"card_model_1" }}'},
]
}
cell.save()
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
other_page = Page.objects.create(title='Other Test', slug='other-test', template_name='standard')
cell.mark_as_valid()
cell.custom_schema = {'cells': [{'page': other_page.pk}]}
cell.save()
assert other_page in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert other_page not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_category_cell(mock_send):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
cell = WcsCategoryCell(page=page, placeholder='content', order=0, category_reference='default:test-3')
cell.save()
assert {
'type': 'forms-categories',
'id': 'test-3',
'text': 'Test 3',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/forms-categories/test-3/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/forms-categories/test-3/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/forms-xategories/test-3/redirect/',
},
} in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert {
'type': 'forms-categories',
'id': 'test-3',
'text': 'Test 3',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/forms-categories/test-3/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/forms-categories/test-3/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/forms-xategories/test-3/redirect/',
},
} not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_search_cell(mock_send):
page = Page.objects.create(title='Test', slug='test', template_name='standard')
page2 = Page.objects.create(title='second page', slug='second-page')
cell = SearchCell.objects.create(
page=page,
placeholder='content',
_search_services={'data': ['_text_page_second-page']},
order=0,
)
assert page2 in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page.get_dependencies()
cell.mark_as_valid()
cell._search_services = {'data': ['_text'], 'options': {'_text': {'target_page': page2.pk}}}
cell.save()
assert page2 in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert page2 not in page.get_dependencies()
cell.mark_as_valid()
Page.objects.create(slug='foo', title='Foo', sub_slug='card_model_1_id')
cell._search_services = {'data': ['cards:c21f969b:card_model_1']}
cell.save()
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell._search_services = {'data': ['cards:c21f969b:card_model_1__without-user__']}
cell.save()
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_weekly_agenda_cell(mock_send):
page = Page.objects.create(title='Family', slug='family', template_name='standard')
cell = WeeklyAgendaCell.objects.create(
page=page,
placeholder='content',
order=0,
)
fields = [
'agenda_references_template',
'agenda_categories',
'start_date_filter',
'end_date_filter',
'user_external_template',
]
for field in fields:
cell.mark_as_valid()
for f in fields:
setattr(cell, f, '')
setattr(cell, field, '{{ cards|objects:"card_model_1" }}')
cell.save()
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_invoices_cell(mock_send):
payment_backend = PaymentBackend.objects.create(
label='test1', slug='test1', service='dummy', service_options={'siret': '1234'}
)
Regie.objects.create(
label='Remote',
slug='remote',
payment_backend=payment_backend,
webservice_url='http://example.org/regie', # is_remote
)
page = Page.objects.create(title='xxx', slug='invoices', template_name='standard')
cell = InvoicesCell.objects.create(
regie='remote',
page=page,
placeholder='content',
order=0,
payer_external_id_template='{{ cards|objects:"card_model_1" }}',
)
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_payments_cell(mock_send):
payment_backend = PaymentBackend.objects.create(
label='test1', slug='test1', service='dummy', service_options={'siret': '1234'}
)
Regie.objects.create(
label='Remote',
slug='remote',
payment_backend=payment_backend,
webservice_url='http://example.org/regie', # is_remote
)
page = Page.objects.create(title='xxx', slug='payments', template_name='standard')
cell = PaymentsCell.objects.create(
regie='remote',
page=page,
placeholder='content',
order=0,
payer_external_id_template='{{ cards|objects:"card_model_1" }}',
)
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_page_dependencies_credits_cell(mock_send):
payment_backend = PaymentBackend.objects.create(
label='test1', slug='test1', service='dummy', service_options={'siret': '1234'}
)
Regie.objects.create(
label='Remote',
slug='remote',
payment_backend=payment_backend,
webservice_url='http://example.org/regie', # is_remote
)
page = Page.objects.create(title='xxx', slug='credits', template_name='standard')
cell = CreditsCell.objects.create(
regie='remote',
page=page,
placeholder='content',
order=0,
payer_external_id_template='{{ cards|objects:"card_model_1" }}',
)
card_dep = {
'type': 'cards',
'id': 'card_model_1',
'text': 'Card Model 1',
'urls': {
'export': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/',
'dependencies': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/dependencies/',
'redirect': 'http://127.0.0.1:8999/api/export-import/cards/card_model_1/redirect/',
},
}
assert card_dep in page.get_dependencies()
cell.mark_as_invalid(reason_code='foobar')
assert card_dep not in page.get_dependencies()
def test_hourly(freezer):
job = ApplicationAsyncJob.objects.create(action='foo', bundle=File(io.BytesIO(b'test'), 'test.tar'))
ApplicationAsyncJob.objects.create(
action='foo',
)
bundle_path = os.path.join(default_storage.path(''), job.bundle.path)
assert os.path.exists(bundle_path)
appconfig = apps.get_app_config('export_import')
appconfig.hourly()
assert ApplicationAsyncJob.objects.count() == 2
assert os.path.exists(bundle_path) is True
freezer.move_to(datetime.timedelta(days=7))
appconfig = apps.get_app_config('export_import')
appconfig.hourly()
assert ApplicationAsyncJob.objects.count() == 0
assert os.path.exists(bundle_path) is False