From 38724a65f1127dc24f3d52b35fffbcedf037dbb3 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Thu, 19 Dec 2019 15:27:39 +0100 Subject: [PATCH 2/2] base: add import/export UI (#15269) Site export as well as connector export. --- passerelle/base/forms.py | 6 ++++ passerelle/base/urls.py | 8 ++++- passerelle/base/views.py | 36 ++++++++++++++++--- passerelle/templates/passerelle/manage.html | 3 ++ .../passerelle/manage/service_view.html | 1 + passerelle/urls.py | 8 +++-- passerelle/views.py | 8 +++++ 7 files changed, 63 insertions(+), 7 deletions(-) diff --git a/passerelle/base/forms.py b/passerelle/base/forms.py index 2ac0605d..7f7969bb 100644 --- a/passerelle/base/forms.py +++ b/passerelle/base/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import ugettext_lazy as _ from .models import ApiUser, AccessRight, AvailabilityParameters @@ -27,3 +28,8 @@ class AvailabilityParametersForm(forms.ModelForm): widgets = { 'notification_delays': forms.TextInput, } + + +class ImportSiteForm(forms.Form): + site_json = forms.FileField(label=_('Site Export File')) + import_users = forms.BooleanField(label=_('Import users and access rights'), required=False) diff --git a/passerelle/base/urls.py b/passerelle/base/urls.py index 33536a31..6664e3b8 100644 --- a/passerelle/base/urls.py +++ b/passerelle/base/urls.py @@ -2,7 +2,8 @@ from django.conf.urls import url from .views import ApiUserCreateView, ApiUserUpdateView, ApiUserDeleteView, \ ApiUserListView, AccessRightDeleteView, AccessRightCreateView, \ - LoggingParametersUpdateView, ManageAvailabilityView + LoggingParametersUpdateView, ManageAvailabilityView, ImportSiteView, \ + ExportSiteView access_urlpatterns = [ url(r'^$', ApiUserListView.as_view(), name='apiuser-list'), @@ -20,3 +21,8 @@ access_urlpatterns = [ ManageAvailabilityView.as_view(), name='manage-availability') ] + +import_export_urlpatterns = [ + url(r'^import$', ImportSiteView.as_view(), name='import-site'), + url(r'^export$', ExportSiteView.as_view(), name='export-site'), +] diff --git a/passerelle/base/views.py b/passerelle/base/views.py index c9470928..a3d8ca13 100644 --- a/passerelle/base/views.py +++ b/passerelle/base/views.py @@ -15,6 +15,7 @@ # along with this program. If not, see . import datetime +import json from dateutil import parser as date_parser @@ -25,15 +26,15 @@ from django.core.exceptions import ObjectDoesNotExist, PermissionDenied from django.db.models import Q from django.forms import models as model_forms from django.views.generic import ( - DetailView, ListView, CreateView, UpdateView, DeleteView, FormView) -from django.http import Http404 + View, DetailView, ListView, CreateView, UpdateView, DeleteView, FormView) +from django.http import Http404, HttpResponse from django.utils.timezone import make_aware from django.utils.translation import ugettext_lazy as _ from .models import ApiUser, AccessRight, LoggingParameters, ResourceStatus, Job -from .forms import ApiUserForm, AccessRightForm, AvailabilityParametersForm +from .forms import ApiUserForm, AccessRightForm, AvailabilityParametersForm, ImportSiteForm from ..views import GenericConnectorMixin -from ..utils import get_trusted_services +from ..utils import get_trusted_services, import_site, export_site class ResourceView(DetailView): @@ -277,3 +278,30 @@ class GenericJobView(GenericConnectorMixin, DetailView): except Job.DoesNotExist: raise Http404() return context + + +class ImportSiteView(FormView): + template_name = 'passerelle/manage/import_site.html' + form_class = ImportSiteForm + + def get_success_url(self): + return reverse('manage-home') + + def form_valid(self, form): + try: + site_json = json.load(self.request.FILES['site_json']) + except ValueError: + form.add_error('site_json', _('File is not in the expected JSON format.')) + return self.form_invalid(form) + + results = import_site(site_json, overwrite=True, + import_users=form.cleaned_data['import_users']) + return super(ImportSiteView, self).form_valid(form) + + +class ExportSiteView(View): + + def get(self, request, *args, **kwargs): + response = HttpResponse(content_type='application/json') + json.dump(export_site(), response, indent=2) + return response diff --git a/passerelle/templates/passerelle/manage.html b/passerelle/templates/passerelle/manage.html index beb8c7a0..d2279834 100644 --- a/passerelle/templates/passerelle/manage.html +++ b/passerelle/templates/passerelle/manage.html @@ -20,6 +20,9 @@ {% endfor %} +
+{% trans 'Import' %} +{% trans 'Export' %} {% endblock %} diff --git a/passerelle/templates/passerelle/manage/service_view.html b/passerelle/templates/passerelle/manage/service_view.html index 567024a9..8d6c547e 100644 --- a/passerelle/templates/passerelle/manage/service_view.html +++ b/passerelle/templates/passerelle/manage/service_view.html @@ -27,6 +27,7 @@ {% if object|can_delete:request.user %} {% trans 'delete' %} {% endif %} +{% trans 'export' %} {% endblock %} diff --git a/passerelle/urls.py b/passerelle/urls.py index 4a1947e1..4461b2e5 100644 --- a/passerelle/urls.py +++ b/passerelle/urls.py @@ -9,11 +9,11 @@ from django.views.static import serve as static_serve from .views import (HomePageView, ManageView, ManageAddView, GenericCreateConnectorView, GenericDeleteConnectorView, GenericEditConnectorView, GenericEndpointView, GenericConnectorView, - GenericViewLogsConnectorView, GenericLogView, + GenericViewLogsConnectorView, GenericLogView, GenericExportConnectorView, login, logout, menu_json) from .base.views import GenericViewJobsConnectorView, GenericJobView from .urls_utils import decorated_includes, required, app_enabled, manager_required -from .base.urls import access_urlpatterns +from .base.urls import access_urlpatterns, import_export_urlpatterns from .plugins import register_apps_urls from passerelle.apps.pastell import urls as pastell_urls @@ -34,6 +34,8 @@ urlpatterns = [ url(r'^manage/access/', decorated_includes(manager_required, include(access_urlpatterns))), + url(r'^manage/', + decorated_includes(manager_required, include(import_export_urlpatterns))), ] urlpatterns += required( @@ -73,6 +75,8 @@ urlpatterns += [ GenericViewJobsConnectorView.as_view(), name='view-jobs-connector'), url(r'^(?P[\w,-]+)/jobs/(?P\d+)/$', GenericJobView.as_view(), name='view-job'), + url(r'^(?P[\w,-]+)/export$', + GenericExportConnectorView.as_view(), name='export-connector'), ]))) ] diff --git a/passerelle/views.py b/passerelle/views.py index a82f219e..edf94afd 100644 --- a/passerelle/views.py +++ b/passerelle/views.py @@ -477,3 +477,11 @@ class GenericEndpointView(GenericConnectorMixin, SingleObjectMixin, View): def delete(self, request, *args, **kwargs): return self.get(request, *args, **kwargs) + + +class GenericExportConnectorView(GenericConnectorMixin, DetailView): + + def get(self, request, *args, **kwargs): + response = HttpResponse(content_type='application/json') + json.dump({'resources': [self.get_object().export_json()]}, response, indent=2) + return response -- 2.20.1