diff options
Diffstat (limited to 'shared')
75 files changed, 1067 insertions, 406 deletions
diff --git a/shared/core-utils/miscs/miscs.ts b/shared/core-utils/miscs/miscs.ts index 5de024c08..1eee22d82 100644 --- a/shared/core-utils/miscs/miscs.ts +++ b/shared/core-utils/miscs/miscs.ts | |||
@@ -11,7 +11,7 @@ function compareSemVer (a: string, b: string) { | |||
11 | const l = Math.min(segmentsA.length, segmentsB.length) | 11 | const l = Math.min(segmentsA.length, segmentsB.length) |
12 | 12 | ||
13 | for (let i = 0; i < l; i++) { | 13 | for (let i = 0; i < l; i++) { |
14 | const diff = parseInt(segmentsA[ i ], 10) - parseInt(segmentsB[ i ], 10) | 14 | const diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10) |
15 | 15 | ||
16 | if (diff) return diff | 16 | if (diff) return diff |
17 | } | 17 | } |
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' | |||
18 | export * from './users/accounts' | 18 | export * from './users/accounts' |
19 | export * from './videos/video-abuses' | 19 | export * from './videos/video-abuses' |
20 | export * from './videos/video-blacklist' | 20 | export * from './videos/video-blacklist' |
21 | export * from './videos/video-captions' | ||
21 | export * from './videos/video-channels' | 22 | export * from './videos/video-channels' |
22 | export * from './videos/video-comments' | 23 | export * from './videos/video-comments' |
23 | export * from './videos/video-streaming-playlists' | 24 | export * from './videos/video-streaming-playlists' |
@@ -26,3 +27,4 @@ export * from './videos/video-change-ownership' | |||
26 | export * from './feeds/feeds' | 27 | export * from './feeds/feeds' |
27 | export * from './instances-index/mock-instances-index' | 28 | export * from './instances-index/mock-instances-index' |
28 | export * from './search/videos' | 29 | export * from './search/videos' |
30 | export * 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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | 2 | ||
3 | export class MockInstancesIndex { | 3 | export 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 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { basename, dirname, isAbsolute, join, resolve } from 'path' | 4 | import { basename, dirname, isAbsolute, join, resolve } from 'path' |
@@ -10,11 +10,11 @@ import * as ffmpeg from 'fluent-ffmpeg' | |||
10 | const expect = chai.expect | 10 | const expect = chai.expect |
11 | let webtorrent: WebTorrent.Instance | 11 | let webtorrent: WebTorrent.Instance |
12 | 12 | ||
13 | function immutableAssign <T, U> (target: T, source: U) { | 13 | function 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 |
18 | function dateIsValid (dateString: string, interval = 300000) { | 18 | function 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 | ||
107 | async 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 | ||
109 | export { | 131 | export { |
@@ -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 @@ | |||
1 | import { QueryTypes, Sequelize } from 'sequelize' | 1 | import { QueryTypes, Sequelize } from 'sequelize' |
2 | import { ServerInfo } from '../server/servers' | 2 | import { ServerInfo } from '../server/servers' |
3 | 3 | ||
4 | let sequelizes: { [ id: number ]: Sequelize } = {} | 4 | const sequelizes: { [ id: number ]: Sequelize } = {} |
5 | 5 | ||
6 | function getSequelize (internalServerNumber: number) { | 6 | function 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 | ||
66 | async function closeAllSequelize (servers: ServerInfo[]) { | 66 | async 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 @@ | |||
1 | import { makeGetRequest } from '../requests/requests' | 1 | import { makeGetRequest } from '../requests/requests' |
2 | 2 | ||
3 | function getVideosOverview (url: string, useCache = false) { | 3 | function 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 | ||
18 | export { getVideosOverview } | 16 | function 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 | |||
30 | export { | ||
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 @@ | |||
1 | import * as express from 'express' | ||
2 | |||
3 | type BlocklistResponse = { | ||
4 | data: { | ||
5 | value: string | ||
6 | action?: 'add' | 'remove' | ||
7 | updatedAt?: string | ||
8 | }[] | ||
9 | } | ||
10 | |||
11 | export 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 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { buildAbsoluteFixturePath, root } from '../miscs/miscs' | 4 | import { buildAbsoluteFixturePath, root } from '../miscs/miscs' |
3 | import { isAbsolute, join } from 'path' | 5 | import { isAbsolute, join } from 'path' |
4 | import { parse } from 'url' | 6 | import { URL } from 'url' |
7 | import { decode } from 'querystring' | ||
5 | 8 | ||
6 | function get4KFileUrl () { | 9 | function 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 | ||
10 | function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { | 13 | function 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 | ||
16 | function makeGetRequest (options: { | 19 | function 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 | ||
38 | function makeDeleteRequest (options: { | 43 | function 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 | ||
55 | function makeUploadRequest (options: { | 60 | function 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 | ||
103 | function makePostBodyRequest (options: { | 108 | function 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 | ||
123 | function makePutBodyRequest (options: { | 128 | function 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 | ||
149 | function updateAvatarRequest (options: { | 154 | function 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 | ||
177 | function decodeQueryString (path: string) { | ||
178 | return decode(path.split('?')[1]) | ||
179 | } | ||
180 | |||
172 | // --------------------------------------------------------------------------- | 181 | // --------------------------------------------------------------------------- |
173 | 182 | ||
174 | export { | 183 | export { |
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 | ||
3 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
4 | import { VideosSearchQuery } from '../../models/search' | 4 | import { 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 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import * as urlUtil from 'url' | 2 | import { URL } from 'url' |
3 | 3 | ||
4 | function getClient (url: string) { | 4 | function 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' | |||
2 | import { ContactForm } from '../../models/server' | 2 | import { ContactForm } from '../../models/server' |
3 | 3 | ||
4 | function sendContactForm (options: { | 4 | function 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' | |||
5 | import { ActivityPubActorType, FollowState } from '@shared/models' | 5 | import { ActivityPubActorType, FollowState } from '@shared/models' |
6 | 6 | ||
7 | function getFollowersListPaginationAndSort (options: { | 7 | function 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 | ||
58 | function getFollowingListPaginationAndSort (options: { | 58 | function 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 | ||
18 | function getJobsListPaginationAndSort (options: { | 18 | function 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' | |||
7 | import { join } from 'path' | 7 | import { join } from 'path' |
8 | 8 | ||
9 | function listPlugins (parameters: { | 9 | function 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 | ||
37 | function listAvailablePlugins (parameters: { | 37 | function 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 | ||
69 | function getPlugin (parameters: { | 69 | function 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 | ||
86 | function updatePluginSettings (parameters: { | 86 | function 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 | ||
105 | function getPluginRegisteredSettings (parameters: { | 105 | function 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 | ||
122 | function getPublicSettings (parameters: { | 122 | function 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 | ||
137 | function getPluginTranslations (parameters: { | 137 | function 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 | ||
152 | function installPlugin (parameters: { | 152 | function 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 | ||
171 | function updatePlugin (parameters: { | 171 | function 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 | ||
190 | function uninstallPlugin (parameters: { | 190 | function 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 | ||
238 | function 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 | |||
238 | export { | 259 | export { |
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 @@ | |||
1 | import { makePutBodyRequest } from '../requests/requests' | 1 | import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' |
2 | import { VideoRedundanciesTarget } from '@shared/models' | ||
2 | 3 | ||
3 | async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { | 4 | function 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 | ||
16 | function 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 | |||
43 | function 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 | |||
60 | function 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 | |||
15 | export { | 76 | export { |
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 | ||
3 | import { ChildProcess, exec, fork } from 'child_process' | 3 | import { ChildProcess, exec, fork } from 'child_process' |
4 | import { join } from 'path' | 4 | import { join } from 'path' |
5 | import { root, wait } from '../miscs/miscs' | 5 | import { root, wait } from '../miscs/miscs' |
6 | import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' | 6 | import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' |
7 | import { existsSync } from 'fs' | ||
8 | import { expect } from 'chai' | 7 | import { expect } from 'chai' |
9 | import { VideoChannel } from '../../models/videos' | 8 | import { VideoChannel } from '../../models/videos' |
10 | import { randomInt } from '../../core-utils/miscs/miscs' | 9 | import { randomInt } from '../../core-utils/miscs/miscs' |
11 | 10 | ||
12 | interface ServerInfo { | 11 | interface 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 | ||
59 | function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { | 58 | function 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 | ||
289 | async function waitUntilLog (server: ServerInfo, str: string, count = 1) { | 288 | async 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 | ||
3 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
4 | import { expect } from 'chai' | 4 | import { 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 | ||
3 | import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' | 3 | import { 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 | ||
30 | function 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 | |||
30 | async function serverLogin (server: Server) { | 40 | async 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 | ||
46 | function 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 | |||
36 | async function userLogin (server: Server, user: User, expectedStatus = 200) { | 64 | async 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 | ||
98 | function 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 | ||
72 | export { | 120 | export { |
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 | ||
3 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' | 3 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' |
4 | import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' | 4 | import { 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 | |||
57 | function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { | 58 | function 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 | ||
182 | async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { | 183 | async 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 | ||
205 | async function checkMyVideoImportIsFinished ( | 206 | async 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 | ||
238 | async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) { | 239 | async 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 | ||
262 | async function checkNewActorFollow ( | 263 | async 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 | ||
302 | async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) { | 303 | async 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 | ||
331 | async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) { | 332 | async 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 | ||
362 | async function checkCommentMention ( | 363 | async 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 | ||
396 | let lastEmailCount = 0 | 397 | let lastEmailCount = 0 |
398 | |||
397 | async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { | 399 | async 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 | ||
454 | async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 457 | async 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 | ||
479 | async function checkNewBlacklistOnMyVideo ( | 482 | async 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' | |||
9 | import { omit } from 'lodash' | 9 | import { omit } from 'lodash' |
10 | 10 | ||
11 | type CreateUserArgs = { | 11 | type 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 | } |
22 | function createUser (parameters: CreateUserArgs) { | 22 | function createUser (parameters: CreateUserArgs) { |
@@ -74,8 +74,8 @@ function registerUser (url: string, username: string, password: string, specialS | |||
74 | } | 74 | } |
75 | 75 | ||
76 | function registerUserWithChannel (options: { | 76 | function 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 | ||
133 | function getUserInformation (url: string, accessToken: string, userId: number) { | 133 | function 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 | ||
232 | function updateMyAvatar (options: { | 233 | function 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 | ||
242 | function updateUser (options: { | 243 | function 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 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' | 2 | import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' |
3 | import { makeDeleteRequest, makePutBodyRequest } from '../requests/requests' | 3 | import { makeDeleteRequest, makePutBodyRequest, makeGetRequest } from '../requests/requests' |
4 | import { VideoAbuseState } from '@shared/models' | ||
5 | import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' | ||
4 | 6 | ||
5 | function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) { | 7 | function 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 | ||
16 | function getVideoAbusesList (url: string, token: string) { | 18 | function 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 | ||
28 | function updateVideoAbuse ( | 65 | function 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 | ||
23 | function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { | 23 | function 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 | ||
44 | function getBlacklistedVideosList (parameters: { | 44 | function 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' | |||
6 | const expect = chai.expect | 6 | const expect = chai.expect |
7 | 7 | ||
8 | function createVideoCaption (args: { | 8 | function 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 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' | 4 | import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' |
3 | import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' | 5 | import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' |
@@ -6,7 +8,7 @@ import { ServerInfo } from '../server/servers' | |||
6 | import { User } from '../../models/users/user.model' | 8 | import { User } from '../../models/users/user.model' |
7 | import { getMyUserInformation } from '../users/users' | 9 | import { getMyUserInformation } from '../users/users' |
8 | 10 | ||
9 | function getVideoChannelsList (url: string, start: number, count: number, sort?: string) { | 11 | function 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 | ||
24 | function getAccountVideoChannelsList (parameters: { | 27 | function 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 | ||
115 | function updateVideoChannelAvatar (options: { | 120 | function 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 | |||
1 | import * as request from 'supertest' | 3 | import * as request from 'supertest' |
2 | import { makeDeleteRequest } from '../requests/requests' | 4 | import { 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 | ||
9 | function getMagnetURI () { | 9 | function 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 | ||
125 | function createVideoPlaylist (options: { | 125 | function 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 | ||
150 | function updateVideoPlaylist (options: { | 150 | function 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 | ||
176 | async function addVideoInPlaylist (options: { | 176 | async 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 | ||
196 | function updateVideoPlaylistElement (options: { | 196 | function 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 | ||
215 | function removeVideoFromPlaylist (options: { | 215 | function 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 | ||
232 | function reorderVideosPlaylist (options: { | 232 | function 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 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { pathExists, readdir, readFile } from 'fs-extra' | 4 | import { 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 | ||
98 | function getVideoFileMetadataUrl (url: string) { | ||
99 | return request(url) | ||
100 | .get('/') | ||
101 | .set('Accept', 'application/json') | ||
102 | .expect(200) | ||
103 | .expect('Content-Type', /json/) | ||
104 | } | ||
105 | |||
98 | function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) { | 106 | function 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 | ||
610 | async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) { | 619 | async 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 | ||
635 | async 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 | ||
621 | export { | 643 | export { |
@@ -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 | } |
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts index 492b672c7..20ecf176c 100644 --- a/shared/models/activitypub/activity.ts +++ b/shared/models/activitypub/activity.ts | |||
@@ -8,12 +8,33 @@ import { ViewObject } from './objects/view-object' | |||
8 | import { APObject } from './objects/object.model' | 8 | import { APObject } from './objects/object.model' |
9 | import { PlaylistObject } from './objects/playlist-object' | 9 | import { PlaylistObject } from './objects/playlist-object' |
10 | 10 | ||
11 | export type Activity = ActivityCreate | ActivityUpdate | | 11 | export type Activity = |
12 | ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce | | 12 | ActivityCreate | |
13 | ActivityUndo | ActivityLike | ActivityReject | ActivityView | ActivityDislike | ActivityFlag | 13 | ActivityUpdate | |
14 | 14 | ActivityDelete | | |
15 | export type ActivityType = 'Create' | 'Update' | 'Delete' | 'Follow' | 'Accept' | 'Announce' | 'Undo' | 'Like' | 'Reject' | | 15 | ActivityFollow | |
16 | 'View' | 'Dislike' | 'Flag' | 16 | ActivityAccept | |
17 | ActivityAnnounce | | ||
18 | ActivityUndo | | ||
19 | ActivityLike | | ||
20 | ActivityReject | | ||
21 | ActivityView | | ||
22 | ActivityDislike | | ||
23 | ActivityFlag | ||
24 | |||
25 | export type ActivityType = | ||
26 | 'Create' | | ||
27 | 'Update' | | ||
28 | 'Delete' | | ||
29 | 'Follow' | | ||
30 | 'Accept' | | ||
31 | 'Announce' | | ||
32 | 'Undo' | | ||
33 | 'Like' | | ||
34 | 'Reject' | | ||
35 | 'View' | | ||
36 | 'Dislike' | | ||
37 | 'Flag' | ||
17 | 38 | ||
18 | export interface ActivityAudience { | 39 | export interface ActivityAudience { |
19 | to: string[] | 40 | to: string[] |
@@ -66,17 +87,17 @@ export interface ActivityAnnounce extends BaseActivity { | |||
66 | } | 87 | } |
67 | 88 | ||
68 | export interface ActivityUndo extends BaseActivity { | 89 | export interface ActivityUndo extends BaseActivity { |
69 | type: 'Undo', | 90 | type: 'Undo' |
70 | object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce | 91 | object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce |
71 | } | 92 | } |
72 | 93 | ||
73 | export interface ActivityLike extends BaseActivity { | 94 | export interface ActivityLike extends BaseActivity { |
74 | type: 'Like', | 95 | type: 'Like' |
75 | object: APObject | 96 | object: APObject |
76 | } | 97 | } |
77 | 98 | ||
78 | export interface ActivityView extends BaseActivity { | 99 | export interface ActivityView extends BaseActivity { |
79 | type: 'View', | 100 | type: 'View' |
80 | actor: string | 101 | actor: string |
81 | object: APObject | 102 | object: APObject |
82 | } | 103 | } |
@@ -89,7 +110,7 @@ export interface ActivityDislike extends BaseActivity { | |||
89 | } | 110 | } |
90 | 111 | ||
91 | export interface ActivityFlag extends BaseActivity { | 112 | export interface ActivityFlag extends BaseActivity { |
92 | type: 'Flag', | 113 | type: 'Flag' |
93 | content: string, | 114 | content: string |
94 | object: APObject | APObject[] | 115 | object: APObject | APObject[] |
95 | } | 116 | } |
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts index b8a2dc925..f022f3d02 100644 --- a/shared/models/activitypub/activitypub-actor.ts +++ b/shared/models/activitypub/activitypub-actor.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { ActivityPubAttributedTo } from './objects/common-objects' | 1 | import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects' |
2 | 2 | ||
3 | export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' | 3 | export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' |
4 | 4 | ||
@@ -27,9 +27,5 @@ export interface ActivityPubActor { | |||
27 | publicKeyPem: string | 27 | publicKeyPem: string |
28 | } | 28 | } |
29 | 29 | ||
30 | icon: { | 30 | icon: ActivityIconObject |
31 | type: 'Image' | ||
32 | mediaType: 'image/png' | ||
33 | url: string | ||
34 | } | ||
35 | } | 31 | } |
diff --git a/shared/models/activitypub/activitypub-signature.ts b/shared/models/activitypub/activitypub-signature.ts index 1d9f4b3b3..fafdc246d 100644 --- a/shared/models/activitypub/activitypub-signature.ts +++ b/shared/models/activitypub/activitypub-signature.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | export interface ActivityPubSignature { | 1 | export interface ActivityPubSignature { |
2 | type: 'GraphSignature2012' | 2 | type: string |
3 | created: Date, | 3 | created: Date |
4 | creator: string | 4 | creator: string |
5 | signatureValue: string | 5 | signatureValue: string |
6 | } | 6 | } |
diff --git a/shared/models/activitypub/context.ts b/shared/models/activitypub/context.ts new file mode 100644 index 000000000..bd795a2fd --- /dev/null +++ b/shared/models/activitypub/context.ts | |||
@@ -0,0 +1 @@ | |||
export type ContextType = 'All' | 'View' | 'Announce' | 'CacheFile' | |||
diff --git a/shared/models/activitypub/objects/cache-file-object.ts b/shared/models/activitypub/objects/cache-file-object.ts index 4b0a3a724..19a817582 100644 --- a/shared/models/activitypub/objects/cache-file-object.ts +++ b/shared/models/activitypub/objects/cache-file-object.ts | |||
@@ -2,7 +2,7 @@ import { ActivityVideoUrlObject, ActivityPlaylistUrlObject } from './common-obje | |||
2 | 2 | ||
3 | export interface CacheFileObject { | 3 | export interface CacheFileObject { |
4 | id: string | 4 | id: string |
5 | type: 'CacheFile', | 5 | type: 'CacheFile' |
6 | object: string | 6 | object: string |
7 | expires: string | 7 | expires: string |
8 | url: ActivityVideoUrlObject | ActivityPlaylistUrlObject | 8 | url: ActivityVideoUrlObject | ActivityPlaylistUrlObject |
diff --git a/shared/models/activitypub/objects/common-objects.ts b/shared/models/activitypub/objects/common-objects.ts index de1116ab3..bb3ffe678 100644 --- a/shared/models/activitypub/objects/common-objects.ts +++ b/shared/models/activitypub/objects/common-objects.ts | |||
@@ -1,14 +1,15 @@ | |||
1 | export interface ActivityIdentifierObject { | 1 | export interface ActivityIdentifierObject { |
2 | identifier: string | 2 | identifier: string |
3 | name: string | 3 | name: string |
4 | url?: string | ||
4 | } | 5 | } |
5 | 6 | ||
6 | export interface ActivityIconObject { | 7 | export interface ActivityIconObject { |
7 | type: 'Image' | 8 | type: 'Image' |
8 | url: string | 9 | url: string |
9 | mediaType: 'image/jpeg' | 10 | mediaType: 'image/jpeg' | 'image/png' |
10 | width: number | 11 | width?: number |
11 | height: number | 12 | height?: number |
12 | } | 13 | } |
13 | 14 | ||
14 | export type ActivityVideoUrlObject = { | 15 | export type ActivityVideoUrlObject = { |
@@ -27,6 +28,15 @@ export type ActivityPlaylistSegmentHashesObject = { | |||
27 | href: string | 28 | href: string |
28 | } | 29 | } |
29 | 30 | ||
31 | export type ActivityVideoFileMetadataObject = { | ||
32 | type: 'Link' | ||
33 | rel: [ 'metadata', any ] | ||
34 | mediaType: 'application/json' | ||
35 | height: number | ||
36 | href: string | ||
37 | fps: number | ||
38 | } | ||
39 | |||
30 | export type ActivityPlaylistInfohashesObject = { | 40 | export type ActivityPlaylistInfohashesObject = { |
31 | type: 'Infohash' | 41 | type: 'Infohash' |
32 | name: string | 42 | name: string |
@@ -71,19 +81,23 @@ export interface ActivityMentionObject { | |||
71 | name: string | 81 | name: string |
72 | } | 82 | } |
73 | 83 | ||
74 | export type ActivityTagObject = ActivityPlaylistSegmentHashesObject | | 84 | export type ActivityTagObject = |
75 | ActivityPlaylistInfohashesObject | | 85 | ActivityPlaylistSegmentHashesObject |
76 | ActivityVideoUrlObject | | 86 | | ActivityPlaylistInfohashesObject |
77 | ActivityHashTagObject | | 87 | | ActivityVideoUrlObject |
78 | ActivityMentionObject | | 88 | | ActivityHashTagObject |
79 | ActivityBitTorrentUrlObject | | 89 | | ActivityMentionObject |
80 | ActivityMagnetUrlObject | 90 | | ActivityBitTorrentUrlObject |
91 | | ActivityMagnetUrlObject | ||
92 | | ActivityVideoFileMetadataObject | ||
81 | 93 | ||
82 | export type ActivityUrlObject = ActivityVideoUrlObject | | 94 | export type ActivityUrlObject = |
83 | ActivityPlaylistUrlObject | | 95 | ActivityVideoUrlObject |
84 | ActivityBitTorrentUrlObject | | 96 | | ActivityPlaylistUrlObject |
85 | ActivityMagnetUrlObject | | 97 | | ActivityBitTorrentUrlObject |
86 | ActivityHtmlUrlObject | 98 | | ActivityMagnetUrlObject |
99 | | ActivityHtmlUrlObject | ||
100 | | ActivityVideoFileMetadataObject | ||
87 | 101 | ||
88 | export interface ActivityPubAttributedTo { | 102 | export interface ActivityPubAttributedTo { |
89 | type: 'Group' | 'Person' | 103 | type: 'Group' | 'Person' |
diff --git a/shared/models/activitypub/objects/video-abuse-object.ts b/shared/models/activitypub/objects/video-abuse-object.ts index 5f1264a76..d9622b414 100644 --- a/shared/models/activitypub/objects/video-abuse-object.ts +++ b/shared/models/activitypub/objects/video-abuse-object.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface VideoAbuseObject { | 1 | export interface VideoAbuseObject { |
2 | type: 'Flag', | 2 | type: 'Flag' |
3 | content: string | 3 | content: string |
4 | object: string | string[] | 4 | object: string | string[] |
5 | } | 5 | } |
diff --git a/shared/models/activitypub/objects/video-torrent-object.ts b/shared/models/activitypub/objects/video-torrent-object.ts index 239822bc4..11de8fc56 100644 --- a/shared/models/activitypub/objects/video-torrent-object.ts +++ b/shared/models/activitypub/objects/video-torrent-object.ts | |||
@@ -20,8 +20,8 @@ export interface VideoTorrentObject { | |||
20 | subtitleLanguage: ActivityIdentifierObject[] | 20 | subtitleLanguage: ActivityIdentifierObject[] |
21 | views: number | 21 | views: number |
22 | sensitive: boolean | 22 | sensitive: boolean |
23 | commentsEnabled: boolean, | 23 | commentsEnabled: boolean |
24 | downloadEnabled: boolean, | 24 | downloadEnabled: boolean |
25 | waitTranscoding: boolean | 25 | waitTranscoding: boolean |
26 | state: VideoState | 26 | state: VideoState |
27 | published: string | 27 | published: string |
@@ -30,7 +30,9 @@ export interface VideoTorrentObject { | |||
30 | mediaType: 'text/markdown' | 30 | mediaType: 'text/markdown' |
31 | content: string | 31 | content: string |
32 | support: string | 32 | support: string |
33 | icon: ActivityIconObject | 33 | |
34 | icon: ActivityIconObject[] | ||
35 | |||
34 | url: ActivityUrlObject[] | 36 | url: ActivityUrlObject[] |
35 | likes: string | 37 | likes: string |
36 | dislikes: string | 38 | dislikes: string |
diff --git a/shared/models/activitypub/objects/view-object.ts b/shared/models/activitypub/objects/view-object.ts index 00348116a..4dd21ce8e 100644 --- a/shared/models/activitypub/objects/view-object.ts +++ b/shared/models/activitypub/objects/view-object.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface ViewObject { | 1 | export interface ViewObject { |
2 | type: 'View', | 2 | type: 'View' |
3 | actor: string | 3 | actor: string |
4 | object: string | 4 | object: string |
5 | } | 5 | } |
diff --git a/shared/models/i18n/i18n.ts b/shared/models/i18n/i18n.ts index 032944281..46940772f 100644 --- a/shared/models/i18n/i18n.ts +++ b/shared/models/i18n/i18n.ts | |||
@@ -1,46 +1,56 @@ | |||
1 | export const LOCALE_FILES = [ 'player', 'server' ] | 1 | export const LOCALE_FILES = [ 'player', 'server' ] |
2 | 2 | ||
3 | export const I18N_LOCALES = { | 3 | export const I18N_LOCALES = { |
4 | // Always first to avoid issues when using express acceptLanguages function when no accept language header is set | ||
4 | 'en-US': 'English', | 5 | 'en-US': 'English', |
5 | 'fr-FR': 'Français', | 6 | |
6 | 'ja-JP': '日本語', | ||
7 | 'eu-ES': 'Euskara', | ||
8 | 'ca-ES': 'Català', | 7 | 'ca-ES': 'Català', |
9 | 'cs-CZ': 'Čeština', | 8 | 'cs-CZ': 'Čeština', |
10 | 'eo': 'Esperanto', | ||
11 | 'el-GR': 'ελληνικά', | ||
12 | 'de-DE': 'Deutsch', | 9 | 'de-DE': 'Deutsch', |
13 | 'it-IT': 'Italiano', | 10 | 'el-GR': 'ελληνικά', |
14 | 'nl-NL': 'Nederlands', | 11 | 'eo': 'Esperanto', |
15 | 'es-ES': 'Español', | 12 | 'es-ES': 'Español', |
16 | 'oc': 'Occitan', | 13 | 'eu-ES': 'Euskara', |
14 | 'fi-FI': 'suomi', | ||
15 | 'fr-FR': 'Français', | ||
17 | 'gd': 'Gàidhlig', | 16 | 'gd': 'Gàidhlig', |
18 | 'zh-Hant-TW': '繁體中文(台灣)', | 17 | 'hu-HU': 'magyar', |
18 | 'it-IT': 'Italiano', | ||
19 | 'ja-JP': '日本語', | ||
20 | 'nl-NL': 'Nederlands', | ||
21 | 'pl-PL': 'Polski', | ||
19 | 'pt-BR': 'Português (Brasil)', | 22 | 'pt-BR': 'Português (Brasil)', |
20 | 'pt-PT': 'Português (Portugal)', | 23 | 'pt-PT': 'Português (Portugal)', |
21 | 'sv-SE': 'svenska', | ||
22 | 'pl-PL': 'Polski', | ||
23 | 'fi-FI': 'suomi', | ||
24 | 'ru-RU': 'русский', | 24 | 'ru-RU': 'русский', |
25 | 'zh-Hans-CN': '简体中文(中国)' | 25 | 'sv-SE': 'svenska', |
26 | 'th-TH': 'ไทย', | ||
27 | 'zh-Hans-CN': '简体中文(中国)', | ||
28 | 'zh-Hant-TW': '繁體中文(台灣)' | ||
26 | } | 29 | } |
27 | 30 | ||
28 | const I18N_LOCALE_ALIAS = { | 31 | const I18N_LOCALE_ALIAS = { |
29 | 'en': 'en-US', | ||
30 | 'fr': 'fr-FR', | ||
31 | 'eu': 'eu-ES', | ||
32 | 'ca': 'ca-ES', | 32 | 'ca': 'ca-ES', |
33 | 'cs': 'cs-CZ', | 33 | 'cs': 'cs-CZ', |
34 | 'de': 'de-DE', | 34 | 'de': 'de-DE', |
35 | 'el': 'el-GR', | ||
36 | 'en': 'en-US', | ||
35 | 'es': 'es-ES', | 37 | 'es': 'es-ES', |
36 | 'pt': 'pt-PT', | 38 | 'eu': 'eu-ES', |
37 | 'fi': 'fi-FI', | 39 | 'fi': 'fi-FI', |
38 | 'sv': 'sv-SE', | 40 | 'fr': 'fr-FR', |
41 | 'ja': 'ja-JP', | ||
42 | 'it': 'it-IT', | ||
43 | 'hu': 'hu-HU', | ||
44 | 'nl': 'nl-NL', | ||
39 | 'pl': 'pl-PL', | 45 | 'pl': 'pl-PL', |
46 | 'pt': 'pt-BR', | ||
40 | 'ru': 'ru-RU', | 47 | 'ru': 'ru-RU', |
41 | 'nl': 'nl-NL', | 48 | 'sv': 'sv-SE', |
49 | 'th': 'th-TH', | ||
42 | 'zh': 'zh-Hans-CN', | 50 | 'zh': 'zh-Hans-CN', |
51 | 'zh-Hans': 'zh-Hans-CN', | ||
43 | 'zh-CN': 'zh-Hans-CN', | 52 | 'zh-CN': 'zh-Hans-CN', |
53 | 'zh-Hant': 'zh-Hant-TW', | ||
44 | 'zh-TW': 'zh-Hant-TW' | 54 | 'zh-TW': 'zh-Hant-TW' |
45 | } | 55 | } |
46 | 56 | ||
@@ -56,16 +66,18 @@ export function isDefaultLocale (locale: string) { | |||
56 | } | 66 | } |
57 | 67 | ||
58 | export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { | 68 | export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { |
69 | // FIXME: remove disable rule when the client is upgraded to typescript 3.7 | ||
70 | // eslint-disable-next-line | ||
59 | return translations && translations[str] ? translations[str] : str | 71 | return translations && translations[str] ? translations[str] : str |
60 | } | 72 | } |
61 | 73 | ||
62 | const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) | 74 | const possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l) |
63 | export function is18nPath (path: string) { | 75 | export function is18nPath (path: string) { |
64 | return possiblePaths.indexOf(path) !== -1 | 76 | return possiblePaths.includes(path) |
65 | } | 77 | } |
66 | 78 | ||
67 | export function is18nLocale (locale: string) { | 79 | export function is18nLocale (locale: string) { |
68 | return POSSIBLE_LOCALES.indexOf(locale) !== -1 | 80 | return POSSIBLE_LOCALES.includes(locale) |
69 | } | 81 | } |
70 | 82 | ||
71 | export function getCompleteLocale (locale: string) { | 83 | export function getCompleteLocale (locale: string) { |
@@ -77,7 +89,7 @@ export function getCompleteLocale (locale: string) { | |||
77 | } | 89 | } |
78 | 90 | ||
79 | export function getShortLocale (locale: string) { | 91 | export function getShortLocale (locale: string) { |
80 | if (locale.indexOf('-') === -1) return locale | 92 | if (locale.includes('-') === false) return locale |
81 | 93 | ||
82 | return locale.split('-')[0] | 94 | return locale.split('-')[0] |
83 | } | 95 | } |
diff --git a/shared/models/nodeinfo/index.d.ts b/shared/models/nodeinfo/index.d.ts index 0a2d0492e..336cb66d2 100644 --- a/shared/models/nodeinfo/index.d.ts +++ b/shared/models/nodeinfo/index.d.ts | |||
@@ -98,7 +98,7 @@ export interface HttpNodeinfoDiasporaSoftwareNsSchema20 { | |||
98 | * The amount of users that signed in at least once in the last 30 days. | 98 | * The amount of users that signed in at least once in the last 30 days. |
99 | */ | 99 | */ |
100 | activeMonth?: number | 100 | activeMonth?: number |
101 | }; | 101 | } |
102 | /** | 102 | /** |
103 | * The amount of posts that were made by users that are registered on this server. | 103 | * The amount of posts that were made by users that are registered on this server. |
104 | */ | 104 | */ |
diff --git a/shared/models/overviews/videos-overview.ts b/shared/models/overviews/videos-overview.ts index e725f166b..0f3cb4a52 100644 --- a/shared/models/overviews/videos-overview.ts +++ b/shared/models/overviews/videos-overview.ts | |||
@@ -1,18 +1,24 @@ | |||
1 | import { Video, VideoChannelSummary, VideoConstant } from '../videos' | 1 | import { Video, VideoChannelSummary, VideoConstant } from '../videos' |
2 | 2 | ||
3 | export interface ChannelOverview { | ||
4 | channel: VideoChannelSummary | ||
5 | videos: Video[] | ||
6 | } | ||
7 | |||
8 | export interface CategoryOverview { | ||
9 | category: VideoConstant<number> | ||
10 | videos: Video[] | ||
11 | } | ||
12 | |||
13 | export interface TagOverview { | ||
14 | tag: string | ||
15 | videos: Video[] | ||
16 | } | ||
17 | |||
3 | export interface VideosOverview { | 18 | export interface VideosOverview { |
4 | channels: { | 19 | channels: ChannelOverview[] |
5 | channel: VideoChannelSummary | ||
6 | videos: Video[] | ||
7 | }[] | ||
8 | 20 | ||
9 | categories: { | 21 | categories: CategoryOverview[] |
10 | category: VideoConstant<number> | ||
11 | videos: Video[] | ||
12 | }[] | ||
13 | 22 | ||
14 | tags: { | 23 | tags: TagOverview[] |
15 | tag: string | ||
16 | videos: Video[] | ||
17 | }[] | ||
18 | } | 24 | } |
diff --git a/shared/models/plugins/client-hook.model.ts b/shared/models/plugins/client-hook.model.ts index ecbe8bd3c..b53b8de99 100644 --- a/shared/models/plugins/client-hook.model.ts +++ b/shared/models/plugins/client-hook.model.ts | |||
@@ -65,6 +65,13 @@ export const clientActionHookObject = { | |||
65 | 'action:video-watch.video.loaded': true, | 65 | 'action:video-watch.video.loaded': true, |
66 | // Fired when the player finished loading | 66 | // Fired when the player finished loading |
67 | 'action:video-watch.player.loaded': true, | 67 | 'action:video-watch.player.loaded': true, |
68 | // Fired when the video watch page comments(threads) are loaded and load more comments on scroll | ||
69 | 'action:video-watch.video-threads.loaded': true, | ||
70 | // Fired when a user click on 'View x replies' and they're loaded | ||
71 | 'action:video-watch.video-thread-replies.loaded': true, | ||
72 | |||
73 | // Fired when the login page is being initialized | ||
74 | 'action:login.init': true, | ||
68 | 75 | ||
69 | // Fired when the search page is being initialized | 76 | // Fired when the search page is being initialized |
70 | 'action:search.init': true, | 77 | 'action:search.init': true, |
diff --git a/shared/models/plugins/peertube-plugin-latest-version.model.ts b/shared/models/plugins/peertube-plugin-latest-version.model.ts index dec4618fa..811a64429 100644 --- a/shared/models/plugins/peertube-plugin-latest-version.model.ts +++ b/shared/models/plugins/peertube-plugin-latest-version.model.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export interface PeertubePluginLatestVersionRequest { | 1 | export interface PeertubePluginLatestVersionRequest { |
2 | currentPeerTubeEngine?: string, | 2 | currentPeerTubeEngine?: string |
3 | 3 | ||
4 | npmNames: string[] | 4 | npmNames: string[] |
5 | } | 5 | } |
diff --git a/shared/models/plugins/plugin-client-scope.type.ts b/shared/models/plugins/plugin-client-scope.type.ts index 1c6d884f0..d112434e8 100644 --- a/shared/models/plugins/plugin-client-scope.type.ts +++ b/shared/models/plugins/plugin-client-scope.type.ts | |||
@@ -1 +1 @@ | |||
export type PluginClientScope = 'common' | 'video-watch' | 'search' | 'signup' | export type PluginClientScope = 'common' | 'video-watch' | 'search' | 'signup' | 'login' | ||
diff --git a/shared/models/plugins/plugin-package-json.model.ts b/shared/models/plugins/plugin-package-json.model.ts index 3f3077671..c26e9ae5b 100644 --- a/shared/models/plugins/plugin-package-json.model.ts +++ b/shared/models/plugins/plugin-package-json.model.ts | |||
@@ -5,7 +5,7 @@ export type PluginTranslationPaths = { | |||
5 | } | 5 | } |
6 | 6 | ||
7 | export type ClientScript = { | 7 | export type ClientScript = { |
8 | script: string, | 8 | script: string |
9 | scopes: PluginClientScope[] | 9 | scopes: PluginClientScope[] |
10 | } | 10 | } |
11 | 11 | ||
@@ -13,12 +13,12 @@ export type PluginPackageJson = { | |||
13 | name: string | 13 | name: string |
14 | version: string | 14 | version: string |
15 | description: string | 15 | description: string |
16 | engine: { peertube: string }, | 16 | engine: { peertube: string } |
17 | 17 | ||
18 | homepage: string, | 18 | homepage: string |
19 | author: string, | 19 | author: string |
20 | bugs: string, | 20 | bugs: string |
21 | library: string, | 21 | library: string |
22 | 22 | ||
23 | staticDirs: { [ name: string ]: string } | 23 | staticDirs: { [ name: string ]: string } |
24 | css: string[] | 24 | css: string[] |
diff --git a/shared/models/plugins/plugin-playlist-privacy-manager.model.ts b/shared/models/plugins/plugin-playlist-privacy-manager.model.ts new file mode 100644 index 000000000..f9630c77f --- /dev/null +++ b/shared/models/plugins/plugin-playlist-privacy-manager.model.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { VideoPlaylistPrivacy } from '@shared/models' | ||
2 | |||
3 | export interface PluginPlaylistPrivacyManager { | ||
4 | // PUBLIC = 1, | ||
5 | // UNLISTED = 2, | ||
6 | // PRIVATE = 3 | ||
7 | deletePlaylistPrivacy: (privacyKey: VideoPlaylistPrivacy) => boolean | ||
8 | } | ||
diff --git a/shared/models/plugins/plugin-settings-manager.model.ts b/shared/models/plugins/plugin-settings-manager.model.ts index 63390a190..db88ae6e7 100644 --- a/shared/models/plugins/plugin-settings-manager.model.ts +++ b/shared/models/plugins/plugin-settings-manager.model.ts | |||
@@ -1,7 +1,11 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | 2 | ||
3 | export interface PluginSettingsManager { | 3 | export interface PluginSettingsManager { |
4 | getSetting: (name: string) => Bluebird<string> | 4 | getSetting: (name: string) => Bluebird<string | boolean> |
5 | |||
6 | getSettings: (names: string[]) => Bluebird<{ [settingName: string]: string | boolean }> | ||
5 | 7 | ||
6 | setSetting: (name: string, value: string) => Bluebird<any> | 8 | setSetting: (name: string, value: string) => Bluebird<any> |
9 | |||
10 | onSettingsChange: (cb: (names: string[]) => void) => void | ||
7 | } | 11 | } |
diff --git a/shared/models/plugins/plugin-video-privacy-manager.model.ts b/shared/models/plugins/plugin-video-privacy-manager.model.ts new file mode 100644 index 000000000..d602ba297 --- /dev/null +++ b/shared/models/plugins/plugin-video-privacy-manager.model.ts | |||
@@ -0,0 +1,9 @@ | |||
1 | import { VideoPrivacy } from '@shared/models' | ||
2 | |||
3 | export interface PluginVideoPrivacyManager { | ||
4 | // PUBLIC = 1 | ||
5 | // UNLISTED = 2 | ||
6 | // PRIVATE = 3 | ||
7 | // INTERNAL = 4 | ||
8 | deletePrivacy: (privacyKey: VideoPrivacy) => boolean | ||
9 | } | ||
diff --git a/shared/models/plugins/register-server-auth.model.ts b/shared/models/plugins/register-server-auth.model.ts new file mode 100644 index 000000000..4ffce9456 --- /dev/null +++ b/shared/models/plugins/register-server-auth.model.ts | |||
@@ -0,0 +1,52 @@ | |||
1 | import { UserRole } from '@shared/models' | ||
2 | import { MOAuthToken, MUser } from '@server/typings/models' | ||
3 | import * as express from 'express' | ||
4 | |||
5 | export type RegisterServerAuthOptions = RegisterServerAuthPassOptions | RegisterServerAuthExternalOptions | ||
6 | |||
7 | export interface RegisterServerAuthenticatedResult { | ||
8 | username: string | ||
9 | email: string | ||
10 | role?: UserRole | ||
11 | displayName?: string | ||
12 | } | ||
13 | |||
14 | export interface RegisterServerExternalAuthenticatedResult extends RegisterServerAuthenticatedResult { | ||
15 | req: express.Request | ||
16 | res: express.Response | ||
17 | } | ||
18 | |||
19 | interface RegisterServerAuthBase { | ||
20 | // Authentication name (a plugin can register multiple auth strategies) | ||
21 | authName: string | ||
22 | |||
23 | // Called by PeerTube when a user from your plugin logged out | ||
24 | onLogout?(user: MUser): void | ||
25 | |||
26 | // Your plugin can hook PeerTube access/refresh token validity | ||
27 | // So you can control for your plugin the user session lifetime | ||
28 | hookTokenValidity?(options: { token: MOAuthToken, type: 'access' | 'refresh' }): Promise<{ valid: boolean }> | ||
29 | } | ||
30 | |||
31 | export interface RegisterServerAuthPassOptions extends RegisterServerAuthBase { | ||
32 | // Weight of this authentication so PeerTube tries the auth methods in DESC weight order | ||
33 | getWeight(): number | ||
34 | |||
35 | // Used by PeerTube to login a user | ||
36 | // Returns null if the login failed, or { username, email } on success | ||
37 | login(body: { | ||
38 | id: string | ||
39 | password: string | ||
40 | }): Promise<RegisterServerAuthenticatedResult | null> | ||
41 | } | ||
42 | |||
43 | export interface RegisterServerAuthExternalOptions extends RegisterServerAuthBase { | ||
44 | // Will be displayed in a block next to the login form | ||
45 | authDisplayName: () => string | ||
46 | |||
47 | onAuthRequest: (req: express.Request, res: express.Response) => void | ||
48 | } | ||
49 | |||
50 | export interface RegisterServerAuthExternalResult { | ||
51 | userAuthenticated (options: RegisterServerExternalAuthenticatedResult): void | ||
52 | } | ||
diff --git a/shared/models/plugins/register-server-setting.model.ts b/shared/models/plugins/register-server-setting.model.ts index 65a181705..920c3480f 100644 --- a/shared/models/plugins/register-server-setting.model.ts +++ b/shared/models/plugins/register-server-setting.model.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | export interface RegisterServerSettingOptions { | 1 | export interface RegisterServerSettingOptions { |
2 | name: string | 2 | name: string |
3 | label: string | 3 | label: string |
4 | type: 'input' | 4 | type: 'input' | 'input-checkbox' | 'input-textarea' | 'markdown-text' | 'markdown-enhanced' |
5 | 5 | ||
6 | // If the setting is not private, anyone can view its value (client code included) | 6 | // If the setting is not private, anyone can view its value (client code included) |
7 | // If the setting is private, only server-side hooks can access it | 7 | // If the setting is private, only server-side hooks can access it |
@@ -9,7 +9,7 @@ export interface RegisterServerSettingOptions { | |||
9 | private: boolean | 9 | private: boolean |
10 | 10 | ||
11 | // Default setting value | 11 | // Default setting value |
12 | default?: string | 12 | default?: string | boolean |
13 | } | 13 | } |
14 | 14 | ||
15 | export interface RegisteredServerSettings { | 15 | export interface RegisteredServerSettings { |
diff --git a/shared/models/plugins/server-hook.model.ts b/shared/models/plugins/server-hook.model.ts index 80ecd9e24..20f89b86d 100644 --- a/shared/models/plugins/server-hook.model.ts +++ b/shared/models/plugins/server-hook.model.ts | |||
@@ -70,7 +70,7 @@ export const serverActionHookObject = { | |||
70 | // Fired when a user is updated by an admin/moderator | 70 | // Fired when a user is updated by an admin/moderator |
71 | 'action:api.user.updated': true, | 71 | 'action:api.user.updated': true, |
72 | 72 | ||
73 | // Fired when a user got a new oauth2 token | 73 | // Fired when a user got a new oauth2 token |
74 | 'action:api.user.oauth2-got-token': true | 74 | 'action:api.user.oauth2-got-token': true |
75 | } | 75 | } |
76 | 76 | ||
diff --git a/shared/models/redundancy/index.ts b/shared/models/redundancy/index.ts index 61bf0fca7..649cc489f 100644 --- a/shared/models/redundancy/index.ts +++ b/shared/models/redundancy/index.ts | |||
@@ -1 +1,3 @@ | |||
1 | export * from './videos-redundancy.model' | 1 | export * from './videos-redundancy-strategy.model' |
2 | export * from './video-redundancies-filters.model' | ||
3 | export * from './video-redundancy.model' | ||
diff --git a/shared/models/redundancy/video-redundancies-filters.model.ts b/shared/models/redundancy/video-redundancies-filters.model.ts new file mode 100644 index 000000000..05ba7dfd3 --- /dev/null +++ b/shared/models/redundancy/video-redundancies-filters.model.ts | |||
@@ -0,0 +1 @@ | |||
export type VideoRedundanciesTarget = 'my-videos' | 'remote-videos' | |||
diff --git a/shared/models/redundancy/video-redundancy-config-filter.type.ts b/shared/models/redundancy/video-redundancy-config-filter.type.ts new file mode 100644 index 000000000..bb1ae701c --- /dev/null +++ b/shared/models/redundancy/video-redundancy-config-filter.type.ts | |||
@@ -0,0 +1 @@ | |||
export type VideoRedundancyConfigFilter = 'nobody' | 'anybody' | 'followings' | |||
diff --git a/shared/models/redundancy/video-redundancy.model.ts b/shared/models/redundancy/video-redundancy.model.ts new file mode 100644 index 000000000..fa6e05832 --- /dev/null +++ b/shared/models/redundancy/video-redundancy.model.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | export interface VideoRedundancy { | ||
2 | id: number | ||
3 | name: string | ||
4 | url: string | ||
5 | uuid: string | ||
6 | |||
7 | redundancies: { | ||
8 | files: FileRedundancyInformation[] | ||
9 | |||
10 | streamingPlaylists: StreamingPlaylistRedundancyInformation[] | ||
11 | } | ||
12 | } | ||
13 | |||
14 | interface RedundancyInformation { | ||
15 | id: number | ||
16 | fileUrl: string | ||
17 | strategy: string | ||
18 | |||
19 | createdAt: Date | string | ||
20 | updatedAt: Date | string | ||
21 | |||
22 | expiresOn: Date | string | ||
23 | |||
24 | size: number | ||
25 | } | ||
26 | |||
27 | // eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
28 | export interface FileRedundancyInformation extends RedundancyInformation { | ||
29 | |||
30 | } | ||
31 | |||
32 | // eslint-disable-next-line @typescript-eslint/no-empty-interface | ||
33 | export interface StreamingPlaylistRedundancyInformation extends RedundancyInformation { | ||
34 | |||
35 | } | ||
diff --git a/shared/models/redundancy/videos-redundancy.model.ts b/shared/models/redundancy/videos-redundancy-strategy.model.ts index a8c2743c1..15409abf0 100644 --- a/shared/models/redundancy/videos-redundancy.model.ts +++ b/shared/models/redundancy/videos-redundancy-strategy.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added' | 1 | export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added' |
2 | export type VideoRedundancyStrategyWithManual = VideoRedundancyStrategy | 'manual' | ||
2 | 3 | ||
3 | export type MostViewsRedundancyStrategy = { | 4 | export type MostViewsRedundancyStrategy = { |
4 | strategy: 'most-views' | 5 | strategy: 'most-views' |
@@ -19,4 +20,4 @@ export type RecentlyAddedStrategy = { | |||
19 | minLifetime: number | 20 | minLifetime: number |
20 | } | 21 | } |
21 | 22 | ||
22 | export type VideosRedundancy = MostViewsRedundancyStrategy | TrendingRedundancyStrategy | RecentlyAddedStrategy | 23 | export type VideosRedundancyStrategy = MostViewsRedundancyStrategy | TrendingRedundancyStrategy | RecentlyAddedStrategy |
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index 032b91a29..07e17bda2 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -97,7 +97,7 @@ export interface CustomConfig { | |||
97 | videos: { | 97 | videos: { |
98 | http: { | 98 | http: { |
99 | enabled: boolean | 99 | enabled: boolean |
100 | }, | 100 | } |
101 | torrent: { | 101 | torrent: { |
102 | enabled: boolean | 102 | enabled: boolean |
103 | } | 103 | } |
@@ -114,7 +114,7 @@ export interface CustomConfig { | |||
114 | 114 | ||
115 | followers: { | 115 | followers: { |
116 | instance: { | 116 | instance: { |
117 | enabled: boolean, | 117 | enabled: boolean |
118 | manualApproval: boolean | 118 | manualApproval: boolean |
119 | } | 119 | } |
120 | } | 120 | } |
diff --git a/shared/models/server/emailer.model.ts b/shared/models/server/emailer.model.ts new file mode 100644 index 000000000..069ef0bab --- /dev/null +++ b/shared/models/server/emailer.model.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | export type SendEmailOptions = { | ||
2 | to: string[] | ||
3 | |||
4 | template?: string | ||
5 | locals?: { [key: string]: any } | ||
6 | |||
7 | // override defaults | ||
8 | subject?: string | ||
9 | text?: string | ||
10 | from?: string | { name?: string, address: string } | ||
11 | replyTo?: string | ||
12 | } | ||
diff --git a/shared/models/server/index.ts b/shared/models/server/index.ts index bf61ab270..b0afb2c66 100644 --- a/shared/models/server/index.ts +++ b/shared/models/server/index.ts | |||
@@ -2,6 +2,7 @@ export * from './about.model' | |||
2 | export * from './contact-form.model' | 2 | export * from './contact-form.model' |
3 | export * from './custom-config.model' | 3 | export * from './custom-config.model' |
4 | export * from './debug.model' | 4 | export * from './debug.model' |
5 | export * from './emailer.model' | ||
5 | export * from './job.model' | 6 | export * from './job.model' |
6 | export * from './server-config.model' | 7 | export * from './server-config.model' |
7 | export * from './server-stats.model' | 8 | export * from './server-stats.model' |
diff --git a/shared/models/server/job.model.ts b/shared/models/server/job.model.ts index b82a633b2..57d61c480 100644 --- a/shared/models/server/job.model.ts +++ b/shared/models/server/job.model.ts | |||
@@ -1,23 +1,125 @@ | |||
1 | import { SendEmailOptions } from './emailer.model' | ||
2 | import { VideoResolution } from '@shared/models' | ||
3 | import { ContextType } from '../activitypub/context' | ||
4 | |||
1 | export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' | 5 | export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' |
2 | 6 | ||
3 | export type JobType = 'activitypub-http-unicast' | | 7 | export type JobType = |
4 | 'activitypub-http-broadcast' | | 8 | | 'activitypub-http-unicast' |
5 | 'activitypub-http-fetcher' | | 9 | | 'activitypub-http-broadcast' |
6 | 'activitypub-follow' | | 10 | | 'activitypub-http-fetcher' |
7 | 'video-file-import' | | 11 | | 'activitypub-follow' |
8 | 'video-transcoding' | | 12 | | 'video-file-import' |
9 | 'email' | | 13 | | 'video-transcoding' |
10 | 'video-import' | | 14 | | 'email' |
11 | 'videos-views' | | 15 | | 'video-import' |
12 | 'activitypub-refresher' | 16 | | 'videos-views' |
17 | | 'activitypub-refresher' | ||
18 | | 'video-redundancy' | ||
13 | 19 | ||
14 | export interface Job { | 20 | export interface Job { |
15 | id: number | 21 | id: number |
16 | state: JobState | 22 | state: JobState |
17 | type: JobType | 23 | type: JobType |
18 | data: any, | 24 | data: any |
19 | error: any, | 25 | error: any |
20 | createdAt: Date | string | 26 | createdAt: Date | string |
21 | finishedOn: Date | string | 27 | finishedOn: Date | string |
22 | processedOn: Date | string | 28 | processedOn: Date | string |
23 | } | 29 | } |
30 | |||
31 | export type ActivitypubHttpBroadcastPayload = { | ||
32 | uris: string[] | ||
33 | signatureActorId?: number | ||
34 | body: any | ||
35 | contextType?: ContextType | ||
36 | } | ||
37 | |||
38 | export type ActivitypubFollowPayload = { | ||
39 | followerActorId: number | ||
40 | name: string | ||
41 | host: string | ||
42 | isAutoFollow?: boolean | ||
43 | assertIsChannel?: boolean | ||
44 | } | ||
45 | |||
46 | export type FetchType = 'activity' | 'video-likes' | 'video-dislikes' | 'video-shares' | 'video-comments' | 'account-playlists' | ||
47 | export type ActivitypubHttpFetcherPayload = { | ||
48 | uri: string | ||
49 | type: FetchType | ||
50 | videoId?: number | ||
51 | accountId?: number | ||
52 | } | ||
53 | |||
54 | export type ActivitypubHttpUnicastPayload = { | ||
55 | uri: string | ||
56 | signatureActorId?: number | ||
57 | body: any | ||
58 | contextType?: ContextType | ||
59 | } | ||
60 | |||
61 | export type RefreshPayload = { | ||
62 | type: 'video' | 'video-playlist' | 'actor' | ||
63 | url: string | ||
64 | } | ||
65 | |||
66 | export type EmailPayload = SendEmailOptions | ||
67 | |||
68 | export type VideoFileImportPayload = { | ||
69 | videoUUID: string | ||
70 | filePath: string | ||
71 | } | ||
72 | |||
73 | export type VideoImportYoutubeDLPayload = { | ||
74 | type: 'youtube-dl' | ||
75 | videoImportId: number | ||
76 | |||
77 | generateThumbnail: boolean | ||
78 | generatePreview: boolean | ||
79 | |||
80 | fileExt?: string | ||
81 | } | ||
82 | export type VideoImportTorrentPayload = { | ||
83 | type: 'magnet-uri' | 'torrent-file' | ||
84 | videoImportId: number | ||
85 | } | ||
86 | export type VideoImportPayload = VideoImportYoutubeDLPayload | VideoImportTorrentPayload | ||
87 | |||
88 | export type VideoRedundancyPayload = { | ||
89 | videoId: number | ||
90 | } | ||
91 | |||
92 | // Video transcoding payloads | ||
93 | |||
94 | interface BaseTranscodingPayload { | ||
95 | videoUUID: string | ||
96 | isNewVideo?: boolean | ||
97 | } | ||
98 | |||
99 | interface HLSTranscodingPayload extends BaseTranscodingPayload { | ||
100 | type: 'hls' | ||
101 | isPortraitMode?: boolean | ||
102 | resolution: VideoResolution | ||
103 | copyCodecs: boolean | ||
104 | } | ||
105 | |||
106 | export interface NewResolutionTranscodingPayload extends BaseTranscodingPayload { | ||
107 | type: 'new-resolution' | ||
108 | isPortraitMode?: boolean | ||
109 | resolution: VideoResolution | ||
110 | } | ||
111 | |||
112 | export interface MergeAudioTranscodingPayload extends BaseTranscodingPayload { | ||
113 | type: 'merge-audio' | ||
114 | resolution: VideoResolution | ||
115 | } | ||
116 | |||
117 | export interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | ||
118 | type: 'optimize' | ||
119 | } | ||
120 | |||
121 | export type VideoTranscodingPayload = | ||
122 | HLSTranscodingPayload | ||
123 | | NewResolutionTranscodingPayload | ||
124 | | OptimizeTranscodingPayload | ||
125 | | MergeAudioTranscodingPayload | ||
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts index f1bb2153c..a1f9b3b5d 100644 --- a/shared/models/server/server-config.model.ts +++ b/shared/models/server/server-config.model.ts | |||
@@ -12,6 +12,22 @@ export interface ServerConfigTheme extends ServerConfigPlugin { | |||
12 | css: string[] | 12 | css: string[] |
13 | } | 13 | } |
14 | 14 | ||
15 | export interface RegisteredExternalAuthConfig { | ||
16 | npmName: string | ||
17 | name: string | ||
18 | version: string | ||
19 | authName: string | ||
20 | authDisplayName: string | ||
21 | } | ||
22 | |||
23 | export interface RegisteredIdAndPassAuthConfig { | ||
24 | npmName: string | ||
25 | name: string | ||
26 | version: string | ||
27 | authName: string | ||
28 | weight: number | ||
29 | } | ||
30 | |||
15 | export interface ServerConfig { | 31 | export interface ServerConfig { |
16 | serverVersion: string | 32 | serverVersion: string |
17 | serverCommit?: string | 33 | serverCommit?: string |
@@ -28,8 +44,19 @@ export interface ServerConfig { | |||
28 | } | 44 | } |
29 | } | 45 | } |
30 | 46 | ||
47 | search: { | ||
48 | remoteUri: { | ||
49 | users: boolean | ||
50 | anonymous: boolean | ||
51 | } | ||
52 | } | ||
53 | |||
31 | plugin: { | 54 | plugin: { |
32 | registered: ServerConfigPlugin[] | 55 | registered: ServerConfigPlugin[] |
56 | |||
57 | registeredExternalAuths: RegisteredExternalAuthConfig[] | ||
58 | |||
59 | registeredIdAndPassAuths: RegisteredIdAndPassAuthConfig[] | ||
33 | } | 60 | } |
34 | 61 | ||
35 | theme: { | 62 | theme: { |
@@ -46,7 +73,7 @@ export interface ServerConfig { | |||
46 | } | 73 | } |
47 | 74 | ||
48 | signup: { | 75 | signup: { |
49 | allowed: boolean, | 76 | allowed: boolean |
50 | allowedForCurrentIP: boolean | 77 | allowedForCurrentIP: boolean |
51 | requiresEmailVerification: boolean | 78 | requiresEmailVerification: boolean |
52 | } | 79 | } |
@@ -97,7 +124,7 @@ export interface ServerConfig { | |||
97 | max: number | 124 | max: number |
98 | } | 125 | } |
99 | extensions: string[] | 126 | extensions: string[] |
100 | }, | 127 | } |
101 | file: { | 128 | file: { |
102 | extensions: string[] | 129 | extensions: string[] |
103 | } | 130 | } |
@@ -107,7 +134,7 @@ export interface ServerConfig { | |||
107 | file: { | 134 | file: { |
108 | size: { | 135 | size: { |
109 | max: number | 136 | max: number |
110 | }, | 137 | } |
111 | extensions: string[] | 138 | extensions: string[] |
112 | } | 139 | } |
113 | } | 140 | } |
diff --git a/shared/models/server/server-stats.model.ts b/shared/models/server/server-stats.model.ts index 74f3de5d3..75d7dc554 100644 --- a/shared/models/server/server-stats.model.ts +++ b/shared/models/server/server-stats.model.ts | |||
@@ -1,7 +1,11 @@ | |||
1 | import { VideoRedundancyStrategy } from '../redundancy' | 1 | import { VideoRedundancyStrategyWithManual } from '../redundancy' |
2 | 2 | ||
3 | export interface ServerStats { | 3 | export interface ServerStats { |
4 | totalUsers: number | 4 | totalUsers: number |
5 | totalDailyActiveUsers: number | ||
6 | totalWeeklyActiveUsers: number | ||
7 | totalMonthlyActiveUsers: number | ||
8 | |||
5 | totalLocalVideos: number | 9 | totalLocalVideos: number |
6 | totalLocalVideoViews: number | 10 | totalLocalVideoViews: number |
7 | totalLocalVideoComments: number | 11 | totalLocalVideoComments: number |
@@ -13,11 +17,13 @@ export interface ServerStats { | |||
13 | totalInstanceFollowers: number | 17 | totalInstanceFollowers: number |
14 | totalInstanceFollowing: number | 18 | totalInstanceFollowing: number |
15 | 19 | ||
16 | videosRedundancy: { | 20 | videosRedundancy: VideosRedundancyStats[] |
17 | strategy: VideoRedundancyStrategy | 21 | } |
18 | totalSize: number | 22 | |
19 | totalUsed: number | 23 | export interface VideosRedundancyStats { |
20 | totalVideoFiles: number | 24 | strategy: VideoRedundancyStrategyWithManual |
21 | totalVideos: number | 25 | totalSize: number |
22 | }[] | 26 | totalUsed: number |
27 | totalVideoFiles: number | ||
28 | totalVideos: number | ||
23 | } | 29 | } |
diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts index 4a28a229d..2f88a65de 100644 --- a/shared/models/users/user-right.enum.ts +++ b/shared/models/users/user-right.enum.ts | |||
@@ -33,5 +33,7 @@ export enum UserRight { | |||
33 | SEE_ALL_VIDEOS, | 33 | SEE_ALL_VIDEOS, |
34 | CHANGE_VIDEO_OWNERSHIP, | 34 | CHANGE_VIDEO_OWNERSHIP, |
35 | 35 | ||
36 | MANAGE_PLUGINS | 36 | MANAGE_PLUGINS, |
37 | |||
38 | MANAGE_VIDEOS_REDUNDANCIES | ||
37 | } | 39 | } |
diff --git a/shared/models/users/user-role.ts b/shared/models/users/user-role.ts index 0b6554e51..2b08b5850 100644 --- a/shared/models/users/user-role.ts +++ b/shared/models/users/user-role.ts | |||
@@ -7,15 +7,13 @@ export enum UserRole { | |||
7 | USER = 2 | 7 | USER = 2 |
8 | } | 8 | } |
9 | 9 | ||
10 | // TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed | 10 | export const USER_ROLE_LABELS: { [ id in UserRole ]: string } = { |
11 | export const USER_ROLE_LABELS: { [ id: number ]: string } = { | ||
12 | [UserRole.USER]: 'User', | 11 | [UserRole.USER]: 'User', |
13 | [UserRole.MODERATOR]: 'Moderator', | 12 | [UserRole.MODERATOR]: 'Moderator', |
14 | [UserRole.ADMINISTRATOR]: 'Administrator' | 13 | [UserRole.ADMINISTRATOR]: 'Administrator' |
15 | } | 14 | } |
16 | 15 | ||
17 | // TODO: use UserRole for key once https://github.com/Microsoft/TypeScript/issues/13042 is fixed | 16 | const userRoleRights: { [ id in UserRole ]: UserRight[] } = { |
18 | const userRoleRights: { [ id: number ]: UserRight[] } = { | ||
19 | [UserRole.ADMINISTRATOR]: [ | 17 | [UserRole.ADMINISTRATOR]: [ |
20 | UserRight.ALL | 18 | UserRight.ALL |
21 | ], | 19 | ], |
@@ -40,5 +38,5 @@ const userRoleRights: { [ id: number ]: UserRight[] } = { | |||
40 | export function hasUserRight (userRole: UserRole, userRight: UserRight) { | 38 | export function hasUserRight (userRole: UserRole, userRight: UserRight) { |
41 | const userRights = userRoleRights[userRole] | 39 | const userRights = userRoleRights[userRole] |
42 | 40 | ||
43 | return userRights.indexOf(UserRight.ALL) !== -1 || userRights.indexOf(userRight) !== -1 | 41 | return userRights.includes(UserRight.ALL) || userRights.includes(userRight) |
44 | } | 42 | } |
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 168851196..6c959ceea 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Account } from '../actors' | 1 | import { Account } from '../actors' |
2 | import { VideoChannel } from '../videos/channel/video-channel.model' | 2 | import { VideoChannel } from '../videos/channel/video-channel.model' |
3 | import { VideoPlaylist } from '../videos/playlist/video-playlist.model' | ||
4 | import { UserRole } from './user-role' | 3 | import { UserRole } from './user-role' |
5 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' | 4 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' |
6 | import { UserNotificationSetting } from './user-notification-setting.model' | 5 | import { UserNotificationSetting } from './user-notification-setting.model' |
@@ -32,6 +31,11 @@ export interface User { | |||
32 | videoQuotaDaily: number | 31 | videoQuotaDaily: number |
33 | videoQuotaUsed?: number | 32 | videoQuotaUsed?: number |
34 | videoQuotaUsedDaily?: number | 33 | videoQuotaUsedDaily?: number |
34 | videosCount?: number | ||
35 | videoAbusesCount?: number | ||
36 | videoAbusesAcceptedCount?: number | ||
37 | videoAbusesCreatedCount?: number | ||
38 | videoCommentsCount? : number | ||
35 | 39 | ||
36 | theme: string | 40 | theme: string |
37 | 41 | ||
@@ -46,6 +50,10 @@ export interface User { | |||
46 | noWelcomeModal: boolean | 50 | noWelcomeModal: boolean |
47 | 51 | ||
48 | createdAt: Date | 52 | createdAt: Date |
53 | |||
54 | pluginAuth: string | null | ||
55 | |||
56 | lastLoginDate: Date | null | ||
49 | } | 57 | } |
50 | 58 | ||
51 | export interface MyUserSpecialPlaylist { | 59 | export interface MyUserSpecialPlaylist { |
diff --git a/shared/models/videos/abuse/video-abuse-video-is.type.ts b/shared/models/videos/abuse/video-abuse-video-is.type.ts new file mode 100644 index 000000000..e86018993 --- /dev/null +++ b/shared/models/videos/abuse/video-abuse-video-is.type.ts | |||
@@ -0,0 +1 @@ | |||
export type VideoAbuseVideoIs = 'deleted' | 'blacklisted' | |||
diff --git a/shared/models/videos/abuse/video-abuse.model.ts b/shared/models/videos/abuse/video-abuse.model.ts index 4f668795a..f2c2cdc41 100644 --- a/shared/models/videos/abuse/video-abuse.model.ts +++ b/shared/models/videos/abuse/video-abuse.model.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import { Account } from '../../actors/index' | 1 | import { Account } from '../../actors/index' |
2 | import { VideoConstant } from '../video-constant.model' | 2 | import { VideoConstant } from '../video-constant.model' |
3 | import { VideoAbuseState } from './video-abuse-state.model' | 3 | import { VideoAbuseState } from './video-abuse-state.model' |
4 | import { VideoChannel } from '../channel/video-channel.model' | ||
4 | 5 | ||
5 | export interface VideoAbuse { | 6 | export interface VideoAbuse { |
6 | id: number | 7 | id: number |
@@ -14,7 +15,19 @@ export interface VideoAbuse { | |||
14 | id: number | 15 | id: number |
15 | name: string | 16 | name: string |
16 | uuid: string | 17 | uuid: string |
18 | nsfw: boolean | ||
19 | deleted: boolean | ||
20 | blacklisted: boolean | ||
21 | thumbnailPath?: string | ||
22 | channel?: VideoChannel | ||
17 | } | 23 | } |
18 | 24 | ||
19 | createdAt: Date | 25 | createdAt: Date |
26 | updatedAt: Date | ||
27 | |||
28 | count?: number | ||
29 | nth?: number | ||
30 | |||
31 | countReportsForReporter?: number | ||
32 | countReportsForReportee?: number | ||
20 | } | 33 | } |
diff --git a/shared/models/videos/blacklist/video-blacklist.model.ts b/shared/models/videos/blacklist/video-blacklist.model.ts index 68d59e489..a6e0ef175 100644 --- a/shared/models/videos/blacklist/video-blacklist.model.ts +++ b/shared/models/videos/blacklist/video-blacklist.model.ts | |||
@@ -7,11 +7,12 @@ export enum VideoBlacklistType { | |||
7 | 7 | ||
8 | export interface VideoBlacklist { | 8 | export interface VideoBlacklist { |
9 | id: number | 9 | id: number |
10 | createdAt: Date | ||
11 | updatedAt: Date | ||
12 | unfederated: boolean | 10 | unfederated: boolean |
13 | reason?: string | 11 | reason?: string |
14 | type: VideoBlacklistType | 12 | type: VideoBlacklistType |
15 | 13 | ||
16 | video: Video | 14 | video: Video |
15 | |||
16 | createdAt: Date | ||
17 | updatedAt: Date | ||
17 | } | 18 | } |
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts index de4c26b3d..421004e68 100644 --- a/shared/models/videos/channel/video-channel.model.ts +++ b/shared/models/videos/channel/video-channel.model.ts | |||
@@ -2,12 +2,18 @@ import { Actor } from '../../actors/actor.model' | |||
2 | import { Account } from '../../actors/index' | 2 | import { Account } from '../../actors/index' |
3 | import { Avatar } from '../../avatars' | 3 | import { Avatar } from '../../avatars' |
4 | 4 | ||
5 | export type ViewsPerDate = { | ||
6 | date: Date | ||
7 | views: number | ||
8 | } | ||
9 | |||
5 | export interface VideoChannel extends Actor { | 10 | export interface VideoChannel extends Actor { |
6 | displayName: string | 11 | displayName: string |
7 | description: string | 12 | description: string |
8 | support: string | 13 | support: string |
9 | isLocal: boolean | 14 | isLocal: boolean |
10 | ownerAccount?: Account | 15 | ownerAccount?: Account |
16 | viewsPerDay?: ViewsPerDate[] // chronologically ordered | ||
11 | } | 17 | } |
12 | 18 | ||
13 | export interface VideoChannelSummary { | 19 | export interface VideoChannelSummary { |
diff --git a/shared/models/videos/video-file-metadata.ts b/shared/models/videos/video-file-metadata.ts new file mode 100644 index 000000000..15683cacf --- /dev/null +++ b/shared/models/videos/video-file-metadata.ts | |||
@@ -0,0 +1,18 @@ | |||
1 | import { FfprobeData } from "fluent-ffmpeg" | ||
2 | import { DeepOmit } from "@server/models/utils" | ||
3 | |||
4 | export type VideoFileMetadataModel = DeepOmit<FfprobeData, 'filename'> | ||
5 | |||
6 | export class VideoFileMetadata implements VideoFileMetadataModel { | ||
7 | streams: { [x: string]: any, [x: number]: any }[] | ||
8 | format: { [x: string]: any, [x: number]: any } | ||
9 | chapters: any[] | ||
10 | |||
11 | constructor (hash: Partial<VideoFileMetadataModel>) { | ||
12 | this.chapters = hash.chapters | ||
13 | this.format = hash.format | ||
14 | this.streams = hash.streams | ||
15 | |||
16 | delete this.format.filename | ||
17 | } | ||
18 | } | ||
diff --git a/shared/models/videos/video-file.model.ts b/shared/models/videos/video-file.model.ts index 04da0627e..6cc2d5aee 100644 --- a/shared/models/videos/video-file.model.ts +++ b/shared/models/videos/video-file.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { VideoConstant, VideoResolution } from '@shared/models' | 1 | import { VideoConstant, VideoResolution } from '@shared/models' |
2 | import { FfprobeData } from 'fluent-ffmpeg' | ||
2 | 3 | ||
3 | export interface VideoFile { | 4 | export interface VideoFile { |
4 | magnetUri: string | 5 | magnetUri: string |
@@ -9,4 +10,6 @@ export interface VideoFile { | |||
9 | fileUrl: string | 10 | fileUrl: string |
10 | fileDownloadUrl: string | 11 | fileDownloadUrl: string |
11 | fps: number | 12 | fps: number |
13 | metadata?: FfprobeData | ||
14 | metadataUrl?: string | ||
12 | } | 15 | } |
diff --git a/shared/models/videos/video-transcoding-fps.model.ts b/shared/models/videos/video-transcoding-fps.model.ts index 82022d2f1..25fc1c2da 100644 --- a/shared/models/videos/video-transcoding-fps.model.ts +++ b/shared/models/videos/video-transcoding-fps.model.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | export type VideoTranscodingFPS = { | 1 | export type VideoTranscodingFPS = { |
2 | MIN: number, | 2 | MIN: number |
3 | AVERAGE: number, | 3 | STANDARD: number[] |
4 | MAX: number, | 4 | HD_STANDARD: number[] |
5 | AVERAGE: number | ||
6 | MAX: number | ||
5 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: number | 7 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: number |
6 | } | 8 | } |
diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts index 7576439fe..a69152759 100644 --- a/shared/models/videos/video.model.ts +++ b/shared/models/videos/video.model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index' | 1 | import { AccountSummary, VideoChannelSummary, VideoState } from '../../index' |
2 | import { Account } from '../actors' | 2 | import { Account } from '../actors' |
3 | import { VideoChannel } from './channel/video-channel.model' | 3 | import { VideoChannel } from './channel/video-channel.model' |
4 | import { VideoPrivacy } from './video-privacy.enum' | 4 | import { VideoPrivacy } from './video-privacy.enum' |