вложения, канальчики, бим-бим + бам-бам

This commit is contained in:
2026-04-25 00:51:12 +06:00
parent 0b75148a3f
commit ad477ee813
61 changed files with 14636 additions and 375 deletions

View File

@@ -0,0 +1,96 @@
import type { FastifyPluginAsyncTypebox } from '@fastify/type-provider-typebox'
import * as fs from 'node:fs'
import * as path from 'node:path'
import { Type } from 'typebox'
const plugin: FastifyPluginAsyncTypebox = async (fastify) => {
const uploadDir = path.join(process.cwd(), 'uploads')
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true })
}
fastify.post(
'/attachment/upload',
{
schema: {
summary: 'Upload attachment',
tags: ['Attachment'],
operationId: 'attachment.upload',
description: 'Pass file to multipart/form-data',
response: {
200: Type.String({ format: 'uuid', description: 'Attachment UUID' }),
},
},
},
async (req, reply) => {
const data = await req.file()
if (!data) {
return reply.notAcceptable()
}
const meta = await fastify.prisma.attachment.create({
data: {
name: data.filename,
mimetype: data.mimetype,
size: 0,
},
})
if (!meta) {
return reply.notAcceptable()
}
const filePath = path.join(process.cwd(), 'uploads', meta.id)
await new Promise((resolve, reject) => {
const writeStream = fs.createWriteStream(filePath)
data.file.pipe(writeStream)
data.file.on('end', resolve)
data.file.on('error', reject)
})
return meta.id
},
)
fastify.get(
'/attachment/:id',
{
schema: {
summary: 'Get attachment',
tags: ['Attachment'],
operationId: 'attachment.get',
params: Type.Object({
id: Type.String({ format: 'uuid' }),
}),
response: {
200: Type.Any({ description: 'Attachment content' }),
},
},
config: {
skipAuth: true,
},
},
async (req, reply) => {
const meta = await fastify.prisma.attachment.findFirst({
where: { id: req.params.id },
})
if (!meta) {
return reply.notFound('Attachment not found')
}
const filePath = path.join(process.cwd(), 'uploads', meta.id)
reply.type(meta.mimetype)
reply.header('Cache-Control', 'public, max-age=31536000')
reply.header('Content-Disposition', `inline; filename="${meta.name}"`)
return fs.createReadStream(filePath)
},
)
}
export default plugin