diff --git a/confiture-rest-api/package.json b/confiture-rest-api/package.json
index 5f51bdea..a77dd76c 100644
--- a/confiture-rest-api/package.json
+++ b/confiture-rest-api/package.json
@@ -28,6 +28,7 @@
"bcrypt": "^5.1.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
+ "express-http-proxy": "^2.0.0",
"got": "^11.8.5",
"handlebars": "^4.7.7",
"joi": "^17.6.0",
diff --git a/confiture-rest-api/prisma/migrations/20240530143825_remove_file_urls/migration.sql b/confiture-rest-api/prisma/migrations/20240530143825_remove_file_urls/migration.sql
new file mode 100644
index 00000000..9be7fdd9
--- /dev/null
+++ b/confiture-rest-api/prisma/migrations/20240530143825_remove_file_urls/migration.sql
@@ -0,0 +1,10 @@
+/*
+ Warnings:
+
+ - You are about to drop the column `thumbnailUrl` on the `StoredFile` table. All the data in the column will be lost.
+ - You are about to drop the column `url` on the `StoredFile` table. All the data in the column will be lost.
+
+*/
+-- AlterTable
+ALTER TABLE "StoredFile" DROP COLUMN "thumbnailUrl",
+DROP COLUMN "url";
diff --git a/confiture-rest-api/prisma/schema.prisma b/confiture-rest-api/prisma/schema.prisma
index 14f33036..9e6d6004 100644
--- a/confiture-rest-api/prisma/schema.prisma
+++ b/confiture-rest-api/prisma/schema.prisma
@@ -169,13 +169,10 @@ model AuditTrace {
model StoredFile {
id Int @id @default(autoincrement())
originalFilename String
- url String
size Int
- // S3 storage key
+ // S3 storage keys
key String
-
- thumbnailUrl String
thumbnailKey String
criterionResult CriterionResult? @relation(fields: [criterionResultId], references: [id], onDelete: Cascade, onUpdate: Cascade)
diff --git a/confiture-rest-api/src/audits/audit.service.ts b/confiture-rest-api/src/audits/audit.service.ts
index c1ca725f..4256b6eb 100644
--- a/confiture-rest-api/src/audits/audit.service.ts
+++ b/confiture-rest-api/src/audits/audit.service.ts
@@ -477,9 +477,6 @@ export class AuditService {
)
]);
- const publicUrl = this.fileStorageService.getPublicUrl(key);
- const thumbnailUrl = this.fileStorageService.getPublicUrl(thumbnailKey);
-
const storedFile = await this.prisma.storedFile.create({
data: {
criterionResult: {
@@ -495,10 +492,7 @@ export class AuditService {
key,
originalFilename: file.originalname,
size: file.size,
- url: publicUrl,
-
- thumbnailKey,
- thumbnailUrl
+ thumbnailKey
}
});
@@ -929,8 +923,9 @@ export class AuditService {
userImpact: r.userImpact,
quickWin: r.quickWin,
exampleImages: r.exampleImages.map((img) => ({
- url: img.url,
- filename: img.originalFilename
+ filename: img.originalFilename,
+ key: img.key,
+ thumbnailKey: img.thumbnailKey
}))
}))
};
diff --git a/confiture-rest-api/src/audits/dto/audit-report.dto.ts b/confiture-rest-api/src/audits/dto/audit-report.dto.ts
index f7baacf2..dd36b4b5 100644
--- a/confiture-rest-api/src/audits/dto/audit-report.dto.ts
+++ b/confiture-rest-api/src/audits/dto/audit-report.dto.ts
@@ -207,8 +207,10 @@ class ReportCriterionResult {
}
class ExampleImage {
- /** @example "https://example.com/mon-image.jpg" */
- url: string;
/** @example "mon-image.jpg" */
filename: string;
+ /** @example "audit/xxxx/my-image.jpg" */
+ key: string;
+ /** @example "audit/xxxx/my-image_thumbnail.jpg" */
+ thumbnailKey: string;
}
diff --git a/confiture-rest-api/src/audits/file-storage.service.ts b/confiture-rest-api/src/audits/file-storage.service.ts
index a555ab06..b5b44725 100644
--- a/confiture-rest-api/src/audits/file-storage.service.ts
+++ b/confiture-rest-api/src/audits/file-storage.service.ts
@@ -35,7 +35,7 @@ export class FileStorageService {
}
getPublicUrl(key: string): string {
- return `${this.config.get("S3_VIRTUAL_HOST")}${key}`;
+ return `${this.config.get("FRONT_BASE_URL")}/${key}}`;
}
async deleteStoredFile(key: string) {
diff --git a/confiture-rest-api/src/main.ts b/confiture-rest-api/src/main.ts
index eb66293b..c3dcdd3b 100644
--- a/confiture-rest-api/src/main.ts
+++ b/confiture-rest-api/src/main.ts
@@ -3,6 +3,7 @@ import { NestFactory } from "@nestjs/core";
import { SwaggerModule, DocumentBuilder } from "@nestjs/swagger";
import type { NestExpressApplication } from "@nestjs/platform-express";
import morgan from "morgan";
+import proxy from "express-http-proxy";
import { AppModule } from "./app.module";
@@ -17,6 +18,7 @@ async function bootstrap() {
app.useBodyParser("json", { limit: "500kb" });
app.use(morgan(process.env.NODE_ENV !== "production" ? "dev" : "common"));
+ app.use("/uploads", proxy(process.env.S3_VIRTUAL_HOST));
app.setGlobalPrefix("/api");
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));
diff --git a/confiture-web-app/config/config_nginx/dpl/sites-enabled/frontend.conf b/confiture-web-app/config/config_nginx/dpl/sites-enabled/frontend.conf
index 6d5e39bd..0d93c3e6 100644
--- a/confiture-web-app/config/config_nginx/dpl/sites-enabled/frontend.conf
+++ b/confiture-web-app/config/config_nginx/dpl/sites-enabled/frontend.conf
@@ -31,7 +31,6 @@ server {
# auth_basic off;
# allow all;
#}
-
location / {
# This is due to nginx and the try_files behavior below, it will always
@@ -49,9 +48,9 @@ server {
# This seperate location is so the no cache policy only applies to the index and nothing else.
location @index {
- add_header Cache-Control no-cache;
- expires 0;
- try_files /index.html =404;
+ add_header Cache-Control no-cache;
+ expires 0;
+ try_files /index.html =404;
}
# # reverse proxy for backend
@@ -70,12 +69,12 @@ server {
# proxy_pass $upstream_backend;
proxy_pass http://backend:8085;
- proxy_set_header Host $http_host;
- proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
- proxy_set_header CLIENT_IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto https;
- proxy_read_timeout 900;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
+ proxy_set_header CLIENT_IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto https;
+ proxy_read_timeout 900;
proxy_buffers 16 16k;
proxy_buffer_size 16k;
@@ -83,5 +82,23 @@ server {
}
+ location /uploads/ {
+ if ($request_method !~ ^(OPTIONS|GET|HEAD)$ ) {
+ return 405;
+ }
+
+ proxy_pass http://backend:8085;
+
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
+ proxy_set_header CLIENT_IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto https;
+
+ proxy_read_timeout 900;
+ proxy_buffers 16 16k;
+ proxy_buffer_size 16k;
+ }
+
}
diff --git a/confiture-web-app/public/_redirects b/confiture-web-app/public/_redirects
index 28a9f957..cf12d6ab 100644
--- a/confiture-web-app/public/_redirects
+++ b/confiture-web-app/public/_redirects
@@ -1,2 +1,3 @@
-/api/* https://confiture-api.herokuapp.com/api/:splat 200
-/* /index.html 200
+/api/* https://confiture-api.herokuapp.com/api/:splat 200
+/uploads/* https://confiture-api.herokuapp.com/uploads/:splat 200
+/* /index.html 200
\ No newline at end of file
diff --git a/confiture-web-app/src/components/audit/CriteriumNotCompliantAccordion.vue b/confiture-web-app/src/components/audit/CriteriumNotCompliantAccordion.vue
index 92819d7e..08d8838a 100644
--- a/confiture-web-app/src/components/audit/CriteriumNotCompliantAccordion.vue
+++ b/confiture-web-app/src/components/audit/CriteriumNotCompliantAccordion.vue
@@ -7,6 +7,7 @@ import LazyAccordion from "./LazyAccordion.vue";
import MarkdownHelpButton from "./MarkdownHelpButton.vue";
import { RadioColor } from "../ui/Radio.vue";
import RadioGroup from "../ui/RadioGroup.vue";
+import { getUploadUrl } from "../../utils";
const props = defineProps<{
id: string;
@@ -162,13 +163,13 @@ const isOffline = useIsOffline();
diff --git a/confiture-web-app/src/components/report/ReportErrors.vue b/confiture-web-app/src/components/report/ReportErrors.vue
index fa0d7461..0cdc0a40 100644
--- a/confiture-web-app/src/components/report/ReportErrors.vue
+++ b/confiture-web-app/src/components/report/ReportErrors.vue
@@ -14,6 +14,7 @@ import { formatStatus, formatUserImpact, pluralize } from "../../utils";
import CriteriumTestsAccordion from "../audit/CriteriumTestsAccordion.vue";
import LazyAccordion from "../audit/LazyAccordion.vue";
import MarkdownRenderer from "../ui/MarkdownRenderer.vue";
+import { getUploadUrl } from "../../utils";
const report = useReportStore();
@@ -516,15 +517,19 @@ function getPage(pageId: number | string) {
>
Ouvrir l’image dans une nouvelle fenêtre
-
+
@@ -636,15 +641,19 @@ function getPage(pageId: number | string) {
>
Ouvrir l’image dans une nouvelle fenêtre
-
+
diff --git a/confiture-web-app/src/types/report.ts b/confiture-web-app/src/types/report.ts
index 86e2494d..207725fe 100644
--- a/confiture-web-app/src/types/report.ts
+++ b/confiture-web-app/src/types/report.ts
@@ -46,7 +46,8 @@ export interface AuditReport {
results: Array<
Omit & {
exampleImages: {
- url: string;
+ key: string;
+ thumbnailKey: string;
filename: string;
}[];
}
diff --git a/confiture-web-app/src/types/types.ts b/confiture-web-app/src/types/types.ts
index 41d84b97..d3bc244f 100644
--- a/confiture-web-app/src/types/types.ts
+++ b/confiture-web-app/src/types/types.ts
@@ -111,9 +111,8 @@ export interface ExampleImage {
id: number;
originalFilename: string;
size: number;
- url: string;
-
- thumbnailUrl: string;
+ key: string;
+ thumbnailKey: string;
}
export interface CriteriumResult {
diff --git a/confiture-web-app/src/utils.ts b/confiture-web-app/src/utils.ts
index 8ad9f066..36088e57 100644
--- a/confiture-web-app/src/utils.ts
+++ b/confiture-web-app/src/utils.ts
@@ -231,3 +231,7 @@ export function waitForElement(selector: string): Promise {
});
});
}
+
+export function getUploadUrl(key: string): string {
+ return `/uploads/${key}`;
+}
diff --git a/confiture-web-app/vite.config.ts b/confiture-web-app/vite.config.ts
index 6574c875..82b9cceb 100644
--- a/confiture-web-app/vite.config.ts
+++ b/confiture-web-app/vite.config.ts
@@ -30,7 +30,8 @@ export default defineConfig({
],
server: {
proxy: {
- "/api": "http://localhost:4000"
+ "/api": "http://localhost:4000",
+ "/uploads": "http://localhost:4000"
},
port: 3000
}
diff --git a/yarn.lock b/yarn.lock
index d6a8949e..cce051b8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3736,7 +3736,7 @@ debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4:
dependencies:
ms "2.1.2"
-debug@^3.1.0:
+debug@^3.0.1, debug@^3.1.0:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
@@ -4069,6 +4069,11 @@ es-module-lexer@^1.2.1:
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5"
integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==
+es6-promise@^4.1.1:
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
+ integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
+
esbuild@^0.18.10:
version "0.18.20"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
@@ -4348,6 +4353,15 @@ expand-template@^2.0.3:
resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+express-http-proxy@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/express-http-proxy/-/express-http-proxy-2.0.0.tgz#c47f4d8b53e8d9c2b9a2f1d158eedf6eb84828a5"
+ integrity sha512-TXxcPFTWVUMSEmyM6iX2sT/JtmqhqngTq29P+eXTVFdtxZrTmM8THUYK59rUXiln0FfPGvxEpGRnVrgvHksXDw==
+ dependencies:
+ debug "^3.0.1"
+ es6-promise "^4.1.1"
+ raw-body "^2.3.0"
+
express@4.18.2:
version "4.18.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59"
@@ -6990,7 +7004,7 @@ raw-body@2.5.1:
iconv-lite "0.4.24"
unpipe "1.0.0"
-raw-body@2.5.2:
+raw-body@2.5.2, raw-body@^2.3.0:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==