2024-02-14 10:20:02 +01:00
|
|
|
import express, { Request, Response, NextFunction, RequestHandler } from 'express'
|
2023-07-31 14:34:36 +02:00
|
|
|
import { buildLogger } from '@server/helpers/logger.js'
|
|
|
|
import { getResumableUploadPath } from '@server/helpers/upload.js'
|
|
|
|
import { CONFIG } from '@server/initializers/config.js'
|
2024-02-14 10:20:02 +01:00
|
|
|
import { FileQuery, LogLevel, Uploadx, Metadata as UploadXMetadata } from '@uploadx/core'
|
2023-04-21 14:55:10 +02:00
|
|
|
import { extname } from 'path'
|
2024-02-14 10:20:02 +01:00
|
|
|
import { authenticate } from '@server/middlewares/auth.js'
|
|
|
|
import { resumableInitValidator } from '@server/middlewares/validators/resumable-upload.js'
|
2022-11-07 10:40:43 +01:00
|
|
|
|
|
|
|
const logger = buildLogger('uploadx')
|
2021-12-03 14:00:40 +01:00
|
|
|
|
2024-02-14 10:20:02 +01:00
|
|
|
export const uploadx = new Uploadx({
|
2021-12-17 15:49:52 +01:00
|
|
|
directory: getResumableUploadPath(),
|
2022-04-19 11:44:03 +02:00
|
|
|
|
|
|
|
expiration: { maxAge: undefined, rolling: true },
|
|
|
|
|
2021-12-17 15:49:52 +01:00
|
|
|
// Could be big with thumbnails/previews
|
2022-01-18 09:29:46 +01:00
|
|
|
maxMetadataSize: '10MB',
|
2022-04-19 11:44:03 +02:00
|
|
|
|
2022-11-07 10:40:43 +01:00
|
|
|
logger: {
|
|
|
|
logLevel: CONFIG.LOG.LEVEL as LogLevel,
|
|
|
|
debug: logger.debug.bind(logger),
|
|
|
|
info: logger.info.bind(logger),
|
|
|
|
warn: logger.warn.bind(logger),
|
|
|
|
error: logger.error.bind(logger)
|
|
|
|
},
|
2022-10-28 10:47:06 +02:00
|
|
|
|
2022-01-18 09:29:46 +01:00
|
|
|
userIdentifier: (_, res: express.Response) => {
|
|
|
|
if (!res.locals.oauth) return undefined
|
|
|
|
|
|
|
|
return res.locals.oauth.token.user.id + ''
|
2023-04-21 14:55:10 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
filename: file => `${file.userId}-${file.id}${extname(file.metadata.filename)}`
|
2021-12-17 15:49:52 +01:00
|
|
|
})
|
2021-12-03 14:00:40 +01:00
|
|
|
|
2024-02-14 10:20:02 +01:00
|
|
|
export function safeUploadXCleanup (file: FileQuery) {
|
|
|
|
uploadx.storage.delete(file)
|
|
|
|
.catch(err => logger.error('Cannot delete the file %s', file.name, { err }))
|
|
|
|
}
|
|
|
|
|
|
|
|
export function buildUploadXFile <T extends UploadXMetadata> (reqBody: T) {
|
|
|
|
return {
|
|
|
|
...reqBody,
|
|
|
|
|
|
|
|
path: getResumableUploadPath(reqBody.name),
|
|
|
|
filename: reqBody.metadata.filename
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function setupUploadResumableRoutes (options: {
|
|
|
|
router: express.Router
|
|
|
|
routePath: string
|
|
|
|
|
|
|
|
uploadInitBeforeMiddlewares?: RequestHandler[]
|
|
|
|
uploadInitAfterMiddlewares?: RequestHandler[]
|
|
|
|
|
|
|
|
uploadedMiddlewares?: ((req: Request<any>, res: Response, next: NextFunction) => void)[]
|
|
|
|
uploadedController: (req: Request<any>, res: Response, next: NextFunction) => void
|
|
|
|
|
|
|
|
uploadDeleteMiddlewares?: RequestHandler[]
|
|
|
|
}) {
|
|
|
|
const {
|
|
|
|
router,
|
|
|
|
routePath,
|
|
|
|
uploadedMiddlewares = [],
|
|
|
|
uploadedController,
|
|
|
|
uploadInitBeforeMiddlewares = [],
|
|
|
|
uploadInitAfterMiddlewares = [],
|
|
|
|
uploadDeleteMiddlewares = []
|
|
|
|
} = options
|
|
|
|
|
|
|
|
router.post(routePath,
|
|
|
|
authenticate,
|
|
|
|
...uploadInitBeforeMiddlewares,
|
|
|
|
resumableInitValidator,
|
|
|
|
...uploadInitAfterMiddlewares,
|
2024-03-15 17:01:14 +01:00
|
|
|
(req, res) => uploadx.upload(req, res) // Prevent next() call, explicitly tell to uploadx it's the end
|
2024-02-14 10:20:02 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
router.delete(routePath,
|
|
|
|
authenticate,
|
|
|
|
...uploadDeleteMiddlewares,
|
2024-03-15 17:01:14 +01:00
|
|
|
(req, res) => uploadx.upload(req, res) // Prevent next() call, explicitly tell to uploadx it's the end
|
2024-02-14 10:20:02 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
router.put(routePath,
|
|
|
|
authenticate,
|
|
|
|
uploadx.upload, // uploadx doesn't next() before the file upload completes
|
|
|
|
...uploadedMiddlewares,
|
|
|
|
uploadedController
|
|
|
|
)
|
2021-12-03 14:00:40 +01:00
|
|
|
}
|