Skip to content

Commit

Permalink
fix: use minio for image upload
Browse files Browse the repository at this point in the history
  • Loading branch information
ledouxm committed Oct 14, 2024
1 parent c26ecf3 commit 6182ef8
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 94 deletions.
14 changes: 14 additions & 0 deletions .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=

MINIO_USER=
MINIO_PASSWORD=

PG_PROXY_PORT=
PG_PROXY_PASSWORD=

Expand All @@ -22,6 +25,17 @@ EMAIL_PORT=
EMAIL_USER=
EMAIL_PASSWORD=

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_BUCKET_NAME=
AWS_REGION=
AWS_ENDPOINT=

MINIO_URL=
MINIO_BUCKET=
MINIO_ACCESS_KEY_ID=
MINIO_SECRET_KEY=

# FRONTEND
VITE_BACKEND_URL=
VITE_ELECTRIC_URL=
Expand Down
13 changes: 13 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ version: "3.1"

volumes:
pg_data:
minio_data:

services:
# frontend:
Expand Down Expand Up @@ -57,3 +58,15 @@ services:
restart: always
ports:
- "${ADMINER_PORT:-8081}:8080"

minio:
image: minio/minio
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
environment:
MINIO_ROOT_USER: ${MINIO_USER}
MINIO_ROOT_PASSWORD: ${MINIO_PASSWORD}
command: server --console-address ":9001" /data
4 changes: 4 additions & 0 deletions packages/backend/src/envVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ const envSchema = z.object({
EMAIL_USER: z.string(),
EMAIL_PASSWORD: z.string(),
EMAIL_EMITTER: z.string(),
MINIO_ACCESS_KEY_ID: z.string(),
MINIO_SECRET_KEY: z.string(),
MINIO_URL: z.string(),
MINIO_BUCKET: z.string(),
});

