api: complete agendas dependencies (#82703)

This commit is contained in:
Lauréline Guérin 2023-10-24 10:18:19 +02:00
parent 7bb072e596
commit 6485540db6
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
4 changed files with 272 additions and 45 deletions

View File

@ -445,8 +445,15 @@ class Agenda(models.Model):
def get_dependencies(self): def get_dependencies(self):
yield self.view_role yield self.view_role
yield self.edit_role yield self.edit_role
yield self.category
if self.kind == 'virtual': if self.kind == 'virtual':
yield from self.real_agendas.all() yield from self.real_agendas.all()
if self.kind == 'meetings':
yield from self.resources.all()
for desk in self.desk_set.all():
yield from desk.get_dependencies()
if self.kind == 'events':
yield self.events_type
def export_json(self): def export_json(self):
agenda = { agenda = {
@ -2721,6 +2728,10 @@ class EventsType(models.Model):
label = models.CharField(_('Label'), max_length=150) label = models.CharField(_('Label'), max_length=150)
custom_fields = models.JSONField(blank=True, default=list) custom_fields = models.JSONField(blank=True, default=list)
application_component_type = 'events_types'
application_label_singular = _('Events type')
application_label_plural = _('Events types')
def __str__(self): def __str__(self):
return self.label return self.label
@ -2752,6 +2763,9 @@ class EventsType(models.Model):
custom_fields.append(values) custom_fields.append(values)
return custom_fields return custom_fields
def get_dependencies(self):
return []
@classmethod @classmethod
def import_json(cls, data, overwrite=False): def import_json(cls, data, overwrite=False):
data = clean_import_data(cls, data) data = clean_import_data(cls, data)
@ -3130,6 +3144,9 @@ class Desk(models.Model):
def base_slug(self): def base_slug(self):
return slugify(self.label) return slugify(self.label)
def get_dependencies(self):
yield from self.unavailability_calendars.all()
@classmethod @classmethod
def import_json(cls, data): def import_json(cls, data):
timeperiods = data.pop('timeperiods', []) timeperiods = data.pop('timeperiods', [])
@ -3274,6 +3291,10 @@ class Resource(models.Model):
label = models.CharField(_('Label'), max_length=150) label = models.CharField(_('Label'), max_length=150)
description = models.TextField(_('Description'), blank=True, help_text=_('Optional description.')) description = models.TextField(_('Description'), blank=True, help_text=_('Optional description.'))
application_component_type = 'resources'
application_label_singular = _('Resource')
application_label_plural = _('Resources')
def __str__(self): def __str__(self):
return self.label return self.label
@ -3295,6 +3316,9 @@ class Resource(models.Model):
group_ids = [x.id for x in user.groups.all()] group_ids = [x.id for x in user.groups.all()]
return self.agenda_set.filter(edit_role_id__in=group_ids).exists() return self.agenda_set.filter(edit_role_id__in=group_ids).exists()
def get_dependencies(self):
return []
@classmethod @classmethod
def import_json(cls, data, overwrite=False): def import_json(cls, data, overwrite=False):
data = clean_import_data(cls, data) data = clean_import_data(cls, data)
@ -3314,6 +3338,10 @@ class Category(models.Model):
slug = models.SlugField(_('Identifier'), max_length=160, unique=True) slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
label = models.CharField(_('Label'), max_length=150) label = models.CharField(_('Label'), max_length=150)
application_component_type = 'agendas_categories'
application_label_singular = _('Category (agendas)')
application_label_plural = _('Categories (agendas)')
def __str__(self): def __str__(self):
return self.label return self.label
@ -3329,6 +3357,9 @@ class Category(models.Model):
def base_slug(self): def base_slug(self):
return slugify(self.label) return slugify(self.label)
def get_dependencies(self):
return []
@classmethod @classmethod
def import_json(cls, data, overwrite=False): def import_json(cls, data, overwrite=False):
data = clean_import_data(cls, data) data = clean_import_data(cls, data)
@ -3642,6 +3673,10 @@ class UnavailabilityCalendar(models.Model):
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
) )
application_component_type = 'unavailability_calendars'
application_label_singular = _('Unavailability calendar')
application_label_plural = _('Unavailability calendars')
class Meta: class Meta:
ordering = ['label'] ordering = ['label']
@ -3672,6 +3707,10 @@ class UnavailabilityCalendar(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('chrono-manager-unavailability-calendar-view', kwargs={'pk': self.id}) return reverse('chrono-manager-unavailability-calendar-view', kwargs={'pk': self.id})
def get_dependencies(self):
yield self.view_role
yield self.edit_role
def export_json(self): def export_json(self):
unavailability_calendar = { unavailability_calendar = {
'label': self.label, 'label': self.label,

View File

@ -26,11 +26,18 @@ from rest_framework import permissions
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
from rest_framework.response import Response from rest_framework.response import Response
from chrono.agendas.models import Agenda from chrono.agendas.models import Agenda, Category, EventsType, Resource, UnavailabilityCalendar
from chrono.apps.export_import.models import Application, ApplicationElement from chrono.apps.export_import.models import Application, ApplicationElement
from chrono.manager.utils import import_site from chrono.manager.utils import import_site
klasses = {klass.application_component_type: klass for klass in [Agenda]} klasses = {
klass.application_component_type: klass
for klass in [Agenda, Category, EventsType, Resource, UnavailabilityCalendar]
}
klasses_translation = {
'agendas_categories': 'categories',
}
klasses_translation_reverse = {v: k for k, v in klasses_translation.items()}
class Index(GenericAPIView): class Index(GenericAPIView):
@ -39,21 +46,22 @@ class Index(GenericAPIView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
data = [] data = []
for klass in klasses.values(): for klass in klasses.values():
data.append( component_type = {
{ 'id': klass.application_component_type,
'id': klass.application_component_type, 'text': klass.application_label_plural,
'text': klass.application_label_plural, 'singular': klass.application_label_singular,
'singular': klass.application_label_singular, 'urls': {
'urls': { 'list': request.build_absolute_uri(
'list': request.build_absolute_uri( reverse(
reverse( 'api-export-import-components-list',
'api-export-import-components-list', kwargs={'component_type': klass.application_component_type},
kwargs={'component_type': klass.application_component_type}, )
) ),
),
},
}, },
) }
if klass not in [Agenda]:
component_type['minor'] = True
data.append(component_type)
return Response({'data': data}) return Response({'data': data})
@ -180,14 +188,16 @@ class BundleImport(GenericAPIView):
) )
for element in manifest.get('elements'): for element in manifest.get('elements'):
if element['type'] not in klasses or element['type'] == 'roles': component_type = element['type']
if component_type not in klasses or element['type'] == 'roles':
continue continue
if element['type'] not in components: component_type = klasses_translation.get(component_type, component_type)
components[element['type']] = [] if component_type not in components:
components[component_type] = []
component_content = ( component_content = (
tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode() tar.extractfile('%s/%s' % (element['type'], element['slug'])).read().decode()
) )
components[element['type']].append(json.loads(component_content).get('data')) components[component_type].append(json.loads(component_content).get('data'))
# init cache of application elements, from manifest # init cache of application elements, from manifest
self.application_elements = set() self.application_elements = set()
# import agendas # import agendas
@ -204,6 +214,7 @@ class BundleImport(GenericAPIView):
def link_objects(self, components): def link_objects(self, components):
for component_type, component_list in components.items(): for component_type, component_list in components.items():
component_type = klasses_translation_reverse.get(component_type, component_type)
klass = klasses[component_type] klass = klasses[component_type]
for component in component_list: for component in component_list:
try: try:

View File

@ -106,6 +106,10 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
existing_roles_names = set(existing_roles.values_list('name', flat=True)) existing_roles_names = set(existing_roles.values_list('name', flat=True))
raise AgendaImportError('Missing roles: "%s"' % ', '.join(role_names - existing_roles_names)) raise AgendaImportError('Missing roles: "%s"' % ', '.join(role_names - existing_roles_names))
# sort agendas to import virtual agendas first
if data.get('agendas'):
data['agendas'] = sorted(data['agendas'], key=lambda a: a['kind'] == 'virtual')
with transaction.atomic(): with transaction.atomic():
for cls, key in ( for cls, key in (
(Category, 'categories'), (Category, 'categories'),

View File

@ -7,7 +7,7 @@ import pytest
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from chrono.agendas.models import Agenda from chrono.agendas.models import Agenda, Category, Desk, EventsType, Resource, UnavailabilityCalendar
from chrono.apps.export_import.models import Application, ApplicationElement from chrono.apps.export_import.models import Application, ApplicationElement
pytestmark = pytest.mark.django_db pytestmark = pytest.mark.django_db
@ -23,14 +23,41 @@ def test_object_types(app, user):
'text': 'Agendas', 'text': 'Agendas',
'singular': 'Agenda', 'singular': 'Agenda',
'urls': {'list': 'http://testserver/api/export-import/agendas/'}, 'urls': {'list': 'http://testserver/api/export-import/agendas/'},
} },
{
'id': 'agendas_categories',
'minor': True,
'singular': 'Category (agendas)',
'text': 'Categories (agendas)',
'urls': {'list': 'http://testserver/api/export-import/agendas_categories/'},
},
{
'id': 'events_types',
'minor': True,
'singular': 'Type dévènements',
'text': 'Types dévènements',
'urls': {'list': 'http://testserver/api/export-import/events_types/'},
},
{
'id': 'resources',
'minor': True,
'singular': 'Ressource',
'text': 'Ressources',
'urls': {'list': 'http://testserver/api/export-import/resources/'},
},
{
'id': 'unavailability_calendars',
'minor': True,
'singular': 'Unavailability calendar',
'text': 'Calendrier dindisponibilités',
'urls': {'list': 'http://testserver/api/export-import/unavailability_calendars/'},
},
] ]
} }
def test_list_agendas(app, user): def test_list_agendas(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
Agenda.objects.all().delete()
Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings') Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
Agenda.objects.create(label='Event', slug='event', kind='events') Agenda.objects.create(label='Event', slug='event', kind='events')
resp = app.get('/api/export-import/agendas/') resp = app.get('/api/export-import/agendas/')
@ -64,18 +91,100 @@ def test_export_agenda(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
group1 = Group.objects.create(name='group1') group1 = Group.objects.create(name='group1')
group2 = Group.objects.create(name='group2') group2 = Group.objects.create(name='group2')
Agenda.objects.all().delete()
Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings', edit_role=group1, view_role=group2) Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings', edit_role=group1, view_role=group2)
resp = app.get('/api/export-import/agendas/rdv/') resp = app.get('/api/export-import/agendas/rdv/')
assert resp.json['data']['label'] == 'Rdv' assert resp.json['data']['label'] == 'Rdv'
assert resp.json['data']['permissions'] == {'view': 'group2', 'edit': 'group1'} assert resp.json['data']['permissions'] == {'view': 'group2', 'edit': 'group1'}
def test_export_minor_components(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
Category.objects.create(slug='cat', label='Category')
Resource.objects.create(slug='foo', label='Foo')
EventsType.objects.create(slug='foo', label='Foo')
UnavailabilityCalendar.objects.create(slug='foo', label='Foo')
resp = app.get('/api/export-import/agendas_categories/cat/')
assert resp.json['data']['label'] == 'Category'
resp = app.get('/api/export-import/resources/foo/')
assert resp.json['data']['label'] == 'Foo'
resp = app.get('/api/export-import/events_types/foo/')
assert resp.json['data']['label'] == 'Foo'
resp = app.get('/api/export-import/unavailability_calendars/foo/')
assert resp.json['data']['label'] == 'Foo'
def test_agenda_dependencies_category(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
category = Category.objects.create(slug='cat', label='Category')
Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings', category=category)
resp = app.get('/api/export-import/agendas/rdv/dependencies/')
assert resp.json == {
'data': [
{
'id': 'cat',
'text': 'Category',
'type': 'agendas_categories',
'urls': {
'dependencies': 'http://testserver/api/export-import/agendas_categories/cat/dependencies/',
'export': 'http://testserver/api/export-import/agendas_categories/cat/',
'redirect': 'http://testserver/api/export-import/agendas_categories/cat/redirect/',
},
}
],
'err': 0,
}
def test_agenda_dependencies_resources(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
meetings_agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
meetings_agenda.resources.add(Resource.objects.create(slug='foo', label='Foo'))
resp = app.get('/api/export-import/agendas/rdv/dependencies/')
assert resp.json == {
'data': [
{
'id': 'foo',
'text': 'Foo',
'type': 'resources',
'urls': {
'dependencies': 'http://testserver/api/export-import/resources/foo/dependencies/',
'export': 'http://testserver/api/export-import/resources/foo/',
'redirect': 'http://testserver/api/export-import/resources/foo/redirect/',
},
}
],
'err': 0,
}
def test_agenda_dependencies_unavailability_calendars(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
meetings_agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
desk = Desk.objects.create(slug='foo', label='Foo', agenda=meetings_agenda)
desk.unavailability_calendars.add(UnavailabilityCalendar.objects.create(slug='foo', label='Foo'))
resp = app.get('/api/export-import/agendas/rdv/dependencies/')
assert resp.json == {
'data': [
{
'id': 'foo',
'text': 'Foo',
'type': 'unavailability_calendars',
'urls': {
'dependencies': 'http://testserver/api/export-import/unavailability_calendars/foo/dependencies/',
'export': 'http://testserver/api/export-import/unavailability_calendars/foo/',
'redirect': 'http://testserver/api/export-import/unavailability_calendars/foo/redirect/',
},
}
],
'err': 0,
}
def test_agenda_dependencies_groups(app, user): def test_agenda_dependencies_groups(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
group1 = Group.objects.create(name='group1') group1 = Group.objects.create(name='group1')
group2 = Group.objects.create(name='group2') group2 = Group.objects.create(name='group2')
Agenda.objects.all().delete()
Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings', edit_role=group1, view_role=group2) Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings', edit_role=group1, view_role=group2)
resp = app.get('/api/export-import/agendas/rdv/dependencies/') resp = app.get('/api/export-import/agendas/rdv/dependencies/')
# note: with hobo.agent.common installed, 'groups' will contain group slugs, # note: with hobo.agent.common installed, 'groups' will contain group slugs,
@ -91,7 +200,6 @@ def test_agenda_dependencies_groups(app, user):
def test_agenda_dependencies_virtual_agendas(app, user): def test_agenda_dependencies_virtual_agendas(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
Agenda.objects.all().delete()
rdv1 = Agenda.objects.create(label='Rdv1', slug='rdv1', kind='meetings') rdv1 = Agenda.objects.create(label='Rdv1', slug='rdv1', kind='meetings')
rdv2 = Agenda.objects.create(label='Rdv2', slug='rdv2', kind='meetings') rdv2 = Agenda.objects.create(label='Rdv2', slug='rdv2', kind='meetings')
virt = Agenda.objects.create(label='Virt', slug='virt', kind='virtual') virt = Agenda.objects.create(label='Virt', slug='virt', kind='virtual')
@ -125,6 +233,28 @@ def test_agenda_dependencies_virtual_agendas(app, user):
} }
def test_agenda_dependencies_events_type(app, user):
app.authorization = ('Basic', ('john.doe', 'password'))
events_type = EventsType.objects.create(slug='foo', label='Foo')
Agenda.objects.create(label='Evt', slug='evt', kind='events', events_type=events_type)
resp = app.get('/api/export-import/agendas/evt/dependencies/')
assert resp.json == {
'data': [
{
'id': 'foo',
'text': 'Foo',
'type': 'events_types',
'urls': {
'dependencies': 'http://testserver/api/export-import/events_types/foo/dependencies/',
'export': 'http://testserver/api/export-import/events_types/foo/',
'redirect': 'http://testserver/api/export-import/events_types/foo/redirect/',
},
}
],
'err': 0,
}
def test_agenda_redirect(app, user): def test_agenda_redirect(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings') agenda = Agenda.objects.create(label='Rdv', slug='rdv', kind='meetings')
@ -135,11 +265,39 @@ def test_agenda_redirect(app, user):
def create_bundle(app, user, visible=True, version_number='42.0'): def create_bundle(app, user, visible=True, version_number='42.0'):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
group, _ = Group.objects.get_or_create(name='plop') group, _ = Group.objects.get_or_create(name='plop')
Agenda.objects.get_or_create( category, _ = Category.objects.get_or_create(slug='foo', label='Foo')
slug='rdv', defaults={'label': 'Rdv', 'kind': 'meetings', 'edit_role': group}
meetings_agenda, _ = Agenda.objects.get_or_create(
slug='rdv', label='Rdv', kind='meetings', edit_role=group, category=category
) )
agenda_export = app.get('/api/export-import/agendas/rdv/').content resource, _ = Resource.objects.get_or_create(slug='foo', label='Foo')
meetings_agenda.resources.add(resource)
desk, _ = Desk.objects.get_or_create(slug='foo', label='Foo', agenda=meetings_agenda)
unavailability_calendar, _ = UnavailabilityCalendar.objects.get_or_create(slug='foo', label='Foo')
desk.unavailability_calendars.add(unavailability_calendar)
events_type, _ = EventsType.objects.get_or_create(slug='foo', label='Foo')
events_agenda, _ = Agenda.objects.get_or_create(
label='Evt', slug='evt', kind='events', events_type=events_type
)
Desk.objects.get_or_create(agenda=events_agenda, slug='_exceptions_holder')
sub_agenda, _ = Agenda.objects.get_or_create(slug='sub', label='Sub', kind='meetings')
virtual_agenda, _ = Agenda.objects.get_or_create(label='Virt', slug='virt', kind='virtual')
virtual_agenda.real_agendas.add(sub_agenda)
components = [
(meetings_agenda, False),
(category, True),
(resource, True),
(unavailability_calendar, True),
(events_agenda, False),
(events_type, True),
(virtual_agenda, False),
(sub_agenda, True),
]
tar_io = io.BytesIO() tar_io = io.BytesIO()
with tarfile.open(mode='w', fileobj=tar_io) as tar: with tarfile.open(mode='w', fileobj=tar_io) as tar:
@ -152,11 +310,17 @@ def create_bundle(app, user, visible=True, version_number='42.0'):
'visible': visible, 'visible': visible,
'version_number': version_number, 'version_number': version_number,
'version_notes': 'foo bar blah', 'version_notes': 'foo bar blah',
'elements': [ 'elements': [],
{'type': 'agendas', 'slug': 'rdv', 'name': 'Test agenda', 'auto-dependency': False},
{'type': 'form', 'slug': 'xxx', 'name': 'Xxx'},
],
} }
for component, auto_dependency in components:
manifest_json['elements'].append(
{
'type': component.application_component_type,
'slug': component.slug,
'name': component.label,
'auto-dependency': auto_dependency,
}
)
manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode()) manifest_fd = io.BytesIO(json.dumps(manifest_json, indent=2).encode())
tarinfo = tarfile.TarInfo('manifest.json') tarinfo = tarfile.TarInfo('manifest.json')
tarinfo.size = len(manifest_fd.getvalue()) tarinfo.size = len(manifest_fd.getvalue())
@ -169,9 +333,13 @@ def create_bundle(app, user, visible=True, version_number='42.0'):
tarinfo.size = len(icon_fd.getvalue()) tarinfo.size = len(icon_fd.getvalue())
tar.addfile(tarinfo, fileobj=icon_fd) tar.addfile(tarinfo, fileobj=icon_fd)
tarinfo = tarfile.TarInfo('agendas/rdv') for component, _ in components:
tarinfo.size = len(agenda_export) component_export = app.get(
tar.addfile(tarinfo, fileobj=io.BytesIO(agenda_export)) '/api/export-import/%s/%s/' % (component.application_component_type, component.slug)
).content
tarinfo = tarfile.TarInfo('%s/%s' % (component.application_component_type, component.slug))
tarinfo.size = len(component_export)
tar.addfile(tarinfo, fileobj=io.BytesIO(component_export))
bundle = tar_io.getvalue() bundle = tar_io.getvalue()
return bundle return bundle
@ -184,13 +352,18 @@ def bundle(app, user):
def test_bundle_import(app, user): def test_bundle_import(app, user):
app.authorization = ('Basic', ('john.doe', 'password')) app.authorization = ('Basic', ('john.doe', 'password'))
Agenda.objects.all().delete()
bundles = [] bundles = []
for version_number in ['42.0', '42.1']: for version_number in ['42.0', '42.1']:
bundles.append(create_bundle(app, user, version_number=version_number)) bundles.append(create_bundle(app, user, version_number=version_number))
Agenda.objects.all().delete()
Category.objects.all().delete()
Resource.objects.all().delete()
EventsType.objects.all().delete()
UnavailabilityCalendar.objects.all().delete()
resp = app.put('/api/export-import/bundle-import/', bundles[0]) resp = app.put('/api/export-import/bundle-import/', bundles[0])
assert Agenda.objects.all().count() == 1 assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0 assert resp.json['err'] == 0
assert Application.objects.count() == 1 assert Application.objects.count() == 1
application = Application.objects.latest('pk') application = Application.objects.latest('pk')
@ -203,7 +376,7 @@ def test_bundle_import(app, user):
assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name) assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name)
assert application.editable is False assert application.editable is False
assert application.visible is True assert application.visible is True
assert ApplicationElement.objects.count() == 1 assert ApplicationElement.objects.count() == 8
# check editable flag is kept on install # check editable flag is kept on install
application.editable = True application.editable = True
@ -219,12 +392,12 @@ def test_bundle_import(app, user):
# check update # check update
resp = app.put('/api/export-import/bundle-import/', bundles[1]) resp = app.put('/api/export-import/bundle-import/', bundles[1])
assert Agenda.objects.all().count() == 1 assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0 assert resp.json['err'] == 0
assert Application.objects.count() == 1 assert Application.objects.count() == 1
application = Application.objects.latest('pk') application = Application.objects.latest('pk')
assert application.editable is False assert application.editable is False
assert ApplicationElement.objects.count() == 1 assert ApplicationElement.objects.count() == 8
assert ( assert (
ApplicationElement.objects.filter( ApplicationElement.objects.filter(
application=application, application=application,
@ -240,7 +413,7 @@ def test_bundle_declare(app, user):
bundle = create_bundle(app, user, visible=False) bundle = create_bundle(app, user, visible=False)
resp = app.put('/api/export-import/bundle-declare/', bundle) resp = app.put('/api/export-import/bundle-declare/', bundle)
assert Agenda.objects.all().count() == 1 assert Agenda.objects.all().count() == 4
assert resp.json['err'] == 0 assert resp.json['err'] == 0
assert Application.objects.count() == 1 assert Application.objects.count() == 1
application = Application.objects.latest('pk') application = Application.objects.latest('pk')
@ -253,7 +426,7 @@ def test_bundle_declare(app, user):
assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name) assert re.match(r'applications/icons/foo(_\w+)?.png', application.icon.name)
assert application.editable is True assert application.editable is True
assert application.visible is False assert application.visible is False
assert ApplicationElement.objects.count() == 1 assert ApplicationElement.objects.count() == 8
bundle = create_bundle(app, user, visible=True) bundle = create_bundle(app, user, visible=True)
# create link to element not present in manifest: it should be unlinked # create link to element not present in manifest: it should be unlinked
@ -263,14 +436,14 @@ def test_bundle_declare(app, user):
content_type=ContentType.objects.get_for_model(Agenda), content_type=ContentType.objects.get_for_model(Agenda),
object_id=last_page.pk + 1, object_id=last_page.pk + 1,
) )
# and remove a page to have an unkown reference in manifest # and remove agendas to have unkown references in manifest
Agenda.objects.all().delete() Agenda.objects.all().delete()
resp = app.put('/api/export-import/bundle-declare/', bundle) resp = app.put('/api/export-import/bundle-declare/', bundle)
assert Application.objects.count() == 1 assert Application.objects.count() == 1
application = Application.objects.latest('pk') application = Application.objects.latest('pk')
assert application.visible is True assert application.visible is True
assert ApplicationElement.objects.count() == 0 assert ApplicationElement.objects.count() == 4 # category, events_type, unavailability_calendar, resource
def test_bundle_unlink(app, user, bundle): def test_bundle_unlink(app, user, bundle):