general: display an error when importing a site with missing groups (#16317)

This commit is contained in:
Frédéric Péters 2018-03-04 15:51:56 +01:00
parent 66c6b4ef01
commit 18523bc1ff
4 changed files with 86 additions and 14 deletions

View File

@ -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)

View File

@ -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 [])

View File

@ -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()

View File

@ -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']