aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/core-utils/miscs/miscs.ts2
-rw-r--r--shared/extra-utils/instances-index/mock-instances-index.ts2
-rw-r--r--shared/extra-utils/miscs/miscs.ts33
-rw-r--r--shared/extra-utils/miscs/sql.ts13
-rw-r--r--shared/extra-utils/requests/requests.ts58
-rw-r--r--shared/extra-utils/search/videos.ts2
-rw-r--r--shared/extra-utils/server/clients.ts4
-rw-r--r--shared/extra-utils/server/contact-form.ts10
-rw-r--r--shared/extra-utils/server/follows.ts26
-rw-r--r--shared/extra-utils/server/jobs.ts22
-rw-r--r--shared/extra-utils/server/plugins.ts72
-rw-r--r--shared/extra-utils/server/redundancy.ts70
-rw-r--r--shared/extra-utils/server/servers.ts27
-rw-r--r--shared/extra-utils/users/accounts.ts2
-rw-r--r--shared/extra-utils/users/blocklist.ts2
-rw-r--r--shared/extra-utils/users/login.ts2
-rw-r--r--shared/extra-utils/users/user-notifications.ts33
-rw-r--r--shared/extra-utils/users/users.ts40
-rw-r--r--shared/extra-utils/videos/video-blacklist.ts28
-rw-r--r--shared/extra-utils/videos/video-captions.ts6
-rw-r--r--shared/extra-utils/videos/video-channels.ts20
-rw-r--r--shared/extra-utils/videos/video-comments.ts2
-rw-r--r--shared/extra-utils/videos/video-imports.ts2
-rw-r--r--shared/extra-utils/videos/video-playlists.ts50
-rw-r--r--shared/extra-utils/videos/video-streaming-playlists.ts2
-rw-r--r--shared/extra-utils/videos/videos.ts31
-rw-r--r--shared/models/activitypub/activity.ts43
-rw-r--r--shared/models/activitypub/activitypub-actor.ts8
-rw-r--r--shared/models/activitypub/activitypub-signature.ts4
-rw-r--r--shared/models/activitypub/objects/cache-file-object.ts2
-rw-r--r--shared/models/activitypub/objects/common-objects.ts33
-rw-r--r--shared/models/activitypub/objects/video-abuse-object.ts2
-rw-r--r--shared/models/activitypub/objects/video-torrent-object.ts8
-rw-r--r--shared/models/activitypub/objects/view-object.ts2
-rw-r--r--shared/models/i18n/i18n.ts44
-rw-r--r--shared/models/nodeinfo/index.d.ts2
-rw-r--r--shared/models/plugins/peertube-plugin-latest-version.model.ts2
-rw-r--r--shared/models/plugins/plugin-package-json.model.ts12
-rw-r--r--shared/models/plugins/server-hook.model.ts2
-rw-r--r--shared/models/redundancy/index.ts4
-rw-r--r--shared/models/redundancy/video-redundancies-filters.model.ts1
-rw-r--r--shared/models/redundancy/video-redundancy.model.ts35
-rw-r--r--shared/models/redundancy/videos-redundancy-strategy.model.ts (renamed from shared/models/redundancy/videos-redundancy.model.ts)3
-rw-r--r--shared/models/server/custom-config.model.ts4
-rw-r--r--shared/models/server/job.model.ts26
-rw-r--r--shared/models/server/server-config.model.ts6
-rw-r--r--shared/models/server/server-stats.model.ts18
-rw-r--r--shared/models/users/user-right.enum.ts4
-rw-r--r--shared/models/users/user-role.ts6
-rw-r--r--shared/models/users/user.model.ts1
-rw-r--r--shared/models/videos/video-transcoding-fps.model.ts8
-rw-r--r--shared/models/videos/video.model.ts2
52 files changed, 514 insertions, 329 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/instances-index/mock-instances-index.ts b/shared/extra-utils/instances-index/mock-instances-index.ts
index cfa4523c1..c58e8bcf8 100644
--- a/shared/extra-utils/instances-index/mock-instances-index.ts
+++ b/shared/extra-utils/instances-index/mock-instances-index.ts
@@ -1,7 +1,7 @@
1import * as express from 'express' 1import * as express from 'express'
2 2
3export class MockInstancesIndex { 3export class MockInstancesIndex {
4 private indexInstances: { host: string, createdAt: string }[] = [] 4 private readonly indexInstances: { host: string, createdAt: string }[] = []
5 5
6 initialize () { 6 initialize () {
7 return new Promise(res => { 7 return new Promise(res => {
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
index 6b0f6d990..f4e86b85a 100644
--- a/shared/extra-utils/miscs/miscs.ts
+++ b/shared/extra-utils/miscs/miscs.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import { basename, dirname, isAbsolute, join, resolve } from 'path' 4import { basename, dirname, isAbsolute, join, resolve } from 'path'
@@ -10,11 +10,11 @@ import * as ffmpeg from 'fluent-ffmpeg'
10const expect = chai.expect 10const expect = chai.expect
11let webtorrent: WebTorrent.Instance 11let webtorrent: WebTorrent.Instance
12 12
13function immutableAssign <T, U> (target: T, source: U) { 13function immutableAssign<T, U> (target: T, source: U) {
14 return Object.assign<{}, T, U>({}, target, source) 14 return Object.assign<{}, T, U>({}, target, source)
15} 15}
16 16
17 // Default interval -> 5 minutes 17// Default interval -> 5 minutes
18function dateIsValid (dateString: string, interval = 300000) { 18function dateIsValid (dateString: string, interval = 300000) {
19 const dateToCheck = new Date(dateString) 19 const dateToCheck = new Date(dateString)
20 const now = new Date() 20 const now = new Date()
@@ -89,7 +89,7 @@ async function generateHighBitrateVideo () {
89 // a large file in the repo. The video needs to have a certain minimum length so 89 // a large file in the repo. The video needs to have a certain minimum length so
90 // that FFmpeg properly applies bitrate limits. 90 // that FFmpeg properly applies bitrate limits.
91 // https://stackoverflow.com/a/15795112 91 // https://stackoverflow.com/a/15795112
92 return new Promise<string>(async (res, rej) => { 92 return new Promise<string>((res, rej) => {
93 ffmpeg() 93 ffmpeg()
94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) 94 .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) 95 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
@@ -104,6 +104,28 @@ async function generateHighBitrateVideo () {
104 return tempFixturePath 104 return tempFixturePath
105} 105}
106 106
107async function generateVideoWithFramerate (fps = 60) {
108 const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true)
109
110 await ensureDir(dirname(tempFixturePath))
111
112 const exists = await pathExists(tempFixturePath)
113 if (!exists) {
114 return new Promise<string>((res, rej) => {
115 ffmpeg()
116 .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ])
117 .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
118 .outputOptions([ `-r ${fps}` ])
119 .output(tempFixturePath)
120 .on('error', rej)
121 .on('end', () => res(tempFixturePath))
122 .run()
123 })
124 }
125
126 return tempFixturePath
127}
128
107// --------------------------------------------------------------------------- 129// ---------------------------------------------------------------------------
108 130
109export { 131export {
@@ -115,5 +137,6 @@ export {
115 testImage, 137 testImage,
116 buildAbsoluteFixturePath, 138 buildAbsoluteFixturePath,
117 root, 139 root,
118 generateHighBitrateVideo 140 generateHighBitrateVideo,
141 generateVideoWithFramerate
119} 142}
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
index 167649c6d..5bd5d5d8a 100644
--- a/shared/extra-utils/miscs/sql.ts
+++ b/shared/extra-utils/miscs/sql.ts
@@ -1,7 +1,7 @@
1import { QueryTypes, Sequelize } from 'sequelize' 1import { QueryTypes, Sequelize } from 'sequelize'
2import { ServerInfo } from '../server/servers' 2import { ServerInfo } from '../server/servers'
3 3
4let sequelizes: { [ id: number ]: Sequelize } = {} 4const sequelizes: { [ id: number ]: Sequelize } = {}
5 5
6function getSequelize (internalServerNumber: number) { 6function getSequelize (internalServerNumber: number) {
7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] 7 if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
@@ -52,22 +52,23 @@ async function countVideoViewsOf (internalServerNumber: number, uuid: string) {
52 const seq = getSequelize(internalServerNumber) 52 const seq = getSequelize(internalServerNumber)
53 53
54 // tslint:disable 54 // tslint:disable
55 const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` 55 const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' +
56 `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
56 57
57 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } 58 const options = { type: QueryTypes.SELECT as QueryTypes.SELECT }
58 const [ { total } ] = await seq.query<{ total: number }>(query, options) 59 const [ { total } ] = await seq.query<{ total: number }>(query, options)
59 60
60 if (!total) return 0 61 if (!total) return 0
61 62
62 // FIXME: check if we really need parseInt
63 return parseInt(total + '', 10) 63 return parseInt(total + '', 10)
64} 64}
65 65
66async function closeAllSequelize (servers: ServerInfo[]) { 66async function closeAllSequelize (servers: ServerInfo[]) {
67 for (const server of servers) { 67 for (const server of servers) {
68 if (sequelizes[ server.internalServerNumber ]) { 68 if (sequelizes[server.internalServerNumber]) {
69 await sequelizes[ server.internalServerNumber ].close() 69 await sequelizes[server.internalServerNumber].close()
70 delete sequelizes[ server.internalServerNumber ] 70 // eslint-disable-next-line
71 delete sequelizes[server.internalServerNumber]
71 } 72 }
72 } 73 }
73} 74}
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts
index 3532fb429..61167f212 100644
--- a/shared/extra-utils/requests/requests.ts
+++ b/shared/extra-utils/requests/requests.ts
@@ -1,25 +1,27 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { buildAbsoluteFixturePath, root } from '../miscs/miscs' 4import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
3import { isAbsolute, join } from 'path' 5import { isAbsolute, join } from 'path'
4import { parse } from 'url' 6import { URL } from 'url'
5 7
6function get4KFileUrl () { 8function get4KFileUrl () {
7 return 'https://download.cpy.re/peertube/4k_file.txt' 9 return 'https://download.cpy.re/peertube/4k_file.txt'
8} 10}
9 11
10function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) { 12function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
11 const { host, protocol, pathname } = parse(url) 13 const { host, protocol, pathname } = new URL(url)
12 14
13 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) 15 return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
14} 16}
15 17
16function makeGetRequest (options: { 18function makeGetRequest (options: {
17 url: string, 19 url: string
18 path?: string, 20 path?: string
19 query?: any, 21 query?: any
20 token?: string, 22 token?: string
21 statusCodeExpected?: number, 23 statusCodeExpected?: number
22 contentType?: string, 24 contentType?: string
23 range?: string 25 range?: string
24}) { 26}) {
25 if (!options.statusCodeExpected) options.statusCodeExpected = 400 27 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -36,9 +38,9 @@ function makeGetRequest (options: {
36} 38}
37 39
38function makeDeleteRequest (options: { 40function makeDeleteRequest (options: {
39 url: string, 41 url: string
40 path: string, 42 path: string
41 token?: string, 43 token?: string
42 statusCodeExpected?: number 44 statusCodeExpected?: number
43}) { 45}) {
44 if (!options.statusCodeExpected) options.statusCodeExpected = 400 46 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -53,12 +55,12 @@ function makeDeleteRequest (options: {
53} 55}
54 56
55function makeUploadRequest (options: { 57function makeUploadRequest (options: {
56 url: string, 58 url: string
57 method?: 'POST' | 'PUT', 59 method?: 'POST' | 'PUT'
58 path: string, 60 path: string
59 token?: string, 61 token?: string
60 fields: { [ fieldName: string ]: any }, 62 fields: { [ fieldName: string ]: any }
61 attaches: { [ attachName: string ]: any | any[] }, 63 attaches: { [ attachName: string ]: any | any[] }
62 statusCodeExpected?: number 64 statusCodeExpected?: number
63}) { 65}) {
64 if (!options.statusCodeExpected) options.statusCodeExpected = 400 66 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -101,10 +103,10 @@ function makeUploadRequest (options: {
101} 103}
102 104
103function makePostBodyRequest (options: { 105function makePostBodyRequest (options: {
104 url: string, 106 url: string
105 path: string, 107 path: string
106 token?: string, 108 token?: string
107 fields?: { [ fieldName: string ]: any }, 109 fields?: { [ fieldName: string ]: any }
108 statusCodeExpected?: number 110 statusCodeExpected?: number
109}) { 111}) {
110 if (!options.fields) options.fields = {} 112 if (!options.fields) options.fields = {}
@@ -121,10 +123,10 @@ function makePostBodyRequest (options: {
121} 123}
122 124
123function makePutBodyRequest (options: { 125function makePutBodyRequest (options: {
124 url: string, 126 url: string
125 path: string, 127 path: string
126 token?: string, 128 token?: string
127 fields: { [ fieldName: string ]: any }, 129 fields: { [ fieldName: string ]: any }
128 statusCodeExpected?: number 130 statusCodeExpected?: number
129}) { 131}) {
130 if (!options.statusCodeExpected) options.statusCodeExpected = 400 132 if (!options.statusCodeExpected) options.statusCodeExpected = 400
@@ -147,9 +149,9 @@ function makeHTMLRequest (url: string, path: string) {
147} 149}
148 150
149function updateAvatarRequest (options: { 151function updateAvatarRequest (options: {
150 url: string, 152 url: string
151 path: string, 153 path: string
152 accessToken: string, 154 accessToken: string
153 fixture: string 155 fixture: string
154}) { 156}) {
155 let filePath = '' 157 let filePath = ''
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts
index da806e692..4c52ea11c 100644
--- a/shared/extra-utils/search/videos.ts
+++ b/shared/extra-utils/search/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { VideosSearchQuery } from '../../models/search' 4import { VideosSearchQuery } from '../../models/search'
diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts
index 273aac747..dc631e823 100644
--- a/shared/extra-utils/server/clients.ts
+++ b/shared/extra-utils/server/clients.ts
@@ -1,12 +1,12 @@
1import * as request from 'supertest' 1import * as request from 'supertest'
2import * as urlUtil from 'url' 2import { URL } from 'url'
3 3
4function getClient (url: string) { 4function getClient (url: string) {
5 const path = '/api/v1/oauth-clients/local' 5 const path = '/api/v1/oauth-clients/local'
6 6
7 return request(url) 7 return request(url)
8 .get(path) 8 .get(path)
9 .set('Host', urlUtil.parse(url).host) 9 .set('Host', new URL(url).host)
10 .set('Accept', 'application/json') 10 .set('Accept', 'application/json')
11 .expect(200) 11 .expect(200)
12 .expect('Content-Type', /json/) 12 .expect('Content-Type', /json/)
diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts
index e002e03dd..d50f83241 100644
--- a/shared/extra-utils/server/contact-form.ts
+++ b/shared/extra-utils/server/contact-form.ts
@@ -2,11 +2,11 @@ import * as request from 'supertest'
2import { ContactForm } from '../../models/server' 2import { ContactForm } from '../../models/server'
3 3
4function sendContactForm (options: { 4function sendContactForm (options: {
5 url: string, 5 url: string
6 fromEmail: string, 6 fromEmail: string
7 fromName: string, 7 fromName: string
8 subject: string, 8 subject: string
9 body: string, 9 body: string
10 expectedStatus?: number 10 expectedStatus?: number
11}) { 11}) {
12 const path = '/api/v1/server/contact' 12 const path = '/api/v1/server/contact'
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 3f7729c20..006d59199 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -5,12 +5,12 @@ import { makePostBodyRequest } from '../requests/requests'
5import { ActivityPubActorType, FollowState } from '@shared/models' 5import { ActivityPubActorType, FollowState } from '@shared/models'
6 6
7function getFollowersListPaginationAndSort (options: { 7function getFollowersListPaginationAndSort (options: {
8 url: string, 8 url: string
9 start: number, 9 start: number
10 count: number, 10 count: number
11 sort: string, 11 sort: string
12 search?: string, 12 search?: string
13 actorType?: ActivityPubActorType, 13 actorType?: ActivityPubActorType
14 state?: FollowState 14 state?: FollowState
15}) { 15}) {
16 const { url, start, count, sort, search, state, actorType } = options 16 const { url, start, count, sort, search, state, actorType } = options
@@ -56,12 +56,12 @@ function rejectFollower (url: string, token: string, follower: string, statusCod
56} 56}
57 57
58function getFollowingListPaginationAndSort (options: { 58function getFollowingListPaginationAndSort (options: {
59 url: string, 59 url: string
60 start: number, 60 start: number
61 count: number, 61 count: number
62 sort: string, 62 sort: string
63 search?: string, 63 search?: string
64 actorType?: ActivityPubActorType, 64 actorType?: ActivityPubActorType
65 state?: FollowState 65 state?: FollowState
66}) { 66}) {
67 const { url, start, count, sort, search, state, actorType } = options 67 const { url, start, count, sort, search, state, actorType } = options
@@ -92,7 +92,7 @@ function follow (follower: string, following: string[], accessToken: string, exp
92 .post(path) 92 .post(path)
93 .set('Accept', 'application/json') 93 .set('Accept', 'application/json')
94 .set('Authorization', 'Bearer ' + accessToken) 94 .set('Authorization', 'Bearer ' + accessToken)
95 .send({ 'hosts': followingHosts }) 95 .send({ hosts: followingHosts })
96 .expect(expectedStatus) 96 .expect(expectedStatus)
97} 97}
98 98
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
index 56fe5fa2a..d984b3d1e 100644
--- a/shared/extra-utils/server/jobs.ts
+++ b/shared/extra-utils/server/jobs.ts
@@ -8,20 +8,20 @@ function getJobsList (url: string, accessToken: string, state: JobState) {
8 const path = '/api/v1/jobs/' + state 8 const path = '/api/v1/jobs/' + state
9 9
10 return request(url) 10 return request(url)
11 .get(path) 11 .get(path)
12 .set('Accept', 'application/json') 12 .set('Accept', 'application/json')
13 .set('Authorization', 'Bearer ' + accessToken) 13 .set('Authorization', 'Bearer ' + accessToken)
14 .expect(200) 14 .expect(200)
15 .expect('Content-Type', /json/) 15 .expect('Content-Type', /json/)
16} 16}
17 17
18function getJobsListPaginationAndSort (options: { 18function getJobsListPaginationAndSort (options: {
19 url: string, 19 url: string
20 accessToken: string, 20 accessToken: string
21 state: JobState, 21 state: JobState
22 start: number, 22 start: number
23 count: number, 23 count: number
24 sort: string, 24 sort: string
25 jobType?: JobType 25 jobType?: JobType
26}) { 26}) {
27 const { url, accessToken, state, start, count, sort, jobType } = options 27 const { url, accessToken, state, start, count, sort, jobType } = options
diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts
index 5c0d1e511..2d02d823d 100644
--- a/shared/extra-utils/server/plugins.ts
+++ b/shared/extra-utils/server/plugins.ts
@@ -7,13 +7,13 @@ import { root } from '../miscs/miscs'
7import { join } from 'path' 7import { join } from 'path'
8 8
9function listPlugins (parameters: { 9function listPlugins (parameters: {
10 url: string, 10 url: string
11 accessToken: string, 11 accessToken: string
12 start?: number, 12 start?: number
13 count?: number, 13 count?: number
14 sort?: string, 14 sort?: string
15 pluginType?: PluginType, 15 pluginType?: PluginType
16 uninstalled?: boolean, 16 uninstalled?: boolean
17 expectedStatus?: number 17 expectedStatus?: number
18}) { 18}) {
19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters 19 const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters
@@ -35,13 +35,13 @@ function listPlugins (parameters: {
35} 35}
36 36
37function listAvailablePlugins (parameters: { 37function listAvailablePlugins (parameters: {
38 url: string, 38 url: string
39 accessToken: string, 39 accessToken: string
40 start?: number, 40 start?: number
41 count?: number, 41 count?: number
42 sort?: string, 42 sort?: string
43 pluginType?: PluginType, 43 pluginType?: PluginType
44 currentPeerTubeEngine?: string, 44 currentPeerTubeEngine?: string
45 search?: string 45 search?: string
46 expectedStatus?: number 46 expectedStatus?: number
47}) { 47}) {
@@ -67,9 +67,9 @@ function listAvailablePlugins (parameters: {
67} 67}
68 68
69function getPlugin (parameters: { 69function getPlugin (parameters: {
70 url: string, 70 url: string
71 accessToken: string, 71 accessToken: string
72 npmName: string, 72 npmName: string
73 expectedStatus?: number 73 expectedStatus?: number
74}) { 74}) {
75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 75 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -84,10 +84,10 @@ function getPlugin (parameters: {
84} 84}
85 85
86function updatePluginSettings (parameters: { 86function updatePluginSettings (parameters: {
87 url: string, 87 url: string
88 accessToken: string, 88 accessToken: string
89 npmName: string, 89 npmName: string
90 settings: any, 90 settings: any
91 expectedStatus?: number 91 expectedStatus?: number
92}) { 92}) {
93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters 93 const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters
@@ -103,9 +103,9 @@ function updatePluginSettings (parameters: {
103} 103}
104 104
105function getPluginRegisteredSettings (parameters: { 105function getPluginRegisteredSettings (parameters: {
106 url: string, 106 url: string
107 accessToken: string, 107 accessToken: string
108 npmName: string, 108 npmName: string
109 expectedStatus?: number 109 expectedStatus?: number
110}) { 110}) {
111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters 111 const { url, accessToken, npmName, expectedStatus = 200 } = parameters
@@ -120,8 +120,8 @@ function getPluginRegisteredSettings (parameters: {
120} 120}
121 121
122function getPublicSettings (parameters: { 122function getPublicSettings (parameters: {
123 url: string, 123 url: string
124 npmName: string, 124 npmName: string
125 expectedStatus?: number 125 expectedStatus?: number
126}) { 126}) {
127 const { url, npmName, expectedStatus = 200 } = parameters 127 const { url, npmName, expectedStatus = 200 } = parameters
@@ -135,8 +135,8 @@ function getPublicSettings (parameters: {
135} 135}
136 136
137function getPluginTranslations (parameters: { 137function getPluginTranslations (parameters: {
138 url: string, 138 url: string
139 locale: string, 139 locale: string
140 expectedStatus?: number 140 expectedStatus?: number
141}) { 141}) {
142 const { url, locale, expectedStatus = 200 } = parameters 142 const { url, locale, expectedStatus = 200 } = parameters
@@ -150,9 +150,9 @@ function getPluginTranslations (parameters: {
150} 150}
151 151
152function installPlugin (parameters: { 152function installPlugin (parameters: {
153 url: string, 153 url: string
154 accessToken: string, 154 accessToken: string
155 path?: string, 155 path?: string
156 npmName?: string 156 npmName?: string
157 expectedStatus?: number 157 expectedStatus?: number
158}) { 158}) {
@@ -169,9 +169,9 @@ function installPlugin (parameters: {
169} 169}
170 170
171function updatePlugin (parameters: { 171function updatePlugin (parameters: {
172 url: string, 172 url: string
173 accessToken: string, 173 accessToken: string
174 path?: string, 174 path?: string
175 npmName?: string 175 npmName?: string
176 expectedStatus?: number 176 expectedStatus?: number
177}) { 177}) {
@@ -188,8 +188,8 @@ function updatePlugin (parameters: {
188} 188}
189 189
190function uninstallPlugin (parameters: { 190function uninstallPlugin (parameters: {
191 url: string, 191 url: string
192 accessToken: string, 192 accessToken: string
193 npmName: string 193 npmName: string
194 expectedStatus?: number 194 expectedStatus?: number
195}) { 195}) {
diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts
index c39ff2c8b..08467e4c0 100644
--- a/shared/extra-utils/server/redundancy.ts
+++ b/shared/extra-utils/server/redundancy.ts
@@ -1,6 +1,7 @@
1import { makePutBodyRequest } from '../requests/requests' 1import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
2import { VideoRedundanciesTarget } from '@shared/models'
2 3
3async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) { 4function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) {
4 const path = '/api/v1/server/redundancy/' + host 5 const path = '/api/v1/server/redundancy/' + host
5 6
6 return makePutBodyRequest({ 7 return makePutBodyRequest({
@@ -12,6 +13,69 @@ async function updateRedundancy (url: string, accessToken: string, host: string,
12 }) 13 })
13} 14}
14 15
16function listVideoRedundancies (options: {
17 url: string
18 accessToken: string
19 target: VideoRedundanciesTarget
20 start?: number
21 count?: number
22 sort?: string
23 statusCodeExpected?: number
24}) {
25 const path = '/api/v1/server/redundancy/videos'
26
27 const { url, accessToken, target, statusCodeExpected, start, count, sort } = options
28
29 return makeGetRequest({
30 url,
31 token: accessToken,
32 path,
33 query: {
34 start: start ?? 0,
35 count: count ?? 5,
36 sort: sort ?? 'name',
37 target
38 },
39 statusCodeExpected: statusCodeExpected || 200
40 })
41}
42
43function addVideoRedundancy (options: {
44 url: string
45 accessToken: string
46 videoId: number
47}) {
48 const path = '/api/v1/server/redundancy/videos'
49 const { url, accessToken, videoId } = options
50
51 return makePostBodyRequest({
52 url,
53 token: accessToken,
54 path,
55 fields: { videoId },
56 statusCodeExpected: 204
57 })
58}
59
60function removeVideoRedundancy (options: {
61 url: string
62 accessToken: string
63 redundancyId: number
64}) {
65 const { url, accessToken, redundancyId } = options
66 const path = '/api/v1/server/redundancy/videos/' + redundancyId
67
68 return makeDeleteRequest({
69 url,
70 token: accessToken,
71 path,
72 statusCodeExpected: 204
73 })
74}
75
15export { 76export {
16 updateRedundancy 77 updateRedundancy,
78 listVideoRedundancies,
79 addVideoRedundancy,
80 removeVideoRedundancy
17} 81}
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
index a0720d778..a0f0ce9c9 100644
--- a/shared/extra-utils/server/servers.ts
+++ b/shared/extra-utils/server/servers.ts
@@ -1,16 +1,15 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { ChildProcess, exec, fork } from 'child_process' 3import { ChildProcess, exec, fork } from 'child_process'
4import { join } from 'path' 4import { join } from 'path'
5import { root, wait } from '../miscs/miscs' 5import { root, wait } from '../miscs/miscs'
6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra' 6import { copy, pathExists, readdir, readFile, remove } from 'fs-extra'
7import { existsSync } from 'fs'
8import { expect } from 'chai' 7import { expect } from 'chai'
9import { VideoChannel } from '../../models/videos' 8import { VideoChannel } from '../../models/videos'
10import { randomInt } from '../../core-utils/miscs/miscs' 9import { randomInt } from '../../core-utils/miscs/miscs'
11 10
12interface ServerInfo { 11interface ServerInfo {
13 app: ChildProcess, 12 app: ChildProcess
14 url: string 13 url: string
15 host: string 14 host: string
16 15
@@ -20,13 +19,13 @@ interface ServerInfo {
20 serverNumber: number 19 serverNumber: number
21 20
22 client: { 21 client: {
23 id: string, 22 id: string
24 secret: string 23 secret: string
25 } 24 }
26 25
27 user: { 26 user: {
28 username: string, 27 username: string
29 password: string, 28 password: string
30 email?: string 29 email?: string
31 } 30 }
32 31
@@ -57,7 +56,7 @@ function parallelTests () {
57} 56}
58 57
59function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { 58function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
60 let apps = [] 59 const apps = []
61 let i = 0 60 let i = 0
62 61
63 return new Promise<ServerInfo[]>(res => { 62 return new Promise<ServerInfo[]>(res => {
@@ -203,20 +202,20 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = []
203 202
204 // Capture things if we want to 203 // Capture things if we want to
205 for (const key of Object.keys(regexps)) { 204 for (const key of Object.keys(regexps)) {
206 const regexp = regexps[ key ] 205 const regexp = regexps[key]
207 const matches = data.toString().match(regexp) 206 const matches = data.toString().match(regexp)
208 if (matches !== null) { 207 if (matches !== null) {
209 if (key === 'client_id') server.client.id = matches[ 1 ] 208 if (key === 'client_id') server.client.id = matches[1]
210 else if (key === 'client_secret') server.client.secret = matches[ 1 ] 209 else if (key === 'client_secret') server.client.secret = matches[1]
211 else if (key === 'user_username') server.user.username = matches[ 1 ] 210 else if (key === 'user_username') server.user.username = matches[1]
212 else if (key === 'user_password') server.user.password = matches[ 1 ] 211 else if (key === 'user_password') server.user.password = matches[1]
213 } 212 }
214 } 213 }
215 214
216 // Check if all required sentences are here 215 // Check if all required sentences are here
217 for (const key of Object.keys(serverRunString)) { 216 for (const key of Object.keys(serverRunString)) {
218 if (data.toString().indexOf(key) !== -1) serverRunString[ key ] = true 217 if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
219 if (serverRunString[ key ] === false) dontContinue = true 218 if (serverRunString[key] === false) dontContinue = true
220 } 219 }
221 220
222 // If no, there is maybe one thing not already initialized (client/user credentials generation...) 221 // If no, there is maybe one thing not already initialized (client/user credentials generation...)
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
index 627e17cc3..f87706f6a 100644
--- a/shared/extra-utils/users/accounts.ts
+++ b/shared/extra-utils/users/accounts.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import * as request from 'supertest' 3import * as request from 'supertest'
4import { expect } from 'chai' 4import { expect } from 'chai'
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts
index 5feb84179..39e720b42 100644
--- a/shared/extra-utils/users/blocklist.ts
+++ b/shared/extra-utils/users/blocklist.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' 3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests'
4 4
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts
index f9bfb3cb3..4fe54a74a 100644
--- a/shared/extra-utils/users/login.ts
+++ b/shared/extra-utils/users/login.ts
@@ -60,7 +60,7 @@ function setAccessTokensToServers (servers: ServerInfo[]) {
60 const tasks: Promise<any>[] = [] 60 const tasks: Promise<any>[] = []
61 61
62 for (const server of servers) { 62 for (const server of servers) {
63 const p = serverLogin(server).then(t => server.accessToken = t) 63 const p = serverLogin(server).then(t => { server.accessToken = t })
64 tasks.push(p) 64 tasks.push(p)
65 } 65 }
66 66
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
index 9a5fd7e86..f949878e4 100644
--- a/shared/extra-utils/users/user-notifications.ts
+++ b/shared/extra-utils/users/user-notifications.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2 2
3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' 3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users' 4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
@@ -54,6 +54,7 @@ function markAsReadNotifications (url: string, token: string, ids: number[], sta
54 statusCodeExpected 54 statusCodeExpected
55 }) 55 })
56} 56}
57
57function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) { 58function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
58 const path = '/api/v1/users/me/notifications/read-all' 59 const path = '/api/v1/users/me/notifications/read-all'
59 60
@@ -77,7 +78,7 @@ type CheckerBaseParams = {
77 server: ServerInfo 78 server: ServerInfo
78 emails: object[] 79 emails: object[]
79 socketNotifications: UserNotification[] 80 socketNotifications: UserNotification[]
80 token: string, 81 token: string
81 check?: { web: boolean, mail: boolean } 82 check?: { web: boolean, mail: boolean }
82} 83}
83 84
@@ -172,7 +173,7 @@ async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName
172 } 173 }
173 174
174 function emailFinder (email: object) { 175 function emailFinder (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
@@ -195,7 +196,7 @@ async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string
195 } 196 }
196 197
197 function emailFinder (email: object) { 198 function emailFinder (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
@@ -226,7 +227,7 @@ async function checkMyVideoImportIsFinished (
226 } 227 }
227 228
228 function emailFinder (email: object) { 229 function emailFinder (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)
@@ -251,7 +252,7 @@ async function checkUserRegistered (base: CheckerBaseParams, username: string, t
251 } 252 }
252 253
253 function emailFinder (email: object) { 254 function emailFinder (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 }
@@ -291,7 +292,7 @@ async function checkNewActorFollow (
291 } 292 }
292 293
293 function emailFinder (email: object) { 294 function emailFinder (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('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
297 } 298 }
@@ -320,7 +321,7 @@ async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost:
320 } 321 }
321 322
322 function emailFinder (email: object) { 323 function emailFinder (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 }
@@ -351,7 +352,7 @@ async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost
351 } 352 }
352 353
353 function emailFinder (email: object) { 354 function emailFinder (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 }
@@ -385,7 +386,7 @@ async function checkCommentMention (
385 } 386 }
386 387
387 function emailFinder (email: object) { 388 function emailFinder (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 }
@@ -394,6 +395,7 @@ async function checkCommentMention (
394} 395}
395 396
396let lastEmailCount = 0 397let lastEmailCount = 0
398
397async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { 399async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
398 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO 400 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
399 401
@@ -413,8 +415,9 @@ 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}`
418
416 function emailFinder (email: object) { 419 function emailFinder (email: object) {
417 return email[ 'text' ].indexOf(commentUrl) !== -1 420 return email['text'].indexOf(commentUrl) !== -1
418 } 421 }
419 422
420 await checkNotification(base, notificationChecker, emailFinder, type) 423 await checkNotification(base, notificationChecker, emailFinder, type)
@@ -444,7 +447,7 @@ async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUU
444 } 447 }
445 448
446 function emailFinder (email: object) { 449 function emailFinder (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
@@ -469,8 +472,8 @@ async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, vi
469 } 472 }
470 473
471 function emailFinder (email: object) { 474 function emailFinder (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, emailFinder, type)
@@ -496,7 +499,7 @@ async function checkNewBlacklistOnMyVideo (
496 } 499 }
497 500
498 function emailFinder (email: object) { 501 function emailFinder (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
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
index 2fe0e55c2..248af2d6e 100644
--- a/shared/extra-utils/users/users.ts
+++ b/shared/extra-utils/users/users.ts
@@ -9,14 +9,14 @@ import { UserUpdateMe } from '../../models/users'
9import { omit } from 'lodash' 9import { omit } from 'lodash'
10 10
11type CreateUserArgs = { 11type CreateUserArgs = {
12 url: string, 12 url: string
13 accessToken: string, 13 accessToken: string
14 username: string, 14 username: string
15 password: string, 15 password: string
16 videoQuota?: number, 16 videoQuota?: number
17 videoQuotaDaily?: number, 17 videoQuotaDaily?: number
18 role?: UserRole, 18 role?: UserRole
19 adminFlags?: UserAdminFlag, 19 adminFlags?: UserAdminFlag
20 specialStatus?: number 20 specialStatus?: number
21} 21}
22function createUser (parameters: CreateUserArgs) { 22function createUser (parameters: CreateUserArgs) {
@@ -74,8 +74,8 @@ function registerUser (url: string, username: string, password: string, specialS
74} 74}
75 75
76function registerUserWithChannel (options: { 76function registerUserWithChannel (options: {
77 url: string, 77 url: string
78 user: { username: string, password: string, displayName?: string }, 78 user: { username: string, password: string, displayName?: string }
79 channel: { name: string, displayName: string } 79 channel: { name: string, displayName: string }
80}) { 80}) {
81 const path = '/api/v1/users/register' 81 const path = '/api/v1/users/register'
@@ -230,8 +230,8 @@ function updateMyUser (options: { url: string, accessToken: string } & UserUpdat
230} 230}
231 231
232function updateMyAvatar (options: { 232function updateMyAvatar (options: {
233 url: string, 233 url: string
234 accessToken: string, 234 accessToken: string
235 fixture: string 235 fixture: string
236}) { 236}) {
237 const path = '/api/v1/users/me/avatar/pick' 237 const path = '/api/v1/users/me/avatar/pick'
@@ -241,14 +241,14 @@ function updateMyAvatar (options: {
241 241
242function updateUser (options: { 242function updateUser (options: {
243 url: string 243 url: string
244 userId: number, 244 userId: number
245 accessToken: string, 245 accessToken: string
246 email?: string, 246 email?: string
247 emailVerified?: boolean, 247 emailVerified?: boolean
248 videoQuota?: number, 248 videoQuota?: number
249 videoQuotaDaily?: number, 249 videoQuotaDaily?: number
250 password?: string, 250 password?: string
251 adminFlags?: UserAdminFlag, 251 adminFlags?: UserAdminFlag
252 role?: UserRole 252 role?: UserRole
253}) { 253}) {
254 const path = '/api/v1/users/' + options.userId 254 const path = '/api/v1/users/' + options.userId
diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts
index e25a292fc..ba139ef95 100644
--- a/shared/extra-utils/videos/video-blacklist.ts
+++ b/shared/extra-utils/videos/video-blacklist.ts
@@ -13,11 +13,11 @@ function addVideoToBlacklist (
13 const path = '/api/v1/videos/' + videoId + '/blacklist' 13 const path = '/api/v1/videos/' + videoId + '/blacklist'
14 14
15 return request(url) 15 return request(url)
16 .post(path) 16 .post(path)
17 .send({ reason, unfederate }) 17 .send({ reason, unfederate })
18 .set('Accept', 'application/json') 18 .set('Accept', 'application/json')
19 .set('Authorization', 'Bearer ' + token) 19 .set('Authorization', 'Bearer ' + token)
20 .expect(specialStatus) 20 .expect(specialStatus)
21} 21}
22 22
23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) { 23function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
@@ -35,20 +35,20 @@ function removeVideoFromBlacklist (url: string, token: string, videoId: number |
35 const path = '/api/v1/videos/' + videoId + '/blacklist' 35 const path = '/api/v1/videos/' + videoId + '/blacklist'
36 36
37 return request(url) 37 return request(url)
38 .delete(path) 38 .delete(path)
39 .set('Accept', 'application/json') 39 .set('Accept', 'application/json')
40 .set('Authorization', 'Bearer ' + token) 40 .set('Authorization', 'Bearer ' + token)
41 .expect(specialStatus) 41 .expect(specialStatus)
42} 42}
43 43
44function getBlacklistedVideosList (parameters: { 44function getBlacklistedVideosList (parameters: {
45 url: string, 45 url: string
46 token: string, 46 token: string
47 sort?: string, 47 sort?: string
48 type?: VideoBlacklistType, 48 type?: VideoBlacklistType
49 specialStatus?: number 49 specialStatus?: number
50}) { 50}) {
51 let { url, token, sort, type, specialStatus = 200 } = parameters 51 const { url, token, sort, type, specialStatus = 200 } = parameters
52 const path = '/api/v1/videos/blacklist/' 52 const path = '/api/v1/videos/blacklist/'
53 53
54 const query = { sort, type } 54 const query = { sort, type }
diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts
index 8d67f617b..5bd533bba 100644
--- a/shared/extra-utils/videos/video-captions.ts
+++ b/shared/extra-utils/videos/video-captions.ts
@@ -6,12 +6,12 @@ import { buildAbsoluteFixturePath } from '../miscs/miscs'
6const expect = chai.expect 6const expect = chai.expect
7 7
8function createVideoCaption (args: { 8function createVideoCaption (args: {
9 url: string, 9 url: string
10 accessToken: string 10 accessToken: string
11 videoId: string | number 11 videoId: string | number
12 language: string 12 language: string
13 fixture: string, 13 fixture: string
14 mimeType?: string, 14 mimeType?: string
15 statusCodeExpected?: number 15 statusCodeExpected?: number
16}) { 16}) {
17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language 17 const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
index 053842331..51d433940 100644
--- a/shared/extra-utils/videos/video-channels.ts
+++ b/shared/extra-utils/videos/video-channels.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' 4import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model'
3import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' 5import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
@@ -22,11 +24,11 @@ function getVideoChannelsList (url: string, start: number, count: number, sort?:
22} 24}
23 25
24function getAccountVideoChannelsList (parameters: { 26function getAccountVideoChannelsList (parameters: {
25 url: string, 27 url: string
26 accountName: string, 28 accountName: string
27 start?: number, 29 start?: number
28 count?: number, 30 count?: number
29 sort?: string, 31 sort?: string
30 specialStatus?: number 32 specialStatus?: number
31}) { 33}) {
32 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters 34 const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters
@@ -113,9 +115,9 @@ function getVideoChannel (url: string, channelName: string) {
113} 115}
114 116
115function updateVideoChannelAvatar (options: { 117function updateVideoChannelAvatar (options: {
116 url: string, 118 url: string
117 accessToken: string, 119 accessToken: string
118 fixture: string, 120 fixture: string
119 videoChannelName: string | number 121 videoChannelName: string | number
120}) { 122}) {
121 123
@@ -129,7 +131,7 @@ function setDefaultVideoChannel (servers: ServerInfo[]) {
129 131
130 for (const server of servers) { 132 for (const server of servers) {
131 const p = getMyUserInformation(server.url, server.accessToken) 133 const p = getMyUserInformation(server.url, server.accessToken)
132 .then(res => server.videoChannel = (res.body as User).videoChannels[0]) 134 .then(res => { server.videoChannel = (res.body as User).videoChannels[0] })
133 135
134 tasks.push(p) 136 tasks.push(p)
135 } 137 }
diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts
index 0ebf69ced..81c48412d 100644
--- a/shared/extra-utils/videos/video-comments.ts
+++ b/shared/extra-utils/videos/video-comments.ts
@@ -1,3 +1,5 @@
1/* eslint-disable @typescript-eslint/no-floating-promises */
2
1import * as request from 'supertest' 3import * as request from 'supertest'
2import { makeDeleteRequest } from '../requests/requests' 4import { makeDeleteRequest } from '../requests/requests'
3 5
diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts
index 150cc94ed..8e5abd2f5 100644
--- a/shared/extra-utils/videos/video-imports.ts
+++ b/shared/extra-utils/videos/video-imports.ts
@@ -7,7 +7,7 @@ function getYoutubeVideoUrl () {
7} 7}
8 8
9function getMagnetURI () { 9function getMagnetURI () {
10 // tslint:disable:max-line-length 10 // eslint-disable-next-line max-len
11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4' 11 return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
12} 12}
13 13
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts
index 6762c5973..5bcc02570 100644
--- a/shared/extra-utils/videos/video-playlists.ts
+++ b/shared/extra-utils/videos/video-playlists.ts
@@ -123,9 +123,9 @@ function deleteVideoPlaylist (url: string, token: string, playlistId: number | s
123} 123}
124 124
125function createVideoPlaylist (options: { 125function createVideoPlaylist (options: {
126 url: string, 126 url: string
127 token: string, 127 token: string
128 playlistAttrs: VideoPlaylistCreate, 128 playlistAttrs: VideoPlaylistCreate
129 expectedStatus?: number 129 expectedStatus?: number
130}) { 130}) {
131 const path = '/api/v1/video-playlists' 131 const path = '/api/v1/video-playlists'
@@ -148,10 +148,10 @@ function createVideoPlaylist (options: {
148} 148}
149 149
150function updateVideoPlaylist (options: { 150function updateVideoPlaylist (options: {
151 url: string, 151 url: string
152 token: string, 152 token: string
153 playlistAttrs: VideoPlaylistUpdate, 153 playlistAttrs: VideoPlaylistUpdate
154 playlistId: number | string, 154 playlistId: number | string
155 expectedStatus?: number 155 expectedStatus?: number
156}) { 156}) {
157 const path = '/api/v1/video-playlists/' + options.playlistId 157 const path = '/api/v1/video-playlists/' + options.playlistId
@@ -174,9 +174,9 @@ function updateVideoPlaylist (options: {
174} 174}
175 175
176async function addVideoInPlaylist (options: { 176async function addVideoInPlaylist (options: {
177 url: string, 177 url: string
178 token: string, 178 token: string
179 playlistId: number | string, 179 playlistId: number | string
180 elementAttrs: VideoPlaylistElementCreate | { videoId: string } 180 elementAttrs: VideoPlaylistElementCreate | { videoId: string }
181 expectedStatus?: number 181 expectedStatus?: number
182}) { 182}) {
@@ -194,11 +194,11 @@ async function addVideoInPlaylist (options: {
194} 194}
195 195
196function updateVideoPlaylistElement (options: { 196function updateVideoPlaylistElement (options: {
197 url: string, 197 url: string
198 token: string, 198 token: string
199 playlistId: number | string, 199 playlistId: number | string
200 playlistElementId: number | string, 200 playlistElementId: number | string
201 elementAttrs: VideoPlaylistElementUpdate, 201 elementAttrs: VideoPlaylistElementUpdate
202 expectedStatus?: number 202 expectedStatus?: number
203}) { 203}) {
204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 204 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -213,10 +213,10 @@ function updateVideoPlaylistElement (options: {
213} 213}
214 214
215function removeVideoFromPlaylist (options: { 215function removeVideoFromPlaylist (options: {
216 url: string, 216 url: string
217 token: string, 217 token: string
218 playlistId: number | string, 218 playlistId: number | string
219 playlistElementId: number, 219 playlistElementId: number
220 expectedStatus?: number 220 expectedStatus?: number
221}) { 221}) {
222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId 222 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
@@ -230,14 +230,14 @@ function removeVideoFromPlaylist (options: {
230} 230}
231 231
232function reorderVideosPlaylist (options: { 232function reorderVideosPlaylist (options: {
233 url: string, 233 url: string
234 token: string, 234 token: string
235 playlistId: number | string, 235 playlistId: number | string
236 elementAttrs: { 236 elementAttrs: {
237 startPosition: number, 237 startPosition: number
238 insertAfterPosition: number, 238 insertAfterPosition: number
239 reorderLength?: number 239 reorderLength?: number
240 }, 240 }
241 expectedStatus?: number 241 expectedStatus?: number
242}) { 242}) {
243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' 243 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts
index eb25011cb..e54da84aa 100644
--- a/shared/extra-utils/videos/video-streaming-playlists.ts
+++ b/shared/extra-utils/videos/video-streaming-playlists.ts
@@ -37,7 +37,7 @@ async function checkSegmentHash (
37 37
38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) 38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
39 39
40 const sha256Server = resSha.body[ videoName ][range] 40 const sha256Server = resSha.body[videoName][range]
41 expect(sha256(res2.body)).to.equal(sha256Server) 41 expect(sha256(res2.body)).to.equal(sha256Server)
42} 42}
43 43
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
index 7a77a03ad..39a06b0d7 100644
--- a/shared/extra-utils/videos/videos.ts
+++ b/shared/extra-utils/videos/videos.ts
@@ -1,4 +1,4 @@
1/* tslint:disable:no-unused-expression */ 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
2 2
3import { expect } from 'chai' 3import { expect } from 'chai'
4import { pathExists, readdir, readFile } from 'fs-extra' 4import { pathExists, readdir, readFile } from 'fs-extra'
@@ -488,7 +488,7 @@ async function completeVideoCheck (
488 description: string 488 description: string
489 publishedAt?: string 489 publishedAt?: string
490 support: string 490 support: string
491 originallyPublishedAt?: string, 491 originallyPublishedAt?: string
492 account: { 492 account: {
493 name: string 493 name: string
494 host: string 494 host: string
@@ -509,7 +509,7 @@ async function completeVideoCheck (
509 files: { 509 files: {
510 resolution: number 510 resolution: number
511 size: number 511 size: number
512 }[], 512 }[]
513 thumbnailfile?: string 513 thumbnailfile?: string
514 previewfile?: string 514 previewfile?: string
515 } 515 }
@@ -583,9 +583,10 @@ async function completeVideoCheck (
583 583
584 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) 584 const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
585 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) 585 const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
586 expect(file.size, 586 expect(
587 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')') 587 file.size,
588 .to.be.above(minSize).and.below(maxSize) 588 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
589 ).to.be.above(minSize).and.below(maxSize)
589 590
590 const torrent = await webtorrentAdd(file.magnetUri, true) 591 const torrent = await webtorrentAdd(file.magnetUri, true)
591 expect(torrent.files).to.be.an('array') 592 expect(torrent.files).to.be.an('array')
@@ -607,15 +608,28 @@ async function videoUUIDToId (url: string, id: number | string) {
607 return res.body.id 608 return res.body.id
608} 609}
609 610
610async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) { 611async function uploadVideoAndGetId (options: {
612 server: ServerInfo
613 videoName: string
614 nsfw?: boolean
615 privacy?: VideoPrivacy
616 token?: string
617}) {
611 const videoAttrs: any = { name: options.videoName } 618 const videoAttrs: any = { name: options.videoName }
612 if (options.nsfw) videoAttrs.nsfw = options.nsfw 619 if (options.nsfw) videoAttrs.nsfw = options.nsfw
620 if (options.privacy) videoAttrs.privacy = options.privacy
613 621
614 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs) 622 const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
615 623
616 return { id: res.body.video.id, uuid: res.body.video.uuid } 624 return { id: res.body.video.id, uuid: res.body.video.uuid }
617} 625}
618 626
627async function getLocalIdByUUID (url: string, uuid: string) {
628 const res = await getVideo(url, uuid)
629
630 return res.body.id
631}
632
619// --------------------------------------------------------------------------- 633// ---------------------------------------------------------------------------
620 634
621export { 635export {
@@ -645,5 +659,6 @@ export {
645 completeVideoCheck, 659 completeVideoCheck,
646 checkVideoFilesWereRemoved, 660 checkVideoFilesWereRemoved,
647 getPlaylistVideos, 661 getPlaylistVideos,
648 uploadVideoAndGetId 662 uploadVideoAndGetId,
663 getLocalIdByUUID
649} 664}
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'
8import { APObject } from './objects/object.model' 8import { APObject } from './objects/object.model'
9import { PlaylistObject } from './objects/playlist-object' 9import { PlaylistObject } from './objects/playlist-object'
10 10
11export type Activity = ActivityCreate | ActivityUpdate | 11export type Activity =
12 ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce | 12 ActivityCreate |
13 ActivityUndo | ActivityLike | ActivityReject | ActivityView | ActivityDislike | ActivityFlag 13 ActivityUpdate |
14 14 ActivityDelete |
15export 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
25export 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
18export interface ActivityAudience { 39export interface ActivityAudience {
19 to: string[] 40 to: string[]
@@ -66,17 +87,17 @@ export interface ActivityAnnounce extends BaseActivity {
66} 87}
67 88
68export interface ActivityUndo extends BaseActivity { 89export 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
73export interface ActivityLike extends BaseActivity { 94export interface ActivityLike extends BaseActivity {
74 type: 'Like', 95 type: 'Like'
75 object: APObject 96 object: APObject
76} 97}
77 98
78export interface ActivityView extends BaseActivity { 99export 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
91export interface ActivityFlag extends BaseActivity { 112export 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 @@
1import { ActivityPubAttributedTo } from './objects/common-objects' 1import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects'
2 2
3export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization' 3export 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 @@
1export interface ActivityPubSignature { 1export 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/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
3export interface CacheFileObject { 3export 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..e94d05429 100644
--- a/shared/models/activitypub/objects/common-objects.ts
+++ b/shared/models/activitypub/objects/common-objects.ts
@@ -1,14 +1,15 @@
1export interface ActivityIdentifierObject { 1export interface ActivityIdentifierObject {
2 identifier: string 2 identifier: string
3 name: string 3 name: string
4 url?: string
4} 5}
5 6
6export interface ActivityIconObject { 7export 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
14export type ActivityVideoUrlObject = { 15export type ActivityVideoUrlObject = {
@@ -71,19 +72,21 @@ export interface ActivityMentionObject {
71 name: string 72 name: string
72} 73}
73 74
74export type ActivityTagObject = ActivityPlaylistSegmentHashesObject | 75export type ActivityTagObject =
75 ActivityPlaylistInfohashesObject | 76 ActivityPlaylistSegmentHashesObject
76 ActivityVideoUrlObject | 77 | ActivityPlaylistInfohashesObject
77 ActivityHashTagObject | 78 | ActivityVideoUrlObject
78 ActivityMentionObject | 79 | ActivityHashTagObject
79 ActivityBitTorrentUrlObject | 80 | ActivityMentionObject
80 ActivityMagnetUrlObject 81 | ActivityBitTorrentUrlObject
82 | ActivityMagnetUrlObject
81 83
82export type ActivityUrlObject = ActivityVideoUrlObject | 84export type ActivityUrlObject =
83 ActivityPlaylistUrlObject | 85 ActivityVideoUrlObject
84 ActivityBitTorrentUrlObject | 86 | ActivityPlaylistUrlObject
85 ActivityMagnetUrlObject | 87 | ActivityBitTorrentUrlObject
86 ActivityHtmlUrlObject 88 | ActivityMagnetUrlObject
89 | ActivityHtmlUrlObject
87 90
88export interface ActivityPubAttributedTo { 91export interface ActivityPubAttributedTo {
89 type: 'Group' | 'Person' 92 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 @@
1export interface VideoAbuseObject { 1export 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 @@
1export interface ViewObject { 1export 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..36688382d 100644
--- a/shared/models/i18n/i18n.ts
+++ b/shared/models/i18n/i18n.ts
@@ -1,44 +1,50 @@
1export const LOCALE_FILES = [ 'player', 'server' ] 1export const LOCALE_FILES = [ 'player', 'server' ]
2 2
3export const I18N_LOCALES = { 3export 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',
10 'el-GR': 'ελληνικά',
11 'eo': 'Esperanto',
12 'es-ES': 'Español',
13 'eu-ES': 'Euskara',
14 'fi-FI': 'suomi',
15 'fr-FR': 'Français',
16 'gd': 'Gàidhlig',
17 'hu-HU': 'magyar',
13 'it-IT': 'Italiano', 18 'it-IT': 'Italiano',
19 'ja-JP': '日本語',
14 'nl-NL': 'Nederlands', 20 'nl-NL': 'Nederlands',
15 'es-ES': 'Español',
16 'oc': 'Occitan', 21 'oc': 'Occitan',
17 'gd': 'Gàidhlig', 22 'pl-PL': 'Polski',
18 'zh-Hant-TW': '繁體中文(台灣)',
19 'pt-BR': 'Português (Brasil)', 23 'pt-BR': 'Português (Brasil)',
20 'pt-PT': 'Português (Portugal)', 24 'pt-PT': 'Português (Portugal)',
21 'sv-SE': 'svenska',
22 'pl-PL': 'Polski',
23 'fi-FI': 'suomi',
24 'ru-RU': 'русский', 25 'ru-RU': 'русский',
25 'zh-Hans-CN': '简体中文(中国)' 26 'sv-SE': 'svenska',
27 'th-TH': 'ไทย',
28 'zh-Hans-CN': '简体中文(中国)',
29 'zh-Hant-TW': '繁體中文(台灣)'
26} 30}
27 31
28const I18N_LOCALE_ALIAS = { 32const I18N_LOCALE_ALIAS = {
29 'en': 'en-US',
30 'fr': 'fr-FR',
31 'eu': 'eu-ES',
32 'ca': 'ca-ES', 33 'ca': 'ca-ES',
33 'cs': 'cs-CZ', 34 'cs': 'cs-CZ',
34 'de': 'de-DE', 35 'de': 'de-DE',
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 'hu': 'hu-HU',
42 'nl': 'nl-NL',
39 'pl': 'pl-PL', 43 'pl': 'pl-PL',
44 'pt': 'pt-PT',
40 'ru': 'ru-RU', 45 'ru': 'ru-RU',
41 'nl': 'nl-NL', 46 'sv': 'sv-SE',
47 'th': 'th-TH',
42 'zh': 'zh-Hans-CN', 48 'zh': 'zh-Hans-CN',
43 'zh-CN': 'zh-Hans-CN', 49 'zh-CN': 'zh-Hans-CN',
44 'zh-TW': 'zh-Hant-TW' 50 'zh-TW': 'zh-Hant-TW'
@@ -56,6 +62,8 @@ export function isDefaultLocale (locale: string) {
56} 62}
57 63
58export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) { 64export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {
65 // FIXME: remove disable rule when the client is upgraded to typescript 3.7
66 // eslint-disable-next-line
59 return translations && translations[str] ? translations[str] : str 67 return translations && translations[str] ? translations[str] : str
60} 68}
61 69
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/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 @@
1export interface PeertubePluginLatestVersionRequest { 1export 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-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
7export type ClientScript = { 7export 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/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 @@
1export * from './videos-redundancy.model' 1export * from './videos-redundancy-strategy.model'
2export * from './video-redundancies-filters.model'
3export * 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.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 @@
1export 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
14interface 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
28export interface FileRedundancyInformation extends RedundancyInformation {
29
30}
31
32// eslint-disable-next-line @typescript-eslint/no-empty-interface
33export 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 @@
1export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added' 1export type VideoRedundancyStrategy = 'most-views' | 'trending' | 'recently-added'
2export type VideoRedundancyStrategyWithManual = VideoRedundancyStrategy | 'manual'
2 3
3export type MostViewsRedundancyStrategy = { 4export 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
22export type VideosRedundancy = MostViewsRedundancyStrategy | TrendingRedundancyStrategy | RecentlyAddedStrategy 23export 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/job.model.ts b/shared/models/server/job.model.ts
index b82a633b2..cf29d20d4 100644
--- a/shared/models/server/job.model.ts
+++ b/shared/models/server/job.model.ts
@@ -1,22 +1,24 @@
1export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed' 1export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed'
2 2
3export type JobType = 'activitypub-http-unicast' | 3export type JobType =
4 'activitypub-http-broadcast' | 4 | 'activitypub-http-unicast'
5 'activitypub-http-fetcher' | 5 | 'activitypub-http-broadcast'
6 'activitypub-follow' | 6 | 'activitypub-http-fetcher'
7 'video-file-import' | 7 | 'activitypub-follow'
8 'video-transcoding' | 8 | 'video-file-import'
9 'email' | 9 | 'video-transcoding'
10 'video-import' | 10 | 'email'
11 'videos-views' | 11 | 'video-import'
12 'activitypub-refresher' 12 | 'videos-views'
13 | 'activitypub-refresher'
14 | 'video-redundancy'
13 15
14export interface Job { 16export interface Job {
15 id: number 17 id: number
16 state: JobState 18 state: JobState
17 type: JobType 19 type: JobType
18 data: any, 20 data: any
19 error: any, 21 error: any
20 createdAt: Date | string 22 createdAt: Date | string
21 finishedOn: Date | string 23 finishedOn: Date | string
22 processedOn: Date | string 24 processedOn: Date | string
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts
index f1bb2153c..76e0d6f2d 100644
--- a/shared/models/server/server-config.model.ts
+++ b/shared/models/server/server-config.model.ts
@@ -46,7 +46,7 @@ export interface ServerConfig {
46 } 46 }
47 47
48 signup: { 48 signup: {
49 allowed: boolean, 49 allowed: boolean
50 allowedForCurrentIP: boolean 50 allowedForCurrentIP: boolean
51 requiresEmailVerification: boolean 51 requiresEmailVerification: boolean
52 } 52 }
@@ -97,7 +97,7 @@ export interface ServerConfig {
97 max: number 97 max: number
98 } 98 }
99 extensions: string[] 99 extensions: string[]
100 }, 100 }
101 file: { 101 file: {
102 extensions: string[] 102 extensions: string[]
103 } 103 }
@@ -107,7 +107,7 @@ export interface ServerConfig {
107 file: { 107 file: {
108 size: { 108 size: {
109 max: number 109 max: number
110 }, 110 }
111 extensions: string[] 111 extensions: string[]
112 } 112 }
113 } 113 }
diff --git a/shared/models/server/server-stats.model.ts b/shared/models/server/server-stats.model.ts
index 74f3de5d3..11778e6ed 100644
--- a/shared/models/server/server-stats.model.ts
+++ b/shared/models/server/server-stats.model.ts
@@ -1,4 +1,4 @@
1import { VideoRedundancyStrategy } from '../redundancy' 1import { VideoRedundancyStrategyWithManual } from '../redundancy'
2 2
3export interface ServerStats { 3export interface ServerStats {
4 totalUsers: number 4 totalUsers: number
@@ -13,11 +13,13 @@ export interface ServerStats {
13 totalInstanceFollowers: number 13 totalInstanceFollowers: number
14 totalInstanceFollowing: number 14 totalInstanceFollowing: number
15 15
16 videosRedundancy: { 16 videosRedundancy: VideosRedundancyStats[]
17 strategy: VideoRedundancyStrategy 17}
18 totalSize: number 18
19 totalUsed: number 19export interface VideosRedundancyStats {
20 totalVideoFiles: number 20 strategy: VideoRedundancyStrategyWithManual
21 totalVideos: number 21 totalSize: number
22 }[] 22 totalUsed: number
23 totalVideoFiles: number
24 totalVideos: number
23} 25}
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..ae3a0d983 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 10export const USER_ROLE_LABELS: { [ id in UserRole ]: string } = {
11export 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 16const userRoleRights: { [ id in UserRole ]: UserRight[] } = {
18const userRoleRights: { [ id: number ]: UserRight[] } = {
19 [UserRole.ADMINISTRATOR]: [ 17 [UserRole.ADMINISTRATOR]: [
20 UserRight.ALL 18 UserRight.ALL
21 ], 19 ],
diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts
index 168851196..efb451014 100644
--- a/shared/models/users/user.model.ts
+++ b/shared/models/users/user.model.ts
@@ -1,6 +1,5 @@
1import { Account } from '../actors' 1import { Account } from '../actors'
2import { VideoChannel } from '../videos/channel/video-channel.model' 2import { VideoChannel } from '../videos/channel/video-channel.model'
3import { VideoPlaylist } from '../videos/playlist/video-playlist.model'
4import { UserRole } from './user-role' 3import { UserRole } from './user-role'
5import { NSFWPolicyType } from '../videos/nsfw-policy.type' 4import { NSFWPolicyType } from '../videos/nsfw-policy.type'
6import { UserNotificationSetting } from './user-notification-setting.model' 5import { UserNotificationSetting } from './user-notification-setting.model'
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 @@
1export type VideoTranscodingFPS = { 1export 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 @@
1import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index' 1import { AccountSummary, VideoChannelSummary, VideoState } from '../../index'
2import { Account } from '../actors' 2import { Account } from '../actors'
3import { VideoChannel } from './channel/video-channel.model' 3import { VideoChannel } from './channel/video-channel.model'
4import { VideoPrivacy } from './video-privacy.enum' 4import { VideoPrivacy } from './video-privacy.enum'