aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/helpers/activitypub.ts4
-rw-r--r--server/helpers/core-utils.ts3
-rw-r--r--server/helpers/custom-validators/misc.ts4
-rw-r--r--server/helpers/custom-validators/videos.ts8
-rw-r--r--server/helpers/express-utils.ts2
-rw-r--r--server/helpers/logger.ts3
-rw-r--r--server/helpers/utils.ts3
-rw-r--r--server/initializers/installer.ts2
-rw-r--r--server/initializers/migrations/0005-email-pod.ts3
-rw-r--r--server/initializers/migrations/0010-email-user.ts3
-rw-r--r--server/initializers/migrations/0030-video-category.ts3
-rw-r--r--server/initializers/migrations/0035-video-licence.ts3
-rw-r--r--server/initializers/migrations/0040-video-nsfw.ts3
-rw-r--r--server/initializers/migrations/0055-video-uuid.ts2
-rw-r--r--server/initializers/migrations/0070-user-video-quota.ts3
-rw-r--r--server/initializers/migrations/0155-video-comments-enabled.ts3
-rw-r--r--server/initializers/migrations/0230-kue-to-bull.ts9
-rw-r--r--server/initializers/migrator.ts2
-rw-r--r--server/lib/activitypub/audience.ts6
-rw-r--r--server/lib/activitypub/videos.ts16
-rw-r--r--server/lib/emailer.ts3
-rw-r--r--server/lib/job-queue/handlers/utils/activitypub-http-utils.ts2
-rw-r--r--server/lib/job-queue/handlers/video-file.ts6
-rw-r--r--server/lib/job-queue/job-queue.ts2
-rw-r--r--server/lib/redis.ts15
-rw-r--r--server/lib/user.ts9
-rw-r--r--server/lib/video-comment.ts8
-rw-r--r--server/middlewares/sort.ts2
-rw-r--r--server/models/activitypub/actor-follow.ts8
-rw-r--r--server/models/migrations/index.ts23
-rw-r--r--server/models/oauth/oauth-token.ts9
-rw-r--r--server/models/video/video-comment.ts4
-rw-r--r--server/tests/utils/users/login.ts5
-rw-r--r--server/tools/get-access-token.ts30
34 files changed, 127 insertions, 84 deletions
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
67 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) 67 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
68 const result = await handler(start, count) 68 const result = await handler(start, count)
69 69
70 let next: string 70 let next: string | undefined
71 let prev: string 71 let prev: string | undefined
72 72
73 // Assert page is a number 73 // Assert page is a number
74 page = parseInt(page, 10) 74 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 () {
42 const paths = [ __dirname, '..', '..' ] 42 const paths = [ __dirname, '..', '..' ]
43 43
44 // We are under /dist directory 44 // We are under /dist directory
45 if (process.mainModule.filename.endsWith('.ts') === false) { 45 if (process.mainModule && process.mainModule.filename.endsWith('.ts') === false) {
46 paths.push('..') 46 paths.push('..')
47 } 47 }
48 48
@@ -143,6 +143,7 @@ const renamePromise = promisify2WithVoid<string, string>(rename)
143const writeFilePromise = promisify2WithVoid<string, any>(writeFile) 143const writeFilePromise = promisify2WithVoid<string, any>(writeFile)
144const readdirPromise = promisify1<string, string[]>(readdir) 144const readdirPromise = promisify1<string, string[]>(readdir)
145const mkdirpPromise = promisify1<string, string>(mkdirp) 145const mkdirpPromise = promisify1<string, string>(mkdirp)
146// we cannot modify the Promise types, so we should make the promisify instance check mkdirp
146const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes) 147const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
147const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) 148const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
148const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) 149const getPublicKey = promisify1<string, { publicKey: string }>(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 (
51 files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], 51 files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[],
52 mimeTypeRegex: string, 52 mimeTypeRegex: string,
53 field: string, 53 field: string,
54 maxSize: number, 54 maxSize: number | null,
55 optional = false 55 optional = false
56) { 56) {
57 // Should have files 57 // Should have files
@@ -69,7 +69,7 @@ function isFileValid (
69 if (!file || !file.originalname) return false 69 if (!file || !file.originalname) return false
70 70
71 // Check size 71 // Check size
72 if (maxSize && file.size > maxSize) return false 72 if ((maxSize !== null) && file.size > maxSize) return false
73 73
74 return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype) 74 return new RegExp(`^${mimeTypeRegex}$`, 'i').test(file.mimetype)
75} 75}
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
150} 150}
151 151
152async function isVideoExist (id: string, res: Response) { 152async function isVideoExist (id: string, res: Response) {
153 let video: VideoModel 153 let video: VideoModel | null
154 154
155 if (validator.isInt(id)) { 155 if (validator.isInt(id)) {
156 video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id) 156 video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
@@ -158,7 +158,7 @@ async function isVideoExist (id: string, res: Response) {
158 video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id) 158 video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
159 } 159 }
160 160
161 if (!video) { 161 if (video && video !== null) {
162 res.status(404) 162 res.status(404)
163 .json({ error: 'Video not found' }) 163 .json({ error: 'Video not found' })
164 .end() 164 .end()
@@ -173,7 +173,7 @@ async function isVideoExist (id: string, res: Response) {
173async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) { 173async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
174 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) { 174 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
175 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId) 175 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
176 if (!videoChannel) { 176 if (videoChannel && videoChannel !== null) {
177 res.status(400) 177 res.status(400)
178 .json({ error: 'Unknown video video channel on this instance.' }) 178 .json({ error: 'Unknown video video channel on this instance.' })
179 .end() 179 .end()
@@ -186,7 +186,7 @@ async function isVideoChannelOfAccountExist (channelId: number, user: UserModel,
186 } 186 }
187 187
188 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id) 188 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
189 if (!videoChannel) { 189 if (videoChannel && videoChannel !== null) {
190 res.status(400) 190 res.status(400)
191 .json({ error: 'Unknown video video channel for this account.' }) 191 .json({ error: 'Unknown video video channel for this account.' })
192 .end() 192 .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 (
64 } 64 }
65 }) 65 })
66 66
67 const fields = [] 67 let fields: { name: string, maxCount: number }[] = []
68 for (const fieldName of fieldNames) { 68 for (const fieldName of fieldNames) {
69 fields.push({ 69 fields.push({
70 name: fieldName, 70 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({
80function bunyanLogFactory (level: string) { 80function bunyanLogFactory (level: string) {
81 return function () { 81 return function () {
82 let meta = null 82 let meta = null
83 let args = [].concat(arguments) 83 let args: any[] = []
84 args.concat(arguments)
84 85
85 if (arguments[ 0 ] instanceof Error) { 86 if (arguments[ 0 ] instanceof Error) {
86 meta = arguments[ 0 ].toString() 87 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 () {
52function isSignupAllowedForCurrentIP (ip: string) { 52function isSignupAllowedForCurrentIP (ip: string) {
53 const addr = ipaddr.parse(ip) 53 const addr = ipaddr.parse(ip)
54 let excludeList = [ 'blacklist' ] 54 let excludeList = [ 'blacklist' ]
55 let matched: string 55 let matched = ''
56 56
57 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too 57 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
58 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) { 58 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
@@ -144,6 +144,7 @@ let serverActor: ActorModel
144async function getServerActor () { 144async function getServerActor () {
145 if (serverActor === undefined) { 145 if (serverActor === undefined) {
146 const application = await ApplicationModel.load() 146 const application = await ApplicationModel.load()
147 if (!application) throw Error('Could not application.')
147 serverActor = application.Account.Actor 148 serverActor = application.Account.Actor
148 } 149 }
149 150
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 () {
52 const cacheDirectories = Object.keys(CACHE) 52 const cacheDirectories = Object.keys(CACHE)
53 .map(k => CACHE[k].DIRECTORY) 53 .map(k => CACHE[k].DIRECTORY)
54 54
55 const tasks = [] 55 const tasks: Promise<string>[] = []
56 for (const key of Object.keys(storage)) { 56 for (const key of Object.keys(storage)) {
57 const dir = storage[key] 57 const dir = storage[key]
58 tasks.push(mkdirpPromise(dir)) 58 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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -12,7 +13,7 @@ function up (utils: {
12 type: Sequelize.STRING(400), 13 type: Sequelize.STRING(400),
13 allowNull: false, 14 allowNull: false,
14 defaultValue: '' 15 defaultValue: ''
15 } 16 } as Migration.String
16 17
17 return q.addColumn('Pods', 'email', data) 18 return q.addColumn('Pods', 'email', data)
18 .then(() => { 19 .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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -12,7 +13,7 @@ function up (utils: {
12 type: Sequelize.STRING(400), 13 type: Sequelize.STRING(400),
13 allowNull: false, 14 allowNull: false,
14 defaultValue: '' 15 defaultValue: ''
15 } 16 } as Migration.String
16 return q.addColumn('Users', 'email', data) 17 return q.addColumn('Users', 'email', data)
17 .then(() => { 18 .then(() => {
18 const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')' 19 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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -12,7 +13,7 @@ function up (utils: {
12 type: Sequelize.INTEGER, 13 type: Sequelize.INTEGER,
13 allowNull: false, 14 allowNull: false,
14 defaultValue: 0 15 defaultValue: 0
15 } 16 } as Migration.Integer
16 17
17 return q.addColumn('Videos', 'category', data) 18 return q.addColumn('Videos', 'category', data)
18 .then(() => { 19 .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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -12,7 +13,7 @@ function up (utils: {
12 type: Sequelize.INTEGER, 13 type: Sequelize.INTEGER,
13 allowNull: false, 14 allowNull: false,
14 defaultValue: 0 15 defaultValue: 0
15 } 16 } as Migration.Integer
16 17
17 return q.addColumn('Videos', 'licence', data) 18 return q.addColumn('Videos', 'licence', data)
18 .then(() => { 19 .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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -12,7 +13,7 @@ function up (utils: {
12 type: Sequelize.BOOLEAN, 13 type: Sequelize.BOOLEAN,
13 allowNull: false, 14 allowNull: false,
14 defaultValue: false 15 defaultValue: false
15 } 16 } as Migration.Boolean
16 17
17 return q.addColumn('Videos', 'nsfw', data) 18 return q.addColumn('Videos', 'nsfw', data)
18 .then(() => { 19 .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: {
24 return utils.sequelize.query(query) 24 return utils.sequelize.query(query)
25 }) 25 })
26 .then(() => { 26 .then(() => {
27 dataUUID.defaultValue = null 27 dataUUID.defaultValue = null // FIXME:default value cannot be null if string
28 28
29 return q.changeColumn('Videos', 'uuid', dataUUID) 29 return q.changeColumn('Videos', 'uuid', dataUUID)
30 }) 30 })
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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Promise from 'bluebird' 2import * as Promise from 'bluebird'
3import { Migration } from '../../models/migrations'
3 4
4function up (utils: { 5function up (utils: {
5 transaction: Sequelize.Transaction, 6 transaction: Sequelize.Transaction,
@@ -13,7 +14,7 @@ function up (utils: {
13 type: Sequelize.BIGINT, 14 type: Sequelize.BIGINT,
14 allowNull: false, 15 allowNull: false,
15 defaultValue: -1 16 defaultValue: -1
16 } 17 } as Migration.BigInteger
17 18
18 return q.addColumn('Users', 'videoQuota', data) 19 return q.addColumn('Users', 'videoQuota', data)
19 .then(() => { 20 .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 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import { Migration } from '../../models/migrations'
2 3
3async function up (utils: { 4async function up (utils: {
4 transaction: Sequelize.Transaction, 5 transaction: Sequelize.Transaction,
@@ -9,7 +10,7 @@ async function up (utils: {
9 type: Sequelize.BOOLEAN, 10 type: Sequelize.BOOLEAN,
10 allowNull: false, 11 allowNull: false,
11 defaultValue: true 12 defaultValue: true
12 } 13 } as Migration.Boolean
13 await utils.queryInterface.addColumn('video', 'commentsEnabled', data) 14 await utils.queryInterface.addColumn('video', 'commentsEnabled', data)
14 15
15 data.defaultValue = null 16 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'
2import { createClient } from 'redis' 2import { createClient } from 'redis'
3import { CONFIG } from '../constants' 3import { CONFIG } from '../constants'
4import { JobQueue } from '../../lib/job-queue' 4import { JobQueue } from '../../lib/job-queue'
5import { Redis } from '../../lib/redis'
5import { initDatabaseModels } from '../database' 6import { initDatabaseModels } from '../database'
6 7
7async function up (utils: { 8async function up (utils: {
@@ -12,11 +13,7 @@ async function up (utils: {
12 await initDatabaseModels(false) 13 await initDatabaseModels(false)
13 14
14 return new Promise((res, rej) => { 15 return new Promise((res, rej) => {
15 const client = createClient({ 16 const client = createClient(Redis.getRedisClient())
16 host: CONFIG.REDIS.HOSTNAME,
17 port: CONFIG.REDIS.PORT,
18 db: CONFIG.REDIS.DB
19 })
20 17
21 const jobsPrefix = 'q-' + CONFIG.WEBSERVER.HOST 18 const jobsPrefix = 'q-' + CONFIG.WEBSERVER.HOST
22 19
@@ -36,7 +33,7 @@ async function up (utils: {
36 return res({ type: job.type, payload: parsedData }) 33 return res({ type: job.type, payload: parsedData })
37 } catch (err) { 34 } catch (err) {
38 console.error('Cannot parse data %s.', job.data) 35 console.error('Cannot parse data %s.', job.data)
39 return res(null) 36 return res(undefined)
40 } 37 }
41 }) 38 })
42 }) 39 })
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 () {
11 // The installer will do that 11 // The installer will do that
12 if (tables.length === 0) return 12 if (tables.length === 0) return
13 13
14 let actualVersion: number = null 14 let actualVersion: number | null = null
15 15
16 const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"') 16 const [ rows ] = await sequelizeTypescript.query('SELECT "migrationVersion" FROM "application"')
17 if (rows && rows[0] && rows[0].migrationVersion) { 17 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 (
20 isOrigin = false 20 isOrigin = false
21) { 21) {
22 const to = [ ACTIVITY_PUB.PUBLIC ] 22 const to = [ ACTIVITY_PUB.PUBLIC ]
23 const cc = [] 23 const cc: string[] = []
24 24
25 // Owner of the video we comment 25 // Owner of the video we comment
26 if (isOrigin === false) { 26 if (isOrigin === false) {
@@ -60,8 +60,8 @@ function getAudience (actorSender: ActorModel, isPublic = true) {
60} 60}
61 61
62function buildAudience (followerUrls: string[], isPublic = true) { 62function buildAudience (followerUrls: string[], isPublic = true) {
63 let to = [] 63 let to: string[] = []
64 let cc = [] 64 let cc: string[] = []
65 65
66 if (isPublic) { 66 if (isPublic) {
67 to = [ ACTIVITY_PUB.PUBLIC ] 67 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 (
88 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED 88 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
89 const duration = videoObject.duration.replace(/[^\d]+/, '') 89 const duration = videoObject.duration.replace(/[^\d]+/, '')
90 90
91 let language: string = null 91 let language: string | undefined
92 if (videoObject.language) { 92 if (videoObject.language) {
93 language = videoObject.language.identifier 93 language = videoObject.language.identifier
94 } 94 }
95 95
96 let category: number = null 96 let category: number | undefined
97 if (videoObject.category) { 97 if (videoObject.category) {
98 category = parseInt(videoObject.category.identifier, 10) 98 category = parseInt(videoObject.category.identifier, 10)
99 } 99 }
100 100
101 let licence: number = null 101 let licence: number | undefined
102 if (videoObject.licence) { 102 if (videoObject.licence) {
103 licence = parseInt(videoObject.licence.identifier, 10) 103 licence = parseInt(videoObject.licence.identifier, 10)
104 } 104 }
@@ -143,7 +143,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
143 throw new Error('Cannot find video files for ' + videoCreated.url) 143 throw new Error('Cannot find video files for ' + videoCreated.url)
144 } 144 }
145 145
146 const attributes = [] 146 const attributes: VideoFileModel[] = []
147 for (const fileUrl of fileUrls) { 147 for (const fileUrl of fileUrls) {
148 // Fetch associated magnet uri 148 // Fetch associated magnet uri
149 const magnet = videoObject.url.find(u => { 149 const magnet = videoObject.url.find(u => {
@@ -153,7 +153,11 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
153 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href) 153 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href)
154 154
155 const parsed = magnetUtil.decode(magnet.href) 155 const parsed = magnetUtil.decode(magnet.href)
156 if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.href) 156 if (!parsed ||
157 (parsed.infoHash &&
158 (isVideoFileInfoHashValid(parsed.infoHash) === false))) {
159 throw new Error('Cannot parse magnet URI ' + magnet.href)
160 }
157 161
158 const attribute = { 162 const attribute = {
159 extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ], 163 extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ],
@@ -161,7 +165,7 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje
161 resolution: fileUrl.width, 165 resolution: fileUrl.width,
162 size: fileUrl.size, 166 size: fileUrl.size,
163 videoId: videoCreated.id 167 videoId: videoCreated.id
164 } 168 } as VideoFileModel
165 attributes.push(attribute) 169 attributes.push(attribute)
166 } 170 }
167 171
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 {
91 91
92 async addVideoAbuseReport (videoId: number) { 92 async addVideoAbuseReport (videoId: number) {
93 const video = await VideoModel.load(videoId) 93 const video = await VideoModel.load(videoId)
94 if (!video) throw new Error('Unknown Video id during Abuse report.')
94 95
95 const text = `Hi,\n\n` + 96 const text = `Hi,\n\n` +
96 `Your instance received an abuse for video the following video ${video.url}\n\n` + 97 `Your instance received an abuse for the following video ${video.url}\n\n` +
97 `Cheers,\n` + 98 `Cheers,\n` +
98 `PeerTube.` 99 `PeerTube.`
99 100
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 }) {
15} 15}
16 16
17async function buildSignedRequestOptions (payload: { signatureActorId?: number }) { 17async function buildSignedRequestOptions (payload: { signatureActorId?: number }) {
18 let actor: ActorModel 18 let actor: ActorModel | null
19 if (payload.signatureActorId) { 19 if (payload.signatureActorId) {
20 actor = await ActorModel.load(payload.signatureActorId) 20 actor = await ActorModel.load(payload.signatureActorId)
21 if (!actor) throw new Error('Unknown signature actor id.') 21 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) {
28 const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID) 28 const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
29 // No video, maybe deleted? 29 // No video, maybe deleted?
30 if (!video) { 30 if (!video) {
31 logger.info('Do not process job %d, video does not exist.', job.id, { videoUUID: video.uuid }) 31 logger.info('Do not process job %d, video does not exist.', job.id)
32 return undefined 32 return undefined
33 } 33 }
34 34
@@ -45,13 +45,13 @@ async function processVideoFile (job: Bull.Job) {
45 const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID) 45 const video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(payload.videoUUID)
46 // No video, maybe deleted? 46 // No video, maybe deleted?
47 if (!video) { 47 if (!video) {
48 logger.info('Do not process job %d, video does not exist.', job.id, { videoUUID: video.uuid }) 48 logger.info('Do not process job %d, video does not exist.', job.id)
49 return undefined 49 return undefined
50 } 50 }
51 51
52 // Transcoding in other resolution 52 // Transcoding in other resolution
53 if (payload.resolution) { 53 if (payload.resolution) {
54 await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode) 54 await video.transcodeOriginalVideofile(payload.resolution, payload.isPortraitMode || false)
55 55
56 await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video) 56 await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video)
57 } else { 57 } 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 {
87 const queue = this.queues[obj.type] 87 const queue = this.queues[obj.type]
88 if (queue === undefined) { 88 if (queue === undefined) {
89 logger.error('Unknown queue %s: cannot create job.', obj.type) 89 logger.error('Unknown queue %s: cannot create job.', obj.type)
90 return 90 throw Error('Unknown queue, cannot create job')
91 } 91 }
92 92
93 const jobArgs: Bull.JobOptions = { 93 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
6 6
7type CachedRoute = { 7type CachedRoute = {
8 body: string, 8 body: string,
9 contentType?: string 9 contentType: string
10 statusCode?: string 10 statusCode: string
11} 11}
12 12
13class Redis { 13class Redis {
@@ -75,11 +75,12 @@ class Redis {
75 } 75 }
76 76
77 setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { 77 setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) {
78 const cached: CachedRoute = { 78 const cached: CachedRoute = Object.assign({}, {
79 body: body.toString(), 79 body: body.toString()
80 contentType, 80 },
81 statusCode: statusCode.toString() 81 (contentType) ? { contentType } : null,
82 } 82 (statusCode) ? { statusCode: statusCode.toString() } : null
83 )
83 84
84 return this.setObject(this.buildCachedRouteKey(req), cached, lifetime) 85 return this.setObject(this.buildCachedRouteKey(req), cached, lifetime)
85 } 86 }
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'
6import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' 6import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub'
7import { createVideoChannel } from './video-channel' 7import { createVideoChannel } from './video-channel'
8import { VideoChannelModel } from '../models/video/video-channel' 8import { VideoChannelModel } from '../models/video/video-channel'
9import { FilteredModelAttributes } from 'sequelize-typescript/lib/models/Model'
9 10
10async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) { 11async function createUserAccountAndChannel (userToCreate: UserModel, validateUser = true) {
11 const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { 12 const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
@@ -34,9 +35,9 @@ async function createUserAccountAndChannel (userToCreate: UserModel, validateUse
34 35
35async function createLocalAccountWithoutKeys ( 36async function createLocalAccountWithoutKeys (
36 name: string, 37 name: string,
37 userId: number, 38 userId: number | null,
38 applicationId: number, 39 applicationId: number | null,
39 t: Sequelize.Transaction, 40 t: Sequelize.Transaction | undefined,
40 type: ActivityPubActorType= 'Person' 41 type: ActivityPubActorType= 'Person'
41) { 42) {
42 const url = getAccountActivityPubUrl(name) 43 const url = getAccountActivityPubUrl(name)
@@ -49,7 +50,7 @@ async function createLocalAccountWithoutKeys (
49 userId, 50 userId,
50 applicationId, 51 applicationId,
51 actorId: actorInstanceCreated.id 52 actorId: actorInstanceCreated.id
52 }) 53 } as FilteredModelAttributes<AccountModel>)
53 54
54 const accountInstanceCreated = await accountInstance.save({ transaction: t }) 55 const accountInstanceCreated = await accountInstance.save({ transaction: t })
55 accountInstanceCreated.Actor = actorInstanceCreated 56 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'
9 9
10async function createVideoComment (obj: { 10async function createVideoComment (obj: {
11 text: string, 11 text: string,
12 inReplyToComment: VideoCommentModel, 12 inReplyToComment: VideoCommentModel | null,
13 video: VideoModel 13 video: VideoModel
14 account: AccountModel 14 account: AccountModel
15}, t: Sequelize.Transaction) { 15}, t: Sequelize.Transaction) {
16 let originCommentId: number = null 16 let originCommentId: number | null = null
17 let inReplyToCommentId: number = null 17 let inReplyToCommentId: number | null = null
18 18
19 if (obj.inReplyToComment) { 19 if (obj.inReplyToComment && obj.inReplyToComment !== null) {
20 originCommentId = obj.inReplyToComment.originCommentId || obj.inReplyToComment.id 20 originCommentId = obj.inReplyToComment.originCommentId || obj.inReplyToComment.id
21 inReplyToCommentId = obj.inReplyToComment.id 21 inReplyToCommentId = obj.inReplyToComment.id
22 } 22 }
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
15} 15}
16 16
17function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { 17function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
18 let newSort: SortType = { sortModel: undefined, sortValue: undefined } 18 let newSort: SortType = { sortModel: undefined, sortValue: '' }
19 19
20 if (!req.query.sort) req.query.sort = '-createdAt' 20 if (!req.query.sort) req.query.sort = '-createdAt'
21 21
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<ActorFollowModel> {
111 if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved) 111 if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved)
112 } 112 }
113 113
114 static updateActorFollowsScore (goodInboxes: string[], badInboxes: string[], t: Sequelize.Transaction) { 114 static updateActorFollowsScore (goodInboxes: string[], badInboxes: string[], t: Sequelize.Transaction | undefined) {
115 if (goodInboxes.length === 0 && badInboxes.length === 0) return 115 if (goodInboxes.length === 0 && badInboxes.length === 0) return
116 116
117 logger.info('Updating %d good actor follows and %d bad actor follows scores.', goodInboxes.length, badInboxes.length) 117 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> {
344 } 344 }
345 } 345 }
346 346
347 private static incrementScores (inboxUrls: string[], value: number, t: Sequelize.Transaction) { 347 private static incrementScores (inboxUrls: string[], value: number, t: Sequelize.Transaction | undefined) {
348 const inboxUrlsString = inboxUrls.map(url => `'${url}'`).join(',') 348 const inboxUrlsString = inboxUrls.map(url => `'${url}'`).join(',')
349 349
350 const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + 350 const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` +
@@ -354,10 +354,10 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
354 'WHERE "actor"."inboxUrl" IN (' + inboxUrlsString + ') OR "actor"."sharedInboxUrl" IN (' + inboxUrlsString + ')' + 354 'WHERE "actor"."inboxUrl" IN (' + inboxUrlsString + ') OR "actor"."sharedInboxUrl" IN (' + inboxUrlsString + ')' +
355 ')' 355 ')'
356 356
357 const options = { 357 const options = t ? {
358 type: Sequelize.QueryTypes.BULKUPDATE, 358 type: Sequelize.QueryTypes.BULKUPDATE,
359 transaction: t 359 transaction: t
360 } 360 } : undefined
361 361
362 return ActorFollowModel.sequelize.query(query, options) 362 return ActorFollowModel.sequelize.query(query, options)
363 } 363 }
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 @@
1import * as Sequelize from 'sequelize'
2
3declare namespace Migration {
4 interface Boolean extends Sequelize.DefineAttributeColumnOptions {
5 defaultValue: boolean | null
6 }
7
8 interface String extends Sequelize.DefineAttributeColumnOptions {
9 defaultValue: string | null
10 }
11
12 interface Integer extends Sequelize.DefineAttributeColumnOptions {
13 defaultValue: number | null
14 }
15
16 interface BigInteger extends Sequelize.DefineAttributeColumnOptions {
17 defaultValue: Sequelize.DataTypeBigInt | number | null
18 }
19}
20
21export {
22 Migration
23}
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<OAuthTokenModel> {
154 return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT) 154 return OAuthTokenModel.scope(ScopeNames.WITH_ACCOUNT)
155 .findOne(query) 155 .findOne(query)
156 .then(token => { 156 .then(token => {
157 token['user'] = token.User 157 if (token) {
158 158 token['user'] = token.User
159 return token 159 return token
160 } else {
161 return new OAuthTokenModel()
162 }
160 }) 163 })
161 } 164 }
162 165
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<VideoCommentModel> {
156 as: 'InReplyToVideoComment', 156 as: 'InReplyToVideoComment',
157 onDelete: 'CASCADE' 157 onDelete: 'CASCADE'
158 }) 158 })
159 InReplyToVideoComment: VideoCommentModel 159 InReplyToVideoComment: VideoCommentModel | null
160 160
161 @ForeignKey(() => VideoModel) 161 @ForeignKey(() => VideoModel)
162 @Column 162 @Column
@@ -417,7 +417,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
417 toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject { 417 toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject {
418 let inReplyTo: string 418 let inReplyTo: string
419 // New thread, so in AS we reply to the video 419 // New thread, so in AS we reply to the video
420 if (this.inReplyToCommentId === null) { 420 if ((this.inReplyToCommentId !== null) || (this.InReplyToVideoComment !== null)) {
421 inReplyTo = this.Video.url 421 inReplyTo = this.Video.url
422 } else { 422 } else {
423 inReplyTo = this.InReplyToVideoComment.url 423 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 {
55 login, 55 login,
56 serverLogin, 56 serverLogin,
57 userLogin, 57 userLogin,
58 setAccessTokensToServers 58 setAccessTokensToServers,
59 Server,
60 Client,
61 User
59} 62}
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'
2 2
3import { 3import {
4 getClient, 4 getClient,
5 serverLogin 5 serverLogin,
6 Server,
7 Client,
8 User
6} from '../tests/utils/index' 9} from '../tests/utils/index'
7 10
8program 11program
@@ -19,22 +22,19 @@ if (
19 throw new Error('All arguments are required.') 22 throw new Error('All arguments are required.')
20} 23}
21 24
22const server = {
23 url: program['url'],
24 user: {
25 username: program['username'],
26 password: program['password']
27 },
28 client: {
29 id: null,
30 secret: null
31 }
32}
33
34getClient(program.url) 25getClient(program.url)
35 .then(res => { 26 .then(res => {
36 server.client.id = res.body.client_id 27 const server = {
37 server.client.secret = res.body.client_secret 28 url: program['url'],
29 user: {
30 username: program['username'],
31 password: program['password']
32 } as User,
33 client: {
34 id: res.body.client_id as string,
35 secret: res.body.client_secret as string
36 } as Client
37 } as Server
38 38
39 return serverLogin(server) 39 return serverLogin(server)
40 }) 40 })