))}
diff --git a/rdmo/projects/exports.py b/rdmo/projects/exports.py
index 9c3c374484..23237fcd14 100644
--- a/rdmo/projects/exports.py
+++ b/rdmo/projects/exports.py
@@ -156,13 +156,25 @@ def render(self):
class RDMOXMLExport(Export):
def render(self):
- if self.project:
- content_disposition = f'attachment; filename="{self.project.title}.xml"'
- serializer = ProjectExportSerializer(self.project)
+ content_disposition = f'attachment; filename="{self.project.title}.xml"'
+ serializer = ProjectExportSerializer(self.project)
- else:
- content_disposition = f'attachment; filename="{self.snapshot.title}.xml"'
- serializer = SnapshotExportSerializer(self.snapshot)
+ xmldata = XMLRenderer().render(serializer.data)
+ response = HttpResponse(prettify_xml(xmldata), content_type="application/xml")
+
+ if settings.EXPORT_CONTENT_DISPOSITION == 'attachment':
+ response['Content-Disposition'] = content_disposition
+
+ return response
+
+
+class RDMOSnapshotXMLExport(Export):
+
+ plugin_type = 'project_snapshot_export'
+
+ def render(self):
+ content_disposition = f'attachment; filename="{self.snapshot.title}.xml"'
+ serializer = SnapshotExportSerializer(self.snapshot)
xmldata = XMLRenderer().render(serializer.data)
response = HttpResponse(prettify_xml(xmldata), content_type="application/xml")
diff --git a/rdmo/projects/mixins.py b/rdmo/projects/mixins.py
index 530f742b4c..80ddac4612 100644
--- a/rdmo/projects/mixins.py
+++ b/rdmo/projects/mixins.py
@@ -63,22 +63,38 @@ def update_values(self, current_project, catalog, values, snapshots=None):
.get(value.set_index, {}) \
.get(value.collection_index)
- def get_import_plugin(self, key, current_project=None):
- plugins = Plugin.objects.for_context(
+ def get_plugin_by_url_name(self, url_name, project=None):
+ for plugin in Plugin.objects.for_context(
plugin_type=PLUGIN_TYPES.PROJECT_IMPORT,
- project=current_project,
+ project=project,
user=self.request.user,
- format=key
- )
- plugin = next((i for i in plugins if i.url_name == key), None)
- if plugin is None:
- raise Http404
+ ):
+ if plugin.url_name == url_name:
+ return plugin
- import_plugin = plugin.initialize_class()
- import_plugin.request = self.request
- import_plugin.current_project = current_project
+ def get_plugin_by_suffix(self, suffix, project=None):
+ for plugin in Plugin.objects.for_context(
+ plugin_type=PLUGIN_TYPES.PROJECT_IMPORT,
+ project=project,
+ user=self.request.user,
+ ):
+ accept = plugin.plugin_meta.get('accept')
+ if isinstance(accept, dict):
+ for _mime_type, suffixes in accept.items():
+ if suffix in suffixes:
+ return plugin
+
+ def get_import_plugin(self):
+ plugin = self.get_plugin_by_url_name(self.kwargs.get('url_name'), self.object)
+ if plugin:
+ import_plugin = plugin.initialize_class()
+ import_plugin.request = self.request
+ import_plugin.current_project = self.object
+
+ return import_plugin
- return import_plugin
+ # no plugin for this url_name found
+ raise Http404
def upload_file(self):
try:
@@ -106,47 +122,46 @@ def import_form(self):
'errors': [_('There has been an error with your import. No uploaded or retrieved file could be found.')]
}, status=400)
- for plugin in Plugin.objects.for_context(
- plugin_type=PLUGIN_TYPES.PROJECT_IMPORT, project=current_project,
- user=self.request.user, format=Path(import_file_name).suffix.lstrip('.')
- ):
- import_plugin = plugin.initialize_class()
- import_plugin.current_project = current_project
- import_plugin.file_name = import_file_name
- import_plugin.source_title = import_source_title
- import_plugin.request = self.request
+ suffix = Path(import_file_name).suffix
+ plugin = self.get_plugin_by_suffix(suffix, current_project)
+ if plugin is None:
+ return render(self.request, 'core/error.html', {
+ 'title': _('Import error'),
+ 'errors': [_('Files of this type cannot be imported.')]
+ }, status=400)
- if import_plugin.check():
- try:
- import_plugin.process()
- except ValidationError as e:
- return render(self.request, 'core/error.html', {
- 'title': _('Import error'),
- 'errors': e
- }, status=400)
+ import_plugin = plugin.initialize_class()
+ import_plugin.request = self.request
+ import_plugin.current_project = current_project
+ import_plugin.file_name = import_file_name
+ import_plugin.source_title = import_source_title
- # store information in session for ProjectCreateImportView
- self.request.session['import_key'] = plugin.url_name
+ if import_plugin.check():
+ try:
+ import_plugin.process()
+ except ValidationError as e:
+ return render(self.request, 'core/error.html', {
+ 'title': _('Import error'),
+ 'errors': e
+ }, status=400)
- # attach questions and current values
- self.update_values(current_project, import_plugin.catalog,
- import_plugin.values, import_plugin.snapshots)
+ # store information in session for ProjectCreateImportView
+ self.request.session['import_plugin_id'] = plugin.id
- return render(self.request, 'projects/project_import.html', {
- 'method': 'import_file',
- 'current_project': current_project,
- 'source_title': import_plugin.source_title,
- 'source_project': import_plugin.project,
- 'values': import_plugin.values,
- 'snapshots': import_plugin.snapshots if not current_project else None,
- 'tasks': import_plugin.tasks,
- 'views': import_plugin.views
- })
+ # attach questions and current values
+ self.update_values(current_project, import_plugin.catalog,
+ import_plugin.values, import_plugin.snapshots)
- return render(self.request, 'core/error.html', {
- 'title': _('Import error'),
- 'errors': [_('Files of this type cannot be imported.')]
- }, status=400)
+ return render(self.request, 'projects/project_import.html', {
+ 'method': 'import_file',
+ 'current_project': current_project,
+ 'source_title': import_plugin.source_title,
+ 'source_project': import_plugin.project,
+ 'values': import_plugin.values,
+ 'snapshots': import_plugin.snapshots if not current_project else None,
+ 'tasks': import_plugin.tasks,
+ 'views': import_plugin.views
+ })
def import_file(self):
current_project = self.object
@@ -159,7 +174,7 @@ def import_file(self):
try:
import_tmpfile_name = self.request.session.pop('import_file_name')
- import_key = self.request.session.pop('import_key')
+ plugin_id = self.request.session.pop('import_plugin_id')
except KeyError:
return render(self.request, 'core/error.html', {
'title': _('Import error'),
@@ -168,8 +183,16 @@ def import_file(self):
checked = [key for key, value in self.request.POST.items() if 'on' in value]
- if import_tmpfile_name and import_key:
- import_plugin = self.get_import_plugin(import_key, current_project)
+ if import_tmpfile_name and plugin_id:
+ plugin = Plugin.objects.for_context(
+ plugin_type=PLUGIN_TYPES.PROJECT_IMPORT,
+ project=current_project,
+ user=self.request.user,
+ ).get(id=plugin_id)
+
+ import_plugin = plugin.initialize_class()
+ import_plugin.request = self.request
+ import_plugin.current_project = current_project
import_plugin.file_name = import_tmpfile_name
if import_plugin.check():
diff --git a/rdmo/projects/serializers/v1/__init__.py b/rdmo/projects/serializers/v1/__init__.py
index b5cdf415f7..6d273ea8d3 100644
--- a/rdmo/projects/serializers/v1/__init__.py
+++ b/rdmo/projects/serializers/v1/__init__.py
@@ -151,17 +151,13 @@ class Meta:
class ProjectImportPluginSerializer(serializers.ModelSerializer):
- key = serializers.CharField(source='url_name')
- label = serializers.CharField(source='title')
- class_name = serializers.CharField(source='python_path')
href = serializers.SerializerMethodField()
class Meta:
model = Plugin
fields = (
- 'key',
- 'label',
- 'class_name',
+ 'title',
+ 'url_name',
'href',
)
diff --git a/rdmo/projects/serializers/v1/page.py b/rdmo/projects/serializers/v1/page.py
index 12e99676f8..0b707dc7b1 100644
--- a/rdmo/projects/serializers/v1/page.py
+++ b/rdmo/projects/serializers/v1/page.py
@@ -41,6 +41,7 @@ class OptionSetSerializer(ElementModelSerializerMixin, serializers.ModelSerializ
model = serializers.SerializerMethodField()
options = OptionSerializer(source='elements', many=True)
+ has_provider = serializers.BooleanField(source='has_plugins')
class Meta:
model = OptionSet
@@ -49,7 +50,7 @@ class Meta:
'uri',
'model',
'options',
- 'has_plugins',
+ 'has_provider',
'has_search',
'has_refresh',
'has_conditions'
diff --git a/rdmo/projects/static/projects/css/project.scss b/rdmo/projects/static/projects/css/project.scss
index 1fda0c6b55..21d48021b2 100644
--- a/rdmo/projects/static/projects/css/project.scss
+++ b/rdmo/projects/static/projects/css/project.scss
@@ -22,3 +22,8 @@
width: 11px;
}
}
+
+.snapshot-export-button {
+ padding: 0;
+ border: none;
+}
diff --git a/rdmo/projects/templates/projects/project_detail_sidebar.html b/rdmo/projects/templates/projects/project_detail_sidebar.html
index fc51cee15a..6d563115ab 100644
--- a/rdmo/projects/templates/projects/project_detail_sidebar.html
+++ b/rdmo/projects/templates/projects/project_detail_sidebar.html
@@ -123,14 +123,14 @@
{% trans 'Options' %}
{% has_perm 'projects.export_project_object' request.user project as can_export_project %}
-{% if settings.PROJECT_EXPORTS and can_export_project %}
+{% if exports and can_export_project %}
{% trans 'Export' %}
- {% for key, label, class in settings.PROJECT_EXPORTS %}
+ {% for url_name, title in exports %}
{% endif %}
{% has_perm 'projects.import_project_object' request.user project as can_import_project %}
-{% if settings.PROJECT_IMPORTS and can_import_project %}
+{% if can_import_project %}
+{% if upload_import or ancestors_import or imports %}
{% trans 'Import values' %}
+ {% if upload_import %}
{% trans 'Import from file' %}
@@ -149,7 +151,9 @@
{% trans 'Import values' %}
{% url 'project_update_import' project.id as upload_url %}
{% include 'core/upload_form.html' with upload_url=upload_url label=True %}
- {% if settings.NESTED_PROJECTS and ancestors_import %}
+ {% endif %}
+
+ {% if ancestors_import %}
{% trans 'Import from parent project' %}
@@ -157,21 +161,21 @@
{% trans 'Import values' %}
{% include 'projects/project_detail_sidebar_parent_import.html' %}
{% endif %}
- {% if settings.PROJECT_IMPORTS_LIST %}
+
+ {% if url_import %}
{% trans 'Import directly' %}
- {% for key, label, class in settings.PROJECT_IMPORTS %}
- {% if key in settings.PROJECT_IMPORTS_LIST %}
+ {% for url_name, title in url_import %}