diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0dcede41..04d2fb6a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,8 +11,10 @@ and this project adheres to
## Changed
- 🧑💻(frontend) change literal section open source #702
+- ♻️(frontend) replace cors proxy for export #695
## Fixed
+
- 🐛(frontend) remove scroll listener table content #688
- 🔒️(back) restrict access to favorite_list endpoint #690
- 🐛(backend) refactor to fix filtering on children
diff --git a/src/backend/demo/data/template/code.txt b/src/backend/demo/data/template/code.txt
index 56f6736b..229af08d 100644
--- a/src/backend/demo/data/template/code.txt
+++ b/src/backend/demo/data/template/code.txt
@@ -1,2 +1,2 @@
-
+
\ No newline at end of file
diff --git a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts
index 42f3ed90..70acd37e 100644
--- a/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts
+++ b/src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts
@@ -136,6 +136,11 @@ test.describe('Doc Export', () => {
test('it exports the docs with images', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-editor', browserName, 1);
+ const responseCorsPromise = page.waitForResponse(
+ (response) =>
+ response.url().includes('/cors-proxy/') && response.status() === 200,
+ );
+
const fileChooserPromise = page.waitForEvent('filechooser');
const downloadPromise = page.waitForEvent('download', (download) => {
return download.suggestedFilename().includes(`${randomDoc}.pdf`);
@@ -160,6 +165,14 @@ test.describe('Doc Export', () => {
await expect(image).toBeVisible();
+ await page.locator('.bn-block-outer').last().fill('/');
+ await page.getByText('Resizable image with caption').click();
+ await page.getByRole('tab', { name: 'Embed' }).click();
+ await page
+ .getByRole('textbox', { name: 'Enter URL' })
+ .fill('https://docs.numerique.gouv.fr/assets/logo-gouv.png');
+ await page.getByText('Embed image').click();
+
await page
.getByRole('button', {
name: 'download',
@@ -188,6 +201,8 @@ test.describe('Doc Export', () => {
})
.click();
+ const responseCors = await responseCorsPromise;
+ expect(responseCors.ok()).toBe(true);
const download = await downloadPromise;
expect(download.suggestedFilename()).toBe(`${randomDoc}.pdf`);
diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/FileDownloadButton.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/FileDownloadButton.tsx
index c34eb244..0cb00c8f 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/FileDownloadButton.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/FileDownloadButton.tsx
@@ -57,7 +57,7 @@ export const FileDownloadButton = ({
* If not hosted on our domain, means not a file uploaded by the user,
* we do what Blocknote was doing initially.
*/
- if (!url.includes(window.location.hostname)) {
+ if (!url.includes(window.location.hostname) && !url.includes('base64')) {
if (!editor.resolveFileUrl) {
window.open(url);
} else {
@@ -70,11 +70,11 @@ export const FileDownloadButton = ({
}
if (!url.includes('-unsafe')) {
- const blob = (await exportResolveFileUrl(url, undefined)) as Blob;
+ const blob = (await exportResolveFileUrl(url)) as Blob;
downloadFile(blob, url.split('/').pop() || 'file');
} else {
const onConfirm = async () => {
- const blob = (await exportResolveFileUrl(url, undefined)) as Blob;
+ const blob = (await exportResolveFileUrl(url)) as Blob;
downloadFile(blob, url.split('/').pop() || 'file (unsafe)');
};
diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/api/exportResolveFileUrl.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/api/exportResolveFileUrl.tsx
new file mode 100644
index 00000000..531291d1
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/docs/doc-export/api/exportResolveFileUrl.tsx
@@ -0,0 +1,30 @@
+import { baseApiUrl } from '@/api';
+import { Doc } from '@/features/docs/doc-management';
+
+export const exportCorsResolveFileUrl = async (
+ docId: Doc['id'],
+ url: string,
+) => {
+ let resolvedUrl = url;
+ // If the url is not from the same origin, better to proxy the request
+ // to avoid CORS issues
+ if (!url.includes(window.location.hostname) && !url.includes('base64')) {
+ resolvedUrl = `${baseApiUrl()}documents/${docId}/cors-proxy/?url=${encodeURIComponent(url)}`;
+ }
+
+ return exportResolveFileUrl(resolvedUrl);
+};
+
+export const exportResolveFileUrl = async (url: string) => {
+ try {
+ const response = await fetch(url, {
+ credentials: 'include',
+ });
+
+ return response.blob();
+ } catch {
+ console.error(`Failed to fetch image: ${url}`);
+ }
+
+ return url;
+};
diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-export/api/index.ts
new file mode 100644
index 00000000..59fc0c17
--- /dev/null
+++ b/src/frontend/apps/impress/src/features/docs/doc-export/api/index.ts
@@ -0,0 +1 @@
+export * from './exportResolveFileUrl';
diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/components/ModalExport.tsx b/src/frontend/apps/impress/src/features/docs/doc-export/components/ModalExport.tsx
index a2ba6f8a..d35205dd 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-export/components/ModalExport.tsx
+++ b/src/frontend/apps/impress/src/features/docs/doc-export/components/ModalExport.tsx
@@ -18,10 +18,11 @@ import { Box, Text } from '@/components';
import { useEditorStore } from '@/features/docs/doc-editor';
import { Doc, useTrans } from '@/features/docs/doc-management';
+import { exportCorsResolveFileUrl } from '../api/exportResolveFileUrl';
import { TemplatesOrdering, useTemplates } from '../api/useTemplates';
import { docxDocsSchemaMappings } from '../mappingDocx';
import { pdfDocsSchemaMappings } from '../mappingPDF';
-import { downloadFile, exportResolveFileUrl } from '../utils';
+import { downloadFile } from '../utils';
enum DocDownloadFormat {
PDF = 'pdf',
@@ -88,26 +89,14 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
let blobExport: Blob;
if (format === DocDownloadFormat.PDF) {
- const defaultExporter = new PDFExporter(
- editor.schema,
- pdfDocsSchemaMappings,
- );
-
const exporter = new PDFExporter(editor.schema, pdfDocsSchemaMappings, {
- resolveFileUrl: async (url) =>
- exportResolveFileUrl(url, defaultExporter.options.resolveFileUrl),
+ resolveFileUrl: async (url) => exportCorsResolveFileUrl(doc.id, url),
});
const pdfDocument = await exporter.toReactPDFDocument(exportDocument);
blobExport = await pdf(pdfDocument).toBlob();
} else {
- const defaultExporter = new DOCXExporter(
- editor.schema,
- docxDocsSchemaMappings,
- );
-
const exporter = new DOCXExporter(editor.schema, docxDocsSchemaMappings, {
- resolveFileUrl: async (url) =>
- exportResolveFileUrl(url, defaultExporter.options.resolveFileUrl),
+ resolveFileUrl: async (url) => exportCorsResolveFileUrl(doc.id, url),
});
blobExport = await exporter.toBlob(exportDocument);
diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/index.ts b/src/frontend/apps/impress/src/features/docs/doc-export/index.ts
index 590a7f4c..527c58f0 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-export/index.ts
+++ b/src/frontend/apps/impress/src/features/docs/doc-export/index.ts
@@ -1,2 +1,3 @@
+export * from './api';
export * from './components';
export * from './utils';
diff --git a/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts b/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts
index 54a15a25..248b7033 100644
--- a/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts
+++ b/src/frontend/apps/impress/src/features/docs/doc-export/utils.ts
@@ -17,27 +17,6 @@ export function downloadFile(blob: Blob, filename: string) {
window.URL.revokeObjectURL(url);
}
-export const exportResolveFileUrl = async (
- url: string,
- resolveFileUrl: ((url: string) => Promise) | undefined,
-) => {
- if (!url.includes(window.location.hostname) && resolveFileUrl) {
- return resolveFileUrl(url);
- }
-
- try {
- const response = await fetch(url, {
- credentials: 'include',
- });
-
- return response.blob();
- } catch {
- console.error(`Failed to fetch image: ${url}`);
- }
-
- return url;
-};
-
export function docxBlockPropsToStyles(
props: Partial,
colors: typeof COLORS_DEFAULT,