environment: import and export parameters (#33672)
This commit is contained in:
parent
3ead547aa1
commit
60e5bd28d0
|
@ -210,3 +210,7 @@ class VariablesFormMixin(object):
|
|||
messages.info(self.request, self.success_message)
|
||||
|
||||
return HttpResponseRedirect('.')
|
||||
|
||||
|
||||
class ImportForm(forms.Form):
|
||||
parameters_json = forms.FileField(label=_('Parameters Export File'))
|
||||
|
|
|
@ -34,5 +34,8 @@ urlpatterns = [
|
|||
|
||||
url(r'^new-variable-(?P<service>\w+)/(?P<slug>[\w-]+)$',
|
||||
views.VariableCreateView.as_view(), name='new-variable-service',),
|
||||
|
||||
url(r'^import/$', views.ImportView.as_view(), name='environment-import'),
|
||||
url(r'^export/$', views.ExportView.as_view(), name='environment-export'),
|
||||
url(r'^debug.json$', views.debug_json, name='debug-json'),
|
||||
]
|
||||
|
|
|
@ -18,12 +18,13 @@ import hashlib
|
|||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from django.db import connection
|
||||
from django.db import connection, transaction
|
||||
from django.utils.six.moves.urllib.parse import urlparse
|
||||
from django.utils.encoding import force_text
|
||||
|
||||
from hobo.middleware.utils import StoreRequestMiddleware
|
||||
from hobo.multitenant.settings_loaders import KnownServices
|
||||
from hobo.profile.utils import get_profile_dict
|
||||
|
||||
|
||||
def get_installed_services():
|
||||
|
@ -144,3 +145,36 @@ def get_setting_variable(setting_name, label=None, service=None):
|
|||
auto=True)
|
||||
|
||||
return variable
|
||||
|
||||
|
||||
def export_parameters():
|
||||
from .models import Variable
|
||||
|
||||
variables = []
|
||||
for var in Variable.objects.filter(service_pk__isnull=True):
|
||||
variables.append({
|
||||
'name': var.name,
|
||||
'label': var.label,
|
||||
'value': var.value,
|
||||
'auto': var.auto})
|
||||
parameters = {'variables': variables}
|
||||
parameters.update(get_profile_dict())
|
||||
return parameters
|
||||
|
||||
|
||||
def import_parameters(parameters):
|
||||
from .models import Variable
|
||||
from hobo.profile.models import AttributeDefinition
|
||||
|
||||
with transaction.atomic():
|
||||
for variables in parameters.get('variables', []):
|
||||
obj, created = Variable.objects.get_or_create(name=variables['name'])
|
||||
for key, value in variables.items():
|
||||
setattr(obj, key, value)
|
||||
obj.save()
|
||||
|
||||
for fields in parameters.get('profile', {}).get('fields', []):
|
||||
obj, created = AttributeDefinition.objects.get_or_create(name=fields['name'])
|
||||
for key, value in fields.items():
|
||||
setattr(obj, key, value)
|
||||
obj.save()
|
||||
|
|
|
@ -20,10 +20,13 @@ import string
|
|||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.urls import reverse_lazy
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.encoding import force_text
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.generic import View
|
||||
from django.views.generic.base import TemplateView
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView
|
||||
|
||||
from .models import Variable, AVAILABLE_SERVICES
|
||||
from . import forms, utils
|
||||
|
@ -199,6 +202,31 @@ class ServiceDeleteView(DeleteView):
|
|||
return None
|
||||
|
||||
|
||||
class ImportView(FormView):
|
||||
form_class = forms.ImportForm
|
||||
template_name = 'environment/import.html'
|
||||
success_url = reverse_lazy('home')
|
||||
|
||||
def form_valid(self, form):
|
||||
try:
|
||||
parameters_json = json.loads(
|
||||
force_text(self.request.FILES['parameters_json'].read()))
|
||||
except ValueError:
|
||||
form.add_error('parameters_json', _('File is not in the expected JSON format.'))
|
||||
return self.form_invalid(form)
|
||||
|
||||
utils.import_parameters(parameters_json)
|
||||
return super(ImportView, self).form_valid(form)
|
||||
|
||||
|
||||
class ExportView(View):
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
response = JsonResponse(utils.export_parameters(), json_dumps_params={'indent': 2})
|
||||
response['Content-Disposition'] = 'attachment; filename="hobo-export.json"'
|
||||
return response
|
||||
|
||||
|
||||
def operational_check_view(request, service, slug, **kwargs):
|
||||
|
||||
for klass in AVAILABLE_SERVICES:
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
<li><a href="{% url 'seo-home' %}">{% trans 'Indexing' %}</a></li>
|
||||
<li><a href="{% url 'environment-home' %}">{% trans 'Services' %}</a></li>
|
||||
<li><a href="{% url 'environment-variables' %}">{% trans 'Variables' %}</a></li>
|
||||
<li><a rel="popup" href="{% url 'environment-import' %}">{% trans 'Import' %}</a></li>
|
||||
<li><a href="{% url 'environment-export' %}">{% trans 'Export' %}</a></li>
|
||||
<li><a href="{% url 'debug-home' %}">{% trans 'Debugging' %}</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import json
|
||||
import pytest
|
||||
from webtest import Upload
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.management import call_command
|
||||
from django.db.utils import IntegrityError
|
||||
from django.utils import timezone
|
||||
|
||||
from hobo.environment.models import AVAILABLE_SERVICES, Combo, Passerelle, ServiceBase, Variable
|
||||
from hobo.profile.models import AttributeDefinition
|
||||
|
||||
from test_manager import login
|
||||
|
||||
|
@ -316,3 +320,118 @@ def test_check_operational_command(monkeypatch, capsys):
|
|||
'foo is NOT operational',
|
||||
' last operational success: 2022-02-22 00:00:00+00:00'
|
||||
]
|
||||
|
||||
|
||||
def test_export_import_view(app, admin_user):
|
||||
combo = Combo.objects.create(base_url='https://combo.agglo.love',
|
||||
template_name='...portal-user...',
|
||||
slug='portal')
|
||||
Variable.objects.create(name='foo', value='bar').save()
|
||||
Variable.objects.create(name='foo2', value='bar2', service=combo).save()
|
||||
app = login(app, 'admin', 'password')
|
||||
resp = app.get('/sites/export/', status=200)
|
||||
assert sorted(resp.json.keys()) == ['profile', 'variables']
|
||||
assert resp.json['variables'] == [
|
||||
{'name': 'foo', 'label': '', 'value': 'bar', 'auto': False}]
|
||||
assert resp.json['profile']['fields'][0]['name'] == 'title'
|
||||
assert resp.json['profile']['fields'][0]['required'] is False
|
||||
assert resp.json['profile']['fields'][0]['description'] == ''
|
||||
assert resp.json['profile']['fields'][2]['name'] == 'last_name'
|
||||
assert resp.json['profile']['fields'][2]['required'] is True
|
||||
assert resp.json['profile']['fields'][2]['label'] == 'Nom'
|
||||
|
||||
# modify exported file
|
||||
export = resp.json
|
||||
export['variables'][0]['label'] = 'bar'
|
||||
fields = export['profile']['fields']
|
||||
assert fields[0]['name'] == 'title'
|
||||
assert fields[2]['name'] == 'last_name'
|
||||
fields[0]['description'] = 'genre'
|
||||
fields[2]['label'] = 'Nom de naissance'
|
||||
fields[0], fields[2] = fields[2], fields[0]
|
||||
export_json = json.dumps(export)
|
||||
|
||||
# add new content
|
||||
Variable.objects.create(name='foo3', value='bar3').save()
|
||||
AttributeDefinition.objects.create(name='prefered_color', label='not empty').save()
|
||||
assert Variable.objects.count() == 3
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
assert Variable.objects.get(name='foo').label == ''
|
||||
assert AttributeDefinition.objects.get(name='title').description == ''
|
||||
assert AttributeDefinition.objects.get(name='title').order == 1
|
||||
assert AttributeDefinition.objects.get(name='last_name').order == 3
|
||||
assert AttributeDefinition.objects.get(name='prefered_color').order == 12
|
||||
|
||||
# import valid content
|
||||
resp = app.get('/', status=200)
|
||||
resp = resp.click('Import')
|
||||
resp.form['parameters_json'] = Upload(
|
||||
'export.json', export_json.encode('utf-8'), 'application/json')
|
||||
resp = resp.form.submit()
|
||||
assert Variable.objects.count() == 3
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
assert Variable.objects.get(name='foo').label == 'bar'
|
||||
assert AttributeDefinition.objects.get(name='title').description == 'genre'
|
||||
assert AttributeDefinition.objects.get(name='title').order == 1
|
||||
assert AttributeDefinition.objects.get(name='last_name').label == 'Nom de naissance'
|
||||
assert AttributeDefinition.objects.get(name='last_name').order == 3
|
||||
assert AttributeDefinition.objects.get(name='prefered_color').order == 12
|
||||
|
||||
# import empty json
|
||||
resp = app.get('/', status=200)
|
||||
resp = resp.click('Import')
|
||||
resp.form['parameters_json'] = Upload(
|
||||
'export.json', b'{}', 'application/json')
|
||||
resp = resp.form.submit()
|
||||
assert Variable.objects.count() == 3
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
assert Variable.objects.get(name='foo').label == 'bar'
|
||||
assert AttributeDefinition.objects.get(name='title').description == 'genre'
|
||||
assert AttributeDefinition.objects.get(name='title').order == 1
|
||||
assert AttributeDefinition.objects.get(name='last_name').label == 'Nom de naissance'
|
||||
assert AttributeDefinition.objects.get(name='last_name').order == 3
|
||||
assert AttributeDefinition.objects.get(name='prefered_color').order == 12
|
||||
|
||||
# import from scratch
|
||||
Variable.objects.all().delete()
|
||||
AttributeDefinition.objects.all().delete()
|
||||
Variable.objects.create(name='foo2', value='bar2', service=combo).save()
|
||||
AttributeDefinition.objects.create(name='prefered_color', label='not empty').save()
|
||||
assert Variable.objects.count() == 1
|
||||
assert AttributeDefinition.objects.count() == 1
|
||||
resp = app.get('/', status=200)
|
||||
resp = resp.click('Import')
|
||||
resp.form['parameters_json'] = Upload(
|
||||
'export.json', export_json.encode('utf-8'), 'application/json')
|
||||
resp = resp.form.submit()
|
||||
assert Variable.objects.count() == 2
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
assert Variable.objects.get(name='foo').label == 'bar'
|
||||
assert AttributeDefinition.objects.get(name='title').order == 4
|
||||
assert AttributeDefinition.objects.get(name='last_name').order == 2
|
||||
assert AttributeDefinition.objects.get(name='prefered_color').order == 1
|
||||
|
||||
# import invalid json
|
||||
resp = app.get('/', status=200)
|
||||
resp = resp.click('Import')
|
||||
resp.form['parameters_json'] = Upload(
|
||||
'export.json', b'garbage', 'application/json')
|
||||
resp = resp.form.submit()
|
||||
assert Variable.objects.count() == 2
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
|
||||
# import corrupted json
|
||||
export['variables'][0]['label'] = 'foofoo'
|
||||
fields = export['profile']['fields']
|
||||
assert fields[2]['name'] == 'title'
|
||||
fields[2]['label'] = 'Nom de naissance'
|
||||
export_json = json.dumps(export)
|
||||
resp = app.get('/', status=200)
|
||||
resp = resp.click('Import')
|
||||
resp.form['parameters_json'] = Upload(
|
||||
'export.json', export_json.encode('utf-8'), 'application/json')
|
||||
with pytest.raises(IntegrityError):
|
||||
resp = resp.form.submit()
|
||||
assert Variable.objects.count() == 2
|
||||
assert AttributeDefinition.objects.count() == 12
|
||||
assert Variable.objects.get(name='foo').label == 'bar'
|
||||
|
|
Loading…
Reference in New Issue