export const ENV = envSchema.parse(process.env);
Expand Down
3 changes: 1 addition & 2 deletions packages/backend/src/routes/uploadRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ export const uploadPlugin: FastifyPluginAsyncTypebox = async (fastify, _) => {
if (!file) throw new AppError(400, "No file provided");
if (!reportId || !id) throw new AppError(400, "No reportId or id provided");

const url = await request.services.upload.addPDFToReport({
const url = await request.services.upload.addPictureToReport({
reportId: (request.query as any).reportId as string,
buffer: await file.toBuffer(),
name: getPictureName(reportId, id),
publicRead: true,
});

// await db.pictures.create({ data: { id, url, reportId, createdAt: new Date() } });
Expand Down
30 changes: 30 additions & 0 deletions packages/backend/src/services/uploadService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@ import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3
import { ENV } from "../envVars";
import { makeDebug } from "../features/debug";
import { AppError } from "../features/errors";
import { S3 } from "@aws-sdk/client-s3";

const client = new S3Client({ endpoint: ENV.AWS_ENDPOINT, region: ENV.AWS_REGION });
const debug = makeDebug("upload");

const imageClient = new S3({
credentials: {
accessKeyId: ENV.MINIO_ACCESS_KEY_ID,
secretAccessKey: ENV.MINIO_SECRET_KEY,
},
endpoint: ENV.MINIO_URL,
bucketEndpoint: true,
});

export const upload = async () => {};

export class UploadService {
Expand Down Expand Up @@ -34,6 +45,25 @@ export class UploadService {
return url;
}

async addPictureToReport({ reportId, buffer, name }: { reportId: string; buffer: Buffer; name: string }) {
debug("Uploading picture to S3", reportId);

const bucketUrl = `${ENV.MINIO_URL}/${ENV.MINIO_BUCKET}`;

await imageClient.putObject({
Bucket: bucketUrl,
Key: name,
Body: buffer,
ACL: "public-read",
ContentType: "image/png",
});

const url = `${bucketUrl}/${name}`;

debug(url);
return url;
}

async getReportPDF({ reportId }: { reportId: string }) {
const name = getPDFName(reportId);

Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/envVars.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { z } from "zod";

const isDev = !z.boolean().parse(import.meta.env.PROD);
export const isDev = !z.boolean().parse(import.meta.env.PROD);

const envSchema = z.object({
VITE_BACKEND_URL: z.string(),
Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/features/InfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ const PictureThumbnail = ({ picture, index, status }: { picture: Pictures; index

return URL.createObjectURL(blob);
},
refetchOnWindowFocus: false,
});

const idbStatusQuery = useQuery({
Expand Down
16 changes: 12 additions & 4 deletions packages/frontend/src/service-worker/sw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@ import { apiStore, createApiClientWithUrl, getTokenFromIdb } from "../api";
import { getPicturesStore, getToUploadStore, getUploadStatusStore } from "../features/idb";
import { get, keys, del, set } from "idb-keyval";
import { NavigationRoute, registerRoute } from "workbox-routing";
import { isDev } from "../envVars";

declare let self: ServiceWorkerGlobalScope;

skipWaiting();
clients.claim();
self.addEventListener("install", (event) => {
event.waitUntil(self.skipWaiting());
});

self.addEventListener("activate", (event) => {
event.waitUntil(self.clients.claim());
});

const manif = self.__WB_MANIFEST;
console.log(manif);
cleanupOutdatedCaches();
precacheAndRoute(manif);

const handler = createHandlerBoundToURL("/index.html");
registerRoute(new NavigationRoute(handler));
if (!isDev) {
const handler = createHandlerBoundToURL("/index.html");
registerRoute(new NavigationRoute(handler));
}

const broadcastChannel = new BroadcastChannel("sw-messages");

Expand Down
174 changes: 87 additions & 87 deletions packages/pdf/src/report.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,93 +29,93 @@ export const ReportPDFDocument = ({ udap, htmlString, images, pictures }: Report
>{`
<html>
<body>
<style>
body {
font-family: Helvetica;
}
strong {
font-family: Helvetica-Bold;
}
em {
font-family: Helvetica-Oblique;
}
strong em span {
font-family: Helvetica-BoldOblique;
}
em strong span {
font-family: Helvetica-BoldOblique;
}
strong em {
font-family: Helvetica-BoldOblique;
}
em strong {
font-family: Helvetica-BoldOblique;
}
.marianne-img {
width: 35px;
}
.marianne-footer-img {
width: 50px;
}
.header {
display: flex;
margin-top: -16px;
flex-direction: row;
width: 100%;
align-items: flex-start;
justify-content: space-between;
text-align: right;
font-size: 18px;
margin-bottom: 32px;
}
.marianne-text {
text-align: left;
font-weight: bold;
font-size: 12px;
margin-top: 4px;
margin-bottom: 4px;
text-transform: uppercase;
}
.right-texts {
margin-top: 13px;
display: flex;
align-items: flex-end;
flex-direction: column;
justify-content: flex-end;
gap: 20px;
}
.right-texts > div {
text-align: right;
font-size: 14px;
font-family: Helvetica-Bold;
}
.meeting-date {
text-align: right;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}
.pictures {
background-color: #f5f5f5;
}
</style>
<style>
body {
font-family: Helvetica;
}
strong {
font-family: Helvetica-Bold;
}
em {
font-family: Helvetica-Oblique;
}
strong em span {
font-family: Helvetica-BoldOblique;
}
em strong span {
font-family: Helvetica-BoldOblique;
}
strong em {
font-family: Helvetica-BoldOblique;
}
em strong {
font-family: Helvetica-BoldOblique;
}
.marianne-img {
width: 35px;
}
.marianne-footer-img {
width: 50px;
}
.header {
display: flex;
margin-top: -16px;
flex-direction: row;
width: 100%;
align-items: flex-start;
justify-content: space-between;
text-align: right;
font-size: 18px;
margin-bottom: 32px;
}
.marianne-text {
text-align: left;
font-weight: bold;
font-size: 12px;
margin-top: 4px;
margin-bottom: 4px;
text-transform: uppercase;
}
.right-texts {
margin-top: 13px;
display: flex;
align-items: flex-end;
flex-direction: column;
justify-content: flex-end;
gap: 20px;
}
.right-texts > div {
text-align: right;
font-size: 14px;
font-family: Helvetica-Bold;
}
.meeting-date {
text-align: right;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}
.pictures {
background-color: #f5f5f5;
}
</style>
<div class="header">
<div class="marianne">
Expand Down

0 comments on commit 6182ef8

Please sign in to comment.