expliciting type checks and predicates (server only)
This commit is contained in:
parent
5f7021c33d
commit
c1e791bad0
|
@ -67,8 +67,8 @@ async function activityPubCollectionPagination (url: string, handler: ActivityPu
|
||||||
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
|
||||||
const result = await handler(start, count)
|
const result = await handler(start, count)
|
||||||
|
|
||||||
let next: string
|
let next: string | undefined
|
||||||
let prev: string
|
let prev: string | undefined
|
||||||
|
|
||||||
// Assert page is a number
|
// Assert page is a number
|
||||||
page = parseInt(page, 10)
|
page = parseInt(page, 10)
|
||||||
|
|
|
@ -42,7 +42,7 @@ function root () {
|
||||||
const paths = [ __dirname, '..', '..' ]
|
const paths = [ __dirname, '..', '..' ]
|
||||||
|
|
||||||
// We are under /dist directory
|
// We are under /dist directory
|
||||||
if (process.mainModule.filename.endsWith('.ts') === false) {
|
if (process.mainModule && process.mainModule.filename.endsWith('.ts') === false) {
|
||||||
paths.push('..')
|
paths.push('..')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ const renamePromise = promisify2WithVoid<string, string>(rename)
|
||||||
const writeFilePromise = promisify2WithVoid<string, any>(writeFile)
|
const writeFilePromise = promisify2WithVoid<string, any>(writeFile)
|
||||||
const readdirPromise = promisify1<string, string[]>(readdir)
|
const readdirPromise = promisify1<string, string[]>(readdir)
|
||||||
const mkdirpPromise = promisify1<string, string>(mkdirp)
|
const mkdirpPromise = promisify1<string, string>(mkdirp)
|
||||||
|
// we cannot modify the Promise types, so we should make the promisify instance check mkdirp
|
||||||
const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
|
const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
|
||||||
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
|
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
|
||||||
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
|
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
|
||||||
|
|
|
@ -51,7 +51,7 @@ function isFileValid (
|
||||||
files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
|
files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
|
||||||
mimeTypeRegex: string,
|
mimeTypeRegex: string,
|
||||||
field: string,
|
field: string,
|
||||||
maxSize: number,
|
maxSize: number | null,
|
||||||
optional = false
|
optional = false
|
||||||
) {
|
) {
|
||||||
// Should have files
|
// Should have files
|
||||||
|
@ -69,7 +69,7 @@ function isFileValid (
|
||||||
if (!file || !file.originalname) return false
|
if (!file || !file.originalname) return false
|
||||||
|
|
||||||
// Check size
|
// Check size
|
||||||
if (maxSize && file.size > maxSize) return false
|
if ((maxSize !== null) && file.size > maxSize) return false
|
||||||
|
|
||||||
return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype)
|
return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype)
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isVideoExist (id: string, res: Response) {
|
async function isVideoExist (id: string, res: Response) {
|
||||||
let video: VideoModel
|
let video: VideoModel | null
|
||||||
|
|
||||||
if (validator.isInt(id)) {
|
if (validator.isInt(id)) {
|
||||||
video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
|
video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
|
||||||
|
@ -158,7 +158,7 @@ async function isVideoExist (id: string, res: Response) {
|
||||||
video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
|
video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!video) {
|
if (video && video !== null) {
|
||||||
res.status(404)
|
res.status(404)
|
||||||
.json({ error: 'Video not found' })
|
.json({ error: 'Video not found' })
|
||||||
.end()
|
.end()
|
||||||
|
@ -173,7 +173,7 @@ async function isVideoExist (id: string, res: Response) {
|
||||||
async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
|
async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
|
||||||
if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
|
if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
|
||||||
const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
|
const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
|
||||||
if (!videoChannel) {
|
if (videoChannel && videoChannel !== null) {
|
||||||
res.status(400)
|
res.status(400)
|
||||||
.json({ error: 'Unknown video video channel on this instance.' })
|
.json({ error: 'Unknown video video channel on this instance.' })
|
||||||
.end()
|
.end()
|
||||||
|
@ -186,7 +186,7 @@ async function isVideoChannelOfAccountExist (channelId: number, user: UserModel,
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
|
const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
|
||||||
if (!videoChannel) {
|
if (videoChannel && videoChannel !== null) {
|
||||||
res.status(400)
|
res.status(400)
|
||||||
.json({ error: 'Unknown video video channel for this account.' })
|
.json({ error: 'Unknown video video channel for this account.' })
|
||||||
.end()
|
.end()
|
||||||
|
|
|
@ -64,7 +64,7 @@ function createReqFiles (
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const fields = []
|
let fields: { name: string, maxCount: number }[] = []
|
||||||
for (const fieldName of fieldNames) {
|
for (const fieldName of fieldNames) {
|
||||||
fields.push({
|
fields.push({
|
||||||
name: fieldName,
|
name: fieldName,
|
||||||
|
|
|
@ -80,7 +80,8 @@ const logger = winston.createLogger({
|
||||||
function bunyanLogFactory (level: string) {
|
function bunyanLogFactory (level: string) {
|
||||||
return function () {
|
return function () {
|
||||||
let meta = null
|
let meta = null
|
||||||
let args = [].concat(arguments)
|
let args: any[] = []
|
||||||
|
args.concat(arguments)
|
||||||
|
|
||||||
if (arguments[ 0 ] instanceof Error) {
|
if (arguments[ 0 ] instanceof Error) {
|
||||||
meta = arguments[ 0 ].toString()
|
meta = arguments[ 0 ].toString()
|
||||||
|
|
|
@ -52,7 +52,7 @@ async function isSignupAllowed () {
|
||||||
function isSignupAllowedForCurrentIP (ip: string) {
|
function isSignupAllowedForCurrentIP (ip: string) {
|
||||||
const addr = ipaddr.parse(ip)
|
const addr = ipaddr.parse(ip)
|
||||||
let excludeList = [ 'blacklist' ]
|
let excludeList = [ 'blacklist' ]
|
||||||
let matched: string
|
let matched = ''
|
||||||
|
|
||||||
// if there is a valid, non-empty whitelist, we exclude all unknown adresses too
|
// if there is a valid, non-empty whitelist, we exclude all unknown adresses too
|
||||||
if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
|
if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
|
||||||
|
@ -144,6 +144,7 @@ let serverActor: ActorModel
|
||||||
async function getServerActor () {
|
async function getServerActor () {
|
||||||
if (serverActor === undefined) {
|
if (serverActor === undefined) {
|
||||||
const application = await ApplicationModel.load()
|
const application = await ApplicationModel.load()
|
||||||
|
if (!application) throw Error('Could not application.')
|
||||||
serverActor = application.Account.Actor
|
serverActor = application.Account.Actor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ function createDirectoriesIfNotExist () {
|
||||||
const cacheDirectories = Object.keys(CACHE)
|
const cacheDirectories = Object.keys(CACHE)
|
||||||
.map(k => CACHE[k].DIRECTORY)
|
.map(k => CACHE[k].DIRECTORY)
|
||||||
|
|
||||||
const tasks = []
|
const tasks: Promise<string>[] = []
|
||||||
for (const key of Object.keys(storage)) {
|
for (const key of Object.keys(storage)) {
|
||||||
const dir = storage[key]
|
const dir = storage[key]
|
||||||
tasks.push(mkdirpPromise(dir))
|
tasks.push(mkdirpPromise(dir))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -12,7 +13,7 @@ function up (utils: {
|
||||||
type: Sequelize.STRING(400),
|
type: Sequelize.STRING(400),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: ''
|
defaultValue: ''
|
||||||
}
|
} as Migration.String
|
||||||
|
|
||||||
return q.addColumn('Pods', 'email', data)
|
return q.addColumn('Pods', 'email', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -12,7 +13,7 @@ function up (utils: {
|
||||||
type: Sequelize.STRING(400),
|
type: Sequelize.STRING(400),
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: ''
|
defaultValue: ''
|
||||||
}
|
} as Migration.String
|
||||||
return q.addColumn('Users', 'email', data)
|
return q.addColumn('Users', 'email', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')'
|
const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')'
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -12,7 +13,7 @@ function up (utils: {
|
||||||
type: Sequelize.INTEGER,
|
type: Sequelize.INTEGER,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 0
|
defaultValue: 0
|
||||||
}
|
} as Migration.Integer
|
||||||
|
|
||||||
return q.addColumn('Videos', 'category', data)
|
return q.addColumn('Videos', 'category', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -12,7 +13,7 @@ function up (utils: {
|
||||||
type: Sequelize.INTEGER,
|
type: Sequelize.INTEGER,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: 0
|
defaultValue: 0
|
||||||
}
|
} as Migration.Integer
|
||||||
|
|
||||||
return q.addColumn('Videos', 'licence', data)
|
return q.addColumn('Videos', 'licence', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -12,7 +13,7 @@ function up (utils: {
|
||||||
type: Sequelize.BOOLEAN,
|
type: Sequelize.BOOLEAN,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: false
|
defaultValue: false
|
||||||
}
|
} as Migration.Boolean
|
||||||
|
|
||||||
return q.addColumn('Videos', 'nsfw', data)
|
return q.addColumn('Videos', 'nsfw', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -24,7 +24,7 @@ function up (utils: {
|
||||||
return utils.sequelize.query(query)
|
return utils.sequelize.query(query)
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dataUUID.defaultValue = null
|
dataUUID.defaultValue = null // FIXME:default value cannot be null if string
|
||||||
|
|
||||||
return q.changeColumn('Videos', 'uuid', dataUUID)
|
return q.changeColumn('Videos', 'uuid', dataUUID)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
import * as Promise from 'bluebird'
|
import * as Promise from 'bluebird'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
function up (utils: {
|
function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -13,7 +14,7 @@ function up (utils: {
|
||||||
type: Sequelize.BIGINT,
|
type: Sequelize.BIGINT,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: -1
|
defaultValue: -1
|
||||||
}
|
} as Migration.BigInteger
|
||||||
|
|
||||||
return q.addColumn('Users', 'videoQuota', data)
|
return q.addColumn('Users', 'videoQuota', data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import * as Sequelize from 'sequelize'
|
import * as Sequelize from 'sequelize'
|
||||||
|
import { Migration } from '../../models/migrations'
|
||||||
|
|
||||||
async function up (utils: {
|
async function up (utils: {
|
||||||
transaction: Sequelize.Transaction,
|
transaction: Sequelize.Transaction,
|
||||||
|
@ -9,7 +10,7 @@ async function up (utils: {
|
||||||
type: Sequelize.BOOLEAN,
|
type: Sequelize.BOOLEAN,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
defaultValue: true
|
defaultValue: true
|
||||||
}
|
} as Migration.Boolean
|
||||||
await utils.queryInterface.addColumn('video', 'commentsEnabled', data)
|
await utils.queryInterface.addColumn('video', 'commentsEnabled', data)
|
||||||
|
|
||||||
data.defaultValue = null
|
data.defaultValue = null
|
||||||
|
|
|
@ -2,6 +2,7 @@ import * as Sequelize from 'sequelize'
|
||||||
import { createClient } from 'redis'
|
import { createClient } from 'redis'
|
||||||
import { CONFIG } from '../constants'
|
import { CONFIG } from '../constants'
|
||||||
import { JobQueue } from '../../lib/job-queue'
|
import { JobQueue } from '../../lib/job-queue'
|
||||||
|
import { Redis } from '../../lib/redis'
|
||||||
import { initDatabaseModels } from '../database'
|
import { initDatabaseModels } from '../database'
|
||||||
|
|
||||||
async function up (utils: {
|
async function up (utils: {
|
||||||
|
@ -12,11 +13,7 @@ async function up (utils: {
|
||||||
await initDatabaseModels(false)
|
await initDatabaseModels(false)
|
||||||
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
const client = createClient({
|
const client = createClient(Redis.getRedisClient())
|
||||||
host: CONFIG.REDIS.HOSTNAME,
|
|
||||||
port: CONFIG.REDIS.PORT,
|
|
||||||
db: CONFIG.REDIS.DB
|
|
||||||
})
|
|
||||||
|
|
||||||
const jobsPrefix = 'q-' + CONFIG.WEBSERVER.HOST
|
const jobsPrefix = 'q-' + CONFIG.WEBSERVER.HOST
|
||||||
|
|
||||||
|
@ -36,7 +33,7 @@ async function up (utils: {
|
||||||
return res({ type: job.type, payload: parsedData })
|
return res({ type: job.type, payload: parsedData })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Cannot parse data %s.', job.data)
|
console.error('Cannot parse data %s.', job.data)
|
||||||
return res(null)
|
return res(undefined)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,7 +11,7 @@ async function migrate () {
|
||||||
// The installer will do that
|
// The installer will do that
|
||||||
if (tables.length === 0) return
|
if (tables.length === 0) return
|
||||||
|
|
||||||
let actualVersion: number = null
|
let actualVersion: number | null = null
|
||||||
|
|
||||||
const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"')
|
const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"')
|
||||||
if (rows && rows[0] && rows[0].migrationVersion) {
|
if (rows && rows[0] && rows[0].migrationVersion) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ function getVideoCommentAudience (
|
||||||
isOrigin = false
|
isOrigin = false
|
||||||
) {
|
) {
|
||||||
const to = [ ACTIVITY_PUB.PUBLIC ]
|
const to = [ ACTIVITY_PUB.PUBLIC ]
|
||||||
const cc = []
|
const cc: string[] = []
|
||||||
|
|
||||||
// Owner of the video we comment
|
// Owner of the video we comment
|
||||||
if (isOrigin === false) {
|
if (isOrigin === false) {
|
||||||
|
@ -60,8 +60,8 @@ function getAudience (actorSender: ActorModel, isPublic = true) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildAudience (followerUrls: string[], isPublic = true) {
|
function buildAudience (followerUrls: string[], isPublic = true) {
|
||||||
let to = []
|
let to: string[] = []
|
||||||
let cc = []
|
let cc: string[] = []
|
||||||
|
|
||||||
if (isPublic) {
|
if (isPublic) {
|
||||||
to = [ ACTIVITY_PUB.PUBLIC ]
|
to = [ ACTIVITY_PUB.PUBLIC ]
|
||||||
|
|
|
@ -88,17 +88,17 @@ async function videoActivityObjectToDBAttributes (
|
||||||
const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
|
const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
|
||||||
const duration = videoObject.duration.replace(/[^\d]+/, '')
|
const duration = videoObject.duration.replace(/[^\d]+/, '')
|
||||||
|
|
||||||
let language: string = null
|
let language: string | undefined
|
||||||
if (videoObject.language) {
|
if (videoObject.language) {
|
||||||
language = videoObject.language.identifier
|
language = videoObject.language.identifier
|
||||||
}
|
}
|
||||||
|
|
||||||
let category: number = null
|
let category: number | undefined
|
||||||
if (videoObject.category) {
|
if (videoObject.category) {
|
||||||
category = parseInt(videoObject.category.identifier, 10)
|
category = parseInt(videoObject.category.identifier, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
let licence: number = null
|
let licence: number | undefined
|
||||||
if (videoObject.licence) {
|
if (videoObject.licence) {
|
||||||
licence = parseInt(videoObject.licence.identifier, 10)
|
licence = parseInt(videoObject.licence.identifier, 10)
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
|
||||||
throw new Error('Cannot find video files for ' + videoCreated.url)
|
throw new Error('Cannot find video files for ' + videoCreated.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
const attributes = []
|
const attributes: VideoFileModel[] = []
|
||||||
for (const fileUrl of fileUrls) {
|
for (const fileUrl of fileUrls) {
|
||||||
// Fetch associated magnet uri
|
// Fetch associated magnet uri
|
||||||
const magnet = videoObject.url.find(u => {
|
const magnet = videoObject.url.find(u => {
|
||||||
|
@ -153,7 +153,11 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
|
||||||
if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href)
|
if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href)
|
||||||
|
|
||||||
const parsed = magnetUtil.decode(magnet.href)
|
const parsed = magnetUtil.decode(magnet.href)
|
||||||
if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.href)
|
if (!parsed ||
|
||||||
|
(parsed.infoHash &&
|
||||||
|
(isVideoFileInfoHashValid(parsed.infoHash) === false))) {
|
||||||
|
throw new Error('Cannot parse magnet URI ' + magnet.href)
|
||||||
|
}
|
||||||
|
|
||||||
const attribute = {
|
const attribute = {
|
||||||
extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ],
|
extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ],
|
||||||
|
@ -161,7 +165,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
|
||||||
resolution: fileUrl.width,
|
resolution: fileUrl.width,
|
||||||
size: fileUrl.size,
|
size: fileUrl.size,
|
||||||
videoId: videoCreated.id
|
videoId: videoCreated.id
|
||||||
}
|
} as VideoFileModel
|
||||||
attributes.push(attribute)
|
attributes.push(attribute)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,9 +91,10 @@ class Emailer {
|
||||||
|
|
||||||
async addVideoAbuseReport (videoId: number) {
|
async addVideoAbuseReport (videoId: number) {
|
||||||
const video = await VideoModel.load(videoId)
|
const video = await VideoModel.load(videoId)
|
||||||
|
if (!video) throw new Error('Unknown Video id during Abuse report.')
|
||||||
|
|
||||||
const text = `Hi,\n\n` +
|
const text = `Hi,\n\n` +
|
||||||
`Your instance received an abuse for video the following video ${video.url}\n\n` +
|
`Your instance received an abuse for the following video ${video.url}\n\n` +
|
||||||
`Cheers,\n` +
|
`Cheers,\n` +
|
||||||
`PeerTube.`
|
`PeerTube.`
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ async function computeBody (payload: { body: any, signatureActorId?: number }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildSignedRequestOptions (payload: { signatureActorId?: number }) {
|
async function buildSignedRequestOptions (payload: { signatureActorId?: number }) {
|
||||||
let actor: ActorModel
|
let actor: ActorModel | null
|
||||||
if (payload.signatureActorId) {
|
if (payload.signatureActorId) {
|
||||||
actor = await ActorModel.load(payload.signatureActorId)
|
actor = await ActorModel.load(payload.signatureActorId)
|
||||||
if (!actor) throw new Error('Unknown signature actor id.')
|
if (!actor) throw new Error('Unknown signature actor id.')
|
||||||
|
|
|
@ -28,7 +28,7 @@ async function processVideoFileImport (job: Bull.Job) {
|
||||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||||
// No video, maybe deleted?
|
// No video, maybe deleted?
|
||||||
if (!video) {
|
if (!video) {
|
||||||
logger.info('Do not process job %d, video does not exist.', job.id, { videoUUID: video.uuid })
|
logger.info('Do not process job %d, video does not exist.', job.id)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ async function processVideoFile (job: Bull.Job) {
|
||||||
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
|
||||||
// No video, maybe deleted?
|
// No video, maybe deleted?
|
||||||
if (!video) {
|
if (!video) {
|
||||||
logger.info('Do not process job %d, video does not exist.', job.id, { videoUUID: video.uuid })
|
logger.info('Do not process job %d, video does not exist.', job.id)
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transcoding in other resolution
|
// Transcoding in other resolution
|
||||||
if (payload.resolution) {
|
if (payload.resolution) {
|
||||||
await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode)
|
await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode || false)
|
||||||
|
|
||||||
await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video)
|
await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -87,7 +87,7 @@ class JobQueue {
|
||||||
const queue = this.queues[obj.type]
|
const queue = this.queues[obj.type]
|
||||||
if (queue === undefined) {
|
if (queue === undefined) {
|
||||||
logger.error('Unknown queue %s: cannot create job.', obj.type)
|
logger.error('Unknown queue %s: cannot create job.', obj.type)
|
||||||
return
|
throw Error('Unknown queue, cannot create job')
|
||||||
}
|
}
|
||||||
|
|
||||||
const jobArgs: Bull.JobOptions = {
|
const jobArgs: Bull.JobOptions = {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { CONFIG, USER_PASSWORD_RESET_LIFETIME, VIDEO_VIEW_LIFETIME } from '../in
|
||||||
|
|
||||||
type CachedRoute = {
|
type CachedRoute = {
|
||||||
body: string,
|
body: string,
|
||||||
contentType?: string
|
contentType: string
|
||||||
statusCode?: string
|
statusCode: string
|
||||||
}
|
}
|
||||||
|
|
||||||
class Redis {
|
class Redis {
|
||||||
|
@ -75,11 +75,12 @@ class Redis {
|
||||||
}
|
}
|
||||||
|
|
||||||
setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) {
|
setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) {
|
||||||
const cached: CachedRoute = {
|
const cached: CachedRoute = Object.assign({}, {
|
||||||
body: body.toString(),
|
body: body.toString()
|
||||||
contentType,
|
},
|
||||||
statusCode: statusCode.toString()
|
(contentType) ? { contentType } : null,
|
||||||
}
|
(statusCode) ? { statusCode: statusCode.toString() } : null
|
||||||
|
)
|
||||||
|
|
||||||
return this.setObject(this.buildCachedRouteKey(req), cached, lifetime)
|
return this.setObject(this.buildCachedRouteKey(req), cached, lifetime)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { UserModel } from '../models/account/user'
|
||||||
import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub'
|
import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub'
|
||||||
import { createVideoChannel } from './video-channel'
|
import { createVideoChannel } from './video-channel'
|
||||||
import { VideoChannelModel } from '../models/video/video-channel'
|
import { VideoChannelModel } from '../models/video/video-channel'
|
||||||
|
import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
|
||||||
|
|
||||||
async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) {
|
async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) {
|
||||||
const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
|
const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
|
||||||
|
@ -34,9 +35,9 @@ async function createUserAccountAndChannel (userToCreate: UserModel, validateUse
|
||||||
|
|
||||||
async function createLocalAccountWithoutKeys (
|
async function createLocalAccountWithoutKeys (
|
||||||
name: string,
|
name: string,
|
||||||
userId: number,
|
userId: number | null,
|
||||||
applicationId: number,
|
applicationId: number | null,
|
||||||
t: Sequelize.Transaction,
|
t: Sequelize.Transaction | undefined,
|
||||||
type: ActivityPubActorType= 'Person'
|
type: ActivityPubActorType= 'Person'
|
||||||
) {
|
) {
|
||||||
const url = getAccountActivityPubUrl(name)
|
const url = getAccountActivityPubUrl(name)
|
||||||
|
@ -49,7 +50,7 @@ async function createLocalAccountWithoutKeys (
|
||||||
userId,
|
userId,
|
||||||
applicationId,
|
applicationId,
|
||||||
actorId: actorInstanceCreated.id
|
actorId: actorInstanceCreated.id
|
||||||
})
|
} as FilteredModelAttributes<AccountModel>)
|
||||||
|
|
||||||
const accountInstanceCreated = await accountInstance.save({ transaction: t })
|
const accountInstanceCreated = await accountInstance.save({ transaction: t })
|
||||||
accountInstanceCreated.Actor = actorInstanceCreated
|
accountInstanceCreated.Actor = actorInstanceCreated
|
||||||
|
|
|
@ -9,14 +9,14 @@ import { sendCreateVideoComment } from './activitypub/send'
|
||||||
|
|
||||||
async function createVideoComment (obj: {
|
async function createVideoComment (obj: {
|
||||||
text: string,
|
text: string,
|
||||||
inReplyToComment: VideoCommentModel,
|
inReplyToComment: VideoCommentModel | null,
|
||||||
video: VideoModel
|
video: VideoModel
|
||||||
account: AccountModel
|
account: AccountModel
|
||||||
}, t: Sequelize.Transaction) {
|
}, t: Sequelize.Transaction) {
|
||||||
let originCommentId: number = null
|
let originCommentId: number | null = null
|
||||||
let inReplyToCommentId: number = null
|
let inReplyToCommentId: number | null = null
|
||||||
|
|
||||||
if (obj.inReplyToComment) {
|
if (obj.inReplyToComment && obj.inReplyToComment !== null) {
|
||||||
originCommentId = obj.inReplyToComment.originCommentId || obj.inReplyToComment.id
|
originCommentId = obj.inReplyToComment.originCommentId || obj.inReplyToComment.id
|
||||||
inReplyToCommentId = obj.inReplyToComment.id
|
inReplyToCommentId = obj.inReplyToComment.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ function setDefaultSearchSort (req: express.Request, res: express.Response, next
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
let newSort: SortType = { sortModel: undefined, sortValue: undefined }
|
let newSort: SortType = { sortModel: undefined, sortValue: '' }
|
||||||
|
|
||||||
if (!req.query.sort) req.query.sort = '-createdAt'
|
if (!req.query.sort) req.query.sort = '-createdAt'
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
|
||||||
if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved)
|
if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved)
|
||||||
}
|
}
|
||||||
|
|
||||||
static updateActorFollowsScore (goodInboxes: string[], badInboxes: string[], t: Sequelize.Transaction) {
|
static updateActorFollowsScore (goodInboxes: string[], badInboxes: string[], t: Sequelize.Transaction | undefined) {
|
||||||
if (goodInboxes.length === 0 && badInboxes.length === 0) return
|
if (goodInboxes.length === 0 && badInboxes.length === 0) return
|
||||||
|
|
||||||
logger.info('Updating %d good actor follows and %d bad actor follows scores.', goodInboxes.length, badInboxes.length)
|
logger.info('Updating %d good actor follows and %d bad actor follows scores.', goodInboxes.length, badInboxes.length)
|
||||||
|
@ -344,7 +344,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static incrementScores (inboxUrls: string[], value: number, t: Sequelize.Transaction) {
|
private static incrementScores (inboxUrls: string[], value: number, t: Sequelize.Transaction | undefined) {
|
||||||
const inboxUrlsString = inboxUrls.map(url => `'${url}'`).join(',')
|
const inboxUrlsString = inboxUrls.map(url => `'${url}'`).join(',')
|
||||||
|
|
||||||
const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` +
|
const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` +
|
||||||
|
@ -354,10 +354,10 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
|
||||||
'WHERE "actor"."inboxUrl" IN (' + inboxUrlsString + ') OR "actor"."sharedInboxUrl" IN (' + inboxUrlsString + ')' +
|
'WHERE "actor"."inboxUrl" IN (' + inboxUrlsString + ') OR "actor"."sharedInboxUrl" IN (' + inboxUrlsString + ')' +
|
||||||
')'
|
')'
|
||||||
|
|
||||||
const options = {
|
const options = t ? {
|
||||||
type: Sequelize.QueryTypes.BULKUPDATE,
|
type: Sequelize.QueryTypes.BULKUPDATE,
|
||||||
transaction: t
|
transaction: t
|
||||||
}
|
} : undefined
|
||||||
|
|
||||||
return ActorFollowModel.sequelize.query(query, options)
|
return ActorFollowModel.sequelize.query(query, options)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Sequelize from 'sequelize'
|
||||||
|
|
||||||
|
declare namespace Migration {
|
||||||
|
interface Boolean extends Sequelize.DefineAttributeColumnOptions {
|
||||||
|
defaultValue: boolean | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface String extends Sequelize.DefineAttributeColumnOptions {
|
||||||
|
defaultValue: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Integer extends Sequelize.DefineAttributeColumnOptions {
|
||||||
|
defaultValue: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BigInteger extends Sequelize.DefineAttributeColumnOptions {
|
||||||
|
defaultValue: Sequelize.DataTypeBigInt | number | null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Migration
|
||||||
|
}
|
|
@ -154,9 +154,12 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
|
||||||
return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT)
|
return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT)
|
||||||
.findOne(query)
|
.findOne(query)
|
||||||
.then(token => {
|
.then(token => {
|
||||||
token['user'] = token.User
|
if (token) {
|
||||||
|
token['user'] = token.User
|
||||||
return token
|
return token
|
||||||
|
} else {
|
||||||
|
return new OAuthTokenModel()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
||||||
as: 'InReplyToVideoComment',
|
as: 'InReplyToVideoComment',
|
||||||
onDelete: 'CASCADE'
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
InReplyToVideoComment: VideoCommentModel
|
InReplyToVideoComment: VideoCommentModel | null
|
||||||
|
|
||||||
@ForeignKey(() => VideoModel)
|
@ForeignKey(() => VideoModel)
|
||||||
@Column
|
@Column
|
||||||
|
@ -417,7 +417,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
||||||
toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject {
|
toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject {
|
||||||
let inReplyTo: string
|
let inReplyTo: string
|
||||||
// New thread, so in AS we reply to the video
|
// New thread, so in AS we reply to the video
|
||||||
if (this.inReplyToCommentId === null) {
|
if ((this.inReplyToCommentId !== null) || (this.InReplyToVideoComment !== null)) {
|
||||||
inReplyTo = this.Video.url
|
inReplyTo = this.Video.url
|
||||||
} else {
|
} else {
|
||||||
inReplyTo = this.InReplyToVideoComment.url
|
inReplyTo = this.InReplyToVideoComment.url
|
||||||
|
|
|
@ -55,5 +55,8 @@ export {
|
||||||
login,
|
login,
|
||||||
serverLogin,
|
serverLogin,
|
||||||
userLogin,
|
userLogin,
|
||||||
setAccessTokensToServers
|
setAccessTokensToServers,
|
||||||
|
Server,
|
||||||
|
Client,
|
||||||
|
User
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ import * as program from 'commander'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getClient,
|
getClient,
|
||||||
serverLogin
|
serverLogin,
|
||||||
|
Server,
|
||||||
|
Client,
|
||||||
|
User
|
||||||
} from '../tests/utils/index'
|
} from '../tests/utils/index'
|
||||||
|
|
||||||
program
|
program
|
||||||
|
@ -19,22 +22,19 @@ if (
|
||||||
throw new Error('All arguments are required.')
|
throw new Error('All arguments are required.')
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = {
|
|
||||||
url: program['url'],
|
|
||||||
user: {
|
|
||||||
username: program['username'],
|
|
||||||
password: program['password']
|
|
||||||
},
|
|
||||||
client: {
|
|
||||||
id: null,
|
|
||||||
secret: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getClient(program.url)
|
getClient(program.url)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
server.client.id = res.body.client_id
|
const server = {
|
||||||
server.client.secret = res.body.client_secret
|
url: program['url'],
|
||||||
|
user: {
|
||||||
|
username: program['username'],
|
||||||
|
password: program['password']
|
||||||
|
} as User,
|
||||||
|
client: {
|
||||||
|
id: res.body.client_id as string,
|
||||||
|
secret: res.body.client_secret as string
|
||||||
|
} as Client
|
||||||
|
} as Server
|
||||||
|
|
||||||
return serverLogin(server)
|
return serverLogin(server)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue