From 026e3704c6c1bae3e414890b2329a828daae60fd Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Thu, 26 Sep 2024 10:17:24 +0200 Subject: [PATCH 1/9] Clean up projectActions --- .../js/projects/actions/projectsActions.js | 26 +++++++++---------- .../js/projects/reducers/projectsReducer.js | 16 ++++++------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/rdmo/projects/assets/js/projects/actions/projectsActions.js b/rdmo/projects/assets/js/projects/actions/projectsActions.js index d8529cb539..eda01b9537 100644 --- a/rdmo/projects/assets/js/projects/actions/projectsActions.js +++ b/rdmo/projects/assets/js/projects/actions/projectsActions.js @@ -47,9 +47,9 @@ export function fetchProjectsError(error) { export function fetchCatalogs() { return function(dispatch) { dispatch(fetchCatalogsInit()) - const action = (dispatch) => ProjectsApi.fetchCatalogs() - .then(catalogs => { - dispatch(fetchCatalogsSuccess({ catalogs }))}) + const action = (dispatch) => ProjectsApi.fetchCatalogs().then(catalogs => { + dispatch(fetchCatalogsSuccess(catalogs)) + }) return dispatch(action) .catch(error => dispatch(fetchCatalogsError(error))) @@ -71,9 +71,9 @@ export function fetchCatalogsError(error) { export function fetchAllowedFileTypes() { return function(dispatch) { dispatch(fetchAllowedFileTypesInit()) - const action = (dispatch) => ProjectsApi.fetchAllowedFileTypes() - .then(allowedTypes => { - dispatch(fetchAllowedFileTypesSuccess({ allowedTypes }))}) + const action = (dispatch) => ProjectsApi.fetchAllowedFileTypes().then(allowedTypes => { + dispatch(fetchAllowedFileTypesSuccess(allowedTypes)) + }) return dispatch(action) .catch(error => dispatch(fetchAllowedFileTypesError(error))) @@ -95,9 +95,9 @@ export function fetchAllowedFileTypesError(error) { export function fetchImportUrls() { return function(dispatch) { dispatch(fetchImportUrlsInit()) - const action = (dispatch) => ProjectsApi.fetchDirectImportUrls() - .then(importUrls => { - dispatch(fettchImportUrlsSuccess({ importUrls }))}) + const action = (dispatch) => ProjectsApi.fetchDirectImportUrls().then(importUrls => { + dispatch(fettchImportUrlsSuccess(importUrls)) + }) return dispatch(action) .catch(error => dispatch(fetchImportUrlsError(error))) @@ -109,7 +109,7 @@ export function fetchImportUrlsInit() { } export function fettchImportUrlsSuccess(importUrls) { - return {type: FETCH_IMPORT_URLS_SUCCESS, importUrls } + return {type: FETCH_IMPORT_URLS_SUCCESS, importUrls} } export function fetchImportUrlsError(error) { @@ -119,9 +119,9 @@ export function fetchImportUrlsError(error) { export function fetchInvitations() { return function(dispatch) { dispatch(fetchInvitationsInit()) - const action = (dispatch) => ProjectsApi.fetchInvites() - .then(invites => { - dispatch(fetchInvitationsSuccess({ invites }))}) + const action = (dispatch) => ProjectsApi.fetchInvites().then(invites => { + dispatch(fetchInvitationsSuccess(invites)) + }) return dispatch(action) .catch(error => dispatch(fetchInvitationsError(error))) diff --git a/rdmo/projects/assets/js/projects/reducers/projectsReducer.js b/rdmo/projects/assets/js/projects/reducers/projectsReducer.js index c724ade2c6..4c09b221e7 100644 --- a/rdmo/projects/assets/js/projects/reducers/projectsReducer.js +++ b/rdmo/projects/assets/js/projects/reducers/projectsReducer.js @@ -26,27 +26,27 @@ export default function projectsReducer(state = initialState, action) { case FETCH_PROJECTS_ERROR: return {...state, errors: action.error.errors} case FETCH_INVITATIONS_INIT: - return {...state, ...action.invites} + return {...state} case FETCH_INVITATIONS_SUCCESS: - return {...state, ...action.invites} + return {...state, invites: action.invites} case FETCH_INVITATIONS_ERROR: return {...state, errors: action.error.errors} case FETCH_CATALOGS_INIT: - return {...state, ...action.catalogs} + return {...state} case FETCH_CATALOGS_SUCCESS: - return {...state, ...action.catalogs} + return {...state, catalogs: action.catalogs} case FETCH_CATALOGS_ERROR: return {...state, errors: action.error.errors} case FETCH_FILETYPES_INIT: - return {...state, ...action.allowedTypes} + return {...state} case FETCH_FILETYPES_SUCCESS: - return {...state, ...action.allowedTypes} + return {...state, allowedTypes: action.allowedTypes} case FETCH_FILETYPES_ERROR: return {...state, errors: action.error.errors} case FETCH_IMPORT_URLS_INIT: - return {...state, ...action.importUrls} + return {...state} case FETCH_IMPORT_URLS_SUCCESS: - return {...state, ...action.importUrls} + return {...state, importUrls: action.importUrls} case FETCH_IMPORT_URLS_ERROR: return {...state, errors: action.error.errors} default: From e52d0b551bb457b7050f6f886acf1b70f4099e29 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Thu, 26 Sep 2024 10:18:12 +0200 Subject: [PATCH 2/9] Refactor accept field in import plugins to match react-dropzone --- rdmo/projects/imports.py | 8 +++++++- rdmo/projects/utils.py | 14 +++++++++----- rdmo/projects/views/project.py | 4 +++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/rdmo/projects/imports.py b/rdmo/projects/imports.py index f3665111fc..e8c9ccb656 100644 --- a/rdmo/projects/imports.py +++ b/rdmo/projects/imports.py @@ -88,7 +88,10 @@ def get_view(self, view_uri): class RDMOXMLImport(Import): - accept = '.xml' + accept = { + 'application/xml': ['.xml'], + 'text/xml': ['.xml'] + } def check(self): file_type, encoding = mimetypes.guess_type(self.file_name) @@ -231,6 +234,9 @@ def get_value(self, value_node): class URLImport(RDMOXMLImport): + accept = False + upload = False + class Form(forms.Form): url = forms.URLField(label=_('Import project from this URL'), required=True) diff --git a/rdmo/projects/utils.py b/rdmo/projects/utils.py index f699ed4885..ce27042e90 100644 --- a/rdmo/projects/utils.py +++ b/rdmo/projects/utils.py @@ -1,4 +1,5 @@ import logging +from collections import defaultdict from pathlib import Path from django.conf import settings @@ -278,13 +279,16 @@ def set_context_querystring_with_filter_and_page(context: dict) -> dict: def get_upload_accept(): - accept = set() + accept = defaultdict(set) for import_plugin in get_plugins('PROJECT_IMPORTS').values(): if import_plugin.accept: - accept.add(import_plugin.accept) - else: - return None - return ','.join(accept) + for key, values in import_plugin.accept.items(): + accept[key].update(values) + elif import_plugin.upload is True: + # if one of the plugins does not have the accept field, but is marked as upload plugin + # all file types are allowed + return {} + return accept def compute_set_prefix_from_set_value(set_value, value): diff --git a/rdmo/projects/views/project.py b/rdmo/projects/views/project.py index 9760fbd3b6..16ae635d9d 100644 --- a/rdmo/projects/views/project.py +++ b/rdmo/projects/views/project.py @@ -87,7 +87,9 @@ def get_context_data(self, **kwargs): context['snapshots'] = project.snapshots.all() context['invites'] = project.invites.all() context['membership'] = Membership.objects.filter(project=project, user=self.request.user).first() - context['upload_accept'] = get_upload_accept() + context['upload_accept'] = ','.join([ + suffix for suffixes in get_upload_accept().values() for suffix in suffixes + ]) return context From 28e8535904e8a27def0dbeb94f124b07fbdf0d5f Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Thu, 26 Sep 2024 12:18:24 +0200 Subject: [PATCH 3/9] Fix tests --- rdmo/projects/tests/test_viewset_project.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rdmo/projects/tests/test_viewset_project.py b/rdmo/projects/tests/test_viewset_project.py index f45351743b..acf975bce3 100644 --- a/rdmo/projects/tests/test_viewset_project.py +++ b/rdmo/projects/tests/test_viewset_project.py @@ -578,7 +578,10 @@ def test_upload_accept(db, client, username, password): if password: assert response.status_code == 200 - assert response.json() == '.xml' + assert response.json() == { + 'application/xml': ['.xml'], + 'text/xml': ['.xml'] + } else: assert response.status_code == 401 From a0fcda2d6e7617f4cc68877ac931bce9518af0e8 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 15:18:53 +0100 Subject: [PATCH 4/9] Add legacy fallback in get_upload_accept --- rdmo/projects/utils.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rdmo/projects/utils.py b/rdmo/projects/utils.py index ce27042e90..4809ea80b9 100644 --- a/rdmo/projects/utils.py +++ b/rdmo/projects/utils.py @@ -1,4 +1,5 @@ import logging +import mimetypes from collections import defaultdict from pathlib import Path @@ -281,13 +282,21 @@ def set_context_querystring_with_filter_and_page(context: dict) -> dict: def get_upload_accept(): accept = defaultdict(set) for import_plugin in get_plugins('PROJECT_IMPORTS').values(): - if import_plugin.accept: - for key, values in import_plugin.accept.items(): - accept[key].update(values) + if isinstance(import_plugin.accept, dict): + for mime_type, suffixes in import_plugin.accept.items(): + accept[mime_type].update(suffixes) + + elif isinstance(import_plugin.accept, str): + # legacy fallback for pre 2.3.0 RDMO, e.g. `accept = '.xml'` + suffix = import_plugin.accept + mime_type, encoding = mimetypes.guess_type(f'example{suffix}') + accept[mime_type].update([suffix]) + elif import_plugin.upload is True: # if one of the plugins does not have the accept field, but is marked as upload plugin # all file types are allowed return {} + return accept From 9e6070d7d50ba93757c64a1c1cdaef0e48d18e5a Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 15:27:46 +0100 Subject: [PATCH 5/9] Fix propTypes --- rdmo/core/assets/js/components/UploadDropZone.js | 2 +- .../assets/js/projects/components/helper/ProjectImport.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rdmo/core/assets/js/components/UploadDropZone.js b/rdmo/core/assets/js/components/UploadDropZone.js index f9be740aac..4f8ebf17e2 100644 --- a/rdmo/core/assets/js/components/UploadDropZone.js +++ b/rdmo/core/assets/js/components/UploadDropZone.js @@ -40,7 +40,7 @@ const UploadDropZone = ({ acceptedTypes, onImportFile }) => { } UploadDropZone.propTypes = { - acceptedTypes: PropTypes.arrayOf(PropTypes.string), + acceptedTypes: PropTypes.object, onImportFile: PropTypes.func.isRequired, } diff --git a/rdmo/projects/assets/js/projects/components/helper/ProjectImport.js b/rdmo/projects/assets/js/projects/components/helper/ProjectImport.js index ddb741b4f4..fccf9b4139 100644 --- a/rdmo/projects/assets/js/projects/components/helper/ProjectImport.js +++ b/rdmo/projects/assets/js/projects/components/helper/ProjectImport.js @@ -34,7 +34,7 @@ const ProjectImport = ({ allowedTypes, handleImport, importUrls}) => { } ProjectImport.propTypes = { - allowedTypes: PropTypes.arrayOf(PropTypes.string), + allowedTypes: PropTypes.object, handleImport: PropTypes.func.isRequired, importUrls: PropTypes.arrayOf(PropTypes.object).isRequired } From 3b09e84aae7dd307e3f458c9699f947470844e59 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 15:27:55 +0100 Subject: [PATCH 6/9] Fix typos --- rdmo/projects/assets/js/projects/actions/projectsActions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rdmo/projects/assets/js/projects/actions/projectsActions.js b/rdmo/projects/assets/js/projects/actions/projectsActions.js index eda01b9537..49a8da87aa 100644 --- a/rdmo/projects/assets/js/projects/actions/projectsActions.js +++ b/rdmo/projects/assets/js/projects/actions/projectsActions.js @@ -96,7 +96,7 @@ export function fetchImportUrls() { return function(dispatch) { dispatch(fetchImportUrlsInit()) const action = (dispatch) => ProjectsApi.fetchDirectImportUrls().then(importUrls => { - dispatch(fettchImportUrlsSuccess(importUrls)) + dispatch(fetchImportUrlsSuccess(importUrls)) }) return dispatch(action) @@ -108,7 +108,7 @@ export function fetchImportUrlsInit() { return {type: FETCH_IMPORT_URLS_INIT} } -export function fettchImportUrlsSuccess(importUrls) { +export function fetchImportUrlsSuccess(importUrls) { return {type: FETCH_IMPORT_URLS_SUCCESS, importUrls} } From 4dc0c58016661c3395d50262e6512de2b918daaf Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 15:34:27 +0100 Subject: [PATCH 7/9] Fix accept --- rdmo/projects/imports.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rdmo/projects/imports.py b/rdmo/projects/imports.py index e8c9ccb656..446d1769a5 100644 --- a/rdmo/projects/imports.py +++ b/rdmo/projects/imports.py @@ -89,8 +89,7 @@ def get_view(self, view_uri): class RDMOXMLImport(Import): accept = { - 'application/xml': ['.xml'], - 'text/xml': ['.xml'] + 'application/xml': ['.xml'] } def check(self): From af4b5cded546f36bf71a3a88521c348e2aaa3863 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 15:37:58 +0100 Subject: [PATCH 8/9] Fix get_upload_accept --- rdmo/projects/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rdmo/projects/utils.py b/rdmo/projects/utils.py index 4809ea80b9..fc2f9582b9 100644 --- a/rdmo/projects/utils.py +++ b/rdmo/projects/utils.py @@ -290,7 +290,8 @@ def get_upload_accept(): # legacy fallback for pre 2.3.0 RDMO, e.g. `accept = '.xml'` suffix = import_plugin.accept mime_type, encoding = mimetypes.guess_type(f'example{suffix}') - accept[mime_type].update([suffix]) + if mime_type: + accept[mime_type].update([suffix]) elif import_plugin.upload is True: # if one of the plugins does not have the accept field, but is marked as upload plugin From f475cf0aa9a4181dcda6fecc1367d77c6bef64b9 Mon Sep 17 00:00:00 2001 From: Jochen Klar Date: Fri, 7 Feb 2025 16:16:46 +0100 Subject: [PATCH 9/9] Fix tests --- rdmo/projects/tests/test_viewset_project.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rdmo/projects/tests/test_viewset_project.py b/rdmo/projects/tests/test_viewset_project.py index acf975bce3..76048202a3 100644 --- a/rdmo/projects/tests/test_viewset_project.py +++ b/rdmo/projects/tests/test_viewset_project.py @@ -579,8 +579,7 @@ def test_upload_accept(db, client, username, password): if password: assert response.status_code == 200 assert response.json() == { - 'application/xml': ['.xml'], - 'text/xml': ['.xml'] + 'application/xml': ['.xml'] } else: assert response.status_code == 401