Commit aff14312 authored by AWL's avatar AWL

fix: add local upload

parent dcf368ee
# Etapa 1: build da aplicação
FROM node:22-alpine AS builder
# Diretório de trabalho dentro do container
WORKDIR /app
# Copia os arquivos de dependência
COPY package.json package-lock.json ./
# Instala as dependências
RUN npm ci
# Copia o restante dos arquivos
COPY . .
# Build da aplicação Next.js
RUN npm run build
# Etapa 2: imagem final para produção
FROM node:22-alpine
# Diretório de trabalho
WORKDIR /app
# Copia os arquivos necessários do builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
# Garante que a pasta imgs exista
RUN mkdir -p ./public/imgs
# Expõe a porta padrão
EXPOSE 3000
# Comando para iniciar a aplicação
CMD ["npm", "start"]
\ No newline at end of file
version: '3.9'
services:
nextjs-app:
build: .
ports:
- "3000:3000"
volumes:
- ./imgs:/app/public/imgs
environment:
- NODE_ENV=production
\ No newline at end of file
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
"nookies": "^2.5.2", "nookies": "^2.5.2",
"path": "^0.12.7",
"react": "^18", "react": "^18",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18", "react-dom": "^18",
...@@ -3403,6 +3404,19 @@ ...@@ -3403,6 +3404,19 @@
"node": ">=18.0.0" "node": ">=18.0.0"
} }
}, },
"node_modules/@smithy/middleware-retry/node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/@smithy/middleware-serde": { "node_modules/@smithy/middleware-serde": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz", "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.0.2.tgz",
...@@ -7451,6 +7465,16 @@ ...@@ -7451,6 +7465,16 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/path": {
"version": "0.12.7",
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
"integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
"license": "MIT",
"dependencies": {
"process": "^0.11.1",
"util": "^0.10.3"
}
},
"node_modules/path-exists": { "node_modules/path-exists": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
...@@ -7723,6 +7747,15 @@ ...@@ -7723,6 +7747,15 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/process": {
"version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/prop-types": { "node_modules/prop-types": {
"version": "15.8.1", "version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
...@@ -8866,23 +8899,25 @@ ...@@ -8866,23 +8899,25 @@
} }
} }
}, },
"node_modules/util": {
"version": "0.10.4",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
"license": "MIT",
"dependencies": {
"inherits": "2.0.3"
}
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
}, },
"node_modules/uuid": { "node_modules/util/node_modules/inherits": {
"version": "9.0.1", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
"funding": [ "license": "ISC"
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
"uuid": "dist/bin/uuid"
}
}, },
"node_modules/warning": { "node_modules/warning": {
"version": "4.0.3", "version": "4.0.3",
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
"next-themes": "^0.3.0", "next-themes": "^0.3.0",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
"nookies": "^2.5.2", "nookies": "^2.5.2",
"path": "^0.12.7",
"react": "^18", "react": "^18",
"react-day-picker": "^8.10.1", "react-day-picker": "^8.10.1",
"react-dom": "^18", "react-dom": "^18",
......
import { s3 } from '@/lib/cloudflare' import { writeFile } from 'fs/promises'
import { PutObjectCommand } from '@aws-sdk/client-s3' import path from 'path'
import { NextRequest, NextResponse } from 'next/server' import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest) { export async function POST(req: NextRequest) {
...@@ -10,25 +10,20 @@ export async function POST(req: NextRequest) { ...@@ -10,25 +10,20 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: 'No file provided' }, { status: 400 }) return NextResponse.json({ error: 'No file provided' }, { status: 400 })
} }
const arrayBuffer = await file.arrayBuffer() try {
const buffer = Buffer.from(arrayBuffer) const arrayBuffer = await file.arrayBuffer()
const buffer = new Uint8Array(arrayBuffer)
const fileName = `${Date.now()}-${file.name}` const fileName = `${Date.now()}-${file.name}`
const filePath = path.join(process.cwd(), 'public', 'imgs', fileName)
try { await writeFile(filePath, buffer)
await s3.send(
new PutObjectCommand({
Bucket: process.env.NEXT_PUBLIC_CLOUDFLARE_BUCKET!,
Key: fileName,
Body: buffer,
ContentType: file.type,
}),
)
const fileUrl = `https://${process.env.NEXT_PUBLIC_CLOUDFLARE_URL_PUBLIC_BUCKET}/${fileName}` const fileUrl = `/imgs/${fileName}` // caminho relativo acessível pela tag <img src=...>
return NextResponse.json({ url: fileUrl }) return NextResponse.json({ url: fileUrl })
} catch (error) { } catch (error) {
console.error('Upload failed:', error)
return NextResponse.json({ error: 'Upload failed' }, { status: 500 }) return NextResponse.json({ error: 'Upload failed' }, { status: 500 })
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment