From 1aeacce7ee722eaf32885d1e28f1813050a9ec06 Mon Sep 17 00:00:00 2001 From: Bilal MEDDAH Date: Tue, 25 Jul 2023 12:46:49 +0200 Subject: [PATCH 1/2] fix: decode and encode again the contentUrl to be sure that we can resolve the file fix: use _self when possible fix: remove version from files to be able to resolve by the resolver --- .../components/ImagePreview/ImagePreview.tsx | 2 +- src/shared/components/Preview/Preview.tsx | 4 ++-- .../ResourceEditor/ResourcesLRUCache.ts | 18 ++++++++++++++++-- .../components/ResourceEditor/editorUtils.ts | 2 +- .../ResourceEditor/useResolutionActions.tsx | 2 +- .../AnalysisPlugin/AnalysisPluginContainer.tsx | 2 +- .../containers/ResourceActionsContainer.tsx | 15 +++++++++------ src/shared/containers/TableViewerContainer.tsx | 2 +- 8 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/shared/components/ImagePreview/ImagePreview.tsx b/src/shared/components/ImagePreview/ImagePreview.tsx index 43ea7a519..996e541ba 100644 --- a/src/shared/components/ImagePreview/ImagePreview.tsx +++ b/src/shared/components/ImagePreview/ImagePreview.tsx @@ -114,7 +114,7 @@ const fetchImageResources = async ({ const rawData = await nexus.File.get( orgLabel, projectLabel, - parseResourceId(contentUrl), + encodeURIComponent(decodeURIComponent(contentUrl)), { as: 'blob' } ); const blob = new Blob([rawData as string], { diff --git a/src/shared/components/Preview/Preview.tsx b/src/shared/components/Preview/Preview.tsx index 00a264d2a..06f802322 100644 --- a/src/shared/components/Preview/Preview.tsx +++ b/src/shared/components/Preview/Preview.tsx @@ -244,14 +244,14 @@ const Preview: React.FC<{ contentUrl = url; options.rev = parseInt(rev, 10); } + try { const rawData = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(contentUrl), + encodeURIComponent(decodeURIComponent(contentUrl)), options ); - downloadBlobHelper(rawData, asset.name); } catch (error) { notification.error({ diff --git a/src/shared/components/ResourceEditor/ResourcesLRUCache.ts b/src/shared/components/ResourceEditor/ResourcesLRUCache.ts index 698bdf927..63baeef9f 100644 --- a/src/shared/components/ResourceEditor/ResourcesLRUCache.ts +++ b/src/shared/components/ResourceEditor/ResourcesLRUCache.ts @@ -4,6 +4,16 @@ import LRUCache from 'lru-cache'; // TODO: Use nexus.httpGet to prepare for using http cache headers // since the nexus SDK can not accept the headers as an argument + +const parseResourceId = (url: string) => { + const fileUrlPattern = /files\/([\w-]+)\/([\w-]+)\/(.*)/; + if (fileUrlPattern.test(url)) { + const [, , , resourceId] = url.match(fileUrlPattern) as string[]; + return decodeURIComponent(resourceId.split('?rev=')[0]); + } + return decodeURIComponent(url); +}; + const lookByProjectResolver = async ({ nexus, apiEndpoint, @@ -18,7 +28,9 @@ const lookByProjectResolver = async ({ resourceId: string; }): Promise => { return await nexus.httpGet({ - path: `${apiEndpoint}/resolvers/${orgLabel}/${projectLabel}/_/${resourceId}`, + path: `${apiEndpoint}/resolvers/${orgLabel}/${projectLabel}/_/${encodeURIComponent( + parseResourceId(resourceId) + )}`, }); }; const lookBySearchApi = async ({ @@ -31,7 +43,9 @@ const lookBySearchApi = async ({ resourceId: string; }): Promise => { return await nexus.httpGet({ - path: `${apiEndpoint}/resources?locate=${resourceId}`, + path: `${apiEndpoint}/resources?locate=${encodeURIComponent( + parseResourceId(resourceId) + )}`, }); }; diff --git a/src/shared/components/ResourceEditor/editorUtils.ts b/src/shared/components/ResourceEditor/editorUtils.ts index 28448bd43..61f04fa56 100644 --- a/src/shared/components/ResourceEditor/editorUtils.ts +++ b/src/shared/components/ResourceEditor/editorUtils.ts @@ -174,7 +174,7 @@ export async function editorLinkResolutionHandler({ apiEndpoint, orgLabel, projectLabel, - resourceId: encodeURIComponent(url), + resourceId: url, }, })); } diff --git a/src/shared/components/ResourceEditor/useResolutionActions.tsx b/src/shared/components/ResourceEditor/useResolutionActions.tsx index 5512a1260..09bd7973c 100644 --- a/src/shared/components/ResourceEditor/useResolutionActions.tsx +++ b/src/shared/components/ResourceEditor/useResolutionActions.tsx @@ -76,7 +76,7 @@ const useResolvedLinkEditorPopover = () => { const data = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(parseResourceId(resourceId)), + encodeURIComponent(decodeURIComponent(parseResourceId(resourceId))), { as: 'blob' } ); return download(title, ext ?? 'json', data); diff --git a/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx b/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx index 803866589..f0232f320 100644 --- a/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx +++ b/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx @@ -41,7 +41,7 @@ async function fetchImageObjectUrl( const rawData = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(imageResourceId), + encodeURIComponent(decodeURIComponent(imageResourceId)), { as: 'blob', } diff --git a/src/shared/containers/ResourceActionsContainer.tsx b/src/shared/containers/ResourceActionsContainer.tsx index 9ea3c0c35..d19e1d477 100644 --- a/src/shared/containers/ResourceActionsContainer.tsx +++ b/src/shared/containers/ResourceActionsContainer.tsx @@ -154,12 +154,15 @@ const ResourceActionsContainer: React.FunctionComponent<{ }, downloadFile: async () => { try { - const data = await nexus.File.get( - orgLabel, - projectLabel, - parseResourceId(resource._self), - { as: 'blob' } - ); + const data = await nexus.httpGet({ + path: resource._self, + headers: { + Accept: 'application/json', + }, + context: { + as: 'blob', + }, + }); return download( resource._filename || getResourceLabel(resource), resource._mediaType, diff --git a/src/shared/containers/TableViewerContainer.tsx b/src/shared/containers/TableViewerContainer.tsx index 687835413..67e934ab7 100644 --- a/src/shared/containers/TableViewerContainer.tsx +++ b/src/shared/containers/TableViewerContainer.tsx @@ -27,7 +27,7 @@ const TableViewerContainer: React.FC<{ await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(resourceId), + encodeURIComponent(decodeURIComponent(resourceId)), { as: 'text', } From 7a035bac0d2bba1241901b3acfac41f3a3d83059 Mon Sep 17 00:00:00 2001 From: Bilal MEDDAH Date: Tue, 25 Jul 2023 16:31:07 +0200 Subject: [PATCH 2/2] ref: refactor nexusUrlHardEncode --- src/shared/components/ImagePreview/ImagePreview.tsx | 5 +++-- src/shared/components/Preview/Preview.tsx | 3 ++- .../components/ResourceEditor/useResolutionActions.tsx | 3 ++- .../containers/AnalysisPlugin/AnalysisPluginContainer.tsx | 5 +++-- src/shared/containers/TableViewerContainer.tsx | 5 +++-- src/shared/utils/nexusEncode.ts | 5 +++++ 6 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 src/shared/utils/nexusEncode.ts diff --git a/src/shared/components/ImagePreview/ImagePreview.tsx b/src/shared/components/ImagePreview/ImagePreview.tsx index 996e541ba..3ed3cb317 100644 --- a/src/shared/components/ImagePreview/ImagePreview.tsx +++ b/src/shared/components/ImagePreview/ImagePreview.tsx @@ -21,8 +21,9 @@ import { SortDescendingOutlined, DownloadOutlined, } from '@ant-design/icons'; -import { orderBy, isNil, create, isArray, isObject } from 'lodash'; +import { orderBy, isNil, isArray, isObject } from 'lodash'; import { parseProjectUrl, parseResourceId } from '../Preview/Preview'; +import nexusUrlHardEncode from '../../utils/nexusEncode'; import './ImagePreview.less'; @@ -114,7 +115,7 @@ const fetchImageResources = async ({ const rawData = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(decodeURIComponent(contentUrl)), + nexusUrlHardEncode(contentUrl), { as: 'blob' } ); const blob = new Blob([rawData as string], { diff --git a/src/shared/components/Preview/Preview.tsx b/src/shared/components/Preview/Preview.tsx index 06f802322..8814039ca 100644 --- a/src/shared/components/Preview/Preview.tsx +++ b/src/shared/components/Preview/Preview.tsx @@ -15,6 +15,7 @@ import useNotification from '../../hooks/useNotification'; import TableViewerContainer from '../../containers/TableViewerContainer'; import { useSelector } from 'react-redux'; import { RootState } from '../../store/reducers'; +import nexusUrlHardEncode from '../../utils/nexusEncode'; export const parseResourceId = (url: string) => { const fileUrlPattern = /files\/([\w-]+)\/([\w-]+)\/(.*)/; @@ -249,7 +250,7 @@ const Preview: React.FC<{ const rawData = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(decodeURIComponent(contentUrl)), + nexusUrlHardEncode(contentUrl), options ); downloadBlobHelper(rawData, asset.name); diff --git a/src/shared/components/ResourceEditor/useResolutionActions.tsx b/src/shared/components/ResourceEditor/useResolutionActions.tsx index 09bd7973c..1634bbece 100644 --- a/src/shared/components/ResourceEditor/useResolutionActions.tsx +++ b/src/shared/components/ResourceEditor/useResolutionActions.tsx @@ -15,6 +15,7 @@ import { import { parseResourceId } from '../Preview/Preview'; import { download } from '../../utils/download'; import { getDataExplorerResourceItemArray } from './editorUtils'; +import nexusUrlHardEncode from '../../utils/nexusEncode'; const useResolvedLinkEditorPopover = () => { const nexus = useNexusContext(); @@ -76,7 +77,7 @@ const useResolvedLinkEditorPopover = () => { const data = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(decodeURIComponent(parseResourceId(resourceId))), + nexusUrlHardEncode(parseResourceId(resourceId)), { as: 'blob' } ); return download(title, ext ?? 'json', data); diff --git a/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx b/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx index f0232f320..49698ed6e 100644 --- a/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx +++ b/src/shared/containers/AnalysisPlugin/AnalysisPluginContainer.tsx @@ -29,7 +29,8 @@ import { AnalysisAssetSparqlQueryRowResult, ReportGeneration, } from '../../types/plugins/report'; -import useNotification from '../../../shared/hooks/useNotification'; +import useNotification from '../../hooks/useNotification'; +import nexusUrlHardEncode from '../../utils/nexusEncode'; async function fetchImageObjectUrl( nexus: NexusClient, @@ -41,7 +42,7 @@ async function fetchImageObjectUrl( const rawData = await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(decodeURIComponent(imageResourceId)), + nexusUrlHardEncode(imageResourceId), { as: 'blob', } diff --git a/src/shared/containers/TableViewerContainer.tsx b/src/shared/containers/TableViewerContainer.tsx index 67e934ab7..2cb108654 100644 --- a/src/shared/containers/TableViewerContainer.tsx +++ b/src/shared/containers/TableViewerContainer.tsx @@ -5,7 +5,8 @@ import * as csvParser from 'csv-string'; import TableViewer from '../components/TableViewer'; import useNotification from '../hooks/useNotification'; -import { parseResourceId } from '../../shared/components/Preview/Preview'; +import { parseResourceId } from '../components/Preview/Preview'; +import nexusUrlHardEncode from '../utils/nexusEncode'; const TableViewerContainer: React.FC<{ resourceUrl: string; @@ -27,7 +28,7 @@ const TableViewerContainer: React.FC<{ await nexus.File.get( orgLabel, projectLabel, - encodeURIComponent(decodeURIComponent(resourceId)), + nexusUrlHardEncode(resourceId), { as: 'text', } diff --git a/src/shared/utils/nexusEncode.ts b/src/shared/utils/nexusEncode.ts new file mode 100644 index 000000000..130aea861 --- /dev/null +++ b/src/shared/utils/nexusEncode.ts @@ -0,0 +1,5 @@ +const nexusUrlHardEncode = (url: string): string => { + return encodeURIComponent(decodeURIComponent(url)); +}; + +export default nexusUrlHardEncode;