mirror of
https://github.com/inventree/InvenTree.git
synced 2026-10-14 14:11:55 +00:00
strip query strings when deriving file names from media URLs (#12993)
fixes #12992 Co-authored-by: mg <mg@layerx-defence.com>
This commit is contained in:
1 parent
ead118cec5
commit
0a0cccedd9
5 files changed
+22
-9
No files matched your search
@@ -5,6 +5,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
import { t } from '@lingui/core/macro';
|
import { t } from '@lingui/core/macro';
|
||||||
import { api } from '../../../../App';
|
import { api } from '../../../../App';
|
||||||
|
import { fileNameFromUrl } from '../../../../functions/urls';
|
||||||
import type { PreviewAreaComponent } from '../TemplateEditor';
|
import type { PreviewAreaComponent } from '../TemplateEditor';
|
||||||
|
|
||||||
export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
||||||
@@ -22,7 +23,7 @@ export const PdfPreviewComponent: PreviewAreaComponent = forwardRef(
|
|||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
const filename =
|
const filename =
|
||||||
template.template?.split('/').pop() ?? 'template.html';
|
fileNameFromUrl(template.template) || 'template.html';
|
||||||
|
|
||||||
formData.append('template', new File([code], filename));
|
formData.append('template', new File([code], filename));
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import Split from '@uiw/react-split';
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { api } from '../../../App';
|
import { api } from '../../../App';
|
||||||
|
import { fileNameFromUrl } from '../../../functions/urls';
|
||||||
import type { TemplateI } from '../../../tables/settings/TemplateTable';
|
import type { TemplateI } from '../../../tables/settings/TemplateTable';
|
||||||
import { SplitButton } from '../../buttons/SplitButton';
|
import { SplitButton } from '../../buttons/SplitButton';
|
||||||
import { StandaloneField } from '../../forms/StandaloneField';
|
import { StandaloneField } from '../../forms/StandaloneField';
|
||||||
@@ -263,7 +264,7 @@ export function TemplateEditor(props: Readonly<TemplateEditorProps>) {
|
|||||||
if (code === undefined) return;
|
if (code === undefined) return;
|
||||||
|
|
||||||
const filename =
|
const filename =
|
||||||
(template as any)[fileField]?.split('/').pop() ?? 'template.html';
|
fileNameFromUrl((template as any)[fileField]) || 'template.html';
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append(fileField, new File([code], filename));
|
formData.append(fileField, new File([code], filename));
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
IconPhoto
|
IconPhoto
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { type ReactNode, useMemo } from 'react';
|
import { type ReactNode, useMemo } from 'react';
|
||||||
import { generateUrl } from '../../functions/urls';
|
import { fileNameFromUrl, generateUrl } from '../../functions/urls';
|
||||||
import { Thumbnail } from '../images/Thumbnail';
|
import { Thumbnail } from '../images/Thumbnail';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,7 +24,8 @@ export function attachmentIcon(attachment: string): ReactNode {
|
|||||||
return <IconFileUnknown size={sz} />;
|
return <IconFileUnknown size={sz} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const suffix = attachment.split('.').pop()?.toLowerCase() ?? '';
|
const suffix =
|
||||||
|
fileNameFromUrl(attachment).split('.').pop()?.toLowerCase() ?? '';
|
||||||
switch (suffix) {
|
switch (suffix) {
|
||||||
case 'pdf':
|
case 'pdf':
|
||||||
return <IconFileTypePdf size={sz} />;
|
return <IconFileTypePdf size={sz} />;
|
||||||
@@ -80,7 +81,7 @@ export function AttachmentLink({
|
|||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
return external ? attachment : (attachment.split('/').pop() ?? '-');
|
return external ? attachment : fileNameFromUrl(attachment) || '-';
|
||||||
}, [attachment, external]);
|
}, [attachment, external]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -24,3 +24,15 @@ export function generateUrl(url: string | URL, base?: string): string {
|
|||||||
|
|
||||||
return newUrl.toString();
|
return newUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the file name part of a file URL or storage path.
|
||||||
|
* Storage backends such as S3 return presigned URLs, so any query string or fragment is dropped before taking the last path segment.
|
||||||
|
*/
|
||||||
|
export function fileNameFromUrl(url?: string | null): string {
|
||||||
|
if (!url) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.split('?')[0].split('#')[0].split('/').pop() ?? '';
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
import { AttachmentLink } from '../../components/items/AttachmentLink';
|
||||||
import { DescriptionColumn } from '../../components/tables/ColumnRenderers';
|
import { DescriptionColumn } from '../../components/tables/ColumnRenderers';
|
||||||
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
import { InvenTreeTable } from '../../components/tables/InvenTreeTable';
|
||||||
|
import { fileNameFromUrl } from '../../functions/urls';
|
||||||
import {
|
import {
|
||||||
useCreateApiFormModal,
|
useCreateApiFormModal,
|
||||||
useDeleteApiFormModal,
|
useDeleteApiFormModal,
|
||||||
@@ -59,10 +60,7 @@ export function SnippetDrawer({
|
|||||||
pk: id
|
pk: id
|
||||||
});
|
});
|
||||||
|
|
||||||
const filename = useMemo(
|
const filename = useMemo(() => fileNameFromUrl(snippet?.snippet), [snippet]);
|
||||||
() => snippet?.snippet?.split('/').pop() ?? '',
|
|
||||||
[snippet]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
return <LoadingOverlay visible={true} />;
|
return <LoadingOverlay visible={true} />;
|
||||||
|
|||||||
Reference in new issue
Block a user