virtual agendas: handle import/export (#40057)

This commit is contained in:
Emmanuel Cazenave 2020-03-17 13:11:49 +01:00 committed by Frédéric Péters
parent ec474b46d2
commit 7c707f6674
3 changed files with 127 additions and 3 deletions

View File

@ -203,7 +203,6 @@ class Agenda(models.Model):
return gcd
def export_json(self):
# TODO VIRTUAL
agenda = {
'label': self.label,
'slug': self.slug,
@ -220,6 +219,9 @@ class Agenda(models.Model):
elif self.kind == 'meetings':
agenda['meetingtypes'] = [x.export_json() for x in self.meetingtype_set.all()]
agenda['desks'] = [desk.export_json() for desk in self.desk_set.all()]
elif self.kind == 'virtual':
agenda['excluded_timeperiods'] = [x.export_json() for x in self.excluded_timeperiods.all()]
agenda['real_agendas'] = [{'slug': x.slug, 'kind': x.kind} for x in self.real_agendas.all()]
return agenda
@classmethod
@ -231,6 +233,9 @@ class Agenda(models.Model):
elif data['kind'] == 'meetings':
meetingtypes = data.pop('meetingtypes')
desks = data.pop('desks')
elif data['kind'] == 'virtual':
excluded_timeperiods = data.pop('excluded_timeperiods')
real_agendas = data.pop('real_agendas')
for permission in ('view', 'edit'):
if permissions.get(permission):
try:
@ -257,6 +262,23 @@ class Agenda(models.Model):
for desk in desks:
desk['agenda'] = agenda
Desk.import_json(desk).save()
elif data['kind'] == 'virtual':
if overwrite:
TimePeriod.objects.filter(agenda=agenda).delete()
VirtualMember.objects.filter(virtual_agenda=agenda).delete()
for excluded_timeperiod in excluded_timeperiods:
excluded_timeperiod['agenda'] = agenda
TimePeriod.import_json(excluded_timeperiod).save()
for real_agenda in real_agendas:
real_agenda = Agenda.objects.get(slug=real_agenda['slug'], kind=real_agenda['kind'])
try:
vm, created = VirtualMember.objects.get_or_create(
virtual_agenda=agenda, real_agenda=real_agenda
)
vm.clean()
except ValidationError as exc:
raise AgendaImportError(' '.join(exc.messages))
return created

View File

@ -14,7 +14,10 @@
# 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/>.
import itertools
from django.db import transaction
from django.db.models import Q
from chrono.agendas.models import Agenda, AgendaImportError
@ -22,7 +25,9 @@ from chrono.agendas.models import Agenda, AgendaImportError
def export_site():
'''Dump site objects to JSON-dumpable dictionnary'''
data = {}
data['agendas'] = [x.export_json() for x in Agenda.objects.all()]
qs1 = Agenda.objects.filter(~Q(kind='virtual'))
qs2 = Agenda.objects.filter(kind='virtual')
data['agendas'] = [x.export_json() for x in itertools.chain(qs1, qs2)]
return data

View File

@ -16,7 +16,16 @@ from django.core.management import call_command, CommandError
from django.utils.encoding import force_bytes
from django.utils.timezone import make_aware
from chrono.agendas.models import Agenda, Event, TimePeriod, Desk, TimePeriodException, AgendaImportError
from chrono.agendas.models import (
Agenda,
Event,
TimePeriod,
Desk,
TimePeriodException,
AgendaImportError,
MeetingType,
VirtualMember,
)
from chrono.manager.utils import import_site
from test_api import some_data, meetings_agenda, time_zone, mock_now
@ -179,3 +188,91 @@ def test_import_export_permissions(app, some_data, meetings_agenda):
agenda = Agenda.objects.get(slug=meetings_agenda.slug)
assert agenda.view_role == group1
assert agenda.edit_role == group2
def test_import_export_virtual_agenda(app):
virtual_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
output = get_output_of_command('export_site')
payload = json.loads(output)
assert len(payload['agendas']) == 1
virtual_agenda.delete()
import_site(json.loads(output), overwrite=True)
virtual_agenda = Agenda.objects.get(label='Virtual Agenda', slug='virtual-agenda', kind='virtual')
assert virtual_agenda.minimal_booking_delay is None
assert virtual_agenda.maximal_booking_delay is None
assert virtual_agenda.real_agendas.count() == 0
assert virtual_agenda.excluded_timeperiods.count() == 0
# add booking delay
virtual_agenda.minimal_booking_delay = 2
virtual_agenda.maximal_booking_delay = 10
virtual_agenda.save()
output = get_output_of_command('export_site')
payload = json.loads(output)
virtual_agenda.delete()
import_site(json.loads(output), overwrite=True)
virtual_agenda = Agenda.objects.get(label='Virtual Agenda', slug='virtual-agenda', kind='virtual')
assert virtual_agenda.minimal_booking_delay == 2
assert virtual_agenda.maximal_booking_delay == 10
# add excluded timeperiods
tp1 = TimePeriod.objects.create(
agenda=virtual_agenda, weekday=1, start_time=datetime.time(10, 0), end_time=datetime.time(11, 0)
)
tp2 = TimePeriod.objects.create(
agenda=virtual_agenda, weekday=2, start_time=datetime.time(12, 0), end_time=datetime.time(13, 0)
)
output = get_output_of_command('export_site')
payload = json.loads(output)
virtual_agenda.delete()
tp1.delete()
tp2.delete()
import_site(json.loads(output), overwrite=True)
virtual_agenda = Agenda.objects.get(label='Virtual Agenda', slug='virtual-agenda', kind='virtual')
assert virtual_agenda.excluded_timeperiods.count() == 2
tp1 = TimePeriod.objects.get(
agenda=virtual_agenda, weekday=1, start_time=datetime.time(10, 0), end_time=datetime.time(11, 0)
)
tp2 = TimePeriod.objects.get(
agenda=virtual_agenda, weekday=2, start_time=datetime.time(12, 0), end_time=datetime.time(13, 0)
)
def test_import_export_virtual_agenda_with_included_agenda(app):
virtual_agenda = Agenda.objects.create(label='Virtual Agenda', kind='virtual')
foo_agenda = Agenda.objects.create(label='Foo', kind='meetings')
bar_agenda = Agenda.objects.create(label='Bar', kind='meetings')
mt1 = MeetingType.objects.create(agenda=foo_agenda, label='Meeting Type', duration=30)
mt2 = MeetingType.objects.create(agenda=bar_agenda, label='Meeting Type', duration=30)
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=foo_agenda)
VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=bar_agenda)
output = get_output_of_command('export_site')
payload = json.loads(output)
assert len(payload['agendas']) == 3
virtual_agenda.delete()
foo_agenda.delete()
bar_agenda.delete()
mt1.delete()
mt2.delete()
import_site(payload, overwrite=True)
virtual_agenda = Agenda.objects.get(label='Virtual Agenda', slug='virtual-agenda', kind='virtual')
assert virtual_agenda.real_agendas.count() == 2
assert virtual_agenda.real_agendas.filter(label='Foo').count() == 1
assert virtual_agenda.real_agendas.filter(label='Bar').count() == 1
# add incompatible meetingtype
bar_agenda = Agenda.objects.get(label='Bar', kind='meetings')
mt2 = MeetingType.objects.get(agenda=bar_agenda, label='Meeting Type')
mt2.duration = 10
mt2.save()
output = get_output_of_command('export_site')
payload = json.loads(output)
virtual_agenda.delete()
with pytest.raises(AgendaImportError) as excinfo:
import_site(json.loads(output), overwrite=False)
assert (
'This agenda does not have the same meeting types provided by the virtual agenda.'
in '%s' % excinfo.value
)