Stricter import types
Avoid forgetting to sanitize a field by specifying the sanitized object type
This commit is contained in:
parent
02596be702
commit
009d7b39ac
14 changed files with 147 additions and 107 deletions
|
@ -17,48 +17,52 @@ import { exists, isArray, isDateValid, isFileValid } from './misc.js'
|
||||||
|
|
||||||
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
|
||||||
|
|
||||||
function isVideoIncludeValid (include: VideoIncludeType) {
|
export function isVideoIncludeValid (include: VideoIncludeType) {
|
||||||
return exists(include) && validator.default.isInt('' + include)
|
return exists(include) && validator.default.isInt('' + include)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoCategoryValid (value: any) {
|
export function isVideoCategoryValid (value: any) {
|
||||||
return value === null || VIDEO_CATEGORIES[value] !== undefined
|
return value === null || VIDEO_CATEGORIES[value] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoStateValid (value: any) {
|
export function isVideoStateValid (value: any) {
|
||||||
return exists(value) && VIDEO_STATES[value] !== undefined
|
return exists(value) && VIDEO_STATES[value] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoLicenceValid (value: any) {
|
export function isVideoLicenceValid (value: any) {
|
||||||
return value === null || VIDEO_LICENCES[value] !== undefined
|
return value === null || VIDEO_LICENCES[value] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoLanguageValid (value: any) {
|
export function isVideoLanguageValid (value: any) {
|
||||||
return value === null ||
|
return value === null ||
|
||||||
(typeof value === 'string' && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
|
(typeof value === 'string' && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoDurationValid (value: string) {
|
export function isVideoDurationValid (value: string) {
|
||||||
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
|
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoDescriptionValid (value: string) {
|
export function isVideoDescriptionValid (value: string) {
|
||||||
return value === null || (exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
|
return value === null || (exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoSupportValid (value: string) {
|
export function isVideoSupportValid (value: string) {
|
||||||
return value === null || (exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
|
return value === null || (exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoNameValid (value: string) {
|
export function isVideoNameValid (value: string) {
|
||||||
return exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
|
return exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoTagValid (tag: string) {
|
export function isVideoSourceFilenameValid (value: string) {
|
||||||
|
return exists(value) && validator.default.isLength(value, CONSTRAINTS_FIELDS.VIDEO_SOURCE.FILENAME)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isVideoTagValid (tag: string) {
|
||||||
return exists(tag) && validator.default.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
|
return exists(tag) && validator.default.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
function areVideoTagsValid (tags: string[]) {
|
export function areVideoTagsValid (tags: string[]) {
|
||||||
return tags === null || (
|
return tags === null || (
|
||||||
isArray(tags) &&
|
isArray(tags) &&
|
||||||
validator.default.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
|
validator.default.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
|
||||||
|
@ -66,20 +70,20 @@ function areVideoTagsValid (tags: string[]) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoViewsValid (value: string) {
|
export function isVideoViewsValid (value: string) {
|
||||||
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
|
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ratingTypes = new Set(Object.values(VIDEO_RATE_TYPES))
|
const ratingTypes = new Set(Object.values(VIDEO_RATE_TYPES))
|
||||||
function isVideoRatingTypeValid (value: string) {
|
export function isVideoRatingTypeValid (value: string) {
|
||||||
return value === 'none' || ratingTypes.has(value as VideoRateType)
|
return value === 'none' || ratingTypes.has(value as VideoRateType)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileExtnameValid (value: string) {
|
export function isVideoFileExtnameValid (value: string) {
|
||||||
return exists(value) && (value === VIDEO_LIVE.EXTENSION || MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined)
|
return exists(value) && (value === VIDEO_LIVE.EXTENSION || MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileMimeTypeValid (files: UploadFilesForCheck, field = 'videofile') {
|
export function isVideoFileMimeTypeValid (files: UploadFilesForCheck, field = 'videofile') {
|
||||||
return isFileValid({
|
return isFileValid({
|
||||||
files,
|
files,
|
||||||
mimeTypeRegex: MIMETYPES.VIDEO.MIMETYPES_REGEX,
|
mimeTypeRegex: MIMETYPES.VIDEO.MIMETYPES_REGEX,
|
||||||
|
@ -93,7 +97,7 @@ const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
|
||||||
.join('|')
|
.join('|')
|
||||||
const videoImageTypesRegex = `image/(${videoImageTypes})`
|
const videoImageTypesRegex = `image/(${videoImageTypes})`
|
||||||
|
|
||||||
function isVideoImageValid (files: UploadFilesForCheck, field: string, optional = true) {
|
export function isVideoImageValid (files: UploadFilesForCheck, field: string, optional = true) {
|
||||||
return isFileValid({
|
return isFileValid({
|
||||||
files,
|
files,
|
||||||
mimeTypeRegex: videoImageTypesRegex,
|
mimeTypeRegex: videoImageTypesRegex,
|
||||||
|
@ -103,51 +107,51 @@ function isVideoImageValid (files: UploadFilesForCheck, field: string, optional
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoPrivacyValid (value: number) {
|
export function isVideoPrivacyValid (value: number) {
|
||||||
return VIDEO_PRIVACIES[value] !== undefined
|
return VIDEO_PRIVACIES[value] !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoReplayPrivacyValid (value: number) {
|
export function isVideoReplayPrivacyValid (value: number) {
|
||||||
return VIDEO_PRIVACIES[value] !== undefined && value !== VideoPrivacy.PASSWORD_PROTECTED
|
return VIDEO_PRIVACIES[value] !== undefined && value !== VideoPrivacy.PASSWORD_PROTECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
function isScheduleVideoUpdatePrivacyValid (value: number) {
|
export function isScheduleVideoUpdatePrivacyValid (value: number) {
|
||||||
return value === VideoPrivacy.UNLISTED || value === VideoPrivacy.PUBLIC || value === VideoPrivacy.INTERNAL
|
return value === VideoPrivacy.UNLISTED || value === VideoPrivacy.PUBLIC || value === VideoPrivacy.INTERNAL
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoOriginallyPublishedAtValid (value: string | null) {
|
export function isVideoOriginallyPublishedAtValid (value: string | null) {
|
||||||
return value === null || isDateValid(value)
|
return value === null || isDateValid(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileInfoHashValid (value: string | null | undefined) {
|
export function isVideoFileInfoHashValid (value: string | null | undefined) {
|
||||||
return exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
|
return exists(value) && validator.default.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileResolutionValid (value: string) {
|
export function isVideoFileResolutionValid (value: string) {
|
||||||
return exists(value) && validator.default.isInt(value + '')
|
return exists(value) && validator.default.isInt(value + '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFPSResolutionValid (value: string) {
|
export function isVideoFPSResolutionValid (value: string) {
|
||||||
return value === null || validator.default.isInt(value + '')
|
return value === null || validator.default.isInt(value + '')
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoFileSizeValid (value: string) {
|
export function isVideoFileSizeValid (value: string) {
|
||||||
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
|
return exists(value) && validator.default.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isVideoMagnetUriValid (value: string) {
|
export function isVideoMagnetUriValid (value: string) {
|
||||||
if (!exists(value)) return false
|
if (!exists(value)) return false
|
||||||
|
|
||||||
const parsed = magnetUriDecode(value)
|
const parsed = magnetUriDecode(value)
|
||||||
return parsed && isVideoFileInfoHashValid(parsed.infoHash)
|
return parsed && isVideoFileInfoHashValid(parsed.infoHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPasswordValid (password: string) {
|
export function isPasswordValid (password: string) {
|
||||||
return password.length >= CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.min &&
|
return password.length >= CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.min &&
|
||||||
password.length < CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.max
|
password.length < CONSTRAINTS_FIELDS.VIDEO_PASSWORD.LENGTH.max
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidPasswordProtectedPrivacy (req: Request, res: Response) {
|
export function isValidPasswordProtectedPrivacy (req: Request, res: Response) {
|
||||||
const fail = (message: string) => {
|
const fail = (message: string) => {
|
||||||
res.fail({
|
res.fail({
|
||||||
status: HttpStatusCode.BAD_REQUEST_400,
|
status: HttpStatusCode.BAD_REQUEST_400,
|
||||||
|
@ -184,35 +188,3 @@ function isValidPasswordProtectedPrivacy (req: Request, res: Response) {
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
isVideoCategoryValid,
|
|
||||||
isVideoLicenceValid,
|
|
||||||
isVideoLanguageValid,
|
|
||||||
isVideoDescriptionValid,
|
|
||||||
isVideoFileInfoHashValid,
|
|
||||||
isVideoNameValid,
|
|
||||||
areVideoTagsValid,
|
|
||||||
isVideoFPSResolutionValid,
|
|
||||||
isScheduleVideoUpdatePrivacyValid,
|
|
||||||
isVideoOriginallyPublishedAtValid,
|
|
||||||
isVideoMagnetUriValid,
|
|
||||||
isVideoStateValid,
|
|
||||||
isVideoIncludeValid,
|
|
||||||
isVideoViewsValid,
|
|
||||||
isVideoRatingTypeValid,
|
|
||||||
isVideoFileExtnameValid,
|
|
||||||
isVideoFileMimeTypeValid,
|
|
||||||
isVideoDurationValid,
|
|
||||||
isVideoTagValid,
|
|
||||||
isVideoPrivacyValid,
|
|
||||||
isVideoReplayPrivacyValid,
|
|
||||||
isVideoFileResolutionValid,
|
|
||||||
isVideoFileSizeValid,
|
|
||||||
isVideoImageValid,
|
|
||||||
isVideoSupportValid,
|
|
||||||
isPasswordValid,
|
|
||||||
isValidPasswordProtectedPrivacy
|
|
||||||
}
|
|
||||||
|
|
|
@ -414,6 +414,9 @@ const CONSTRAINTS_FIELDS = {
|
||||||
PARTIAL_UPLOAD_SIZE: { max: 50 * 1024 * 1024 * 1024 }, // 50GB
|
PARTIAL_UPLOAD_SIZE: { max: 50 * 1024 * 1024 * 1024 }, // 50GB
|
||||||
URL: { min: 3, max: 2000 } // Length
|
URL: { min: 3, max: 2000 } // Length
|
||||||
},
|
},
|
||||||
|
VIDEO_SOURCE: {
|
||||||
|
FILENAME: { min: 1, max: 1000 } // Length
|
||||||
|
},
|
||||||
VIDEO_PLAYLISTS: {
|
VIDEO_PLAYLISTS: {
|
||||||
NAME: { min: 1, max: 120 }, // Length
|
NAME: { min: 1, max: 120 }, // Length
|
||||||
DESCRIPTION: { min: 3, max: 1000 }, // Length
|
DESCRIPTION: { min: 3, max: 1000 }, // Length
|
||||||
|
|
|
@ -4,16 +4,19 @@ import { loadOrCreateVideoIfAllowedForUser } from '@server/lib/model-loaders/vid
|
||||||
import { userRateVideo } from '@server/lib/rate.js'
|
import { userRateVideo } from '@server/lib/rate.js'
|
||||||
import { VideoModel } from '@server/models/video/video.js'
|
import { VideoModel } from '@server/models/video/video.js'
|
||||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
export abstract class AbstractRatesImporter <E, O> extends AbstractUserImporter <E, O> {
|
export type SanitizedRateObject = { videoUrl: string }
|
||||||
|
|
||||||
|
export abstract class AbstractRatesImporter <ROOT_OBJECT, OBJECT> extends AbstractUserImporter <ROOT_OBJECT, OBJECT, SanitizedRateObject> {
|
||||||
|
|
||||||
protected sanitizeRate <O extends { videoUrl: string }> (data: O) {
|
protected sanitizeRate <O extends { videoUrl: string }> (data: O) {
|
||||||
if (!isUrlValid(data.videoUrl)) return undefined
|
if (!isUrlValid(data.videoUrl)) return undefined
|
||||||
|
|
||||||
return data
|
return pick(data, [ 'videoUrl' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importRate (data: { videoUrl: string }, rateType: VideoRateType) {
|
protected async importRate (data: SanitizedRateObject, rateType: VideoRateType) {
|
||||||
const videoUrl = data.videoUrl
|
const videoUrl = data.videoUrl
|
||||||
const videoImmutable = await loadOrCreateVideoIfAllowedForUser(videoUrl)
|
const videoImmutable = await loadOrCreateVideoIfAllowedForUser(videoUrl)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,11 @@ import { dirname, resolve } from 'path'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export abstract class AbstractUserImporter <E, O extends { archiveFiles?: Record<string, string | Record<string, string>> }> {
|
export abstract class AbstractUserImporter <
|
||||||
|
ROOT_OBJECT,
|
||||||
|
OBJECT extends { archiveFiles?: Record<string, string | Record<string, string>> },
|
||||||
|
SANITIZED_OBJECT
|
||||||
|
> {
|
||||||
protected user: MUserDefault
|
protected user: MUserDefault
|
||||||
protected extractedDirectory: string
|
protected extractedDirectory: string
|
||||||
protected jsonFilePath: string
|
protected jsonFilePath: string
|
||||||
|
@ -78,7 +82,7 @@ export abstract class AbstractUserImporter <E, O extends { archiveFiles?: Record
|
||||||
}
|
}
|
||||||
|
|
||||||
async import () {
|
async import () {
|
||||||
const importData: E = await readJSON(this.jsonFilePath)
|
const importData: ROOT_OBJECT = await readJSON(this.jsonFilePath)
|
||||||
const summary = {
|
const summary = {
|
||||||
duplicates: 0,
|
duplicates: 0,
|
||||||
success: 0,
|
success: 0,
|
||||||
|
@ -111,9 +115,9 @@ export abstract class AbstractUserImporter <E, O extends { archiveFiles?: Record
|
||||||
return summary
|
return summary
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract getImportObjects (object: E): O[]
|
protected abstract getImportObjects (object: ROOT_OBJECT): OBJECT[]
|
||||||
|
|
||||||
protected abstract sanitize (object: O): O | undefined
|
protected abstract sanitize (object: OBJECT): SANITIZED_OBJECT | undefined
|
||||||
|
|
||||||
protected abstract importObject (object: O): Awaitable<{ duplicate: boolean }>
|
protected abstract importObject (object: SANITIZED_OBJECT): Awaitable<{ duplicate: boolean }>
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,13 @@ import { ServerModel } from '@server/models/server/server.js'
|
||||||
import { AccountModel } from '@server/models/account/account.js'
|
import { AccountModel } from '@server/models/account/account.js'
|
||||||
import { isValidActorHandle } from '@server/helpers/custom-validators/activitypub/actor.js'
|
import { isValidActorHandle } from '@server/helpers/custom-validators/activitypub/actor.js'
|
||||||
import { isHostValid } from '@server/helpers/custom-validators/servers.js'
|
import { isHostValid } from '@server/helpers/custom-validators/servers.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
type ImportObject = { handle: string | null, host: string | null, archiveFiles?: never }
|
type ImportObject = { handle: string | null, host: string | null, archiveFiles?: never }
|
||||||
|
|
||||||
export class BlocklistImporter extends AbstractUserImporter <BlocklistExportJSON, ImportObject> {
|
export class BlocklistImporter extends AbstractUserImporter <BlocklistExportJSON, ImportObject, ImportObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: BlocklistExportJSON) {
|
protected getImportObjects (json: BlocklistExportJSON) {
|
||||||
return [
|
return [
|
||||||
|
@ -23,7 +24,7 @@ export class BlocklistImporter extends AbstractUserImporter <BlocklistExportJSON
|
||||||
protected sanitize (blocklistImportData: ImportObject) {
|
protected sanitize (blocklistImportData: ImportObject) {
|
||||||
if (!isValidActorHandle(blocklistImportData.handle) && !isHostValid(blocklistImportData.host)) return undefined
|
if (!isValidActorHandle(blocklistImportData.handle) && !isHostValid(blocklistImportData.host)) return undefined
|
||||||
|
|
||||||
return blocklistImportData
|
return pick(blocklistImportData, [ 'handle', 'host' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (blocklistImportData: ImportObject) {
|
protected async importObject (blocklistImportData: ImportObject) {
|
||||||
|
|
|
@ -6,24 +6,27 @@ import { saveInTransactionWithRetries } from '@server/helpers/database-utils.js'
|
||||||
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js'
|
import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js'
|
||||||
import { MAccountDefault } from '@server/types/models/index.js'
|
import { MAccountDefault } from '@server/types/models/index.js'
|
||||||
import { isUserDescriptionValid, isUserDisplayNameValid } from '@server/helpers/custom-validators/users.js'
|
import { isUserDescriptionValid, isUserDisplayNameValid } from '@server/helpers/custom-validators/users.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class AccountImporter extends AbstractUserImporter <AccountExportJSON, AccountExportJSON> {
|
type SanitizedObject = Pick<AccountExportJSON, 'description' | 'displayName' | 'archiveFiles'>
|
||||||
|
|
||||||
|
export class AccountImporter extends AbstractUserImporter <AccountExportJSON, AccountExportJSON, SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: AccountExportJSON) {
|
protected getImportObjects (json: AccountExportJSON) {
|
||||||
return [ json ]
|
return [ json ]
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sanitize (blocklistImportData: AccountExportJSON) {
|
protected sanitize (blocklistImportData: AccountExportJSON) {
|
||||||
if (!isUserDisplayNameValid(blocklistImportData.name)) return undefined
|
if (!isUserDisplayNameValid(blocklistImportData.displayName)) return undefined
|
||||||
|
|
||||||
if (!isUserDescriptionValid(blocklistImportData.description)) blocklistImportData.description = null
|
if (!isUserDescriptionValid(blocklistImportData.description)) blocklistImportData.description = null
|
||||||
|
|
||||||
return blocklistImportData
|
return pick(blocklistImportData, [ 'displayName', 'description', 'archiveFiles' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (accountImportData: AccountExportJSON) {
|
protected async importObject (accountImportData: SanitizedObject) {
|
||||||
const account = this.user.Account
|
const account = this.user.Account
|
||||||
|
|
||||||
account.name = accountImportData.displayName
|
account.name = accountImportData.displayName
|
||||||
|
@ -38,7 +41,7 @@ export class AccountImporter extends AbstractUserImporter <AccountExportJSON, Ac
|
||||||
return { duplicate: false }
|
return { duplicate: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async importAvatar (account: MAccountDefault, accountImportData: AccountExportJSON) {
|
private async importAvatar (account: MAccountDefault, accountImportData: SanitizedObject) {
|
||||||
const avatarPath = this.getSafeArchivePathOrThrow(accountImportData.archiveFiles.avatar)
|
const avatarPath = this.getSafeArchivePathOrThrow(accountImportData.archiveFiles.avatar)
|
||||||
if (!avatarPath) return undefined
|
if (!avatarPath) return undefined
|
||||||
|
|
||||||
|
|
|
@ -17,23 +17,25 @@ import { CONSTRAINTS_FIELDS } from '@server/initializers/constants.js'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class ChannelsImporter extends AbstractUserImporter <ChannelExportJSON, ChannelExportJSON['channels'][0]> {
|
type SanitizedObject = Pick<ChannelExportJSON['channels'][0], 'name' | 'displayName' | 'description' | 'support' | 'archiveFiles'>
|
||||||
|
|
||||||
|
export class ChannelsImporter extends AbstractUserImporter <ChannelExportJSON, ChannelExportJSON['channels'][0], SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: ChannelExportJSON) {
|
protected getImportObjects (json: ChannelExportJSON) {
|
||||||
return json.channels
|
return json.channels
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sanitize (blocklistImportData: ChannelExportJSON['channels'][0]) {
|
protected sanitize (channelImportData: ChannelExportJSON['channels'][0]) {
|
||||||
if (!isVideoChannelUsernameValid(blocklistImportData.name)) return undefined
|
if (!isVideoChannelUsernameValid(channelImportData.name)) return undefined
|
||||||
if (!isVideoChannelDisplayNameValid(blocklistImportData.name)) return undefined
|
if (!isVideoChannelDisplayNameValid(channelImportData.displayName)) return undefined
|
||||||
|
|
||||||
if (!isVideoChannelDescriptionValid(blocklistImportData.description)) blocklistImportData.description = null
|
if (!isVideoChannelDescriptionValid(channelImportData.description)) channelImportData.description = null
|
||||||
if (!isVideoChannelSupportValid(blocklistImportData.support)) blocklistImportData.description = null
|
if (!isVideoChannelSupportValid(channelImportData.support)) channelImportData.support = null
|
||||||
|
|
||||||
return blocklistImportData
|
return pick(channelImportData, [ 'name', 'displayName', 'description', 'support', 'archiveFiles' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (channelImportData: ChannelExportJSON['channels'][0]) {
|
protected async importObject (channelImportData: SanitizedObject) {
|
||||||
const account = this.user.Account
|
const account = this.user.Account
|
||||||
const existingChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(channelImportData.name)
|
const existingChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(channelImportData.name)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { DislikesExportJSON } from '@peertube/peertube-models'
|
import { DislikesExportJSON } from '@peertube/peertube-models'
|
||||||
import { AbstractRatesImporter } from './abstract-rates-importer.js'
|
import { AbstractRatesImporter, SanitizedRateObject } from './abstract-rates-importer.js'
|
||||||
|
|
||||||
export class DislikesImporter extends AbstractRatesImporter <DislikesExportJSON, DislikesExportJSON['dislikes'][0]> {
|
export class DislikesImporter extends AbstractRatesImporter <DislikesExportJSON, DislikesExportJSON['dislikes'][0]> {
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ export class DislikesImporter extends AbstractRatesImporter <DislikesExportJSON,
|
||||||
return this.sanitizeRate(o)
|
return this.sanitizeRate(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (dislikesImportData: DislikesExportJSON['dislikes'][0]) {
|
protected async importObject (dislikesImportData: SanitizedRateObject) {
|
||||||
return this.importRate(dislikesImportData, 'dislike')
|
return this.importRate(dislikesImportData, 'dislike')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,13 @@ import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
|
||||||
import { AbstractUserImporter } from './abstract-user-importer.js'
|
import { AbstractUserImporter } from './abstract-user-importer.js'
|
||||||
import { JobQueue } from '@server/lib/job-queue/job-queue.js'
|
import { JobQueue } from '@server/lib/job-queue/job-queue.js'
|
||||||
import { isValidActorHandle } from '@server/helpers/custom-validators/activitypub/actor.js'
|
import { isValidActorHandle } from '@server/helpers/custom-validators/activitypub/actor.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class FollowingImporter extends AbstractUserImporter <FollowingExportJSON, FollowingExportJSON['following'][0]> {
|
type SanitizedObject = Pick<FollowingExportJSON['following'][0], 'targetHandle'>
|
||||||
|
|
||||||
|
export class FollowingImporter extends AbstractUserImporter <FollowingExportJSON, FollowingExportJSON['following'][0], SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: FollowingExportJSON) {
|
protected getImportObjects (json: FollowingExportJSON) {
|
||||||
return json.following
|
return json.following
|
||||||
|
@ -15,10 +18,10 @@ export class FollowingImporter extends AbstractUserImporter <FollowingExportJSON
|
||||||
protected sanitize (followingImportData: FollowingExportJSON['following'][0]) {
|
protected sanitize (followingImportData: FollowingExportJSON['following'][0]) {
|
||||||
if (!isValidActorHandle(followingImportData.targetHandle)) return undefined
|
if (!isValidActorHandle(followingImportData.targetHandle)) return undefined
|
||||||
|
|
||||||
return followingImportData
|
return pick(followingImportData, [ 'targetHandle' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (followingImportData: FollowingExportJSON['following'][0]) {
|
protected async importObject (followingImportData: SanitizedObject) {
|
||||||
const [ name, host ] = followingImportData.targetHandle.split('@')
|
const [ name, host ] = followingImportData.targetHandle.split('@')
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { LikesExportJSON } from '@peertube/peertube-models'
|
import { LikesExportJSON } from '@peertube/peertube-models'
|
||||||
import { AbstractRatesImporter } from './abstract-rates-importer.js'
|
import { AbstractRatesImporter, SanitizedRateObject } from './abstract-rates-importer.js'
|
||||||
|
|
||||||
export class LikesImporter extends AbstractRatesImporter <LikesExportJSON, LikesExportJSON['likes'][0]> {
|
export class LikesImporter extends AbstractRatesImporter <LikesExportJSON, LikesExportJSON['likes'][0]> {
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ export class LikesImporter extends AbstractRatesImporter <LikesExportJSON, Likes
|
||||||
return this.sanitizeRate(o)
|
return this.sanitizeRate(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (likesImportData: LikesExportJSON['likes'][0]) {
|
protected async importObject (likesImportData: SanitizedRateObject) {
|
||||||
return this.importRate(likesImportData, 'like')
|
return this.importRate(likesImportData, 'like')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,14 @@ import {
|
||||||
import { isThemeNameValid } from '@server/helpers/custom-validators/plugins.js'
|
import { isThemeNameValid } from '@server/helpers/custom-validators/plugins.js'
|
||||||
import { isThemeRegistered } from '@server/lib/plugins/theme-utils.js'
|
import { isThemeRegistered } from '@server/lib/plugins/theme-utils.js'
|
||||||
import { isUserNotificationSettingValid } from '@server/helpers/custom-validators/user-notifications.js'
|
import { isUserNotificationSettingValid } from '@server/helpers/custom-validators/user-notifications.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class UserSettingsImporter extends AbstractUserImporter <UserSettingsExportJSON, UserSettingsExportJSON> {
|
type SanitizedObject = Pick<UserSettingsExportJSON, 'nsfwPolicy' | 'autoPlayVideo' | 'autoPlayNextVideo' | 'autoPlayNextVideo' |
|
||||||
|
'autoPlayNextVideoPlaylist' | 'p2pEnabled' | 'videosHistoryEnabled' | 'videoLanguages' | 'theme' | 'notificationSettings'>
|
||||||
|
|
||||||
|
export class UserSettingsImporter extends AbstractUserImporter <UserSettingsExportJSON, UserSettingsExportJSON, SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: UserSettingsExportJSON) {
|
protected getImportObjects (json: UserSettingsExportJSON) {
|
||||||
return [ json ]
|
return [ json ]
|
||||||
|
@ -27,7 +31,6 @@ export class UserSettingsImporter extends AbstractUserImporter <UserSettingsExpo
|
||||||
|
|
||||||
protected sanitize (o: UserSettingsExportJSON) {
|
protected sanitize (o: UserSettingsExportJSON) {
|
||||||
if (!isUserNSFWPolicyValid(o.nsfwPolicy)) o.nsfwPolicy = undefined
|
if (!isUserNSFWPolicyValid(o.nsfwPolicy)) o.nsfwPolicy = undefined
|
||||||
|
|
||||||
if (!isUserAutoPlayVideoValid(o.autoPlayVideo)) o.autoPlayVideo = undefined
|
if (!isUserAutoPlayVideoValid(o.autoPlayVideo)) o.autoPlayVideo = undefined
|
||||||
if (!isUserAutoPlayNextVideoValid(o.autoPlayNextVideo)) o.autoPlayNextVideo = undefined
|
if (!isUserAutoPlayNextVideoValid(o.autoPlayNextVideo)) o.autoPlayNextVideo = undefined
|
||||||
if (!isUserAutoPlayNextVideoPlaylistValid(o.autoPlayNextVideoPlaylist)) o.autoPlayNextVideoPlaylist = undefined
|
if (!isUserAutoPlayNextVideoPlaylistValid(o.autoPlayNextVideoPlaylist)) o.autoPlayNextVideoPlaylist = undefined
|
||||||
|
@ -40,10 +43,20 @@ export class UserSettingsImporter extends AbstractUserImporter <UserSettingsExpo
|
||||||
if (!isUserNotificationSettingValid(o.notificationSettings[key])) (o.notificationSettings[key] as any) = undefined
|
if (!isUserNotificationSettingValid(o.notificationSettings[key])) (o.notificationSettings[key] as any) = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return o
|
return pick(o, [
|
||||||
|
'nsfwPolicy',
|
||||||
|
'autoPlayVideo',
|
||||||
|
'autoPlayNextVideo',
|
||||||
|
'autoPlayNextVideoPlaylist',
|
||||||
|
'p2pEnabled',
|
||||||
|
'videosHistoryEnabled',
|
||||||
|
'videoLanguages',
|
||||||
|
'theme',
|
||||||
|
'notificationSettings'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (userImportData: UserSettingsExportJSON) {
|
protected async importObject (userImportData: SanitizedObject) {
|
||||||
if (exists(userImportData.nsfwPolicy)) this.user.nsfwPolicy = userImportData.nsfwPolicy
|
if (exists(userImportData.nsfwPolicy)) this.user.nsfwPolicy = userImportData.nsfwPolicy
|
||||||
if (exists(userImportData.autoPlayVideo)) this.user.autoPlayVideo = userImportData.autoPlayVideo
|
if (exists(userImportData.autoPlayVideo)) this.user.autoPlayVideo = userImportData.autoPlayVideo
|
||||||
if (exists(userImportData.autoPlayNextVideo)) this.user.autoPlayNextVideo = userImportData.autoPlayNextVideo
|
if (exists(userImportData.autoPlayNextVideo)) this.user.autoPlayNextVideo = userImportData.autoPlayNextVideo
|
||||||
|
|
|
@ -27,16 +27,21 @@ import { isActorPreferredUsernameValid } from '@server/helpers/custom-validators
|
||||||
import { saveInTransactionWithRetries } from '@server/helpers/database-utils.js'
|
import { saveInTransactionWithRetries } from '@server/helpers/database-utils.js'
|
||||||
import { isArray } from '@server/helpers/custom-validators/misc.js'
|
import { isArray } from '@server/helpers/custom-validators/misc.js'
|
||||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
||||||
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylistsExportJSON, VideoPlaylistsExportJSON['videoPlaylists'][0]> {
|
type ImportObject = VideoPlaylistsExportJSON['videoPlaylists'][0]
|
||||||
|
type SanitizedObject = Pick<ImportObject, 'type' | 'displayName' | 'privacy' | 'elements' | 'description' | 'elements' | 'channel' |
|
||||||
|
'archiveFiles'>
|
||||||
|
|
||||||
|
export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylistsExportJSON, ImportObject, SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: VideoPlaylistsExportJSON) {
|
protected getImportObjects (json: VideoPlaylistsExportJSON) {
|
||||||
return json.videoPlaylists
|
return json.videoPlaylists
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sanitize (o: VideoPlaylistsExportJSON['videoPlaylists'][0]) {
|
protected sanitize (o: ImportObject) {
|
||||||
if (!isVideoPlaylistTypeValid(o.type)) return undefined
|
if (!isVideoPlaylistTypeValid(o.type)) return undefined
|
||||||
if (!isVideoPlaylistNameValid(o.displayName)) return undefined
|
if (!isVideoPlaylistNameValid(o.displayName)) return undefined
|
||||||
if (!isVideoPlaylistPrivacyValid(o.privacy)) return undefined
|
if (!isVideoPlaylistPrivacyValid(o.privacy)) return undefined
|
||||||
|
@ -53,10 +58,10 @@ export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylists
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
return o
|
return pick(o, [ 'type', 'displayName', 'privacy', 'elements', 'channel', 'description', 'archiveFiles' ])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (playlistImportData: VideoPlaylistsExportJSON['videoPlaylists'][0]) {
|
protected async importObject (playlistImportData: SanitizedObject) {
|
||||||
const existingPlaylist = await VideoPlaylistModel.loadRegularByAccountAndName(this.user.Account, playlistImportData.displayName)
|
const existingPlaylist = await VideoPlaylistModel.loadRegularByAccountAndName(this.user.Account, playlistImportData.displayName)
|
||||||
|
|
||||||
if (existingPlaylist) {
|
if (existingPlaylist) {
|
||||||
|
@ -77,7 +82,7 @@ export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylists
|
||||||
return { duplicate: false }
|
return { duplicate: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createPlaylist (playlistImportData: VideoPlaylistsExportJSON['videoPlaylists'][0]) {
|
private async createPlaylist (playlistImportData: SanitizedObject) {
|
||||||
let videoChannel: MChannelBannerAccountDefault
|
let videoChannel: MChannelBannerAccountDefault
|
||||||
|
|
||||||
if (playlistImportData.channel.name) {
|
if (playlistImportData.channel.name) {
|
||||||
|
@ -115,7 +120,7 @@ export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylists
|
||||||
return VideoPlaylistModel.loadWatchLaterOf(this.user.Account)
|
return VideoPlaylistModel.loadWatchLaterOf(this.user.Account)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createThumbnail (playlist: MVideoPlaylistThumbnail, playlistImportData: VideoPlaylistsExportJSON['videoPlaylists'][0]) {
|
private async createThumbnail (playlist: MVideoPlaylistThumbnail, playlistImportData: SanitizedObject) {
|
||||||
const thumbnailPath = this.getSafeArchivePathOrThrow(playlistImportData.archiveFiles.thumbnail)
|
const thumbnailPath = this.getSafeArchivePathOrThrow(playlistImportData.archiveFiles.thumbnail)
|
||||||
if (!thumbnailPath) return undefined
|
if (!thumbnailPath) return undefined
|
||||||
|
|
||||||
|
@ -130,7 +135,7 @@ export class VideoPlaylistsImporter extends AbstractUserImporter <VideoPlaylists
|
||||||
await playlist.setAndSaveThumbnail(thumbnail, undefined)
|
await playlist.setAndSaveThumbnail(thumbnail, undefined)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createElements (playlist: MVideoPlaylist, playlistImportData: VideoPlaylistsExportJSON['videoPlaylists'][0]) {
|
private async createElements (playlist: MVideoPlaylist, playlistImportData: SanitizedObject) {
|
||||||
const elementsToCreate: { videoId: number, startTimestamp: number, stopTimestamp: number }[] = []
|
const elementsToCreate: { videoId: number, startTimestamp: number, stopTimestamp: number }[] = []
|
||||||
|
|
||||||
for (const element of playlistImportData.elements.slice(0, USER_IMPORT.MAX_PLAYLIST_ELEMENTS)) {
|
for (const element of playlistImportData.elements.slice(0, USER_IMPORT.MAX_PLAYLIST_ELEMENTS)) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import {
|
||||||
isVideoOriginallyPublishedAtValid,
|
isVideoOriginallyPublishedAtValid,
|
||||||
isVideoPrivacyValid,
|
isVideoPrivacyValid,
|
||||||
isVideoReplayPrivacyValid,
|
isVideoReplayPrivacyValid,
|
||||||
|
isVideoSourceFilenameValid,
|
||||||
isVideoSupportValid,
|
isVideoSupportValid,
|
||||||
isVideoTagValid
|
isVideoTagValid
|
||||||
} from '@server/helpers/custom-validators/videos.js'
|
} from '@server/helpers/custom-validators/videos.js'
|
||||||
|
@ -50,13 +51,18 @@ import { isLocalVideoFileAccepted } from '@server/lib/moderation.js'
|
||||||
|
|
||||||
const lTags = loggerTagsFactory('user-import')
|
const lTags = loggerTagsFactory('user-import')
|
||||||
|
|
||||||
export class VideosImporter extends AbstractUserImporter <VideoExportJSON, VideoExportJSON['videos'][0]> {
|
type ImportObject = VideoExportJSON['videos'][0]
|
||||||
|
type SanitizedObject = Pick<ImportObject, 'name' | 'duration' | 'channel' | 'privacy' | 'archiveFiles' | 'captions' | 'category' |
|
||||||
|
'licence' | 'language' | 'description' | 'support' | 'nsfw' | 'isLive' | 'commentsEnabled' | 'downloadEnabled' | 'waitTranscoding' |
|
||||||
|
'originallyPublishedAt' | 'tags' | 'live' | 'passwords' | 'source'>
|
||||||
|
|
||||||
|
export class VideosImporter extends AbstractUserImporter <VideoExportJSON, ImportObject, SanitizedObject> {
|
||||||
|
|
||||||
protected getImportObjects (json: VideoExportJSON) {
|
protected getImportObjects (json: VideoExportJSON) {
|
||||||
return json.videos
|
return json.videos
|
||||||
}
|
}
|
||||||
|
|
||||||
protected sanitize (o: VideoExportJSON['videos'][0]) {
|
protected sanitize (o: ImportObject) {
|
||||||
if (!isVideoNameValid(o.name)) return undefined
|
if (!isVideoNameValid(o.name)) return undefined
|
||||||
if (!isVideoDurationValid(o.duration + '')) return undefined
|
if (!isVideoDurationValid(o.duration + '')) return undefined
|
||||||
if (!isVideoChannelUsernameValid(o.channel?.name)) return undefined
|
if (!isVideoChannelUsernameValid(o.channel?.name)) return undefined
|
||||||
|
@ -75,6 +81,8 @@ export class VideosImporter extends AbstractUserImporter <VideoExportJSON, Video
|
||||||
if (!isBooleanValid(o.downloadEnabled)) o.downloadEnabled = CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED
|
if (!isBooleanValid(o.downloadEnabled)) o.downloadEnabled = CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED
|
||||||
if (!isBooleanValid(o.waitTranscoding)) o.waitTranscoding = true
|
if (!isBooleanValid(o.waitTranscoding)) o.waitTranscoding = true
|
||||||
|
|
||||||
|
if (!isVideoSourceFilenameValid(o.source?.filename)) o.source = undefined
|
||||||
|
|
||||||
if (!isVideoOriginallyPublishedAtValid(o.originallyPublishedAt)) o.originallyPublishedAt = null
|
if (!isVideoOriginallyPublishedAtValid(o.originallyPublishedAt)) o.originallyPublishedAt = null
|
||||||
|
|
||||||
if (!isArray(o.tags)) o.tags = []
|
if (!isArray(o.tags)) o.tags = []
|
||||||
|
@ -102,10 +110,32 @@ export class VideosImporter extends AbstractUserImporter <VideoExportJSON, Video
|
||||||
if (o.passwords.some(p => !isPasswordValid(p))) return undefined
|
if (o.passwords.some(p => !isPasswordValid(p))) return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return o
|
return pick(o, [
|
||||||
|
'name',
|
||||||
|
'duration',
|
||||||
|
'channel',
|
||||||
|
'privacy',
|
||||||
|
'archiveFiles',
|
||||||
|
'category',
|
||||||
|
'licence',
|
||||||
|
'language',
|
||||||
|
'description',
|
||||||
|
'support',
|
||||||
|
'nsfw',
|
||||||
|
'isLive',
|
||||||
|
'commentsEnabled',
|
||||||
|
'downloadEnabled',
|
||||||
|
'waitTranscoding',
|
||||||
|
'originallyPublishedAt',
|
||||||
|
'tags',
|
||||||
|
'captions',
|
||||||
|
'live',
|
||||||
|
'passwords',
|
||||||
|
'source'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async importObject (videoImportData: VideoExportJSON['videos'][0]) {
|
protected async importObject (videoImportData: SanitizedObject) {
|
||||||
const videoFilePath = this.getSafeArchivePathOrThrow(videoImportData.archiveFiles.videoFile)
|
const videoFilePath = this.getSafeArchivePathOrThrow(videoImportData.archiveFiles.videoFile)
|
||||||
const videoSize = await getFileSize(videoFilePath)
|
const videoSize = await getFileSize(videoFilePath)
|
||||||
|
|
||||||
|
@ -247,7 +277,7 @@ export class VideosImporter extends AbstractUserImporter <VideoExportJSON, Video
|
||||||
return { duplicate: false }
|
return { duplicate: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async importCaptions (video: MVideoFullLight, videoImportData: VideoExportJSON['videos'][0]) {
|
private async importCaptions (video: MVideoFullLight, videoImportData: SanitizedObject) {
|
||||||
const captionPaths: string[] = []
|
const captionPaths: string[] = []
|
||||||
|
|
||||||
for (const captionImport of videoImportData.captions) {
|
for (const captionImport of videoImportData.captions) {
|
||||||
|
@ -284,7 +314,7 @@ export class VideosImporter extends AbstractUserImporter <VideoExportJSON, Video
|
||||||
videoFilePath: string
|
videoFilePath: string
|
||||||
size: number
|
size: number
|
||||||
channel: MChannelId
|
channel: MChannelId
|
||||||
videoImportData: VideoExportJSON['videos'][0]
|
videoImportData: SanitizedObject
|
||||||
}) {
|
}) {
|
||||||
const { videoFilePath, size, videoImportData, channel } = options
|
const { videoFilePath, size, videoImportData, channel } = options
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import {
|
||||||
isVideoNameValid,
|
isVideoNameValid,
|
||||||
isVideoOriginallyPublishedAtValid,
|
isVideoOriginallyPublishedAtValid,
|
||||||
isVideoPrivacyValid,
|
isVideoPrivacyValid,
|
||||||
|
isVideoSourceFilenameValid,
|
||||||
isVideoSupportValid
|
isVideoSupportValid
|
||||||
} from '../../../helpers/custom-validators/videos.js'
|
} from '../../../helpers/custom-validators/videos.js'
|
||||||
import { cleanUpReqFiles } from '../../../helpers/express-utils.js'
|
import { cleanUpReqFiles } from '../../../helpers/express-utils.js'
|
||||||
|
@ -133,7 +134,7 @@ const videosAddResumableValidator = [
|
||||||
*/
|
*/
|
||||||
const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
|
const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
|
||||||
body('filename')
|
body('filename')
|
||||||
.exists(),
|
.custom(isVideoSourceFilenameValid),
|
||||||
body('name')
|
body('name')
|
||||||
.trim()
|
.trim()
|
||||||
.custom(isVideoNameValid).withMessage(
|
.custom(isVideoNameValid).withMessage(
|
||||||
|
|
Loading…
Reference in a new issue