general: display an error when importing a site with missing groups (#16317)
This commit is contained in:
parent
66c6b4ef01
commit
18523bc1ff
|
@ -19,7 +19,7 @@ import sys
|
|||
|
||||
from django.core.management.base import BaseCommand
|
||||
|
||||
from combo.data.utils import import_site
|
||||
from combo.data.utils import import_site, MissingGroups
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Import an exported site'
|
||||
|
@ -39,6 +39,9 @@ class Command(BaseCommand):
|
|||
fd = sys.stdin
|
||||
else:
|
||||
fd = open(filename)
|
||||
import_site(json.load(fd),
|
||||
if_empty=options['if_empty'],
|
||||
clean=options['clean'])
|
||||
try:
|
||||
import_site(json.load(fd),
|
||||
if_empty=options['if_empty'],
|
||||
clean=options['clean'])
|
||||
except MissingGroups as e:
|
||||
print >> sys.stderr, unicode(e)
|
||||
|
|
|
@ -14,11 +14,22 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
from django.db import transaction
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from combo.apps.maps.models import MapLayer
|
||||
from .models import Page
|
||||
|
||||
|
||||
class MissingGroups(Exception):
|
||||
def __init__(self, names):
|
||||
self.names = names
|
||||
|
||||
def __unicode__(self):
|
||||
return _('Missing groups: %s') % ', '.join(self.names)
|
||||
|
||||
|
||||
def export_site():
|
||||
'''Dump site objects to JSON-dumpable dictionnary'''
|
||||
return {'pages': Page.export_all_for_json(),
|
||||
|
@ -26,18 +37,32 @@ def export_site():
|
|||
|
||||
|
||||
def import_site(data, if_empty=False, clean=False):
|
||||
if if_empty and (Page.objects.count() or MapLayer.objects.count()):
|
||||
return
|
||||
|
||||
if clean:
|
||||
MapLayer.objects.all().delete()
|
||||
Page.objects.all().delete()
|
||||
|
||||
if isinstance(data, list):
|
||||
# old export form with a list of pages, convert it to new dictionary
|
||||
# format.
|
||||
data = {'pages': data}
|
||||
|
||||
if if_empty and (Page.objects.count() or MapLayer.objects.count()):
|
||||
return
|
||||
|
||||
# check groups used in access control are all available.
|
||||
groups = set()
|
||||
for page in data.get('pages') or []:
|
||||
for group in page['fields']['groups']:
|
||||
groups.add(group if isinstance(group, basestring) else group[0])
|
||||
for cell in page['cells']:
|
||||
for group in cell['fields']['groups']:
|
||||
groups.add(group if isinstance(group, basestring) else group[0])
|
||||
|
||||
existing_groups = set([x.name for x in Group.objects.filter(name__in=groups)])
|
||||
missing_groups = groups - existing_groups
|
||||
if missing_groups:
|
||||
raise MissingGroups(names=sorted([x for x in missing_groups]))
|
||||
|
||||
if clean:
|
||||
MapLayer.objects.all().delete()
|
||||
Page.objects.all().delete()
|
||||
|
||||
with transaction.atomic():
|
||||
MapLayer.load_serialized_objects(data.get('map-layers') or [])
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ from django.views.generic import (TemplateView, RedirectView, DetailView,
|
|||
|
||||
from combo.data.models import Page, CellBase, ParentContentCell
|
||||
from combo.data.library import get_cell_class
|
||||
from combo.data.utils import export_site, import_site
|
||||
from combo.data.utils import export_site, import_site, MissingGroups
|
||||
from combo import plugins
|
||||
|
||||
from .forms import (PageEditTitleForm, PageVisibilityForm, SiteImportForm,
|
||||
|
@ -73,7 +73,12 @@ class SiteImportView(FormView):
|
|||
|
||||
def form_valid(self, form):
|
||||
json_site = json.load(self.request.FILES['site_json'])
|
||||
import_site(json_site)
|
||||
try:
|
||||
import_site(json_site)
|
||||
except MissingGroups as e:
|
||||
form.add_error('site_json', unicode(e))
|
||||
return self.form_invalid(form)
|
||||
|
||||
return super(SiteImportView, self).form_valid(form)
|
||||
|
||||
site_import = SiteImportView.as_view()
|
||||
|
|
|
@ -7,11 +7,12 @@ import sys
|
|||
import tempfile
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.management import call_command
|
||||
|
||||
from combo.apps.maps.models import MapLayer, Map
|
||||
from combo.data.models import Page, TextCell
|
||||
from combo.data.utils import export_site, import_site
|
||||
from combo.data.utils import export_site, import_site, MissingGroups
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
|
||||
|
@ -123,3 +124,41 @@ def test_import_export_map_cells(app, some_data, some_map_layers):
|
|||
import_site(data=json.loads(site_export), clean=True)
|
||||
assert Map.objects.count() == 1
|
||||
assert Map.objects.all()[0].layers.all()[0].slug == 'foo'
|
||||
|
||||
def test_group_restrictions_import_export(app, some_data):
|
||||
group = Group(name='A Group')
|
||||
group.save()
|
||||
|
||||
page = Page.objects.get(slug='one')
|
||||
page.groups = [group]
|
||||
page.save()
|
||||
|
||||
cell = TextCell.objects.get(order=0)
|
||||
cell.groups = [group]
|
||||
cell.save()
|
||||
|
||||
output = get_output_of_command('export_site')
|
||||
assert len(json.loads(output)['pages']) == 3
|
||||
import_site(data={}, clean=True)
|
||||
assert Page.objects.all().count() == 0
|
||||
assert TextCell.objects.all().count() == 0
|
||||
|
||||
Group.objects.all().delete()
|
||||
|
||||
with pytest.raises(MissingGroups) as excinfo:
|
||||
import_site(json.loads(output), clean=True)
|
||||
|
||||
assert excinfo.value.names == ['A Group']
|
||||
|
||||
group = Group(name='A Group')
|
||||
group.save()
|
||||
|
||||
import_site(json.loads(output), clean=True)
|
||||
assert Page.objects.all().count() == 3
|
||||
assert TextCell.objects.all().count() == 1
|
||||
|
||||
page = Page.objects.get(slug='one')
|
||||
assert [x.name for x in page.groups.all()] == ['A Group']
|
||||
|
||||
cell = TextCell.objects.get(order=0)
|
||||
assert [x.name for x in cell.groups.all()] == ['A Group']
|
||||
|
|
Loading…
Reference in New Issue