aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/extra-utils
diff options
context:
space:
mode:
Diffstat (limited to 'shared/extra-utils')
-rw-r--r--shared/extra-utils/index.ts2
-rw-r--r--shared/extra-utils/instances-index/mock-instances-index.ts2
-rw-r--r--shared/extra-utils/miscs/email.ts4
-rw-r--r--shared/extra-utils/miscs/miscs.ts33
-rw-r--r--shared/extra-utils/miscs/sql.ts13
-rw-r--r--shared/extra-utils/overviews/overviews.ts27
-rw-r--r--shared/extra-utils/plugins/mock-blocklist.ts29
-rw-r--r--shared/extra-utils/requests/requests.ts66
-rw-r--r--shared/extra-utils/search/videos.ts2
-rw-r--r--shared/extra-utils/server/clients.ts4
-rw-r--r--shared/extra-utils/server/contact-form.ts10
-rw-r--r--shared/extra-utils/server/follows.ts26
-rw-r--r--shared/extra-utils/server/jobs.ts22
-rw-r--r--shared/extra-utils/server/plugins.ts96
-rw-r--r--shared/extra-utils/server/redundancy.ts70
-rw-r--r--shared/extra-utils/server/servers.ts30
-rw-r--r--shared/extra-utils/users/accounts.ts2
-rw-r--r--shared/extra-utils/users/blocklist.ts2
-rw-r--r--shared/extra-utils/users/login.ts55
-rw-r--r--shared/extra-utils/users/user-notifications.ts93
-rw-r--r--shared/extra-utils/users/users.ts43
-rw-r--r--shared/extra-utils/videos/video-abuses.ts55
-rw-r--r--shared/extra-utils/videos/video-blacklist.ts28
-rw-r--r--shared/extra-utils/videos/video-captions.ts6
-rw-r--r--shared/extra-utils/videos/video-channels.ts29
-rw-r--r--shared/extra-utils/videos/video-comments.ts2
-rw-r--r--shared/extra-utils/videos/video-imports.ts2
-rw-r--r--shared/extra-utils/videos/video-playlists.ts50
-rw-r--r--shared/extra-utils/videos/video-streaming-playlists.ts2
-rw-r--r--shared/extra-utils/videos/videos.ts40
30 files changed, 567 insertions, 278 deletions
diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts
index 78acf72aa..d3f010b20 100644
--- a/shared/extra-utils/index.ts
+++ b/shared/extra-utils/index.ts
@@ -18,6 +18,7 @@ export * from './users/users'
18export * from './users/accounts' 18export * from './users/accounts'
19export * from './videos/video-abuses' 19export * from './videos/video-abuses'
20export * from './videos/video-blacklist' 20export * from './videos/video-blacklist'
21export * from './videos/video-captions'
21export * from './videos/video-channels' 22export * from './videos/video-channels'
22export * from './videos/video-comments' 23export * from './videos/video-comments'
23export * from './videos/video-streaming-playlists' 24export * from './videos/video-streaming-playlists'
@@ -26,3 +27,4 @@ export * from './videos/video-change-ownership'
26export * from './feeds/feeds' 27export * from './feeds/feeds'
27export * from './instances-index/mock-instances-index' 28export * from './instances-index/mock-instances-index'
28export * from './search/videos' 29export * from './search/videos'
30export * from './plugins/mock-blocklist'
diff --git a/shared/extra-utils/instances-index/mock-instances-index.ts b/shared/extra-utils/instances-index/mock-instances-index.ts
index cfa4523c1..c58e8bcf8 100644
--- a/shared/extra-utils/instances-index/mock-instances-index.ts
+++ b/shared/extra-utils/instances-index/mock-instances-index.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2 2
3export class MockInstancesIndex { 3export class MockInstancesIndex {
4 private indexInstances: { host: string, createdAt: string }[] = [] 4 private readonly indexInstances: { host: string, createdAt: string }[] = []
5 5
6 initialize () { 6 initialize () {
7 return new Promise(res => { 7 return new Promise(res => {
diff --git a/shared/extra-utils/miscs/email.ts b/shared/extra-utils/miscs/email.ts
index b2a1093da..d6219deb3 100644
--- a/shared/extra-utils/miscs/email.ts
+++ b/shared/extra-utils/miscs/email.ts
@@ -12,7 +12,7 @@ class MockSmtpServer {
12 private constructor () { 12 private constructor () {
13 this.emailChildProcess = fork(`${__dirname}/email-child-process`, []) 13 this.emailChildProcess = fork(`${__dirname}/email-child-process`, [])
14 14
15 this.emailChildProcess.on('message', (msg) => { 15 this.emailChildProcess.on('message', (msg: any) => {
16 if (msg.email) { 16 if (msg.email) {
17 return this.emails.push(msg.email) 17 return this.emails.push(msg.email)
18 } 18 }
@@ -36,7 +36,7 @@ class MockSmtpServer {
36 this.emailChildProcess.on('exit', () => { 36 this.emailChildProcess.on('exit', () => {
37 return rej(new Error('maildev exited unexpectedly, confirm port not in use')) 37 return rej(new Error('maildev exited unexpectedly, confirm port not in use'))
38 }) 38 })
39 this.emailChildProcess.on('message', (msg) => { 39 this.emailChildProcess.on('message', (msg: any) => {
40 if (msg.err) { 40 if (msg.err) {
41 return rej(new Error(msg.err)) 41 return rej(new Error(msg.err))
42 } 42 }
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
index 6b0f6d990..f4e86b85a 100644
--- a/shared/extra-utils/miscs/miscs.ts
+++ b/shared/extra-utils/miscs/miscs.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { basename, dirname, isAbsolute, join, resolve } from 'path' 4import { basename, dirname, isAbsolute, join, resolve } from 'path'
@@ -10,11 +10,11 @@ import * as ffmpeg from 'fluent-ffmpeg'
10const expect = chai.expect 10const expect = chai.expect
11let webtorrent: WebTorrent.Instance 11let webtorrent: WebTorrent.Instance
12 12
13function immutableAssign <T, U> (target: T, source: U) { 13function immutableAssign<T, U> (target: T, source: U) {
14 return Object.assign<{}, T, U>({}, target, source) 14 return Object.assign<{}, T, U>({}, target, source)
15} 15}
16 16
17 // Default interval -> 5 minutes 17// Default interval -> 5 minutes
18function dateIsValid (dateString: string, interval = 300000) { 18function dateIsValid (dateString: string, interval = 300000) {
19 const dateToCheck = new Date(dateString) 19 const dateToCheck = new Date(dateString)
20 const now = new Date() 20 const now = new Date()
@@ -89,7 +89,7 @@ async function generateHighBitrateVideo () {
89 // a large file in the repo. The video needs to have a certain minimum length so 89 // a large file in the repo. The video needs to have a certain minimum length so
90 // that FFmpeg properly applies bitrate limits. 90 // that FFmpeg properly applies bitrate limits.
91 // https://stackoverflow.com/a/15795112 91 // https://stackoverflow.com/a/15795112
92 return new Promise<string>(async (res, rej) => { 92 return new Promise<string>((res, rej) => {
93 ffmpeg() 93 ffmpeg()
94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) 94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) 95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
@@ -104,6 +104,28 @@ async function generateHighBitrateVideo () {
104 return tempFixturePath 104 return tempFixturePath
105} 105}
106 106
107async function generateVideoWithFramerate (fps = 60) {
108 const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true)
109
110 await ensureDir(dirname(tempFixturePath))
111
112 const exists = await pathExists(tempFixturePath)
113 if (!exists) {
114 return new Promise<string>((res, rej) => {
115 ffmpeg()
116 .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ])
117 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
118 .outputOptions([ `-r ${fps}` ])
119 .output(tempFixturePath)
120 .on('error', rej)
121 .on('end', () => res(tempFixturePath))
122 .run()
123 })
124 }
125
126 return tempFixturePath
127}
128
107// --------------------------------------------------------------------------- 129// ---------------------------------------------------------------------------
108 130
109export { 131export {
@@ -115,5 +137,6 @@ export {
115 testImage, 137 testImage,
116 buildAbsoluteFixturePath, 138 buildAbsoluteFixturePath,
117 root, 139 root,
118 generateHighBitrateVideo 140 generateHighBitrateVideo,
141 generateVideoWithFramerate
119} 142}
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
index 167649c6d..5bd5d5d8a 100644
--- a/shared/extra-utils/miscs/sql.ts
+++ b/shared/extra-utils/miscs/sql.ts
@@ -1,7 +1,7 @@
1import { QueryTypes, Sequelize } from 'sequelize' 1import { QueryTypes, Sequelize } from 'sequelize'
2import { ServerInfo } from '../server/servers' 2import { ServerInfo } from '../server/servers'
3 3
4let sequelizes: { [ id: number ]: Sequelize } = {} 4const sequelizes: { [ id: number ]: Sequelize } = {}
5 5
6function getSequelize (internalServerNumber: number) { 6function getSequelize (internalServerNumber: number) {
7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] 7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
@@ -52,22 +52,23 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
52 const seq = getSequelize(internalServerNumber) 52 const seq = getSequelize(internalServerNumber)
53 53
54 // tslint:disable 54 // tslint:disable
55 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` 55 const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' +
56 `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
56 57
57 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } 58 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT }
58 const [ { total } ] = await seq.query<{ total: number }>(query, options) 59 const [ { total } ] = await seq.query<{ total: number }>(query, options)
59 60
60 if (!total) return 0 61 if (!total) return 0
61 62
62 // FIXME: check if we really need parseInt
63 return parseInt(total + '', 10) 63 return parseInt(total + '', 10)
64} 64}
65 65
66async function closeAllSequelize (servers: ServerInfo[]) { 66async function closeAllSequelize (servers: ServerInfo[]) {
67 for (const server of servers) { 67 for (const server of servers) {
68 if (sequelizes[ server.internalServerNumber ]) { 68 if (sequelizes[server.internalServerNumber]) {
69 await sequelizes[ server.internalServerNumber ].close() 69 await sequelizes[server.internalServerNumber].close()
70 delete sequelizes[ server.internalServerNumber ] 70 // eslint-disable-next-line
71 delete sequelizes[server.internalServerNumber]
71 } 72 }
72 } 73 }
73} 74}
diff --git a/shared/extra-utils/overviews/overviews.ts b/shared/extra-utils/overviews/overviews.ts
index 23e3ceb1e..ae4d31aa3 100644
--- a/shared/extra-utils/overviews/overviews.ts
+++ b/shared/extra-utils/overviews/overviews.ts
@@ -1,18 +1,33 @@
1import { makeGetRequest } from '../requests/requests' 1import { makeGetRequest } from '../requests/requests'
2 2
3function getVideosOverview (url: string, useCache = false) { 3function getVideosOverview (url: string, page: number, statusCodeExpected = 200) {
4 const path = '/api/v1/overviews/videos' 4 const path = '/api/v1/overviews/videos'
5 5
6 const query = { 6 const query = { page }
7 t: useCache ? undefined : new Date().getTime()
8 }
9 7
10 return makeGetRequest({ 8 return makeGetRequest({
11 url, 9 url,
12 path, 10 path,
13 query, 11 query,
14 statusCodeExpected: 200 12 statusCodeExpected
15 }) 13 })
16} 14}
17 15
18export { getVideosOverview } 16function getVideosOverviewWithToken (url: string, page: number, token: string, statusCodeExpected = 200) {
17 const path = '/api/v1/overviews/videos'
18
19 const query = { page }
20
21 return makeGetRequest({
22 url,
23 path,
24 query,
25 token,
26 statusCodeExpected
27 })
28}
29
30export {
31 getVideosOverview,
32 getVideosOverviewWithToken
33}
diff --git a/shared/extra-utils/plugins/mock-blocklist.ts b/shared/extra-utils/plugins/mock-blocklist.ts
new file mode 100644
index 000000000..6fe3dee9f
--- /dev/null
+++ b/shared/extra-utils/plugins/mock-blocklist.ts
@@ -0,0 +1,29 @@
1import * as express from 'express'
2
3type BlocklistResponse = {
4 data: {
5 value: string
6 action?: 'add' | 'remove'
7 updatedAt?: string
8 }[]
9}
10
11export class MockBlocklist {
12 private body: BlocklistResponse
13
14 initialize () {
15 return new Promise(res => {
16 const app = express()
17
18 app.get('/blocklist', (req: express.Request, res: express.Response) => {
19 return res.json(this.body)
20 })
21
22 app.listen(42100, () => res())
23 })
24 }
25
26 replace (body: BlocklistResponse) {
27 this.body = body
28 }
29}
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts
index 3532fb429..0e9d67f0b 100644
--- a/shared/extra-utils/requests/requests.ts
+++ b/shared/extra-utils/requests/requests.ts
@@ -1,26 +1,30 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { buildAbsoluteFixturePath, root } from '../miscs/miscs' 4import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
3import { isAbsolute, join } from 'path' 5import { isAbsolute, join } from 'path'
4import { parse } from 'url' 6import { URL } from 'url'
7import { decode } from 'querystring'
5 8
6function get4KFileUrl () { 9function get4KFileUrl () {
7 return 'https://download.cpy.re/peertube/4k_file.txt' 10 return 'https://download.cpy.re/peertube/4k_file.txt'
8} 11}
9 12
10function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { 13function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
11 const { host, protocol, pathname } = parse(url) 14 const { host, protocol, pathname } = new URL(url)
12 15
13 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) 16 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
14} 17}
15 18
16function makeGetRequest (options: { 19function makeGetRequest (options: {
17 url: string, 20 url: string
18 path?: string, 21 path?: string
19 query?: any, 22 query?: any
20 token?: string, 23 token?: string
21 statusCodeExpected?: number, 24 statusCodeExpected?: number
22 contentType?: string, 25 contentType?: string
23 range?: string 26 range?: string
27 redirects?: number
24}) { 28}) {
25 if (!options.statusCodeExpected) options.statusCodeExpected = 400 29 if (!options.statusCodeExpected) options.statusCodeExpected = 400
26 if (options.contentType === undefined) options.contentType = 'application/json' 30 if (options.contentType === undefined) options.contentType = 'application/json'
@@ -31,14 +35,15 @@ function makeGetRequest (options: {
31 if (options.token) req.set('Authorization', 'Bearer ' + options.token) 35 if (options.token) req.set('Authorization', 'Bearer ' + options.token)
32 if (options.query) req.query(options.query) 36 if (options.query) req.query(options.query)
33 if (options.range) req.set('Range', options.range) 37 if (options.range) req.set('Range', options.range)
38 if (options.redirects) req.redirects(options.redirects)
34 39
35 return req.expect(options.statusCodeExpected) 40 return req.expect(options.statusCodeExpected)
36} 41}
37 42
38function makeDeleteRequest (options: { 43function makeDeleteRequest (options: {
39 url: string, 44 url: string
40 path: string, 45 path: string
41 token?: string, 46 token?: string
42 statusCodeExpected?: number 47 statusCodeExpected?: number
43}) { 48}) {
44 if (!options.statusCodeExpected) options.statusCodeExpected = 400 49 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -53,12 +58,12 @@ function makeDeleteRequest (options: {
53} 58}
54 59
55function makeUploadRequest (options: { 60function makeUploadRequest (options: {
56 url: string, 61 url: string
57 method?: 'POST' | 'PUT', 62 method?: 'POST' | 'PUT'
58 path: string, 63 path: string
59 token?: string, 64 token?: string
60 fields: { [ fieldName: string ]: any }, 65 fields: { [ fieldName: string ]: any }
61 attaches: { [ attachName: string ]: any | any[] }, 66 attaches: { [ attachName: string ]: any | any[] }
62 statusCodeExpected?: number 67 statusCodeExpected?: number
63}) { 68}) {
64 if (!options.statusCodeExpected) options.statusCodeExpected = 400 69 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -101,10 +106,10 @@ function makeUploadRequest (options: {
101} 106}
102 107
103function makePostBodyRequest (options: { 108function makePostBodyRequest (options: {
104 url: string, 109 url: string
105 path: string, 110 path: string
106 token?: string, 111 token?: string
107 fields?: { [ fieldName: string ]: any }, 112 fields?: { [ fieldName: string ]: any }
108 statusCodeExpected?: number 113 statusCodeExpected?: number
109}) { 114}) {
110 if (!options.fields) options.fields = {} 115 if (!options.fields) options.fields = {}
@@ -121,10 +126,10 @@ function makePostBodyRequest (options: {
121} 126}
122 127
123function makePutBodyRequest (options: { 128function makePutBodyRequest (options: {
124 url: string, 129 url: string
125 path: string, 130 path: string
126 token?: string, 131 token?: string
127 fields: { [ fieldName: string ]: any }, 132 fields: { [ fieldName: string ]: any }
128 statusCodeExpected?: number 133 statusCodeExpected?: number
129}) { 134}) {
130 if (!options.statusCodeExpected) options.statusCodeExpected = 400 135 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -147,9 +152,9 @@ function makeHTMLRequest (url: string, path: string) {
147} 152}
148 153
149function updateAvatarRequest (options: { 154function updateAvatarRequest (options: {
150 url: string, 155 url: string
151 path: string, 156 path: string
152 accessToken: string, 157 accessToken: string
153 fixture: string 158 fixture: string
154}) { 159}) {
155 let filePath = '' 160 let filePath = ''
@@ -169,12 +174,17 @@ function updateAvatarRequest (options: {
169 }) 174 })
170} 175}
171 176
177function decodeQueryString (path: string) {
178 return decode(path.split('?')[1])
179}
180
172// --------------------------------------------------------------------------- 181// ---------------------------------------------------------------------------
173 182
174export { 183export {
175 get4KFileUrl, 184 get4KFileUrl,
176 makeHTMLRequest, 185 makeHTMLRequest,
177 makeGetRequest, 186 makeGetRequest,
187 decodeQueryString,
178 makeUploadRequest, 188 makeUploadRequest,
179 makePostBodyRequest, 189 makePostBodyRequest,
180 makePutBodyRequest, 190 makePutBodyRequest,
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts
index da806e692..4c52ea11c 100644
--- a/shared/extra-utils/search/videos.ts
+++ b/shared/extra-utils/search/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { VideosSearchQuery } from '../../models/search' 4import { VideosSearchQuery } from '../../models/search'
diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts
index 273aac747..dc631e823 100644
--- a/shared/extra-utils/server/clients.ts
+++ b/shared/extra-utils/server/clients.ts
@@ -1,12 +1,12 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import * as urlUtil from 'url' 2import { URL } from 'url'
3 3
4function getClient (url: string) { 4function getClient (url: string) {
5 const path = '/api/v1/oauth-clients/local' 5 const path = '/api/v1/oauth-clients/local'
6 6
7 return request(url) 7 return request(url)
8 .get(path) 8 .get(path)
9 .set('Host', urlUtil.parse(url).host) 9 .set('Host', new URL(url).host)
10 .set('Accept', 'application/json') 10 .set('Accept', 'application/json')
11 .expect(200) 11 .expect(200)
12 .expect('Content-Type', /json/) 12 .expect('Content-Type', /json/)
diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts
index e002e03dd..d50f83241 100644
--- a/shared/extra-utils/server/contact-form.ts
+++ b/shared/extra-utils/server/contact-form.ts
@@ -2,11 +2,11 @@ import * as request from 'supertest'
2import { ContactForm } from '../../models/server' 2import { ContactForm } from '../../models/server'
3 3
4function sendContactForm (options: { 4function sendContactForm (options: {
5 url: string, 5 url: string
6 fromEmail: string, 6 fromEmail: string
7 fromName: string, 7 fromName: string
8 subject: string, 8 subject: string
9 body: string, 9 body: string
10 expectedStatus?: number 10 expectedStatus?: number
11}) { 11}) {
12 const path = '/api/v1/server/contact' 12 const path = '/api/v1/server/contact'
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 3f7729c20..006d59199 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -5,12 +5,12 @@ import { makePostBodyRequest } from '../requests/requests'
5import { ActivityPubActorType, FollowState } from '@shared/models' 5import { ActivityPubActorType, FollowState } from '@shared/models'
6 6
7function getFollowersListPaginationAndSort (options: { 7function getFollowersListPaginationAndSort (options: {
8 url: string, 8 url: string
9 start: number, 9 start: number
10 count: number, 10 count: number
11 sort: string, 11 sort: string
12 search?: string, 12 search?: string
13 actorType?: ActivityPubActorType, 13 actorType?: ActivityPubActorType
14 state?: FollowState 14 state?: FollowState
15}) { 15}) {
16 const { url, start, count, sort, search, state, actorType } = options 16 const { url, start, count, sort, search, state, actorType } = options
@@ -56,12 +56,12 @@ function rejectFollower (url: string, token: string, follower: string, statusCod
56} 56}
57 57
58function getFollowingListPaginationAndSort (options: { 58function getFollowingListPaginationAndSort (options: {
59 url: string, 59 url: string
60 start: number, 60 start: number
61 count: number, 61 count: number
62 sort: string, 62 sort: string
63 search?: string, 63 search?: string
64 actorType?: ActivityPubActorType, 64 actorType?: ActivityPubActorType
65 state?: FollowState 65 state?: FollowState
66}) { 66}) {
67 const { url, start, count, sort, search, state, actorType } = options 67 const { url, start, count, sort, search, state, actorType } = options
@@ -92,7 +92,7 @@ function follow (follower: string, following: string[], accessToken: string, exp
92 .post(path) 92 .post(path)
93 .set('Accept', 'application/json') 93 .set('Accept', 'application/json')
94 .set('Authorization', 'Bearer ' + accessToken) 94 .set('Authorization', 'Bearer ' + accessToken)
95 .send({ 'hosts': followingHosts }) 95 .send({ hosts: followingHosts })
96 .expect(expectedStatus) 96 .expect(expectedStatus)
97} 97}
98 98
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
index 56fe5fa2a..d984b3d1e 100644
--- a/shared/extra-utils/server/jobs.ts
+++ b/shared/extra-utils/server/jobs.ts
@@ -8,20 +8,20 @@ function getJobsList (url: string, accessToken: string, state: JobState) {
8 const path = '/api/v1/jobs/' + state 8 const path = '/api/v1/jobs/' + state
9 9
10 return request(url) 10 return request(url)
11 .get(path) 11 .get(path)
12 .set('Accept', 'application/json') 12 .set('Accept', 'application/json')
13 .set('Authorization', 'Bearer ' + accessToken) 13 .set('Authorization', 'Bearer ' + accessToken)
14 .expect(200) 14 .expect(200)
15 .expect('Content-Type', /json/) 15 .expect('Content-Type', /json/)
16} 16}
17 17
18function getJobsListPaginationAndSort (options: { 18function getJobsListPaginationAndSort (options: {
19 url: string, 19 url: string
20 accessToken: string, 20 accessToken: string
21 state: JobState, 21 state: JobState
22 start: number, 22 start: number
23 count: number, 23 count: number
24 sort: string, 24 sort: string
25 jobType?: JobType 25 jobType?: JobType
26}) { 26}) {
27 const { url, accessToken, state, start, count, sort, jobType } = options 27 const { url, accessToken, state, start, count, sort, jobType } = options
diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts
index 5c0d1e511..b6b5e3958 100644
--- a/shared/extra-utils/server/plugins.ts
+++ b/shared/extra-utils/server/plugins.ts
@@ -7,13 +7,13 @@ import { root } from '../miscs/miscs'
7import { join } from 'path' 7import { join } from 'path'
8 8
9function listPlugins (parameters: { 9function listPlugins (parameters: {
10 url: string, 10 url: string
11 accessToken: string, 11 accessToken: string
12 start?: number, 12 start?: number
13 count?: number, 13 count?: number
14 sort?: string, 14 sort?: string
15 pluginType?: PluginType, 15 pluginType?: PluginType
16 uninstalled?: boolean, 16 uninstalled?: boolean
17 expectedStatus?: number 17 expectedStatus?: number
18}) { 18}) {
19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters 19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters
@@ -35,13 +35,13 @@ function listPlugins (parameters: {
35} 35}
36 36
37function listAvailablePlugins (parameters: { 37function listAvailablePlugins (parameters: {
38 url: string, 38 url: string
39 accessToken: string, 39 accessToken: string
40 start?: number, 40 start?: number
41 count?: number, 41 count?: number
42 sort?: string, 42 sort?: string
43 pluginType?: PluginType, 43 pluginType?: PluginType
44 currentPeerTubeEngine?: string, 44 currentPeerTubeEngine?: string
45 search?: string 45 search?: string
46 expectedStatus?: number 46 expectedStatus?: number
47}) { 47}) {
@@ -67,9 +67,9 @@ function listAvailablePlugins (parameters: {
67} 67}
68 68
69function getPlugin (parameters: { 69function getPlugin (parameters: {
70 url: string, 70 url: string
71 accessToken: string, 71 accessToken: string
72 npmName: string, 72 npmName: string
73 expectedStatus?: number 73 expectedStatus?: number
74}) { 74}) {
75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -84,10 +84,10 @@ function getPlugin (parameters: {
84} 84}
85 85
86function updatePluginSettings (parameters: { 86function updatePluginSettings (parameters: {
87 url: string, 87 url: string
88 accessToken: string, 88 accessToken: string
89 npmName: string, 89 npmName: string
90 settings: any, 90 settings: any
91 expectedStatus?: number 91 expectedStatus?: number
92}) { 92}) {
93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters 93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters
@@ -103,9 +103,9 @@ function updatePluginSettings (parameters: {
103} 103}
104 104
105function getPluginRegisteredSettings (parameters: { 105function getPluginRegisteredSettings (parameters: {
106 url: string, 106 url: string
107 accessToken: string, 107 accessToken: string
108 npmName: string, 108 npmName: string
109 expectedStatus?: number 109 expectedStatus?: number
110}) { 110}) {
111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -120,8 +120,8 @@ function getPluginRegisteredSettings (parameters: {
120} 120}
121 121
122function getPublicSettings (parameters: { 122function getPublicSettings (parameters: {
123 url: string, 123 url: string
124 npmName: string, 124 npmName: string
125 expectedStatus?: number 125 expectedStatus?: number
126}) { 126}) {
127 const { url, npmName, expectedStatus = 200 } = parameters 127 const { url, npmName, expectedStatus = 200 } = parameters
@@ -135,8 +135,8 @@ function getPublicSettings (parameters: {
135} 135}
136 136
137function getPluginTranslations (parameters: { 137function getPluginTranslations (parameters: {
138 url: string, 138 url: string
139 locale: string, 139 locale: string
140 expectedStatus?: number 140 expectedStatus?: number
141}) { 141}) {
142 const { url, locale, expectedStatus = 200 } = parameters 142 const { url, locale, expectedStatus = 200 } = parameters
@@ -150,9 +150,9 @@ function getPluginTranslations (parameters: {
150} 150}
151 151
152function installPlugin (parameters: { 152function installPlugin (parameters: {
153 url: string, 153 url: string
154 accessToken: string, 154 accessToken: string
155 path?: string, 155 path?: string
156 npmName?: string 156 npmName?: string
157 expectedStatus?: number 157 expectedStatus?: number
158}) { 158}) {
@@ -169,9 +169,9 @@ function installPlugin (parameters: {
169} 169}
170 170
171function updatePlugin (parameters: { 171function updatePlugin (parameters: {
172 url: string, 172 url: string
173 accessToken: string, 173 accessToken: string
174 path?: string, 174 path?: string
175 npmName?: string 175 npmName?: string
176 expectedStatus?: number 176 expectedStatus?: number
177}) { 177}) {
@@ -188,8 +188,8 @@ function updatePlugin (parameters: {
188} 188}
189 189
190function uninstallPlugin (parameters: { 190function uninstallPlugin (parameters: {
191 url: string, 191 url: string
192 accessToken: string, 192 accessToken: string
193 npmName: string 193 npmName: string
194 expectedStatus?: number 194 expectedStatus?: number
195}) { 195}) {
@@ -235,6 +235,27 @@ function getPluginTestPath (suffix = '') {
235 return join(root(), 'server', 'tests', 'fixtures', 'peertube-plugin-test' + suffix) 235 return join(root(), 'server', 'tests', 'fixtures', 'peertube-plugin-test' + suffix)
236} 236}
237 237
238function getExternalAuth (options: {
239 url: string
240 npmName: string
241 npmVersion: string
242 authName: string
243 query?: any
244 statusCodeExpected?: number
245}) {
246 const { url, npmName, npmVersion, authName, statusCodeExpected, query } = options
247
248 const path = '/plugins/' + npmName + '/' + npmVersion + '/auth/' + authName
249
250 return makeGetRequest({
251 url,
252 path,
253 query,
254 statusCodeExpected: statusCodeExpected || 200,
255 redirects: 0
256 })
257}
258
238export { 259export {
239 listPlugins, 260 listPlugins,
240 listAvailablePlugins, 261 listAvailablePlugins,
@@ -250,5 +271,6 @@ export {
250 updatePluginPackageJSON, 271 updatePluginPackageJSON,
251 getPluginPackageJSON, 272 getPluginPackageJSON,
252 getPluginTestPath, 273 getPluginTestPath,
253 getPublicSettings 274 getPublicSettings,
275 getExternalAuth
254} 276}
diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts
index c39ff2c8b..08467e4c0 100644
--- a/shared/extra-utils/server/redundancy.ts
+++ b/shared/extra-utils/server/redundancy.ts
@@ -1,6 +1,7 @@
1import { makePutBodyRequest } from '../requests/requests' 1import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
2import { VideoRedundanciesTarget } from '@shared/models'
2 3
3async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { 4function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) {
4 const path = '/api/v1/server/redundancy/' + host 5 const path = '/api/v1/server/redundancy/' + host
5 6
6 return makePutBodyRequest({ 7 return makePutBodyRequest({
@@ -12,6 +13,69 @@ async function updateRedundancy (url: string, accessToken: string, host: string,
12 }) 13 })
13} 14}
14 15
16function listVideoRedundancies (options: {
17 url: string
18 accessToken: string
19 target: VideoRedundanciesTarget
20 start?: number
21 count?: number
22 sort?: string
23 statusCodeExpected?: number
24}) {
25 const path = '/api/v1/server/redundancy/videos'
26
27 const { url, accessToken, target, statusCodeExpected, start, count, sort } = options
28
29 return makeGetRequest({
30 url,
31 token: accessToken,
32 path,
33 query: {
34 start: start ?? 0,
35 count: count ?? 5,
36 sort: sort ?? 'name',
37 target
38 },
39 statusCodeExpected: statusCodeExpected || 200
40 })
41}
42
43function addVideoRedundancy (options: {
44 url: string
45 accessToken: string
46 videoId: number
47}) {
48 const path = '/api/v1/server/redundancy/videos'
49 const { url, accessToken, videoId } = options
50
51 return makePostBodyRequest({
52 url,
53 token: accessToken,
54 path,
55 fields: { videoId },
56 statusCodeExpected: 204
57 })
58}
59
60function removeVideoRedundancy (options: {
61 url: string
62 accessToken: string
63 redundancyId: number
64}) {
65 const { url, accessToken, redundancyId } = options
66 const path = '/api/v1/server/redundancy/videos/' + redundancyId
67
68 return makeDeleteRequest({
69 url,
70 token: accessToken,
71 path,
72 statusCodeExpected: 204
73 })
74}
75
15export { 76export {
16 updateRedundancy 77 updateRedundancy,
78 listVideoRedundancies,
79 addVideoRedundancy,
80 removeVideoRedundancy
17} 81}
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index a0720d778..0f883d839 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -1,16 +1,15 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { ChildProcess, exec, fork } from 'child_process' 3import { ChildProcess, exec, fork } from 'child_process'
4import { join } from 'path' 4import { join } from 'path'
5import { root, wait } from '../miscs/miscs' 5import { root, wait } from '../miscs/miscs'
6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' 6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra'
7import { existsSync } from 'fs'
8import { expect } from 'chai' 7import { expect } from 'chai'
9import { VideoChannel } from '../../models/videos' 8import { VideoChannel } from '../../models/videos'
10import { randomInt } from '../../core-utils/miscs/miscs' 9import { randomInt } from '../../core-utils/miscs/miscs'
11 10
12interface ServerInfo { 11interface ServerInfo {
13 app: ChildProcess, 12 app: ChildProcess
14 url: string 13 url: string
15 host: string 14 host: string
16 15
@@ -20,13 +19,13 @@ interface ServerInfo {
20 serverNumber: number 19 serverNumber: number
21 20
22 client: { 21 client: {
23 id: string, 22 id: string
24 secret: string 23 secret: string
25 } 24 }
26 25
27 user: { 26 user: {
28 username: string, 27 username: string
29 password: string, 28 password: string
30 email?: string 29 email?: string
31 } 30 }
32 31
@@ -57,7 +56,7 @@ function parallelTests () {
57} 56}
58 57
59function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { 58function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
60 let apps = [] 59 const apps = []
61 let i = 0 60 let i = 0
62 61
63 return new Promise<ServerInfo[]>(res => { 62 return new Promise<ServerInfo[]>(res => {
@@ -203,20 +202,20 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = []
203 202
204 // Capture things if we want to 203 // Capture things if we want to
205 for (const key of Object.keys(regexps)) { 204 for (const key of Object.keys(regexps)) {
206 const regexp = regexps[ key ] 205 const regexp = regexps[key]
207 const matches = data.toString().match(regexp) 206 const matches = data.toString().match(regexp)
208 if (matches !== null) { 207 if (matches !== null) {
209 if (key === 'client_id') server.client.id = matches[ 1 ] 208 if (key === 'client_id') server.client.id = matches[1]
210 else if (key === 'client_secret') server.client.secret = matches[ 1 ] 209 else if (key === 'client_secret') server.client.secret = matches[1]
211 else if (key === 'user_username') server.user.username = matches[ 1 ] 210 else if (key === 'user_username') server.user.username = matches[1]
212 else if (key === 'user_password') server.user.password = matches[ 1 ] 211 else if (key === 'user_password') server.user.password = matches[1]
213 } 212 }
214 } 213 }
215 214
216 // Check if all required sentences are here 215 // Check if all required sentences are here
217 for (const key of Object.keys(serverRunString)) { 216 for (const key of Object.keys(serverRunString)) {
218 if (data.toString().indexOf(key) !== -1) serverRunString[ key ] = true 217 if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
219 if (serverRunString[ key ] === false) dontContinue = true 218 if (serverRunString[key] === false) dontContinue = true
220 } 219 }
221 220
222 // If no, there is maybe one thing not already initialized (client/user credentials generation...) 221 // If no, there is maybe one thing not already initialized (client/user credentials generation...)
@@ -286,7 +285,7 @@ function cleanupTests (servers: ServerInfo[]) {
286 return Promise.all(p) 285 return Promise.all(p)
287} 286}
288 287
289async function waitUntilLog (server: ServerInfo, str: string, count = 1) { 288async function waitUntilLog (server: ServerInfo, str: string, count = 1, strictCount = true) {
290 const logfile = join(root(), 'test' + server.internalServerNumber, 'logs/peertube.log') 289 const logfile = join(root(), 'test' + server.internalServerNumber, 'logs/peertube.log')
291 290
292 while (true) { 291 while (true) {
@@ -294,6 +293,7 @@ async function waitUntilLog (server: ServerInfo, str: string, count = 1) {
294 293
295 const matches = buf.toString().match(new RegExp(str, 'g')) 294 const matches = buf.toString().match(new RegExp(str, 'g'))
296 if (matches && matches.length === count) return 295 if (matches && matches.length === count) return
296 if (matches && strictCount === false && matches.length >= count) return
297 297
298 await wait(1000) 298 await wait(1000)
299 } 299 }
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
index 627e17cc3..f87706f6a 100644
--- a/shared/extra-utils/users/accounts.ts
+++ b/shared/extra-utils/users/accounts.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { expect } from 'chai' 4import { expect } from 'chai'
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts
index 5feb84179..39e720b42 100644
--- a/shared/extra-utils/users/blocklist.ts
+++ b/shared/extra-utils/users/blocklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' 3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests'
4 4
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts
index f9bfb3cb3..275bb0826 100644
--- a/shared/extra-utils/users/login.ts
+++ b/shared/extra-utils/users/login.ts
@@ -27,12 +27,40 @@ function login (url: string, client: Client, user: User, expectedStatus = 200) {
27 .expect(expectedStatus) 27 .expect(expectedStatus)
28} 28}
29 29
30function logout (url: string, token: string, expectedStatus = 200) {
31 const path = '/api/v1/users/revoke-token'
32
33 return request(url)
34 .post(path)
35 .set('Authorization', 'Bearer ' + token)
36 .type('form')
37 .expect(expectedStatus)
38}
39
30async function serverLogin (server: Server) { 40async function serverLogin (server: Server) {
31 const res = await login(server.url, server.client, server.user, 200) 41 const res = await login(server.url, server.client, server.user, 200)
32 42
33 return res.body.access_token as string 43 return res.body.access_token as string
34} 44}
35 45
46function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus = 200) {
47 const path = '/api/v1/users/token'
48
49 const body = {
50 client_id: server.client.id,
51 client_secret: server.client.secret,
52 refresh_token: refreshToken,
53 response_type: 'code',
54 grant_type: 'refresh_token'
55 }
56
57 return request(server.url)
58 .post(path)
59 .type('form')
60 .send(body)
61 .expect(expectedStatus)
62}
63
36async function userLogin (server: Server, user: User, expectedStatus = 200) { 64async function userLogin (server: Server, user: User, expectedStatus = 200) {
37 const res = await login(server.url, server.client, user, expectedStatus) 65 const res = await login(server.url, server.client, user, expectedStatus)
38 66
@@ -60,22 +88,45 @@ function setAccessTokensToServers (servers: ServerInfo[]) {
60 const tasks: Promise<any>[] = [] 88 const tasks: Promise<any>[] = []
61 89
62 for (const server of servers) { 90 for (const server of servers) {
63 const p = serverLogin(server).then(t => server.accessToken = t) 91 const p = serverLogin(server).then(t => { server.accessToken = t })
64 tasks.push(p) 92 tasks.push(p)
65 } 93 }
66 94
67 return Promise.all(tasks) 95 return Promise.all(tasks)
68} 96}
69 97
98function loginUsingExternalToken (server: Server, username: string, externalAuthToken: string, expectedStatus = 200) {
99 const path = '/api/v1/users/token'
100
101 const body = {
102 client_id: server.client.id,
103 client_secret: server.client.secret,
104 username: username,
105 response_type: 'code',
106 grant_type: 'password',
107 scope: 'upload',
108 externalAuthToken
109 }
110
111 return request(server.url)
112 .post(path)
113 .type('form')
114 .send(body)
115 .expect(expectedStatus)
116}
117
70// --------------------------------------------------------------------------- 118// ---------------------------------------------------------------------------
71 119
72export { 120export {
73 login, 121 login,
122 logout,
74 serverLogin, 123 serverLogin,
124 refreshToken,
75 userLogin, 125 userLogin,
76 getAccessToken, 126 getAccessToken,
77 setAccessTokensToServers, 127 setAccessTokensToServers,
78 Server, 128 Server,
79 Client, 129 Client,
80 User 130 User,
131 loginUsingExternalToken
81} 132}
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
index 9a5fd7e86..bd00894c4 100644
--- a/shared/extra-utils/users/user-notifications.ts
+++ b/shared/extra-utils/users/user-notifications.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' 3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' 4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
@@ -54,6 +54,7 @@ function markAsReadNotifications (url: string, token: string, ids: number[], sta
54 statusCodeExpected 54 statusCodeExpected
55 }) 55 })
56} 56}
57
57function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { 58function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
58 const path = '/api/v1/users/me/notifications/read-all' 59 const path = '/api/v1/users/me/notifications/read-all'
59 60
@@ -77,7 +78,7 @@ type CheckerBaseParams = {
77 server: ServerInfo 78 server: ServerInfo
78 emails: object[] 79 emails: object[]
79 socketNotifications: UserNotification[] 80 socketNotifications: UserNotification[]
80 token: string, 81 token: string
81 check?: { web: boolean, mail: boolean } 82 check?: { web: boolean, mail: boolean }
82} 83}
83 84
@@ -109,10 +110,10 @@ async function checkNotification (
109 110
110 if (checkType === 'presence') { 111 if (checkType === 'presence') {
111 const obj = inspect(base.socketNotifications, { depth: 5 }) 112 const obj = inspect(base.socketNotifications, { depth: 5 })
112 expect(socketNotification, 'The socket notification is absent. ' + obj).to.not.be.undefined 113 expect(socketNotification, 'The socket notification is absent when is should be present. ' + obj).to.not.be.undefined
113 } else { 114 } else {
114 const obj = inspect(socketNotification, { depth: 5 }) 115 const obj = inspect(socketNotification, { depth: 5 })
115 expect(socketNotification, 'The socket notification is present. ' + obj).to.be.undefined 116 expect(socketNotification, 'The socket notification is present when is should not be present. ' + obj).to.be.undefined
116 } 117 }
117 } 118 }
118 119
@@ -124,9 +125,9 @@ async function checkNotification (
124 .find(e => emailNotificationFinder(e)) 125 .find(e => emailNotificationFinder(e))
125 126
126 if (checkType === 'presence') { 127 if (checkType === 'presence') {
127 expect(email, 'The email is absent. ' + inspect(base.emails)).to.not.be.undefined 128 expect(email, 'The email is absent when is should be present. ' + inspect(base.emails)).to.not.be.undefined
128 } else { 129 } else {
129 expect(email, 'The email is present. ' + inspect(email)).to.be.undefined 130 expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined
130 } 131 }
131 } 132 }
132} 133}
@@ -171,12 +172,12 @@ async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName
171 } 172 }
172 } 173 }
173 174
174 function emailFinder (email: object) { 175 function emailNotificationFinder (email: object) {
175 const text = email[ 'text' ] 176 const text = email['text']
176 return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 177 return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
177 } 178 }
178 179
179 await checkNotification(base, notificationChecker, emailFinder, type) 180 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
180} 181}
181 182
182async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { 183async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
@@ -194,12 +195,12 @@ async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string
194 } 195 }
195 } 196 }
196 197
197 function emailFinder (email: object) { 198 function emailNotificationFinder (email: object) {
198 const text: string = email[ 'text' ] 199 const text: string = email['text']
199 return text.includes(videoUUID) && text.includes('Your video') 200 return text.includes(videoUUID) && text.includes('Your video')
200 } 201 }
201 202
202 await checkNotification(base, notificationChecker, emailFinder, type) 203 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
203} 204}
204 205
205async function checkMyVideoImportIsFinished ( 206async function checkMyVideoImportIsFinished (
@@ -225,14 +226,14 @@ async function checkMyVideoImportIsFinished (
225 } 226 }
226 } 227 }
227 228
228 function emailFinder (email: object) { 229 function emailNotificationFinder (email: object) {
229 const text: string = email[ 'text' ] 230 const text: string = email['text']
230 const toFind = success ? ' finished' : ' error' 231 const toFind = success ? ' finished' : ' error'
231 232
232 return text.includes(url) && text.includes(toFind) 233 return text.includes(url) && text.includes(toFind)
233 } 234 }
234 235
235 await checkNotification(base, notificationChecker, emailFinder, type) 236 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
236} 237}
237 238
238async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) { 239async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
@@ -250,13 +251,13 @@ async function checkUserRegistered (base: CheckerBaseParams, username: string, t
250 } 251 }
251 } 252 }
252 253
253 function emailFinder (email: object) { 254 function emailNotificationFinder (email: object) {
254 const text: string = email[ 'text' ] 255 const text: string = email['text']
255 256
256 return text.includes(' registered ') && text.includes(username) 257 return text.includes(' registered.') && text.includes(username)
257 } 258 }
258 259
259 await checkNotification(base, notificationChecker, emailFinder, type) 260 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
260} 261}
261 262
262async function checkNewActorFollow ( 263async function checkNewActorFollow (
@@ -290,13 +291,13 @@ async function checkNewActorFollow (
290 } 291 }
291 } 292 }
292 293
293 function emailFinder (email: object) { 294 function emailNotificationFinder (email: object) {
294 const text: string = email[ 'text' ] 295 const text: string = email['text']
295 296
296 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) 297 return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
297 } 298 }
298 299
299 await checkNotification(base, notificationChecker, emailFinder, type) 300 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
300} 301}
301 302
302async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) { 303async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) {
@@ -319,13 +320,13 @@ async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost:
319 } 320 }
320 } 321 }
321 322
322 function emailFinder (email: object) { 323 function emailNotificationFinder (email: object) {
323 const text: string = email[ 'text' ] 324 const text: string = email['text']
324 325
325 return text.includes('instance has a new follower') && text.includes(followerHost) 326 return text.includes('instance has a new follower') && text.includes(followerHost)
326 } 327 }
327 328
328 await checkNotification(base, notificationChecker, emailFinder, type) 329 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
329} 330}
330 331
331async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) { 332async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) {
@@ -350,13 +351,13 @@ async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost
350 } 351 }
351 } 352 }
352 353
353 function emailFinder (email: object) { 354 function emailNotificationFinder (email: object) {
354 const text: string = email[ 'text' ] 355 const text: string = email['text']
355 356
356 return text.includes(' automatically followed a new instance') && text.includes(followingHost) 357 return text.includes(' automatically followed a new instance') && text.includes(followingHost)
357 } 358 }
358 359
359 await checkNotification(base, notificationChecker, emailFinder, type) 360 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
360} 361}
361 362
362async function checkCommentMention ( 363async function checkCommentMention (
@@ -384,16 +385,17 @@ async function checkCommentMention (
384 } 385 }
385 } 386 }
386 387
387 function emailFinder (email: object) { 388 function emailNotificationFinder (email: object) {
388 const text: string = email[ 'text' ] 389 const text: string = email['text']
389 390
390 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) 391 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
391 } 392 }
392 393
393 await checkNotification(base, notificationChecker, emailFinder, type) 394 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
394} 395}
395 396
396let lastEmailCount = 0 397let lastEmailCount = 0
398
397async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { 399async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
398 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO 400 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
399 401
@@ -413,11 +415,12 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string,
413 } 415 }
414 416
415 const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}` 417 const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}`
416 function emailFinder (email: object) { 418
417 return email[ 'text' ].indexOf(commentUrl) !== -1 419 function emailNotificationFinder (email: object) {
420 return email['text'].indexOf(commentUrl) !== -1
418 } 421 }
419 422
420 await checkNotification(base, notificationChecker, emailFinder, type) 423 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
421 424
422 if (type === 'presence') { 425 if (type === 'presence') {
423 // We cannot detect email duplicates, so check we received another email 426 // We cannot detect email duplicates, so check we received another email
@@ -443,12 +446,12 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU
443 } 446 }
444 } 447 }
445 448
446 function emailFinder (email: object) { 449 function emailNotificationFinder (email: object) {
447 const text = email[ 'text' ] 450 const text = email['text']
448 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 451 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
449 } 452 }
450 453
451 await checkNotification(base, notificationChecker, emailFinder, type) 454 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
452} 455}
453 456
454async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { 457async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
@@ -468,12 +471,12 @@ async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, vi
468 } 471 }
469 } 472 }
470 473
471 function emailFinder (email: object) { 474 function emailNotificationFinder (email: object) {
472 const text = email[ 'text' ] 475 const text = email['text']
473 return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1 476 return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
474 } 477 }
475 478
476 await checkNotification(base, notificationChecker, emailFinder, type) 479 await checkNotification(base, notificationChecker, emailNotificationFinder, type)
477} 480}
478 481
479async function checkNewBlacklistOnMyVideo ( 482async function checkNewBlacklistOnMyVideo (
@@ -495,12 +498,12 @@ async function checkNewBlacklistOnMyVideo (
495 checkVideo(video, videoName, videoUUID) 498 checkVideo(video, videoName, videoUUID)
496 } 499 }
497 500
498 function emailFinder (email: object) { 501 function emailNotificationFinder (email: object) {
499 const text = email[ 'text' ] 502 const text = email['text']
500 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 503 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
501 } 504 }
502 505
503 await checkNotification(base, notificationChecker, emailFinder, 'presence') 506 await checkNotification(base, notificationChecker, emailNotificationFinder, 'presence')
504} 507}
505 508
506// --------------------------------------------------------------------------- 509// ---------------------------------------------------------------------------
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
index 2fe0e55c2..54b506bce 100644
--- a/shared/extra-utils/users/users.ts
+++ b/shared/extra-utils/users/users.ts
@@ -9,14 +9,14 @@ import { UserUpdateMe } from '../../models/users'
9import { omit } from 'lodash' 9import { omit } from 'lodash'
10 10
11type CreateUserArgs = { 11type CreateUserArgs = {
12 url: string, 12 url: string
13 accessToken: string, 13 accessToken: string
14 username: string, 14 username: string
15 password: string, 15 password: string
16 videoQuota?: number, 16 videoQuota?: number
17 videoQuotaDaily?: number, 17 videoQuotaDaily?: number
18 role?: UserRole, 18 role?: UserRole
19 adminFlags?: UserAdminFlag, 19 adminFlags?: UserAdminFlag
20 specialStatus?: number 20 specialStatus?: number
21} 21}
22function createUser (parameters: CreateUserArgs) { 22function createUser (parameters: CreateUserArgs) {
@@ -74,8 +74,8 @@ function registerUser (url: string, username: string, password: string, specialS
74} 74}
75 75
76function registerUserWithChannel (options: { 76function registerUserWithChannel (options: {
77 url: string, 77 url: string
78 user: { username: string, password: string, displayName?: string }, 78 user: { username: string, password: string, displayName?: string }
79 channel: { name: string, displayName: string } 79 channel: { name: string, displayName: string }
80}) { 80}) {
81 const path = '/api/v1/users/register' 81 const path = '/api/v1/users/register'
@@ -130,11 +130,12 @@ function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatu
130 .expect('Content-Type', /json/) 130 .expect('Content-Type', /json/)
131} 131}
132 132
133function getUserInformation (url: string, accessToken: string, userId: number) { 133function getUserInformation (url: string, accessToken: string, userId: number, withStats = false) {
134 const path = '/api/v1/users/' + userId 134 const path = '/api/v1/users/' + userId
135 135
136 return request(url) 136 return request(url)
137 .get(path) 137 .get(path)
138 .query({ withStats })
138 .set('Accept', 'application/json') 139 .set('Accept', 'application/json')
139 .set('Authorization', 'Bearer ' + accessToken) 140 .set('Authorization', 'Bearer ' + accessToken)
140 .expect(200) 141 .expect(200)
@@ -230,8 +231,8 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat
230} 231}
231 232
232function updateMyAvatar (options: { 233function updateMyAvatar (options: {
233 url: string, 234 url: string
234 accessToken: string, 235 accessToken: string
235 fixture: string 236 fixture: string
236}) { 237}) {
237 const path = '/api/v1/users/me/avatar/pick' 238 const path = '/api/v1/users/me/avatar/pick'
@@ -241,14 +242,14 @@ function updateMyAvatar (options: {
241 242
242function updateUser (options: { 243function updateUser (options: {
243 url: string 244 url: string
244 userId: number, 245 userId: number
245 accessToken: string, 246 accessToken: string
246 email?: string, 247 email?: string
247 emailVerified?: boolean, 248 emailVerified?: boolean
248 videoQuota?: number, 249 videoQuota?: number
249 videoQuotaDaily?: number, 250 videoQuotaDaily?: number
250 password?: string, 251 password?: string
251 adminFlags?: UserAdminFlag, 252 adminFlags?: UserAdminFlag
252 role?: UserRole 253 role?: UserRole
253}) { 254}) {
254 const path = '/api/v1/users/' + options.userId 255 const path = '/api/v1/users/' + options.userId
diff --git a/shared/extra-utils/videos/video-abuses.ts b/shared/extra-utils/videos/video-abuses.ts
index 7f011ec0f..81582bfc7 100644
--- a/shared/extra-utils/videos/video-abuses.ts
+++ b/shared/extra-utils/videos/video-abuses.ts
@@ -1,6 +1,8 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' 2import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model'
3import { makeDeleteRequest, makePutBodyRequest } from '../requests/requests' 3import { makeDeleteRequest, makePutBodyRequest, makeGetRequest } from '../requests/requests'
4import { VideoAbuseState } from '@shared/models'
5import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type'
4 6
5function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) { 7function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) {
6 const path = '/api/v1/videos/' + videoId + '/abuse' 8 const path = '/api/v1/videos/' + videoId + '/abuse'
@@ -13,16 +15,51 @@ function reportVideoAbuse (url: string, token: string, videoId: number | string,
13 .expect(specialStatus) 15 .expect(specialStatus)
14} 16}
15 17
16function getVideoAbusesList (url: string, token: string) { 18function getVideoAbusesList (options: {
19 url: string
20 token: string
21 id?: number
22 search?: string
23 state?: VideoAbuseState
24 videoIs?: VideoAbuseVideoIs
25 searchReporter?: string
26 searchReportee?: string
27 searchVideo?: string
28 searchVideoChannel?: string
29}) {
30 const {
31 url,
32 token,
33 id,
34 search,
35 state,
36 videoIs,
37 searchReporter,
38 searchReportee,
39 searchVideo,
40 searchVideoChannel
41 } = options
17 const path = '/api/v1/videos/abuse' 42 const path = '/api/v1/videos/abuse'
18 43
19 return request(url) 44 const query = {
20 .get(path) 45 sort: 'createdAt',
21 .query({ sort: 'createdAt' }) 46 id,
22 .set('Accept', 'application/json') 47 search,
23 .set('Authorization', 'Bearer ' + token) 48 state,
24 .expect(200) 49 videoIs,
25 .expect('Content-Type', /json/) 50 searchReporter,
51 searchReportee,
52 searchVideo,
53 searchVideoChannel
54 }
55
56 return makeGetRequest({
57 url,
58 path,
59 token,
60 query,
61 statusCodeExpected: 200
62 })
26} 63}
27 64
28function updateVideoAbuse ( 65function updateVideoAbuse (
diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts
index e25a292fc..ba139ef95 100644
--- a/shared/extra-utils/videos/video-blacklist.ts
+++ b/shared/extra-utils/videos/video-blacklist.ts
@@ -13,11 +13,11 @@ function addVideoToBlacklist (
13 const path = '/api/v1/videos/' + videoId + '/blacklist' 13 const path = '/api/v1/videos/' + videoId + '/blacklist'
14 14
15 return request(url) 15 return request(url)
16 .post(path) 16 .post(path)
17 .send({ reason, unfederate }) 17 .send({ reason, unfederate })
18 .set('Accept', 'application/json') 18 .set('Accept', 'application/json')
19 .set('Authorization', 'Bearer ' + token) 19 .set('Authorization', 'Bearer ' + token)
20 .expect(specialStatus) 20 .expect(specialStatus)
21} 21}
22 22
23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { 23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
@@ -35,20 +35,20 @@ function removeVideoFromBlacklist (url: string, token: string, videoId: number |
35 const path = '/api/v1/videos/' + videoId + '/blacklist' 35 const path = '/api/v1/videos/' + videoId + '/blacklist'
36 36
37 return request(url) 37 return request(url)
38 .delete(path) 38 .delete(path)
39 .set('Accept', 'application/json') 39 .set('Accept', 'application/json')
40 .set('Authorization', 'Bearer ' + token) 40 .set('Authorization', 'Bearer ' + token)
41 .expect(specialStatus) 41 .expect(specialStatus)
42} 42}
43 43
44function getBlacklistedVideosList (parameters: { 44function getBlacklistedVideosList (parameters: {
45 url: string, 45 url: string
46 token: string, 46 token: string
47 sort?: string, 47 sort?: string
48 type?: VideoBlacklistType, 48 type?: VideoBlacklistType
49 specialStatus?: number 49 specialStatus?: number
50}) { 50}) {
51 let { url, token, sort, type, specialStatus = 200 } = parameters 51 const { url, token, sort, type, specialStatus = 200 } = parameters
52 const path = '/api/v1/videos/blacklist/' 52 const path = '/api/v1/videos/blacklist/'
53 53
54 const query = { sort, type } 54 const query = { sort, type }
diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts
index 8d67f617b..5bd533bba 100644
--- a/shared/extra-utils/videos/video-captions.ts
+++ b/shared/extra-utils/videos/video-captions.ts
@@ -6,12 +6,12 @@ import { buildAbsoluteFixturePath } from '../miscs/miscs'
6const expect = chai.expect 6const expect = chai.expect
7 7
8function createVideoCaption (args: { 8function createVideoCaption (args: {
9 url: string, 9 url: string
10 accessToken: string 10 accessToken: string
11 videoId: string | number 11 videoId: string | number
12 language: string 12 language: string
13 fixture: string, 13 fixture: string
14 mimeType?: string, 14 mimeType?: string
15 statusCodeExpected?: number 15 statusCodeExpected?: number
16}) { 16}) {
17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language 17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
index 053842331..55f08b996 100644
--- a/shared/extra-utils/videos/video-channels.ts
+++ b/shared/extra-utils/videos/video-channels.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' 4import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model'
3import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' 5import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
@@ -6,7 +8,7 @@ import { ServerInfo } from '../server/servers'
6import { User } from '../../models/users/user.model' 8import { User } from '../../models/users/user.model'
7import { getMyUserInformation } from '../users/users' 9import { getMyUserInformation } from '../users/users'
8 10
9function getVideoChannelsList (url: string, start: number, count: number, sort?: string) { 11function getVideoChannelsList (url: string, start: number, count: number, sort?: string, withStats?: boolean) {
10 const path = '/api/v1/video-channels' 12 const path = '/api/v1/video-channels'
11 13
12 const req = request(url) 14 const req = request(url)
@@ -15,6 +17,7 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?:
15 .query({ count: count }) 17 .query({ count: count })
16 18
17 if (sort) req.query({ sort }) 19 if (sort) req.query({ sort })
20 if (withStats) req.query({ withStats })
18 21
19 return req.set('Accept', 'application/json') 22 return req.set('Accept', 'application/json')
20 .expect(200) 23 .expect(200)
@@ -22,14 +25,15 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?:
22} 25}
23 26
24function getAccountVideoChannelsList (parameters: { 27function getAccountVideoChannelsList (parameters: {
25 url: string, 28 url: string
26 accountName: string, 29 accountName: string
27 start?: number, 30 start?: number
28 count?: number, 31 count?: number
29 sort?: string, 32 sort?: string
30 specialStatus?: number 33 specialStatus?: number
34 withStats?: boolean
31}) { 35}) {
32 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters 36 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200, withStats = false } = parameters
33 37
34 const path = '/api/v1/accounts/' + accountName + '/video-channels' 38 const path = '/api/v1/accounts/' + accountName + '/video-channels'
35 39
@@ -39,7 +43,8 @@ function getAccountVideoChannelsList (parameters: {
39 query: { 43 query: {
40 start, 44 start,
41 count, 45 count,
42 sort 46 sort,
47 withStats
43 }, 48 },
44 statusCodeExpected: specialStatus 49 statusCodeExpected: specialStatus
45 }) 50 })
@@ -113,9 +118,9 @@ function getVideoChannel (url: string, channelName: string) {
113} 118}
114 119
115function updateVideoChannelAvatar (options: { 120function updateVideoChannelAvatar (options: {
116 url: string, 121 url: string
117 accessToken: string, 122 accessToken: string
118 fixture: string, 123 fixture: string
119 videoChannelName: string | number 124 videoChannelName: string | number
120}) { 125}) {
121 126
@@ -129,7 +134,7 @@ function setDefaultVideoChannel (servers: ServerInfo[]) {
129 134
130 for (const server of servers) { 135 for (const server of servers) {
131 const p = getMyUserInformation(server.url, server.accessToken) 136 const p = getMyUserInformation(server.url, server.accessToken)
132 .then(res => server.videoChannel = (res.body as User).videoChannels[0]) 137 .then(res => { server.videoChannel = (res.body as User).videoChannels[0] })
133 138
134 tasks.push(p) 139 tasks.push(p)
135 } 140 }
diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts
index 0ebf69ced..81c48412d 100644
--- a/shared/extra-utils/videos/video-comments.ts
+++ b/shared/extra-utils/videos/video-comments.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { makeDeleteRequest } from '../requests/requests' 4import { makeDeleteRequest } from '../requests/requests'
3 5
diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts
index 150cc94ed..8e5abd2f5 100644
--- a/shared/extra-utils/videos/video-imports.ts
+++ b/shared/extra-utils/videos/video-imports.ts
@@ -7,7 +7,7 @@ function getYoutubeVideoUrl () {
7} 7}
8 8
9function getMagnetURI () { 9function getMagnetURI () {
10 // tslint:disable:max-line-length 10 // eslint-disable-next-line max-len
11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4' 11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
12} 12}
13 13
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts
index 6762c5973..5bcc02570 100644
--- a/shared/extra-utils/videos/video-playlists.ts
+++ b/shared/extra-utils/videos/video-playlists.ts
@@ -123,9 +123,9 @@ function deleteVideoPlaylist (url: string, token: string, playlistId: number | s
123} 123}
124 124
125function createVideoPlaylist (options: { 125function createVideoPlaylist (options: {
126 url: string, 126 url: string
127 token: string, 127 token: string
128 playlistAttrs: VideoPlaylistCreate, 128 playlistAttrs: VideoPlaylistCreate
129 expectedStatus?: number 129 expectedStatus?: number
130}) { 130}) {
131 const path = '/api/v1/video-playlists' 131 const path = '/api/v1/video-playlists'
@@ -148,10 +148,10 @@ function createVideoPlaylist (options: {
148} 148}
149 149
150function updateVideoPlaylist (options: { 150function updateVideoPlaylist (options: {
151 url: string, 151 url: string
152 token: string, 152 token: string
153 playlistAttrs: VideoPlaylistUpdate, 153 playlistAttrs: VideoPlaylistUpdate
154 playlistId: number | string, 154 playlistId: number | string
155 expectedStatus?: number 155 expectedStatus?: number
156}) { 156}) {
157 const path = '/api/v1/video-playlists/' + options.playlistId 157 const path = '/api/v1/video-playlists/' + options.playlistId
@@ -174,9 +174,9 @@ function updateVideoPlaylist (options: {
174} 174}
175 175
176async function addVideoInPlaylist (options: { 176async function addVideoInPlaylist (options: {
177 url: string, 177 url: string
178 token: string, 178 token: string
179 playlistId: number | string, 179 playlistId: number | string
180 elementAttrs: VideoPlaylistElementCreate | { videoId: string } 180 elementAttrs: VideoPlaylistElementCreate | { videoId: string }
181 expectedStatus?: number 181 expectedStatus?: number
182}) { 182}) {
@@ -194,11 +194,11 @@ async function addVideoInPlaylist (options: {
194} 194}
195 195
196function updateVideoPlaylistElement (options: { 196function updateVideoPlaylistElement (options: {
197 url: string, 197 url: string
198 token: string, 198 token: string
199 playlistId: number | string, 199 playlistId: number | string
200 playlistElementId: number | string, 200 playlistElementId: number | string
201 elementAttrs: VideoPlaylistElementUpdate, 201 elementAttrs: VideoPlaylistElementUpdate
202 expectedStatus?: number 202 expectedStatus?: number
203}) { 203}) {
204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -213,10 +213,10 @@ function updateVideoPlaylistElement (options: {
213} 213}
214 214
215function removeVideoFromPlaylist (options: { 215function removeVideoFromPlaylist (options: {
216 url: string, 216 url: string
217 token: string, 217 token: string
218 playlistId: number | string, 218 playlistId: number | string
219 playlistElementId: number, 219 playlistElementId: number
220 expectedStatus?: number 220 expectedStatus?: number
221}) { 221}) {
222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -230,14 +230,14 @@ function removeVideoFromPlaylist (options: {
230} 230}
231 231
232function reorderVideosPlaylist (options: { 232function reorderVideosPlaylist (options: {
233 url: string, 233 url: string
234 token: string, 234 token: string
235 playlistId: number | string, 235 playlistId: number | string
236 elementAttrs: { 236 elementAttrs: {
237 startPosition: number, 237 startPosition: number
238 insertAfterPosition: number, 238 insertAfterPosition: number
239 reorderLength?: number 239 reorderLength?: number
240 }, 240 }
241 expectedStatus?: number 241 expectedStatus?: number
242}) { 242}) {
243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' 243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts
index eb25011cb..e54da84aa 100644
--- a/shared/extra-utils/videos/video-streaming-playlists.ts
+++ b/shared/extra-utils/videos/video-streaming-playlists.ts
@@ -37,7 +37,7 @@ async function checkSegmentHash (
37 37
38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) 38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
39 39
40 const sha256Server = resSha.body[ videoName ][range] 40 const sha256Server = resSha.body[videoName][range]
41 expect(sha256(res2.body)).to.equal(sha256Server) 41 expect(sha256(res2.body)).to.equal(sha256Server)
42} 42}
43 43
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
index 7a77a03ad..0d36a38a2 100644
--- a/shared/extra-utils/videos/videos.ts
+++ b/shared/extra-utils/videos/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { pathExists, readdir, readFile } from 'fs-extra' 4import { pathExists, readdir, readFile } from 'fs-extra'
@@ -95,6 +95,14 @@ function getVideo (url: string, id: number | string, expectedStatus = 200) {
95 .expect(expectedStatus) 95 .expect(expectedStatus)
96} 96}
97 97
98function getVideoFileMetadataUrl (url: string) {
99 return request(url)
100 .get('/')
101 .set('Accept', 'application/json')
102 .expect(200)
103 .expect('Content-Type', /json/)
104}
105
98function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) { 106function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) {
99 const path = '/api/v1/videos/' + id + '/views' 107 const path = '/api/v1/videos/' + id + '/views'
100 108
@@ -488,7 +496,7 @@ async function completeVideoCheck (
488 description: string 496 description: string
489 publishedAt?: string 497 publishedAt?: string
490 support: string 498 support: string
491 originallyPublishedAt?: string, 499 originallyPublishedAt?: string
492 account: { 500 account: {
493 name: string 501 name: string
494 host: string 502 host: string
@@ -509,7 +517,7 @@ async function completeVideoCheck (
509 files: { 517 files: {
510 resolution: number 518 resolution: number
511 size: number 519 size: number
512 }[], 520 }[]
513 thumbnailfile?: string 521 thumbnailfile?: string
514 previewfile?: string 522 previewfile?: string
515 } 523 }
@@ -583,9 +591,10 @@ async function completeVideoCheck (
583 591
584 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) 592 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
585 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) 593 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
586 expect(file.size, 594 expect(
587 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') 595 file.size,
588 .to.be.above(minSize).and.below(maxSize) 596 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
597 ).to.be.above(minSize).and.below(maxSize)
589 598
590 const torrent = await webtorrentAdd(file.magnetUri, true) 599 const torrent = await webtorrentAdd(file.magnetUri, true)
591 expect(torrent.files).to.be.an('array') 600 expect(torrent.files).to.be.an('array')
@@ -607,15 +616,28 @@ async function videoUUIDToId (url: string, id: number | string) {
607 return res.body.id 616 return res.body.id
608} 617}
609 618
610async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) { 619async function uploadVideoAndGetId (options: {
620 server: ServerInfo
621 videoName: string
622 nsfw?: boolean
623 privacy?: VideoPrivacy
624 token?: string
625}) {
611 const videoAttrs: any = { name: options.videoName } 626 const videoAttrs: any = { name: options.videoName }
612 if (options.nsfw) videoAttrs.nsfw = options.nsfw 627 if (options.nsfw) videoAttrs.nsfw = options.nsfw
628 if (options.privacy) videoAttrs.privacy = options.privacy
613 629
614 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs) 630 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
615 631
616 return { id: res.body.video.id, uuid: res.body.video.uuid } 632 return { id: res.body.video.id, uuid: res.body.video.uuid }
617} 633}
618 634
635async function getLocalIdByUUID (url: string, uuid: string) {
636 const res = await getVideo(url, uuid)
637
638 return res.body.id
639}
640
619// --------------------------------------------------------------------------- 641// ---------------------------------------------------------------------------
620 642
621export { 643export {
@@ -629,6 +651,7 @@ export {
629 getAccountVideos, 651 getAccountVideos,
630 getVideoChannelVideos, 652 getVideoChannelVideos,
631 getVideo, 653 getVideo,
654 getVideoFileMetadataUrl,
632 getVideoWithToken, 655 getVideoWithToken,
633 getVideosList, 656 getVideosList,
634 getVideosListPagination, 657 getVideosListPagination,
@@ -645,5 +668,6 @@ export {
645 completeVideoCheck, 668 completeVideoCheck,
646 checkVideoFilesWereRemoved, 669 checkVideoFilesWereRemoved,
647 getPlaylistVideos, 670 getPlaylistVideos,
648 uploadVideoAndGetId 671 uploadVideoAndGetId,
672 getLocalIdByUUID
649} 673}