manager: import/export events types (#63285)
This commit is contained in:
parent
597d88cce7
commit
96b5dc941f
|
@ -1853,6 +1853,20 @@ class EventsType(models.Model):
|
|||
custom_fields.append(values)
|
||||
return custom_fields
|
||||
|
||||
@classmethod
|
||||
def import_json(cls, data, overwrite=False):
|
||||
data = clean_import_data(cls, data)
|
||||
slug = data.pop('slug')
|
||||
events_type, created = cls.objects.update_or_create(slug=slug, defaults=data)
|
||||
return created, events_type
|
||||
|
||||
def export_json(self):
|
||||
return {
|
||||
'slug': self.slug,
|
||||
'label': self.label,
|
||||
'custom_fields': self.custom_fields,
|
||||
}
|
||||
|
||||
|
||||
class BookingColor(models.Model):
|
||||
COLOR_COUNT = 8
|
||||
|
|
|
@ -1343,6 +1343,7 @@ class AgendasExportForm(forms.Form):
|
|||
)
|
||||
absence_reason_groups = forms.BooleanField(label=_('Absence reason groups'), required=False, initial=True)
|
||||
categories = forms.BooleanField(label=_('Categories'), required=False, initial=True)
|
||||
events_types = forms.BooleanField(label=_('Events types'), required=False, initial=True)
|
||||
|
||||
|
||||
class SharedCustodyRuleForm(forms.ModelForm):
|
||||
|
|
|
@ -26,15 +26,24 @@ from chrono.agendas.models import (
|
|||
Agenda,
|
||||
AgendaImportError,
|
||||
Category,
|
||||
EventsType,
|
||||
UnavailabilityCalendar,
|
||||
)
|
||||
|
||||
|
||||
def export_site(agendas=True, unavailability_calendars=True, absence_reason_groups=True, categories=True):
|
||||
def export_site(
|
||||
agendas=True,
|
||||
unavailability_calendars=True,
|
||||
absence_reason_groups=True,
|
||||
events_types=True,
|
||||
categories=True,
|
||||
):
|
||||
'''Dump site objects to JSON-dumpable dictionnary'''
|
||||
data = collections.OrderedDict()
|
||||
if categories:
|
||||
data['categories'] = [x.export_json() for x in Category.objects.all()]
|
||||
if events_types:
|
||||
data['events_types'] = [x.export_json() for x in EventsType.objects.all()]
|
||||
if absence_reason_groups:
|
||||
data['absence_reason_groups'] = [x.export_json() for x in AbsenceReasonGroup.objects.all()]
|
||||
if unavailability_calendars:
|
||||
|
@ -47,10 +56,12 @@ def export_site(agendas=True, unavailability_calendars=True, absence_reason_grou
|
|||
|
||||
|
||||
def import_site(data, if_empty=False, clean=False, overwrite=False):
|
||||
# pylint: disable=too-many-boolean-expressions
|
||||
if if_empty and (
|
||||
Agenda.objects.exists()
|
||||
or UnavailabilityCalendar.objects.exists()
|
||||
or AbsenceReasonGroup.objects.exists()
|
||||
or EventsType.objects.exists()
|
||||
or Category.objects.exists()
|
||||
):
|
||||
return
|
||||
|
@ -59,20 +70,23 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
|
|||
Agenda.objects.all().delete()
|
||||
UnavailabilityCalendar.objects.all().delete()
|
||||
AbsenceReasonGroup.objects.all().delete()
|
||||
EventsType.objects.all().delete()
|
||||
Category.objects.all().delete()
|
||||
|
||||
results = {
|
||||
'agendas': collections.defaultdict(list),
|
||||
'unavailability_calendars': collections.defaultdict(list),
|
||||
'absence_reason_groups': collections.defaultdict(list),
|
||||
key: collections.defaultdict(list)
|
||||
for key in [
|
||||
'agendas',
|
||||
'unavailability_calendars',
|
||||
'absence_reason_groups',
|
||||
'events_types',
|
||||
'categories',
|
||||
]
|
||||
}
|
||||
agendas = data.get('agendas', [])
|
||||
unavailability_calendars = data.get('unavailability_calendars', [])
|
||||
absence_reason_groups = data.get('absence_reason_groups', [])
|
||||
categories = data.get('categories', [])
|
||||
|
||||
role_names = set()
|
||||
for objs in (agendas, unavailability_calendars):
|
||||
for key in ['agendas', 'unavailability_calendars']:
|
||||
objs = data.get(key, [])
|
||||
role_names = role_names.union(
|
||||
{name for data in objs for _, name in data.get('permissions', {}).items() if name}
|
||||
)
|
||||
|
@ -82,20 +96,20 @@ def import_site(data, if_empty=False, clean=False, overwrite=False):
|
|||
existing_roles_names = set(existing_roles.values_list('name', flat=True))
|
||||
raise AgendaImportError('Missing roles: "%s"' % ', '.join(role_names - existing_roles_names))
|
||||
|
||||
for category in categories:
|
||||
Category.import_json(category, overwrite=overwrite)
|
||||
|
||||
with transaction.atomic():
|
||||
for objs, cls, label in (
|
||||
(absence_reason_groups, AbsenceReasonGroup, 'absence_reason_groups'),
|
||||
(unavailability_calendars, UnavailabilityCalendar, 'unavailability_calendars'),
|
||||
(agendas, Agenda, 'agendas'),
|
||||
for cls, key in (
|
||||
(Category, 'categories'),
|
||||
(EventsType, 'events_types'),
|
||||
(AbsenceReasonGroup, 'absence_reason_groups'),
|
||||
(UnavailabilityCalendar, 'unavailability_calendars'),
|
||||
(Agenda, 'agendas'),
|
||||
):
|
||||
for data in objs:
|
||||
created, obj = cls.import_json(data, overwrite=overwrite)
|
||||
results[label]['all'].append(obj)
|
||||
objs = data.get(key, [])
|
||||
for obj in objs:
|
||||
created, obj = cls.import_json(obj, overwrite=overwrite)
|
||||
results[key]['all'].append(obj)
|
||||
if created:
|
||||
results[label]['created'].append(obj)
|
||||
results[key]['created'].append(obj)
|
||||
else:
|
||||
results[label]['updated'].append(obj)
|
||||
results[key]['updated'].append(obj)
|
||||
return results
|
||||
|
|
|
@ -995,6 +995,34 @@ class AgendasImportView(FormView):
|
|||
x,
|
||||
),
|
||||
},
|
||||
'events_types': {
|
||||
'create_noop': _('No events type created.'),
|
||||
'create': lambda x: ungettext(
|
||||
'An events type has been created.',
|
||||
'%(count)d events types have been created.',
|
||||
x,
|
||||
),
|
||||
'update_noop': _('No events type updated.'),
|
||||
'update': lambda x: ungettext(
|
||||
'An events type has been updated.',
|
||||
'%(count)d events types have been updated.',
|
||||
x,
|
||||
),
|
||||
},
|
||||
'categories': {
|
||||
'create_noop': _('No category created.'),
|
||||
'create': lambda x: ungettext(
|
||||
'A category has been created.',
|
||||
'%(count)d categories have been created.',
|
||||
x,
|
||||
),
|
||||
'update_noop': _('No category updated.'),
|
||||
'update': lambda x: ungettext(
|
||||
'A category has been updated.',
|
||||
'%(count)d categories have been updated.',
|
||||
x,
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
global_noop = True
|
||||
|
@ -1043,6 +1071,8 @@ class AgendasImportView(FormView):
|
|||
messages.info(self.request, results['agendas']['messages'])
|
||||
messages.info(self.request, results['unavailability_calendars']['messages'])
|
||||
messages.info(self.request, results['absence_reason_groups']['messages'])
|
||||
messages.info(self.request, results['events_types']['messages'])
|
||||
messages.info(self.request, results['categories']['messages'])
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ def test_export_site(app, admin_user):
|
|||
'unavailability_calendars': [],
|
||||
'agendas': [],
|
||||
'absence_reason_groups': [],
|
||||
'events_types': [],
|
||||
'categories': [],
|
||||
}
|
||||
|
||||
|
@ -50,11 +51,13 @@ def test_export_site(app, admin_user):
|
|||
assert len(site_json['agendas']) == 1
|
||||
assert len(site_json['unavailability_calendars']) == 1
|
||||
assert len(site_json['absence_reason_groups']) == 0
|
||||
assert len(site_json['events_types']) == 0
|
||||
assert len(site_json['categories']) == 0
|
||||
|
||||
resp = app.get('/manage/agendas/export/')
|
||||
resp.form['agendas'] = False
|
||||
resp.form['absence_reason_groups'] = False
|
||||
resp.form['events_types'] = False
|
||||
resp.form['categories'] = False
|
||||
resp = resp.form.submit()
|
||||
|
||||
|
@ -62,6 +65,7 @@ def test_export_site(app, admin_user):
|
|||
assert 'agendas' not in site_json
|
||||
assert 'unavailability_calendars' in site_json
|
||||
assert 'absence_reason_groups' not in site_json
|
||||
assert 'events_types' not in site_json
|
||||
assert 'categories' not in site_json
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ from chrono.agendas.models import (
|
|||
Category,
|
||||
Desk,
|
||||
Event,
|
||||
EventsType,
|
||||
MeetingType,
|
||||
Resource,
|
||||
TimePeriod,
|
||||
|
@ -996,6 +997,43 @@ def test_import_export_category(app):
|
|||
assert category.slug == 'foo-bar'
|
||||
|
||||
|
||||
def test_import_export_events_type(app):
|
||||
output = get_output_of_command('export_site')
|
||||
payload = json.loads(output)
|
||||
assert len(payload['events_types']) == 0
|
||||
|
||||
events_type = EventsType.objects.create(label='Foo bar')
|
||||
|
||||
output = get_output_of_command('export_site')
|
||||
payload = json.loads(output)
|
||||
assert len(payload['events_types']) == 1
|
||||
|
||||
events_type.delete()
|
||||
assert not EventsType.objects.exists()
|
||||
|
||||
import_site(copy.deepcopy(payload))
|
||||
assert EventsType.objects.count() == 1
|
||||
events_type = EventsType.objects.first()
|
||||
assert events_type.label == 'Foo bar'
|
||||
assert events_type.slug == 'foo-bar'
|
||||
|
||||
# update
|
||||
update_payload = copy.deepcopy(payload)
|
||||
update_payload['events_types'][0]['label'] = 'Foo bar Updated'
|
||||
import_site(update_payload)
|
||||
events_type.refresh_from_db()
|
||||
assert events_type.label == 'Foo bar Updated'
|
||||
|
||||
# insert another events_type
|
||||
events_type.slug = 'foo-bar-updated'
|
||||
events_type.save()
|
||||
import_site(copy.deepcopy(payload))
|
||||
assert EventsType.objects.count() == 2
|
||||
events_type = EventsType.objects.latest('pk')
|
||||
assert events_type.label == 'Foo bar'
|
||||
assert events_type.slug == 'foo-bar'
|
||||
|
||||
|
||||
@mock.patch('chrono.agendas.models.Agenda.is_available_for_simple_management')
|
||||
def test_import_export_desk_simple_management(available_mock):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='meetings', desk_simple_management=True)
|
||||
|
|
Loading…
Reference in New Issue