diff --git a/packages/tests/src/api/check-params/index.ts b/packages/tests/src/api/check-params/index.ts index 8fc73544e..bf34b5c57 100644 --- a/packages/tests/src/api/check-params/index.ts +++ b/packages/tests/src/api/check-params/index.ts @@ -9,7 +9,7 @@ import './custom-pages.js' import './debug.js' import './follows.js' import './user-export.js' -import './user-import.js.js' +import './user-import.js' import './jobs.js' import './live.js' import './logs.js' diff --git a/server/core/controllers/api/users/user-imports.ts b/server/core/controllers/api/users/user-imports.ts index 2bc1e08f2..a89384aec 100644 --- a/server/core/controllers/api/users/user-imports.ts +++ b/server/core/controllers/api/users/user-imports.ts @@ -3,7 +3,7 @@ import { asyncMiddleware, authenticate } from '../../../middlewares/index.js' -import { uploadx } from '@server/lib/uploadx.js' +import { setupUploadResumableRoutes } from '@server/lib/uploadx.js' import { getLatestImportStatusValidator, userImportRequestResumableInitValidator, @@ -19,30 +19,22 @@ import { saveInTransactionWithRetries } from '@server/helpers/database-utils.js' const userImportRouter = express.Router() -userImportRouter.post('/:userId/imports/import-resumable', - authenticate, - asyncMiddleware(userImportRequestResumableInitValidator), - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) - -userImportRouter.delete('/:userId/imports/import-resumable', - authenticate, - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) - -userImportRouter.put('/:userId/imports/import-resumable', - authenticate, - uploadx.upload, // uploadx doesn't next() before the file upload completes - asyncMiddleware(userImportRequestResumableValidator), - asyncMiddleware(addUserImportResumable) -) - userImportRouter.get('/:userId/imports/latest', authenticate, asyncMiddleware(getLatestImportStatusValidator), asyncMiddleware(getLatestImport) ) +setupUploadResumableRoutes({ + routePath: '/:userId/imports/import-resumable', + router: userImportRouter, + + uploadInitAfterMiddlewares: [ asyncMiddleware(userImportRequestResumableInitValidator) ], + + uploadedMiddlewares: [ asyncMiddleware(userImportRequestResumableValidator) ], + uploadedController: asyncMiddleware(addUserImportResumable) +}) + // --------------------------------------------------------------------------- export { diff --git a/server/core/controllers/api/videos/captions.ts b/server/core/controllers/api/videos/captions.ts index 32fbadd36..9c3db2f90 100644 --- a/server/core/controllers/api/videos/captions.ts +++ b/server/core/controllers/api/videos/captions.ts @@ -47,12 +47,12 @@ async function listVideoCaptions (req: express.Request, res: express.Response) { } async function createVideoCaption (req: express.Request, res: express.Response) { - const videoCaptionPhysicalFile = req.files['captionfile'][0] + const videoCaptionPhysicalFile: Express.Multer.File = req.files['captionfile'][0] const video = res.locals.videoAll const captionLanguage = req.params.captionLanguage - const videoCaption = await createLocalCaption({ video, language: captionLanguage, path: videoCaptionPhysicalFile }) + const videoCaption = await createLocalCaption({ video, language: captionLanguage, path: videoCaptionPhysicalFile.path }) await sequelizeTypescript.transaction(async t => { await federateVideoIfNeeded(video, false, t) diff --git a/server/core/controllers/api/videos/source.ts b/server/core/controllers/api/videos/source.ts index b0172c56d..d5882d489 100644 --- a/server/core/controllers/api/videos/source.ts +++ b/server/core/controllers/api/videos/source.ts @@ -4,7 +4,7 @@ import { sequelizeTypescript } from '@server/initializers/database.js' import { CreateJobArgument, CreateJobOptions, JobQueue } from '@server/lib/job-queue/index.js' import { Hooks } from '@server/lib/plugins/hooks.js' import { regenerateMiniaturesIfNeeded } from '@server/lib/thumbnail.js' -import { uploadx } from '@server/lib/uploadx.js' +import { setupUploadResumableRoutes } from '@server/lib/uploadx.js' import { buildMoveJob, buildStoryboardJobIfNeeded } from '@server/lib/video-jobs.js' import { autoBlacklistVideoIfNeeded } from '@server/lib/video-blacklist.js' import { buildNewFile } from '@server/lib/video-file.js' @@ -35,23 +35,14 @@ videoSourceRouter.get('/:id/source', getVideoLatestSource ) -videoSourceRouter.post('/:id/source/replace-resumable', - authenticate, - asyncMiddleware(replaceVideoSourceResumableInitValidator), - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) +setupUploadResumableRoutes({ + routePath: '/:id/source/replace-resumable', + router: videoSourceRouter, -videoSourceRouter.delete('/:id/source/replace-resumable', - authenticate, - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) - -videoSourceRouter.put('/:id/source/replace-resumable', - authenticate, - uploadx.upload, // uploadx doesn't next() before the file upload completes - asyncMiddleware(replaceVideoSourceResumableValidator), - asyncMiddleware(replaceVideoSourceResumable) -) + uploadInitAfterMiddlewares: [ asyncMiddleware(replaceVideoSourceResumableInitValidator) ], + uploadedMiddlewares: [ asyncMiddleware(replaceVideoSourceResumableValidator) ], + uploadedController: asyncMiddleware(replaceVideoSourceResumable) +}) // --------------------------------------------------------------------------- diff --git a/server/core/controllers/api/videos/upload.ts b/server/core/controllers/api/videos/upload.ts index ae52e4806..3dee3b070 100644 --- a/server/core/controllers/api/videos/upload.ts +++ b/server/core/controllers/api/videos/upload.ts @@ -1,7 +1,7 @@ import express from 'express' import { getResumableUploadPath } from '@server/helpers/upload.js' import { Redis } from '@server/lib/redis.js' -import { uploadx } from '@server/lib/uploadx.js' +import { setupUploadResumableRoutes } from '@server/lib/uploadx.js' import { buildNextVideoState } from '@server/lib/video-state.js' import { openapiOperationDoc } from '@server/middlewares/doc.js' import { uuidToShort } from '@peertube/peertube-node-utils' @@ -45,27 +45,25 @@ uploadRouter.post('/upload', asyncRetryTransactionMiddleware(addVideoLegacy) ) -uploadRouter.post('/upload-resumable', - openapiOperationDoc({ operationId: 'uploadResumableInit' }), - authenticate, - reqVideoFileAddResumable, - asyncMiddleware(videosAddResumableInitValidator), - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) +setupUploadResumableRoutes({ + routePath: '/upload-resumable', + router: uploadRouter, -uploadRouter.delete('/upload-resumable', - authenticate, - asyncMiddleware(deleteUploadResumableCache), - (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end -) + uploadInitBeforeMiddlewares: [ + openapiOperationDoc({ operationId: 'uploadResumableInit' }), + reqVideoFileAddResumable + ], -uploadRouter.put('/upload-resumable', - openapiOperationDoc({ operationId: 'uploadResumable' }), - authenticate, - uploadx.upload, // uploadx doesn't next() before the file upload completes - asyncMiddleware(videosAddResumableValidator), - asyncMiddleware(addVideoResumable) -) + uploadInitAfterMiddlewares: [ asyncMiddleware(videosAddResumableInitValidator) ], + + uploadDeleteMiddlewares: [ asyncMiddleware(deleteUploadResumableCache) ], + + uploadedMiddlewares: [ + openapiOperationDoc({ operationId: 'uploadResumable' }), + asyncMiddleware(videosAddResumableValidator) + ], + uploadedController: asyncMiddleware(addVideoResumable) +}) // --------------------------------------------------------------------------- @@ -110,7 +108,7 @@ async function addVideoResumable (req: express.Request, res: express.Response) { async function addVideo (options: { req: express.Request res: express.Response - videoPhysicalFile: express.VideoUploadFile + videoPhysicalFile: express.VideoLegacyUploadFile videoInfo: VideoCreate files: express.UploadFiles }) { diff --git a/server/core/lib/moderation.ts b/server/core/lib/moderation.ts index 66ca1d308..e16a1400e 100644 --- a/server/core/lib/moderation.ts +++ b/server/core/lib/moderation.ts @@ -1,4 +1,4 @@ -import express, { VideoUploadFile } from 'express' +import express, { VideoLegacyUploadFile } from 'express' import { PathLike } from 'fs-extra/esm' import { Transaction } from 'sequelize' import { AbuseAuditView, auditLoggerFactory } from '@server/helpers/audit-logger.js' @@ -38,7 +38,7 @@ export type AcceptResult = { // Stub function that can be filtered by plugins function isLocalVideoFileAccepted (object: { videoBody: VideoCreate - videoFile: VideoUploadFile + videoFile: VideoLegacyUploadFile user: MUserDefault }): AcceptResult { return { accepted: true } diff --git a/server/core/lib/uploadx.ts b/server/core/lib/uploadx.ts index 81c93f77c..7ecccafb4 100644 --- a/server/core/lib/uploadx.ts +++ b/server/core/lib/uploadx.ts @@ -1,13 +1,15 @@ -import express from 'express' +import express, { Request, Response, NextFunction, RequestHandler } from 'express' import { buildLogger } from '@server/helpers/logger.js' import { getResumableUploadPath } from '@server/helpers/upload.js' import { CONFIG } from '@server/initializers/config.js' -import { LogLevel, Uploadx } from '@uploadx/core' +import { FileQuery, LogLevel, Uploadx, Metadata as UploadXMetadata } from '@uploadx/core' import { extname } from 'path' +import { authenticate } from '@server/middlewares/auth.js' +import { resumableInitValidator } from '@server/middlewares/validators/resumable-upload.js' const logger = buildLogger('uploadx') -const uploadx = new Uploadx({ +export const uploadx = new Uploadx({ directory: getResumableUploadPath(), expiration: { maxAge: undefined, rolling: true }, @@ -32,6 +34,60 @@ const uploadx = new Uploadx({ filename: file => `${file.userId}-${file.id}${extname(file.metadata.filename)}` }) -export { - uploadx +export function safeUploadXCleanup (file: FileQuery) { + uploadx.storage.delete(file) + .catch(err => logger.error('Cannot delete the file %s', file.name, { err })) +} + +export function buildUploadXFile (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, res: Response, next: NextFunction) => void)[] + uploadedController: (req: Request, res: Response, next: NextFunction) => void + + uploadDeleteMiddlewares?: RequestHandler[] +}) { + const { + router, + routePath, + uploadedMiddlewares = [], + uploadedController, + uploadInitBeforeMiddlewares = [], + uploadInitAfterMiddlewares = [], + uploadDeleteMiddlewares = [] + } = options + + router.post(routePath, + authenticate, + ...uploadInitBeforeMiddlewares, + resumableInitValidator, + ...uploadInitAfterMiddlewares, + (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end + ) + + router.delete(routePath, + authenticate, + ...uploadDeleteMiddlewares, + (req, res) => uploadx.upload(req, res) // Prevent next() call, explicitely tell to uploadx it's the end + ) + + router.put(routePath, + authenticate, + uploadx.upload, // uploadx doesn't next() before the file upload completes + ...uploadedMiddlewares, + uploadedController + ) } diff --git a/server/core/middlewares/validators/index.ts b/server/core/middlewares/validators/index.ts index 26f3d8db7..030c888d0 100644 --- a/server/core/middlewares/validators/index.ts +++ b/server/core/middlewares/validators/index.ts @@ -16,6 +16,7 @@ export * from './oembed.js' export * from './pagination.js' export * from './plugins.js' export * from './redundancy.js' +export * from './resumable-upload.js' export * from './search.js' export * from './server.js' export * from './sort.js' diff --git a/server/core/middlewares/validators/resumable-upload.ts b/server/core/middlewares/validators/resumable-upload.ts new file mode 100644 index 000000000..43386931c --- /dev/null +++ b/server/core/middlewares/validators/resumable-upload.ts @@ -0,0 +1,36 @@ +import { logger } from '@server/helpers/logger.js' +import express from 'express' +import { body, header } from 'express-validator' +import { areValidationErrors } from './shared/utils.js' +import { cleanUpReqFiles } from '@server/helpers/express-utils.js' + +export const resumableInitValidator = [ + body('filename') + .exists(), + + header('x-upload-content-length') + .isNumeric() + .exists() + .withMessage('Should specify the file length'), + header('x-upload-content-type') + .isString() + .exists() + .withMessage('Should specify the file mimetype'), + + (req: express.Request, res: express.Response, next: express.NextFunction) => { + logger.debug('Checking resumableInitValidator parameters and headers', { + parameters: req.body, + headers: req.headers + }) + + if (areValidationErrors(req, res, { omitLog: true })) return cleanUpReqFiles(req) + + res.locals.uploadVideoFileResumableMetadata = { + mimetype: req.headers['x-upload-content-type'] as string, + size: +req.headers['x-upload-content-length'], + originalname: req.body.filename + } + + return next() + } +] diff --git a/server/core/middlewares/validators/users/user-import.ts b/server/core/middlewares/validators/users/user-import.ts index bec7db019..53c86110d 100644 --- a/server/core/middlewares/validators/users/user-import.ts +++ b/server/core/middlewares/validators/users/user-import.ts @@ -1,9 +1,7 @@ import express from 'express' -import { body, header, param } from 'express-validator' -import { getResumableUploadPath } from '@server/helpers/upload.js' -import { uploadx } from '@server/lib/uploadx.js' +import { param } from 'express-validator' +import { buildUploadXFile, safeUploadXCleanup } from '@server/lib/uploadx.js' import { Metadata as UploadXMetadata } from '@uploadx/core' -import { logger } from '../../../helpers/logger.js' import { areValidationErrors, checkUserIdExist } from '../shared/index.js' import { CONFIG } from '@server/initializers/config.js' import { HttpStatusCode, ServerErrorCode, UserImportState, UserRight } from '@peertube/peertube-models' @@ -15,9 +13,8 @@ export const userImportRequestResumableValidator = [ .isInt().not().isEmpty().withMessage('Should have a valid userId'), async (req: express.Request, res: express.Response, next: express.NextFunction) => { - const body: express.CustomUploadXFile = req.body - const file = { ...body, path: getResumableUploadPath(body.name), filename: body.metadata.filename } - const cleanup = () => uploadx.storage.delete(file).catch(err => logger.error('Cannot delete the file %s', file.name, { err })) + const file = buildUploadXFile(req.body as express.CustomUploadXFile) + const cleanup = () => safeUploadXCleanup(file) if (!await checkUserIdRight(req.params.userId, res)) return cleanup() @@ -40,25 +37,8 @@ export const userImportRequestResumableInitValidator = [ param('userId') .isInt().not().isEmpty().withMessage('Should have a valid userId'), - body('filename') - .exists(), - - header('x-upload-content-length') - .isNumeric() - .exists() - .withMessage('Should specify the file length'), - header('x-upload-content-type') - .isString() - .exists() - .withMessage('Should specify the file mimetype'), - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - logger.debug('Checking userImportRequestResumableInitValidator parameters and headers', { - parameters: req.body, - headers: req.headers - }) - - if (areValidationErrors(req, res, { omitLog: true })) return + if (areValidationErrors(req, res)) return if (CONFIG.IMPORT.USERS.ENABLED !== true) { return res.fail({ @@ -76,8 +56,9 @@ export const userImportRequestResumableInitValidator = [ if (!await checkUserIdRight(req.params.userId, res)) return + const fileMetadata = res.locals.uploadVideoFileResumableMetadata const user = res.locals.user - if (await isUserQuotaValid({ userId: user.id, uploadSize: +req.headers['x-upload-content-length'] }) === false) { + if (await isUserQuotaValid({ userId: user.id, uploadSize: fileMetadata.size }) === false) { return res.fail({ message: 'User video quota is exceeded with this import', status: HttpStatusCode.PAYLOAD_TOO_LARGE_413, diff --git a/server/core/middlewares/validators/videos/shared/video-validators.ts b/server/core/middlewares/validators/videos/shared/video-validators.ts index 1ac7308fd..470cd842f 100644 --- a/server/core/middlewares/validators/videos/shared/video-validators.ts +++ b/server/core/middlewares/validators/videos/shared/video-validators.ts @@ -41,7 +41,7 @@ export async function commonVideoFileChecks (options: { export async function isVideoFileAccepted (options: { req: express.Request res: express.Response - videoFile: express.VideoUploadFile + videoFile: express.VideoLegacyUploadFile hook: Extract }) { const { req, res, videoFile, hook } = options diff --git a/server/core/middlewares/validators/videos/video-source.ts b/server/core/middlewares/validators/videos/video-source.ts index 3d4f77e21..f7b4bfdb7 100644 --- a/server/core/middlewares/validators/videos/video-source.ts +++ b/server/core/middlewares/validators/videos/video-source.ts @@ -1,14 +1,11 @@ import express from 'express' -import { body, header } from 'express-validator' -import { getResumableUploadPath } from '@server/helpers/upload.js' import { getVideoWithAttributes } from '@server/helpers/video.js' import { CONFIG } from '@server/initializers/config.js' -import { uploadx } from '@server/lib/uploadx.js' +import { buildUploadXFile, safeUploadXCleanup } from '@server/lib/uploadx.js' import { VideoSourceModel } from '@server/models/video/video-source.js' import { MVideoFullLight } from '@server/types/models/index.js' import { HttpStatusCode, UserRight } from '@peertube/peertube-models' import { Metadata as UploadXMetadata } from '@uploadx/core' -import { logger } from '../../../helpers/logger.js' import { areValidationErrors, checkUserCanManageVideo, doesVideoExist, isValidVideoIdParam } from '../shared/index.js' import { addDurationToVideoFileIfNeeded, checkVideoFileCanBeEdited, commonVideoFileChecks, isVideoFileAccepted } from './shared/index.js' @@ -39,9 +36,8 @@ export const videoSourceGetLatestValidator = [ export const replaceVideoSourceResumableValidator = [ async (req: express.Request, res: express.Response, next: express.NextFunction) => { - const body: express.CustomUploadXFile = req.body - const file = { ...body, duration: undefined, path: getResumableUploadPath(body.name), filename: body.metadata.filename } - const cleanup = () => uploadx.storage.delete(file).catch(err => logger.error('Cannot delete the file %s', file.name, { err })) + const file = buildUploadXFile(req.body as express.CustomUploadXFile) + const cleanup = () => safeUploadXCleanup(file) if (!await checkCanUpdateVideoFile({ req, res })) { return cleanup() @@ -62,38 +58,14 @@ export const replaceVideoSourceResumableValidator = [ ] export const replaceVideoSourceResumableInitValidator = [ - body('filename') - .exists(), - - header('x-upload-content-length') - .isNumeric() - .exists() - .withMessage('Should specify the file length'), - header('x-upload-content-type') - .isString() - .exists() - .withMessage('Should specify the file mimetype'), - async (req: express.Request, res: express.Response, next: express.NextFunction) => { const user = res.locals.oauth.token.User - logger.debug('Checking updateVideoFileResumableInitValidator parameters and headers', { - parameters: req.body, - headers: req.headers - }) - - if (areValidationErrors(req, res, { omitLog: true })) return - if (!await checkCanUpdateVideoFile({ req, res })) return - const videoFileMetadata = { - mimetype: req.headers['x-upload-content-type'] as string, - size: +req.headers['x-upload-content-length'], - originalname: req.body.filename - } - - const files = { videofile: [ videoFileMetadata ] } - if (await commonVideoFileChecks({ res, user, videoFileSize: videoFileMetadata.size, files }) === false) return + const fileMetadata = res.locals.uploadVideoFileResumableMetadata + const files = { videofile: [ fileMetadata ] } + if (await commonVideoFileChecks({ res, user, videoFileSize: fileMetadata.size, files }) === false) return return next() } diff --git a/server/core/middlewares/validators/videos/videos.ts b/server/core/middlewares/validators/videos/videos.ts index 808647832..b36be0f31 100644 --- a/server/core/middlewares/validators/videos/videos.ts +++ b/server/core/middlewares/validators/videos/videos.ts @@ -1,10 +1,9 @@ import express from 'express' -import { body, header, param, query, ValidationChain } from 'express-validator' +import { body, param, query, ValidationChain } from 'express-validator' import { arrayify } from '@peertube/peertube-core-utils' import { HttpStatusCode, ServerErrorCode, UserRight, VideoState } from '@peertube/peertube-models' -import { getResumableUploadPath } from '@server/helpers/upload.js' import { Redis } from '@server/lib/redis.js' -import { uploadx } from '@server/lib/uploadx.js' +import { buildUploadXFile, safeUploadXCleanup } from '@server/lib/uploadx.js' import { getServerActor } from '@server/models/application/application.js' import { ExpressPromiseHandler } from '@server/types/express-handler.js' import { MUserAccountId, MVideoFullLight } from '@server/types/models/index.js' @@ -74,7 +73,7 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ async (req: express.Request, res: express.Response, next: express.NextFunction) => { if (areValidationErrors(req, res)) return cleanUpReqFiles(req) - const videoFile: express.VideoUploadFile = req.files['videofile'][0] + const videoFile: express.VideoLegacyUploadFile = req.files['videofile'][0] const user = res.locals.oauth.token.User if ( @@ -96,9 +95,8 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ const videosAddResumableValidator = [ async (req: express.Request, res: express.Response, next: express.NextFunction) => { const user = res.locals.oauth.token.User - const body: express.CustomUploadXFile = req.body - const file = { ...body, duration: undefined, path: getResumableUploadPath(body.name), filename: body.metadata.filename } - const cleanup = () => uploadx.storage.delete(file).catch(err => logger.error('Cannot delete the file %s', file.name, { err })) + const file = buildUploadXFile(req.body as express.CustomUploadXFile) + const cleanup = () => safeUploadXCleanup(file) const uploadId = req.query.upload_id const sessionExists = await Redis.Instance.doesUploadSessionExist(uploadId) @@ -148,22 +146,7 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([ .isArray() .withMessage('Video passwords should be an array.'), - header('x-upload-content-length') - .isNumeric() - .exists() - .withMessage('Should specify the file length'), - header('x-upload-content-type') - .isString() - .exists() - .withMessage('Should specify the file mimetype'), - async (req: express.Request, res: express.Response, next: express.NextFunction) => { - const videoFileMetadata = { - mimetype: req.headers['x-upload-content-type'] as string, - size: +req.headers['x-upload-content-length'], - originalname: req.body.filename - } - const user = res.locals.oauth.token.User const cleanup = () => cleanUpReqFiles(req) @@ -175,8 +158,9 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([ if (areValidationErrors(req, res, { omitLog: true })) return cleanup() - const files = { videofile: [ videoFileMetadata ] } - if (!await commonVideoChecksPass({ req, res, user, videoFileSize: videoFileMetadata.size, files })) return cleanup() + const fileMetadata = res.locals.uploadVideoFileResumableMetadata + const files = { videofile: [ fileMetadata ] } + if (!await commonVideoChecksPass({ req, res, user, videoFileSize: fileMetadata.size, files })) return cleanup() if (!isValidPasswordProtectedPrivacy(req, res)) return cleanup() diff --git a/server/core/types/express.d.ts b/server/core/types/express.d.ts index 9fb333a45..c80e21c6a 100644 --- a/server/core/types/express.d.ts +++ b/server/core/types/express.d.ts @@ -55,12 +55,12 @@ declare module 'express' { method: HttpMethodType } + // --------------------------------------------------------------------------- + // Upload using multer or uploadx middleware export type MulterOrUploadXFile = UploadXFile | Express.Multer.File - export type UploadFiles = { - [fieldname: string]: MulterOrUploadXFile[] - } | MulterOrUploadXFile[] + export type UploadFiles = { [fieldname: string]: MulterOrUploadXFile[] } | MulterOrUploadXFile[] // Partial object used by some functions to check the file mimetype/extension export type UploadFileForCheck = { @@ -69,21 +69,15 @@ declare module 'express' { size: number } - export type UploadFilesForCheck = { - [fieldname: string]: UploadFileForCheck[] - } | UploadFileForCheck[] + export type UploadFilesForCheck = { [fieldname: string]: UploadFileForCheck[] } | UploadFileForCheck[] + + // --------------------------------------------------------------------------- // Upload file with a duration added by our middleware - export type VideoUploadFile = Pick & { + export type VideoLegacyUploadFile = Pick & { duration: number } - // Extends Metadata property of UploadX object - export type UploadXFileMetadata = Metadata & VideoCreate & { - previewfile: Express.Multer.File[] - thumbnailfile: Express.Multer.File[] - } - // Our custom UploadXFile object using our custom metadata export type CustomUploadXFile = UploadXFile & { metadata: T } @@ -94,7 +88,13 @@ declare module 'express' { originalname: string } - export type UploadNewVideoUploadXFile = EnhancedUploadXFile & CustomUploadXFile + // Extends Metadata property of UploadX object when uploading a video + export type UploadNewVideoXFileMetadata = Metadata & VideoCreate & { + previewfile: Express.Multer.File[] + thumbnailfile: Express.Multer.File[] + } + + export type UploadNewVideoUploadXFile = EnhancedUploadXFile & CustomUploadXFile // Extends Response with added functions and potential variables passed by middlewares interface Response { @@ -142,6 +142,11 @@ declare module 'express' { videoFile?: MVideoFile + uploadVideoFileResumableMetadata?: { + mimetype: string + size: number + originalname: string + } uploadVideoFileResumable?: UploadNewVideoUploadXFile updateVideoFileResumable?: EnhancedUploadXFile importUserFileResumable?: EnhancedUploadXFile