feat(services): add POST /channels/[channelId]/messages/uploads
This commit is contained in:
parent
766c9fdbd6
commit
03946f26e7
2
.gitignore
vendored
2
.gitignore
vendored
@ -33,4 +33,4 @@ npm-debug.log*
|
|||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
uploads
|
/uploads
|
||||||
|
2
.swcrc
2
.swcrc
@ -14,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"module": {
|
"module": {
|
||||||
"type": "commonjs",
|
"type": "commonjs",
|
||||||
"strict": true,
|
"strict": false,
|
||||||
"strictMode": true,
|
"strictMode": true,
|
||||||
"lazy": false,
|
"lazy": false,
|
||||||
"noInterop": false
|
"noInterop": false
|
||||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -73,7 +73,7 @@
|
|||||||
"prisma": "3.7.0",
|
"prisma": "3.7.0",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"semantic-release": "18.0.1",
|
"semantic-release": "18.0.1",
|
||||||
"typescript": "4.4.4"
|
"typescript": "4.5.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.0.0",
|
"node": ">=16.0.0",
|
||||||
@ -16576,9 +16576,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "4.4.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
|
||||||
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
@ -29672,9 +29672,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.4.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
|
||||||
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
|
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uc.micro": {
|
"uc.micro": {
|
||||||
|
@ -95,6 +95,6 @@
|
|||||||
"prisma": "3.7.0",
|
"prisma": "3.7.0",
|
||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"semantic-release": "18.0.1",
|
"semantic-release": "18.0.1",
|
||||||
"typescript": "4.4.4"
|
"typescript": "4.5.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ const bodyPostServiceSchema = Type.Object({
|
|||||||
type BodyPostServiceSchemaType = Static<typeof bodyPostServiceSchema>
|
type BodyPostServiceSchemaType = Static<typeof bodyPostServiceSchema>
|
||||||
|
|
||||||
const postServiceSchema: FastifySchema = {
|
const postServiceSchema: FastifySchema = {
|
||||||
description: 'POST a new message in a specific channel using its channelId.',
|
description:
|
||||||
|
'POST a new message (text) in a specific channel using its channelId.',
|
||||||
tags: ['messages'] as string[],
|
tags: ['messages'] as string[],
|
||||||
security: [
|
security: [
|
||||||
{
|
{
|
||||||
@ -43,6 +44,7 @@ const postServiceSchema: FastifySchema = {
|
|||||||
401: fastifyErrors[401],
|
401: fastifyErrors[401],
|
||||||
403: fastifyErrors[403],
|
403: fastifyErrors[403],
|
||||||
404: fastifyErrors[404],
|
404: fastifyErrors[404],
|
||||||
|
431: fastifyErrors[431],
|
||||||
500: fastifyErrors[500]
|
500: fastifyErrors[500]
|
||||||
}
|
}
|
||||||
} as const
|
} as const
|
||||||
|
121
src/services/channels/[channelId]/messages/uploads/post.ts
Normal file
121
src/services/channels/[channelId]/messages/uploads/post.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { Type, Static } from '@sinclair/typebox'
|
||||||
|
import { FastifyPluginAsync, FastifySchema } from 'fastify'
|
||||||
|
import fastifyMultipart from 'fastify-multipart'
|
||||||
|
|
||||||
|
import prisma from '../../../../../tools/database/prisma.js'
|
||||||
|
import { fastifyErrors } from '../../../../../models/utils.js'
|
||||||
|
import authenticateUser from '../../../../../tools/plugins/authenticateUser.js'
|
||||||
|
import { messageSchema } from '../../../../../models/Message.js'
|
||||||
|
import { memberSchema } from '../../../../../models/Member.js'
|
||||||
|
import { userPublicWithoutSettingsSchema } from '../../../../../models/User.js'
|
||||||
|
import { channelSchema } from '../../../../../models/Channel.js'
|
||||||
|
import { uploadFile } from '../../../../../tools/utils/uploadFile.js'
|
||||||
|
import { maximumFileSize } from '../../../../../tools/configurations/index.js'
|
||||||
|
|
||||||
|
const parametersSchema = Type.Object({
|
||||||
|
channelId: channelSchema.id
|
||||||
|
})
|
||||||
|
|
||||||
|
type Parameters = Static<typeof parametersSchema>
|
||||||
|
|
||||||
|
const postServiceSchema: FastifySchema = {
|
||||||
|
description:
|
||||||
|
'POST a new message (file) in a specific channel using its channelId.',
|
||||||
|
tags: ['messages'] as string[],
|
||||||
|
consumes: ['multipart/form-data'] as string[],
|
||||||
|
produces: ['application/json'] as string[],
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
] as Array<{ [key: string]: [] }>,
|
||||||
|
params: parametersSchema,
|
||||||
|
response: {
|
||||||
|
200: Type.Object({
|
||||||
|
...messageSchema,
|
||||||
|
member: Type.Object({
|
||||||
|
...memberSchema,
|
||||||
|
user: Type.Object(userPublicWithoutSettingsSchema)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
400: fastifyErrors[400],
|
||||||
|
401: fastifyErrors[401],
|
||||||
|
403: fastifyErrors[403],
|
||||||
|
404: fastifyErrors[404],
|
||||||
|
500: fastifyErrors[500]
|
||||||
|
}
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const postMessageUploadsByChannelIdService: FastifyPluginAsync = async (
|
||||||
|
fastify
|
||||||
|
) => {
|
||||||
|
await fastify.register(authenticateUser)
|
||||||
|
|
||||||
|
await fastify.register(fastifyMultipart)
|
||||||
|
|
||||||
|
fastify.route<{
|
||||||
|
Params: Parameters
|
||||||
|
}>({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/channels/:channelId/messages/uploads',
|
||||||
|
schema: postServiceSchema,
|
||||||
|
handler: async (request, reply) => {
|
||||||
|
if (request.user == null) {
|
||||||
|
throw fastify.httpErrors.forbidden()
|
||||||
|
}
|
||||||
|
const { channelId } = request.params
|
||||||
|
const channel = await prisma.channel.findUnique({
|
||||||
|
where: { id: channelId }
|
||||||
|
})
|
||||||
|
if (channel == null) {
|
||||||
|
throw fastify.httpErrors.notFound('Channel not found')
|
||||||
|
}
|
||||||
|
const memberCheck = await prisma.member.findFirst({
|
||||||
|
where: { guildId: channel.guildId, userId: request.user.current.id },
|
||||||
|
include: {
|
||||||
|
user: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
logo: true,
|
||||||
|
status: true,
|
||||||
|
biography: true,
|
||||||
|
website: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (memberCheck == null) {
|
||||||
|
throw fastify.httpErrors.notFound('Channel not found')
|
||||||
|
}
|
||||||
|
const file = await uploadFile({
|
||||||
|
fastify,
|
||||||
|
request,
|
||||||
|
folderInUploadsFolder: 'messages',
|
||||||
|
maximumFileSize: maximumFileSize
|
||||||
|
})
|
||||||
|
const message = await prisma.message.create({
|
||||||
|
data: {
|
||||||
|
value: file.pathToStoreInDatabase,
|
||||||
|
type: 'file',
|
||||||
|
mimetype: file.mimetype,
|
||||||
|
channelId,
|
||||||
|
memberId: memberCheck.id
|
||||||
|
}
|
||||||
|
})
|
||||||
|
reply.statusCode = 201
|
||||||
|
return {
|
||||||
|
...message,
|
||||||
|
member: {
|
||||||
|
...memberCheck,
|
||||||
|
user: {
|
||||||
|
...memberCheck.user,
|
||||||
|
email: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -3,9 +3,11 @@ import { FastifyPluginAsync } from 'fastify'
|
|||||||
import { getChannelByIdService } from './[channelId]/get.js'
|
import { getChannelByIdService } from './[channelId]/get.js'
|
||||||
import { getMessagesByChannelIdService } from './[channelId]/messages/get.js'
|
import { getMessagesByChannelIdService } from './[channelId]/messages/get.js'
|
||||||
import { postMessageByChannelIdService } from './[channelId]/messages/post.js'
|
import { postMessageByChannelIdService } from './[channelId]/messages/post.js'
|
||||||
|
import { postMessageUploadsByChannelIdService } from './[channelId]/messages/uploads/post.js'
|
||||||
|
|
||||||
export const channelsService: FastifyPluginAsync = async (fastify) => {
|
export const channelsService: FastifyPluginAsync = async (fastify) => {
|
||||||
await fastify.register(getChannelByIdService)
|
await fastify.register(getChannelByIdService)
|
||||||
await fastify.register(getMessagesByChannelIdService)
|
await fastify.register(getMessagesByChannelIdService)
|
||||||
await fastify.register(postMessageByChannelIdService)
|
await fastify.register(postMessageByChannelIdService)
|
||||||
|
await fastify.register(postMessageUploadsByChannelIdService)
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,12 @@ import authenticateUser from '../../../../tools/plugins/authenticateUser.js'
|
|||||||
import { fastifyErrors } from '../../../../models/utils.js'
|
import { fastifyErrors } from '../../../../models/utils.js'
|
||||||
import fastifyMultipart from 'fastify-multipart'
|
import fastifyMultipart from 'fastify-multipart'
|
||||||
import prisma from '../../../../tools/database/prisma.js'
|
import prisma from '../../../../tools/database/prisma.js'
|
||||||
import { uploadImage } from '../../../../tools/utils/uploadImage.js'
|
import { uploadFile } from '../../../../tools/utils/uploadFile.js'
|
||||||
import { guildSchema } from '../../../../models/Guild.js'
|
import { guildSchema } from '../../../../models/Guild.js'
|
||||||
|
import {
|
||||||
|
maximumImageSize,
|
||||||
|
supportedImageMimetype
|
||||||
|
} from '../../../../tools/configurations/index.js'
|
||||||
|
|
||||||
const parametersSchema = Type.Object({
|
const parametersSchema = Type.Object({
|
||||||
guildId: guildSchema.id
|
guildId: guildSchema.id
|
||||||
@ -60,19 +64,21 @@ export const putGuildIconById: FastifyPluginAsync = async (fastify) => {
|
|||||||
if (guild == null) {
|
if (guild == null) {
|
||||||
throw fastify.httpErrors.notFound()
|
throw fastify.httpErrors.notFound()
|
||||||
}
|
}
|
||||||
const icon = await uploadImage({
|
const file = await uploadFile({
|
||||||
fastify,
|
fastify,
|
||||||
request,
|
request,
|
||||||
folderInUploadsFolder: 'guilds'
|
folderInUploadsFolder: 'guilds',
|
||||||
|
maximumFileSize: maximumImageSize,
|
||||||
|
supportedFileMimetype: supportedImageMimetype
|
||||||
})
|
})
|
||||||
await prisma.guild.update({
|
await prisma.guild.update({
|
||||||
where: { id: guildId },
|
where: { id: guildId },
|
||||||
data: { icon }
|
data: { icon: file.pathToStoreInDatabase }
|
||||||
})
|
})
|
||||||
reply.statusCode = 200
|
reply.statusCode = 200
|
||||||
return {
|
return {
|
||||||
guild: {
|
guild: {
|
||||||
icon
|
icon: file.pathToStoreInDatabase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ import path from 'node:path'
|
|||||||
import { FastifyPluginAsync, FastifySchema } from 'fastify'
|
import { FastifyPluginAsync, FastifySchema } from 'fastify'
|
||||||
import { Static, Type } from '@sinclair/typebox'
|
import { Static, Type } from '@sinclair/typebox'
|
||||||
|
|
||||||
|
import { fastifyErrors } from '../../models/utils'
|
||||||
|
|
||||||
const parametersUploadsSchema = Type.Object({
|
const parametersUploadsSchema = Type.Object({
|
||||||
image: Type.String()
|
image: Type.String()
|
||||||
})
|
})
|
||||||
@ -11,7 +13,16 @@ type ParametersUploadsSchemaType = Static<typeof parametersUploadsSchema>
|
|||||||
|
|
||||||
const getUploadsSchema: FastifySchema = {
|
const getUploadsSchema: FastifySchema = {
|
||||||
tags: ['uploads'] as string[],
|
tags: ['uploads'] as string[],
|
||||||
params: parametersUploadsSchema
|
params: parametersUploadsSchema,
|
||||||
|
response: {
|
||||||
|
200: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'binary'
|
||||||
|
},
|
||||||
|
400: fastifyErrors[400],
|
||||||
|
404: fastifyErrors[404],
|
||||||
|
500: fastifyErrors[500]
|
||||||
|
}
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const uploadsService: FastifyPluginAsync = async (fastify) => {
|
export const uploadsService: FastifyPluginAsync = async (fastify) => {
|
||||||
@ -24,4 +35,24 @@ export const uploadsService: FastifyPluginAsync = async (fastify) => {
|
|||||||
return await reply.sendFile(path.join('users', image))
|
return await reply.sendFile(path.join('users', image))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fastify.route<{ Params: ParametersUploadsSchemaType }>({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/uploads/guilds/:image',
|
||||||
|
schema: getUploadsSchema,
|
||||||
|
handler: async (request, reply) => {
|
||||||
|
const { image } = request.params
|
||||||
|
return await reply.sendFile(path.join('guilds', image))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fastify.route<{ Params: ParametersUploadsSchemaType }>({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/uploads/messages/:image',
|
||||||
|
schema: getUploadsSchema,
|
||||||
|
handler: async (request, reply) => {
|
||||||
|
const { image } = request.params
|
||||||
|
return await reply.sendFile(path.join('messages', image))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,11 @@ import authenticateUser from '../../../../tools/plugins/authenticateUser.js'
|
|||||||
import { fastifyErrors } from '../../../../models/utils.js'
|
import { fastifyErrors } from '../../../../models/utils.js'
|
||||||
import fastifyMultipart from 'fastify-multipart'
|
import fastifyMultipart from 'fastify-multipart'
|
||||||
import prisma from '../../../../tools/database/prisma.js'
|
import prisma from '../../../../tools/database/prisma.js'
|
||||||
import { uploadImage } from '../../../../tools/utils/uploadImage.js'
|
import { uploadFile } from '../../../../tools/utils/uploadFile.js'
|
||||||
|
import {
|
||||||
|
maximumImageSize,
|
||||||
|
supportedImageMimetype
|
||||||
|
} from '../../../../tools/configurations/index.js'
|
||||||
|
|
||||||
const putServiceSchema: FastifySchema = {
|
const putServiceSchema: FastifySchema = {
|
||||||
description: 'Edit the current connected user logo',
|
description: 'Edit the current connected user logo',
|
||||||
@ -44,19 +48,21 @@ export const putCurrentUserLogo: FastifyPluginAsync = async (fastify) => {
|
|||||||
if (request.user == null) {
|
if (request.user == null) {
|
||||||
throw fastify.httpErrors.forbidden()
|
throw fastify.httpErrors.forbidden()
|
||||||
}
|
}
|
||||||
const logo = await uploadImage({
|
const file = await uploadFile({
|
||||||
fastify,
|
fastify,
|
||||||
request,
|
request,
|
||||||
folderInUploadsFolder: 'users'
|
folderInUploadsFolder: 'users',
|
||||||
|
maximumFileSize: maximumImageSize,
|
||||||
|
supportedFileMimetype: supportedImageMimetype
|
||||||
})
|
})
|
||||||
await prisma.user.update({
|
await prisma.user.update({
|
||||||
where: { id: request.user.current.id },
|
where: { id: request.user.current.id },
|
||||||
data: { logo }
|
data: { logo: file.pathToStoreInDatabase }
|
||||||
})
|
})
|
||||||
reply.statusCode = 200
|
reply.statusCode = 200
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
logo
|
logo: file.pathToStoreInDatabase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
src/tools/utils/uploadFile.ts
Normal file
69
src/tools/utils/uploadFile.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
|
import { URL } from 'node:url'
|
||||||
|
import { randomUUID } from 'node:crypto'
|
||||||
|
|
||||||
|
import { FastifyInstance, FastifyRequest } from 'fastify'
|
||||||
|
|
||||||
|
import { Multipart } from 'fastify-multipart'
|
||||||
|
|
||||||
|
import { ROOT_URL } from '../configurations/index.js'
|
||||||
|
|
||||||
|
export interface UploadFileOptions {
|
||||||
|
folderInUploadsFolder: 'guilds' | 'messages' | 'users'
|
||||||
|
request: FastifyRequest
|
||||||
|
fastify: FastifyInstance
|
||||||
|
|
||||||
|
/** in megabytes */
|
||||||
|
maximumFileSize: number
|
||||||
|
|
||||||
|
supportedFileMimetype?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UploadFileResult {
|
||||||
|
pathToStoreInDatabase: string
|
||||||
|
mimetype: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uploadFile = async (
|
||||||
|
options: UploadFileOptions
|
||||||
|
): Promise<UploadFileResult> => {
|
||||||
|
const {
|
||||||
|
fastify,
|
||||||
|
request,
|
||||||
|
folderInUploadsFolder,
|
||||||
|
maximumFileSize,
|
||||||
|
supportedFileMimetype
|
||||||
|
} = options
|
||||||
|
let files: Multipart[] = []
|
||||||
|
try {
|
||||||
|
files = await request.saveRequestFiles({
|
||||||
|
limits: {
|
||||||
|
files: 1,
|
||||||
|
fileSize: maximumFileSize * 1024 * 1024
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
throw fastify.httpErrors.requestHeaderFieldsTooLarge(
|
||||||
|
`File should be less than ${maximumFileSize}mb.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (files.length !== 1) {
|
||||||
|
throw fastify.httpErrors.badRequest('You must upload at most one file.')
|
||||||
|
}
|
||||||
|
const file = files[0]
|
||||||
|
if (
|
||||||
|
supportedFileMimetype != null &&
|
||||||
|
!supportedFileMimetype.includes(file.mimetype)
|
||||||
|
) {
|
||||||
|
throw fastify.httpErrors.badRequest(
|
||||||
|
`The file must have a valid type (${supportedFileMimetype.join(', ')}).`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const splitedMimetype = file.mimetype.split('/')
|
||||||
|
const fileExtension = splitedMimetype[1]
|
||||||
|
const filePath = `uploads/${folderInUploadsFolder}/${randomUUID()}.${fileExtension}`
|
||||||
|
const fileURL = new URL(filePath, ROOT_URL)
|
||||||
|
const pathToStoreInDatabase = `/${filePath}`
|
||||||
|
await fs.promises.copyFile(file.filepath, fileURL)
|
||||||
|
return { pathToStoreInDatabase, mimetype: file.mimetype }
|
||||||
|
}
|
@ -1,54 +0,0 @@
|
|||||||
import fs from 'node:fs'
|
|
||||||
import { URL } from 'node:url'
|
|
||||||
import { randomUUID } from 'node:crypto'
|
|
||||||
|
|
||||||
import { FastifyInstance, FastifyRequest } from 'fastify'
|
|
||||||
|
|
||||||
import { Multipart } from 'fastify-multipart'
|
|
||||||
|
|
||||||
import {
|
|
||||||
maximumImageSize,
|
|
||||||
supportedImageMimetype,
|
|
||||||
ROOT_URL
|
|
||||||
} from '../configurations/index.js'
|
|
||||||
|
|
||||||
export interface UploadImageOptions {
|
|
||||||
folderInUploadsFolder: 'guilds' | 'messages' | 'users'
|
|
||||||
request: FastifyRequest
|
|
||||||
fastify: FastifyInstance
|
|
||||||
}
|
|
||||||
|
|
||||||
export const uploadImage = async (
|
|
||||||
options: UploadImageOptions
|
|
||||||
): Promise<string> => {
|
|
||||||
const { fastify, request, folderInUploadsFolder } = options
|
|
||||||
let files: Multipart[] = []
|
|
||||||
try {
|
|
||||||
files = await request.saveRequestFiles({
|
|
||||||
limits: {
|
|
||||||
files: 1,
|
|
||||||
fileSize: maximumImageSize * 1024 * 1024
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
throw fastify.httpErrors.requestHeaderFieldsTooLarge(
|
|
||||||
`Image should be less than ${maximumImageSize}mb.`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (files.length !== 1) {
|
|
||||||
throw fastify.httpErrors.badRequest('You must upload at most one file.')
|
|
||||||
}
|
|
||||||
const image = files[0]
|
|
||||||
if (!supportedImageMimetype.includes(image.mimetype)) {
|
|
||||||
throw fastify.httpErrors.badRequest(
|
|
||||||
`The file must have a valid type (${supportedImageMimetype.join(', ')}).`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const splitedMimetype = image.mimetype.split('/')
|
|
||||||
const imageExtension = splitedMimetype[1]
|
|
||||||
const imagePath = `uploads/${folderInUploadsFolder}/${randomUUID()}.${imageExtension}`
|
|
||||||
const imageURL = new URL(imagePath, ROOT_URL)
|
|
||||||
const imagePathToStoreInDatabase = `/${imagePath}`
|
|
||||||
await fs.promises.copyFile(image.filepath, imageURL)
|
|
||||||
return imagePathToStoreInDatabase
|
|
||||||
}
|
|
Reference in New Issue
Block a user