From c1e791bad0b079af67398f6407221e6dcbb573dd Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Wed, 25 Jul 2018 22:01:25 +0200 Subject: [PATCH] expliciting type checks and predicates (server only) --- server/helpers/activitypub.ts | 4 +-- server/helpers/core-utils.ts | 3 +- server/helpers/custom-validators/misc.ts | 4 +-- server/helpers/custom-validators/videos.ts | 8 ++--- server/helpers/express-utils.ts | 2 +- server/helpers/logger.ts | 3 +- server/helpers/utils.ts | 3 +- server/initializers/installer.ts | 2 +- .../initializers/migrations/0005-email-pod.ts | 3 +- .../migrations/0010-email-user.ts | 3 +- .../migrations/0030-video-category.ts | 3 +- .../migrations/0035-video-licence.ts | 3 +- .../migrations/0040-video-nsfw.ts | 3 +- .../migrations/0055-video-uuid.ts | 2 +- .../migrations/0070-user-video-quota.ts | 3 +- .../migrations/0155-video-comments-enabled.ts | 3 +- .../migrations/0230-kue-to-bull.ts | 9 ++---- server/initializers/migrator.ts | 2 +- server/lib/activitypub/audience.ts | 6 ++-- server/lib/activitypub/videos.ts | 16 ++++++---- server/lib/emailer.ts | 3 +- .../handlers/utils/activitypub-http-utils.ts | 2 +- server/lib/job-queue/handlers/video-file.ts | 6 ++-- server/lib/job-queue/job-queue.ts | 2 +- server/lib/redis.ts | 15 +++++----- server/lib/user.ts | 9 +++--- server/lib/video-comment.ts | 8 ++--- server/middlewares/sort.ts | 2 +- server/models/activitypub/actor-follow.ts | 8 ++--- server/models/migrations/index.ts | 23 ++++++++++++++ server/models/oauth/oauth-token.ts | 9 ++++-- server/models/video/video-comment.ts | 4 +-- server/tests/utils/users/login.ts | 5 +++- server/tools/get-access-token.ts | 30 +++++++++---------- 34 files changed, 127 insertions(+), 84 deletions(-) create mode 100644 server/models/migrations/index.ts diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index c49142a04..d710f5c97 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts @@ -67,8 +67,8 @@ async function activityPubCollectionPagination (url: string, handler: ActivityPu const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) const result = await handler(start, count) - let next: string - let prev: string + let next: string | undefined + let prev: string | undefined // Assert page is a number page = parseInt(page, 10) diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index c560222d3..2951aef1e 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts @@ -42,7 +42,7 @@ function root () { const paths = [ __dirname, '..', '..' ] // We are under /dist directory - if (process.mainModule.filename.endsWith('.ts') === false) { + if (process.mainModule && process.mainModule.filename.endsWith('.ts') === false) { paths.push('..') } @@ -143,6 +143,7 @@ const renamePromise = promisify2WithVoid(rename) const writeFilePromise = promisify2WithVoid(writeFile) const readdirPromise = promisify1(readdir) const mkdirpPromise = promisify1(mkdirp) +// we cannot modify the Promise types, so we should make the promisify instance check mkdirp const pseudoRandomBytesPromise = promisify1(pseudoRandomBytes) const createPrivateKey = promisify1(pem.createPrivateKey) const getPublicKey = promisify1(pem.getPublicKey) diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 151fc852b..6d10a65a8 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts @@ -51,7 +51,7 @@ function isFileValid ( files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], mimeTypeRegex: string, field: string, - maxSize: number, + maxSize: number | null, optional = false ) { // Should have files @@ -69,7 +69,7 @@ function isFileValid ( if (!file || !file.originalname) return false // 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) } diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index b5cb126d9..70904af0c 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -150,7 +150,7 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use } async function isVideoExist (id: string, res: Response) { - let video: VideoModel + let video: VideoModel | null if (validator.isInt(id)) { video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id) @@ -158,7 +158,7 @@ async function isVideoExist (id: string, res: Response) { video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id) } - if (!video) { + if (video && video !== null) { res.status(404) .json({ error: 'Video not found' }) .end() @@ -173,7 +173,7 @@ async function isVideoExist (id: string, res: Response) { async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) { if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) { const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId) - if (!videoChannel) { + if (videoChannel && videoChannel !== null) { res.status(400) .json({ error: 'Unknown video video channel on this instance.' }) .end() @@ -186,7 +186,7 @@ async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, } const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id) - if (!videoChannel) { + if (videoChannel && videoChannel !== null) { res.status(400) .json({ error: 'Unknown video video channel for this account.' }) .end() diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 76440348f..f136a4329 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts @@ -64,7 +64,7 @@ function createReqFiles ( } }) - const fields = [] + let fields: { name: string, maxCount: number }[] = [] for (const fieldName of fieldNames) { fields.push({ name: fieldName, diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts index 04ddf01a6..7fdfe2125 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts @@ -80,7 +80,8 @@ const logger = winston.createLogger({ function bunyanLogFactory (level: string) { return function () { let meta = null - let args = [].concat(arguments) + let args: any[] = [] + args.concat(arguments) if (arguments[ 0 ] instanceof Error) { meta = arguments[ 0 ].toString() diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index 9efc89d92..7ff1556e3 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts @@ -52,7 +52,7 @@ async function isSignupAllowed () { function isSignupAllowedForCurrentIP (ip: string) { const addr = ipaddr.parse(ip) let excludeList = [ 'blacklist' ] - let matched: string + let matched = '' // 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) { @@ -144,6 +144,7 @@ let serverActor: ActorModel async function getServerActor () { if (serverActor === undefined) { const application = await ApplicationModel.load() + if (!application) throw Error('Could not application.') serverActor = application.Account.Actor } diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 1f513a9c3..1926c40dd 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts @@ -52,7 +52,7 @@ function createDirectoriesIfNotExist () { const cacheDirectories = Object.keys(CACHE) .map(k => CACHE[k].DIRECTORY) - const tasks = [] + const tasks: Promise[] = [] for (const key of Object.keys(storage)) { const dir = storage[key] tasks.push(mkdirpPromise(dir)) diff --git a/server/initializers/migrations/0005-email-pod.ts b/server/initializers/migrations/0005-email-pod.ts index ab60f3adb..c34a12255 100644 --- a/server/initializers/migrations/0005-email-pod.ts +++ b/server/initializers/migrations/0005-email-pod.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -12,7 +13,7 @@ function up (utils: { type: Sequelize.STRING(400), allowNull: false, defaultValue: '' - } + } as Migration.String return q.addColumn('Pods', 'email', data) .then(() => { diff --git a/server/initializers/migrations/0010-email-user.ts b/server/initializers/migrations/0010-email-user.ts index 33d13ce55..37a7b0bb3 100644 --- a/server/initializers/migrations/0010-email-user.ts +++ b/server/initializers/migrations/0010-email-user.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -12,7 +13,7 @@ function up (utils: { type: Sequelize.STRING(400), allowNull: false, defaultValue: '' - } + } as Migration.String return q.addColumn('Users', 'email', data) .then(() => { const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')' diff --git a/server/initializers/migrations/0030-video-category.ts b/server/initializers/migrations/0030-video-category.ts index 41bc1aa98..f784f820d 100644 --- a/server/initializers/migrations/0030-video-category.ts +++ b/server/initializers/migrations/0030-video-category.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -12,7 +13,7 @@ function up (utils: { type: Sequelize.INTEGER, allowNull: false, defaultValue: 0 - } + } as Migration.Integer return q.addColumn('Videos', 'category', data) .then(() => { diff --git a/server/initializers/migrations/0035-video-licence.ts b/server/initializers/migrations/0035-video-licence.ts index 7ab49e147..3d0b0bac9 100644 --- a/server/initializers/migrations/0035-video-licence.ts +++ b/server/initializers/migrations/0035-video-licence.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -12,7 +13,7 @@ function up (utils: { type: Sequelize.INTEGER, allowNull: false, defaultValue: 0 - } + } as Migration.Integer return q.addColumn('Videos', 'licence', data) .then(() => { diff --git a/server/initializers/migrations/0040-video-nsfw.ts b/server/initializers/migrations/0040-video-nsfw.ts index 0460e661d..f7f70d3c4 100644 --- a/server/initializers/migrations/0040-video-nsfw.ts +++ b/server/initializers/migrations/0040-video-nsfw.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -12,7 +13,7 @@ function up (utils: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: false - } + } as Migration.Boolean return q.addColumn('Videos', 'nsfw', data) .then(() => { diff --git a/server/initializers/migrations/0055-video-uuid.ts b/server/initializers/migrations/0055-video-uuid.ts index 9bc65917c..6db25f193 100644 --- a/server/initializers/migrations/0055-video-uuid.ts +++ b/server/initializers/migrations/0055-video-uuid.ts @@ -24,7 +24,7 @@ function up (utils: { return utils.sequelize.query(query) }) .then(() => { - dataUUID.defaultValue = null + dataUUID.defaultValue = null // FIXME:default value cannot be null if string return q.changeColumn('Videos', 'uuid', dataUUID) }) diff --git a/server/initializers/migrations/0070-user-video-quota.ts b/server/initializers/migrations/0070-user-video-quota.ts index dec4d46dd..37683432f 100644 --- a/server/initializers/migrations/0070-user-video-quota.ts +++ b/server/initializers/migrations/0070-user-video-quota.ts @@ -1,5 +1,6 @@ import * as Sequelize from 'sequelize' import * as Promise from 'bluebird' +import { Migration } from '../../models/migrations' function up (utils: { transaction: Sequelize.Transaction, @@ -13,7 +14,7 @@ function up (utils: { type: Sequelize.BIGINT, allowNull: false, defaultValue: -1 - } + } as Migration.BigInteger return q.addColumn('Users', 'videoQuota', data) .then(() => { diff --git a/server/initializers/migrations/0155-video-comments-enabled.ts b/server/initializers/migrations/0155-video-comments-enabled.ts index 59f4110de..6949d3a0c 100644 --- a/server/initializers/migrations/0155-video-comments-enabled.ts +++ b/server/initializers/migrations/0155-video-comments-enabled.ts @@ -1,4 +1,5 @@ import * as Sequelize from 'sequelize' +import { Migration } from '../../models/migrations' async function up (utils: { transaction: Sequelize.Transaction, @@ -9,7 +10,7 @@ async function up (utils: { type: Sequelize.BOOLEAN, allowNull: false, defaultValue: true - } + } as Migration.Boolean await utils.queryInterface.addColumn('video', 'commentsEnabled', data) data.defaultValue = null diff --git a/server/initializers/migrations/0230-kue-to-bull.ts b/server/initializers/migrations/0230-kue-to-bull.ts index 5fad87a61..5f4d88bef 100644 --- a/server/initializers/migrations/0230-kue-to-bull.ts +++ b/server/initializers/migrations/0230-kue-to-bull.ts @@ -2,6 +2,7 @@ import * as Sequelize from 'sequelize' import { createClient } from 'redis' import { CONFIG } from '../constants' import { JobQueue } from '../../lib/job-queue' +import { Redis } from '../../lib/redis' import { initDatabaseModels } from '../database' async function up (utils: { @@ -12,11 +13,7 @@ async function up (utils: { await initDatabaseModels(false) return new Promise((res, rej) => { - const client = createClient({ - host: CONFIG.REDIS.HOSTNAME, - port: CONFIG.REDIS.PORT, - db: CONFIG.REDIS.DB - }) + const client = createClient(Redis.getRedisClient()) const jobsPrefix = 'q-' + CONFIG.WEBSERVER.HOST @@ -36,7 +33,7 @@ async function up (utils: { return res({ type: job.type, payload: parsedData }) } catch (err) { console.error('Cannot parse data %s.', job.data) - return res(null) + return res(undefined) } }) }) diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 466369729..539e2bc8f 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts @@ -11,7 +11,7 @@ async function migrate () { // The installer will do that if (tables.length === 0) return - let actualVersion: number = null + let actualVersion: number | null = null const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"') if (rows && rows[0] && rows[0].migrationVersion) { diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index 7164135b6..7b4067c11 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts @@ -20,7 +20,7 @@ function getVideoCommentAudience ( isOrigin = false ) { const to = [ ACTIVITY_PUB.PUBLIC ] - const cc = [] + const cc: string[] = [] // Owner of the video we comment if (isOrigin === false) { @@ -60,8 +60,8 @@ function getAudience (actorSender: ActorModel, isPublic = true) { } function buildAudience (followerUrls: string[], isPublic = true) { - let to = [] - let cc = [] + let to: string[] = [] + let cc: string[] = [] if (isPublic) { to = [ ACTIVITY_PUB.PUBLIC ] diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index fdc082b61..2944cb729 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -88,17 +88,17 @@ async function videoActivityObjectToDBAttributes ( const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED const duration = videoObject.duration.replace(/[^\d]+/, '') - let language: string = null + let language: string | undefined if (videoObject.language) { language = videoObject.language.identifier } - let category: number = null + let category: number | undefined if (videoObject.category) { category = parseInt(videoObject.category.identifier, 10) } - let licence: number = null + let licence: number | undefined if (videoObject.licence) { 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) } - const attributes = [] + const attributes: VideoFileModel[] = [] for (const fileUrl of fileUrls) { // Fetch associated magnet uri 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) 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 = { extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ], @@ -161,7 +165,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje resolution: fileUrl.width, size: fileUrl.size, videoId: videoCreated.id - } + } as VideoFileModel attributes.push(attribute) } diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 88a06cb79..ded321bf7 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts @@ -91,9 +91,10 @@ class Emailer { async addVideoAbuseReport (videoId: number) { const video = await VideoModel.load(videoId) + if (!video) throw new Error('Unknown Video id during Abuse report.') 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` + `PeerTube.` diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts index c087371c6..36092665e 100644 --- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts +++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts @@ -15,7 +15,7 @@ async function computeBody (payload: { body: any, signatureActorId?: number }) { } async function buildSignedRequestOptions (payload: { signatureActorId?: number }) { - let actor: ActorModel + let actor: ActorModel | null if (payload.signatureActorId) { actor = await ActorModel.load(payload.signatureActorId) if (!actor) throw new Error('Unknown signature actor id.') diff --git a/server/lib/job-queue/handlers/video-file.ts b/server/lib/job-queue/handlers/video-file.ts index bd68dd78b..6b1a8f132 100644 --- a/server/lib/job-queue/handlers/video-file.ts +++ b/server/lib/job-queue/handlers/video-file.ts @@ -28,7 +28,7 @@ async function processVideoFileImport (job: Bull.Job) { const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID) // No video, maybe deleted? 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 } @@ -45,13 +45,13 @@ async function processVideoFile (job: Bull.Job) { const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID) // No video, maybe deleted? 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 } // Transcoding in other resolution if (payload.resolution) { - await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode) + await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode || false) await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video) } else { diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index 1b46180e8..b018d0e8a 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts @@ -87,7 +87,7 @@ class JobQueue { const queue = this.queues[obj.type] if (queue === undefined) { logger.error('Unknown queue %s: cannot create job.', obj.type) - return + throw Error('Unknown queue, cannot create job') } const jobArgs: Bull.JobOptions = { diff --git a/server/lib/redis.ts b/server/lib/redis.ts index 06a340060..e547537c3 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts @@ -6,8 +6,8 @@ import { CONFIG, USER_PASSWORD_RESET_LIFETIME, VIDEO_VIEW_LIFETIME } from '../in type CachedRoute = { body: string, - contentType?: string - statusCode?: string + contentType: string + statusCode: string } class Redis { @@ -75,11 +75,12 @@ class Redis { } setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { - const cached: CachedRoute = { - body: body.toString(), - contentType, - statusCode: statusCode.toString() - } + const cached: CachedRoute = Object.assign({}, { + body: body.toString() + }, + (contentType) ? { contentType } : null, + (statusCode) ? { statusCode: statusCode.toString() } : null + ) return this.setObject(this.buildCachedRouteKey(req), cached, lifetime) } diff --git a/server/lib/user.ts b/server/lib/user.ts index 51050de9b..ac5f55260 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts @@ -6,6 +6,7 @@ import { UserModel } from '../models/account/user' import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' import { createVideoChannel } from './video-channel' import { VideoChannelModel } from '../models/video/video-channel' +import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model' async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) { const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { @@ -34,9 +35,9 @@ async function createUserAccountAndChannel (userToCreate: UserModel, validateUse async function createLocalAccountWithoutKeys ( name: string, - userId: number, - applicationId: number, - t: Sequelize.Transaction, + userId: number | null, + applicationId: number | null, + t: Sequelize.Transaction | undefined, type: ActivityPubActorType= 'Person' ) { const url = getAccountActivityPubUrl(name) @@ -49,7 +50,7 @@ async function createLocalAccountWithoutKeys ( userId, applicationId, actorId: actorInstanceCreated.id - }) + } as FilteredModelAttributes) const accountInstanceCreated = await accountInstance.save({ transaction: t }) accountInstanceCreated.Actor = actorInstanceCreated diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index f88e5cfdf..70ba7c303 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts @@ -9,14 +9,14 @@ import { sendCreateVideoComment } from './activitypub/send' async function createVideoComment (obj: { text: string, - inReplyToComment: VideoCommentModel, + inReplyToComment: VideoCommentModel | null, video: VideoModel account: AccountModel }, t: Sequelize.Transaction) { - let originCommentId: number = null - let inReplyToCommentId: number = null + let originCommentId: number | null = null + let inReplyToCommentId: number | null = null - if (obj.inReplyToComment) { + if (obj.inReplyToComment && obj.inReplyToComment !== null) { originCommentId = obj.inReplyToComment.originCommentId || obj.inReplyToComment.id inReplyToCommentId = obj.inReplyToComment.id } diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index 8a62c8be6..5120804b3 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts @@ -15,7 +15,7 @@ function setDefaultSearchSort (req: express.Request, res: express.Response, next } 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' diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index b8ce6de1d..adec5e92b 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts @@ -111,7 +111,7 @@ export class ActorFollowModel extends Model { 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 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 { } } - 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 query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + @@ -354,10 +354,10 @@ export class ActorFollowModel extends Model { 'WHERE "actor"."inboxUrl" IN (' + inboxUrlsString + ') OR "actor"."sharedInboxUrl" IN (' + inboxUrlsString + ')' + ')' - const options = { + const options = t ? { type: Sequelize.QueryTypes.BULKUPDATE, transaction: t - } + } : undefined return ActorFollowModel.sequelize.query(query, options) } diff --git a/server/models/migrations/index.ts b/server/models/migrations/index.ts new file mode 100644 index 000000000..c2b31b05e --- /dev/null +++ b/server/models/migrations/index.ts @@ -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 +} diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index 759aa2779..026c30135 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts @@ -154,9 +154,12 @@ export class OAuthTokenModel extends Model { return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT) .findOne(query) .then(token => { - token['user'] = token.User - - return token + if (token) { + token['user'] = token.User + return token + } else { + return new OAuthTokenModel() + } }) } diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index e79aff209..03122dc03 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts @@ -156,7 +156,7 @@ export class VideoCommentModel extends Model { as: 'InReplyToVideoComment', onDelete: 'CASCADE' }) - InReplyToVideoComment: VideoCommentModel + InReplyToVideoComment: VideoCommentModel | null @ForeignKey(() => VideoModel) @Column @@ -417,7 +417,7 @@ export class VideoCommentModel extends Model { toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject { let inReplyTo: string // 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 } else { inReplyTo = this.InReplyToVideoComment.url diff --git a/server/tests/utils/users/login.ts b/server/tests/utils/users/login.ts index 338ae1c00..ddeb9df2a 100644 --- a/server/tests/utils/users/login.ts +++ b/server/tests/utils/users/login.ts @@ -55,5 +55,8 @@ export { login, serverLogin, userLogin, - setAccessTokensToServers + setAccessTokensToServers, + Server, + Client, + User } diff --git a/server/tools/get-access-token.ts b/server/tools/get-access-token.ts index 66fa70814..d86c84c8d 100644 --- a/server/tools/get-access-token.ts +++ b/server/tools/get-access-token.ts @@ -2,7 +2,10 @@ import * as program from 'commander' import { getClient, - serverLogin + serverLogin, + Server, + Client, + User } from '../tests/utils/index' program @@ -19,22 +22,19 @@ if ( 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) .then(res => { - server.client.id = res.body.client_id - server.client.secret = res.body.client_secret + const server = { + 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) })