general: add support for importing permissions (#26924)

This commit is contained in:
Frédéric Péters 2018-11-13 20:44:51 +01:00
parent aa7e887dec
commit 9e41e9d77c
6 changed files with 87 additions and 11 deletions

View File

@ -53,6 +53,10 @@ class ICSError(Exception):
pass
class AgendaImportError(Exception):
pass
class Agenda(models.Model):
label = models.CharField(_('Label'), max_length=150)
slug = models.SlugField(_('Identifier'), max_length=160)
@ -130,12 +134,18 @@ class Agenda(models.Model):
@classmethod
def import_json(cls, data, overwrite=False):
data = data.copy()
permissions = data.pop('permissions')
permissions = data.pop('permissions') or {}
if data['kind'] == 'events':
events = data.pop('events')
elif data['kind'] == 'meetings':
meetingtypes = data.pop('meetingtypes')
desks = data.pop('desks')
for permission in ('view', 'edit'):
if permissions.get(permission):
try:
data[permission + '_role'] = Group.objects.get(name=permissions[permission])
except Group.DoesNotExist:
raise AgendaImportError(_('Missing "%s" role') % permissions[permission])
agenda, created = cls.objects.get_or_create(slug=data['slug'], defaults=data)
if data['kind'] == 'events':
if overwrite:

View File

@ -17,8 +17,9 @@
import json
import sys
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
from chrono.agendas.models import AgendaImportError
from chrono.manager.utils import import_site
@ -43,7 +44,10 @@ class Command(BaseCommand):
fd = sys.stdin
else:
fd = open(filename)
import_site(json.load(fd),
if_empty=options['if_empty'],
clean=options['clean'],
overwrite=options['overwrite'])
try:
import_site(json.load(fd),
if_empty=options['if_empty'],
clean=options['clean'],
overwrite=options['overwrite'])
except AgendaImportError as exc:
raise CommandError(u'%s' % exc)

View File

@ -16,7 +16,7 @@
from django.db import transaction
from chrono.agendas.models import Agenda
from chrono.agendas.models import Agenda, AgendaImportError
def export_site():

View File

@ -33,7 +33,8 @@ from django.views.generic import (DetailView, CreateView, UpdateView,
MonthArchiveView)
from chrono.agendas.models import (Agenda, Event, MeetingType, TimePeriod,
Booking, Desk, TimePeriodException, ICSError)
Booking, Desk, TimePeriodException,
ICSError, AgendaImportError)
from .forms import (AgendaAddForm, AgendaEditForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
TimePeriodForm, ImportEventsForm, NewDeskForm, DeskForm, TimePeriodExceptionForm,
@ -95,7 +96,12 @@ class AgendasImportView(FormView):
form.add_error('agendas_json', _('File is not in the expected JSON format.'))
return self.form_invalid(form)
results = import_site(agendas_json, overwrite=True)
try:
results = import_site(agendas_json, overwrite=True)
except AgendaImportError as exc:
form.add_error('agendas_json', u'%s' % exc)
return self.form_invalid(form)
if results.get('created') == 0 and results.get('updated') == 0:
messages.info(self.request, _('No agendas were found.'))
else:

View File

@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import datetime
@ -8,12 +10,14 @@ import sys
import tempfile
import pytest
from django.core.management import call_command
from django.contrib.auth.models import Group
from django.core.management import call_command, CommandError
from django.utils.encoding import force_bytes
from django.utils.six import StringIO
from django.utils.timezone import make_aware
from chrono.agendas.models import (Agenda, Event, TimePeriod, Desk, TimePeriodException)
from chrono.agendas.models import (Agenda, Event, TimePeriod, Desk,
TimePeriodException, AgendaImportError)
from chrono.manager.utils import import_site
from test_api import some_data, meetings_agenda, time_zone, mock_now
@ -112,3 +116,44 @@ def test_import_export(app, some_data, meetings_agenda):
empty_output = get_output_of_command('export_site', output=os.path.join(tempdir, 't.json'))
assert os.path.exists(os.path.join(tempdir, 't.json'))
shutil.rmtree(tempdir)
def test_import_export_permissions(app, some_data, meetings_agenda):
group1 = Group(name=u'gé1')
group1.save()
group2 = Group(name=u'gé2')
group2.save()
meetings_agenda.view_role = group1
meetings_agenda.edit_role = group2
meetings_agenda.save()
output = get_output_of_command('export_site')
assert len(json.loads(output)['agendas']) == 3
import_site(data={}, clean=True)
assert Agenda.objects.count() == 0
Group.objects.all().delete()
with pytest.raises(AgendaImportError) as excinfo:
import_site(json.loads(output), overwrite=True)
assert u'%s' % excinfo.value == u'Missing "gé1" role'
group1 = Group(name=u'gé1')
group1.save()
with pytest.raises(AgendaImportError) as excinfo:
import_site(json.loads(output), overwrite=True)
assert u'%s' % excinfo.value == u'Missing "gé2" role'
with tempfile.NamedTemporaryFile() as f:
f.write(force_bytes(output))
f.flush()
with pytest.raises(CommandError) as excinfo:
call_command('import_site', f.name)
assert u'%s' % excinfo.value == u'Missing "gé2" role'
group2 = Group(name=u'gé2')
group2.save()
import_site(json.loads(output), overwrite=True)
agenda = Agenda.objects.get(slug=meetings_agenda.slug)
assert agenda.view_role == group1
assert agenda.edit_role == group2

View File

@ -1529,3 +1529,14 @@ def test_import_agenda(app, admin_user):
resp = resp.form.submit().follow()
assert 'An agenda has been created. No agenda updated.' in resp.text
assert Agenda.objects.count() == 1
# reference to unknown group
agenda_export_dict = json.loads(agenda_export)
agenda_export_dict['agendas'][0]['permissions']['view'] = u'gé1'
agenda_export = json.dumps(agenda_export_dict).encode('utf-8')
Agenda.objects.all().delete()
resp = app.get('/manage/', status=200)
resp = resp.click('Import')
resp.form['agendas_json'] = Upload('export.json', agenda_export, 'application/json')
resp = resp.form.submit()
assert u'Missing "gé1" role' in resp.text