diff options
Diffstat (limited to 'shared/server-commands')
-rw-r--r-- | shared/server-commands/miscs/sql-command.ts | 5 | ||||
-rw-r--r-- | shared/server-commands/requests/requests.ts | 26 | ||||
-rw-r--r-- | shared/server-commands/server/jobs.ts | 9 | ||||
-rw-r--r-- | shared/server-commands/server/object-storage-command.ts | 105 | ||||
-rw-r--r-- | shared/server-commands/server/server.ts | 48 | ||||
-rw-r--r-- | shared/server-commands/users/index.ts | 1 | ||||
-rw-r--r-- | shared/server-commands/users/login-command.ts | 73 | ||||
-rw-r--r-- | shared/server-commands/users/two-factor-command.ts | 92 | ||||
-rw-r--r-- | shared/server-commands/users/users-command.ts | 8 | ||||
-rw-r--r-- | shared/server-commands/videos/index.ts | 1 | ||||
-rw-r--r-- | shared/server-commands/videos/live-command.ts | 125 | ||||
-rw-r--r-- | shared/server-commands/videos/live.ts | 7 | ||||
-rw-r--r-- | shared/server-commands/videos/streaming-playlists-command.ts | 38 | ||||
-rw-r--r-- | shared/server-commands/videos/video-token-command.ts | 31 | ||||
-rw-r--r-- | shared/server-commands/videos/videos-command.ts | 25 |
15 files changed, 498 insertions, 96 deletions
diff --git a/shared/server-commands/miscs/sql-command.ts b/shared/server-commands/miscs/sql-command.ts index 09a99f834..b0d9ce56d 100644 --- a/shared/server-commands/miscs/sql-command.ts +++ b/shared/server-commands/miscs/sql-command.ts | |||
@@ -23,6 +23,11 @@ export class SQLCommand extends AbstractCommand { | |||
23 | return parseInt(total, 10) | 23 | return parseInt(total, 10) |
24 | } | 24 | } |
25 | 25 | ||
26 | async getInternalFileUrl (fileId: number) { | ||
27 | return this.selectQuery(`SELECT "fileUrl" FROM "videoFile" WHERE id = ${fileId}`) | ||
28 | .then(rows => rows[0].fileUrl as string) | ||
29 | } | ||
30 | |||
26 | setActorField (to: string, field: string, value: string) { | 31 | setActorField (to: string, field: string, value: string) { |
27 | const seq = this.getSequelize() | 32 | const seq = this.getSequelize() |
28 | 33 | ||
diff --git a/shared/server-commands/requests/requests.ts b/shared/server-commands/requests/requests.ts index 85cbc9be9..b247017fd 100644 --- a/shared/server-commands/requests/requests.ts +++ b/shared/server-commands/requests/requests.ts | |||
@@ -3,7 +3,7 @@ | |||
3 | import { decode } from 'querystring' | 3 | import { decode } from 'querystring' |
4 | import request from 'supertest' | 4 | import request from 'supertest' |
5 | import { URL } from 'url' | 5 | import { URL } from 'url' |
6 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | 6 | import { buildAbsoluteFixturePath, pick } from '@shared/core-utils' |
7 | import { HttpStatusCode } from '@shared/models' | 7 | import { HttpStatusCode } from '@shared/models' |
8 | 8 | ||
9 | export type CommonRequestParams = { | 9 | export type CommonRequestParams = { |
@@ -21,10 +21,21 @@ export type CommonRequestParams = { | |||
21 | expectedStatus?: HttpStatusCode | 21 | expectedStatus?: HttpStatusCode |
22 | } | 22 | } |
23 | 23 | ||
24 | function makeRawRequest (url: string, expectedStatus?: HttpStatusCode, range?: string) { | 24 | function makeRawRequest (options: { |
25 | const { host, protocol, pathname } = new URL(url) | 25 | url: string |
26 | token?: string | ||
27 | expectedStatus?: HttpStatusCode | ||
28 | range?: string | ||
29 | query?: { [ id: string ]: string } | ||
30 | }) { | ||
31 | const { host, protocol, pathname } = new URL(options.url) | ||
32 | |||
33 | return makeGetRequest({ | ||
34 | url: `${protocol}//${host}`, | ||
35 | path: pathname, | ||
26 | 36 | ||
27 | return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, expectedStatus, range }) | 37 | ...pick(options, [ 'expectedStatus', 'range', 'token', 'query' ]) |
38 | }) | ||
28 | } | 39 | } |
29 | 40 | ||
30 | function makeGetRequest (options: CommonRequestParams & { | 41 | function makeGetRequest (options: CommonRequestParams & { |
@@ -134,7 +145,12 @@ function unwrapText (test: request.Test): Promise<string> { | |||
134 | function unwrapBodyOrDecodeToJSON <T> (test: request.Test): Promise<T> { | 145 | function unwrapBodyOrDecodeToJSON <T> (test: request.Test): Promise<T> { |
135 | return test.then(res => { | 146 | return test.then(res => { |
136 | if (res.body instanceof Buffer) { | 147 | if (res.body instanceof Buffer) { |
137 | return JSON.parse(new TextDecoder().decode(res.body)) | 148 | try { |
149 | return JSON.parse(new TextDecoder().decode(res.body)) | ||
150 | } catch (err) { | ||
151 | console.error('Cannot decode JSON.', res.body) | ||
152 | throw err | ||
153 | } | ||
138 | } | 154 | } |
139 | 155 | ||
140 | return res.body | 156 | return res.body |
diff --git a/shared/server-commands/server/jobs.ts b/shared/server-commands/server/jobs.ts index fc65a873b..e1d6cdff4 100644 --- a/shared/server-commands/server/jobs.ts +++ b/shared/server-commands/server/jobs.ts | |||
@@ -4,7 +4,14 @@ import { wait } from '@shared/core-utils' | |||
4 | import { JobState, JobType } from '../../models' | 4 | import { JobState, JobType } from '../../models' |
5 | import { PeerTubeServer } from './server' | 5 | import { PeerTubeServer } from './server' |
6 | 6 | ||
7 | async function waitJobs (serversArg: PeerTubeServer[] | PeerTubeServer, skipDelayed = false) { | 7 | async function waitJobs ( |
8 | serversArg: PeerTubeServer[] | PeerTubeServer, | ||
9 | options: { | ||
10 | skipDelayed?: boolean // default false | ||
11 | } = {} | ||
12 | ) { | ||
13 | const { skipDelayed = false } = options | ||
14 | |||
8 | const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT | 15 | const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT |
9 | ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) | 16 | ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) |
10 | : 250 | 17 | : 250 |
diff --git a/shared/server-commands/server/object-storage-command.ts b/shared/server-commands/server/object-storage-command.ts index b4de8f4cb..a1fe4f0f7 100644 --- a/shared/server-commands/server/object-storage-command.ts +++ b/shared/server-commands/server/object-storage-command.ts | |||
@@ -4,74 +4,135 @@ import { makePostBodyRequest } from '../requests' | |||
4 | import { AbstractCommand } from '../shared' | 4 | import { AbstractCommand } from '../shared' |
5 | 5 | ||
6 | export class ObjectStorageCommand extends AbstractCommand { | 6 | export class ObjectStorageCommand extends AbstractCommand { |
7 | static readonly DEFAULT_PLAYLIST_BUCKET = 'streaming-playlists' | 7 | static readonly DEFAULT_PLAYLIST_MOCK_BUCKET = 'streaming-playlists' |
8 | static readonly DEFAULT_WEBTORRENT_BUCKET = 'videos' | 8 | static readonly DEFAULT_WEBTORRENT_MOCK_BUCKET = 'videos' |
9 | 9 | ||
10 | static getDefaultConfig () { | 10 | static readonly DEFAULT_SCALEWAY_BUCKET = 'peertube-ci-test' |
11 | |||
12 | // --------------------------------------------------------------------------- | ||
13 | |||
14 | static getDefaultMockConfig () { | ||
11 | return { | 15 | return { |
12 | object_storage: { | 16 | object_storage: { |
13 | enabled: true, | 17 | enabled: true, |
14 | endpoint: 'http://' + this.getEndpointHost(), | 18 | endpoint: 'http://' + this.getMockEndpointHost(), |
15 | region: this.getRegion(), | 19 | region: this.getMockRegion(), |
16 | 20 | ||
17 | credentials: this.getCredentialsConfig(), | 21 | credentials: this.getMockCredentialsConfig(), |
18 | 22 | ||
19 | streaming_playlists: { | 23 | streaming_playlists: { |
20 | bucket_name: this.DEFAULT_PLAYLIST_BUCKET | 24 | bucket_name: this.DEFAULT_PLAYLIST_MOCK_BUCKET |
21 | }, | 25 | }, |
22 | 26 | ||
23 | videos: { | 27 | videos: { |
24 | bucket_name: this.DEFAULT_WEBTORRENT_BUCKET | 28 | bucket_name: this.DEFAULT_WEBTORRENT_MOCK_BUCKET |
25 | } | 29 | } |
26 | } | 30 | } |
27 | } | 31 | } |
28 | } | 32 | } |
29 | 33 | ||
30 | static getCredentialsConfig () { | 34 | static getMockCredentialsConfig () { |
31 | return { | 35 | return { |
32 | access_key_id: 'AKIAIOSFODNN7EXAMPLE', | 36 | access_key_id: 'AKIAIOSFODNN7EXAMPLE', |
33 | secret_access_key: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' | 37 | secret_access_key: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY' |
34 | } | 38 | } |
35 | } | 39 | } |
36 | 40 | ||
37 | static getEndpointHost () { | 41 | static getMockEndpointHost () { |
38 | return 'localhost:9444' | 42 | return 'localhost:9444' |
39 | } | 43 | } |
40 | 44 | ||
41 | static getRegion () { | 45 | static getMockRegion () { |
42 | return 'us-east-1' | 46 | return 'us-east-1' |
43 | } | 47 | } |
44 | 48 | ||
45 | static getWebTorrentBaseUrl () { | 49 | static getMockWebTorrentBaseUrl () { |
46 | return `http://${this.DEFAULT_WEBTORRENT_BUCKET}.${this.getEndpointHost()}/` | 50 | return `http://${this.DEFAULT_WEBTORRENT_MOCK_BUCKET}.${this.getMockEndpointHost()}/` |
47 | } | 51 | } |
48 | 52 | ||
49 | static getPlaylistBaseUrl () { | 53 | static getMockPlaylistBaseUrl () { |
50 | return `http://${this.DEFAULT_PLAYLIST_BUCKET}.${this.getEndpointHost()}/` | 54 | return `http://${this.DEFAULT_PLAYLIST_MOCK_BUCKET}.${this.getMockEndpointHost()}/` |
51 | } | 55 | } |
52 | 56 | ||
53 | static async prepareDefaultBuckets () { | 57 | static async prepareDefaultMockBuckets () { |
54 | await this.createBucket(this.DEFAULT_PLAYLIST_BUCKET) | 58 | await this.createMockBucket(this.DEFAULT_PLAYLIST_MOCK_BUCKET) |
55 | await this.createBucket(this.DEFAULT_WEBTORRENT_BUCKET) | 59 | await this.createMockBucket(this.DEFAULT_WEBTORRENT_MOCK_BUCKET) |
56 | } | 60 | } |
57 | 61 | ||
58 | static async createBucket (name: string) { | 62 | static async createMockBucket (name: string) { |
59 | await makePostBodyRequest({ | 63 | await makePostBodyRequest({ |
60 | url: this.getEndpointHost(), | 64 | url: this.getMockEndpointHost(), |
61 | path: '/ui/' + name + '?delete', | 65 | path: '/ui/' + name + '?delete', |
62 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 | 66 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 |
63 | }) | 67 | }) |
64 | 68 | ||
65 | await makePostBodyRequest({ | 69 | await makePostBodyRequest({ |
66 | url: this.getEndpointHost(), | 70 | url: this.getMockEndpointHost(), |
67 | path: '/ui/' + name + '?create', | 71 | path: '/ui/' + name + '?create', |
68 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 | 72 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 |
69 | }) | 73 | }) |
70 | 74 | ||
71 | await makePostBodyRequest({ | 75 | await makePostBodyRequest({ |
72 | url: this.getEndpointHost(), | 76 | url: this.getMockEndpointHost(), |
73 | path: '/ui/' + name + '?make-public', | 77 | path: '/ui/' + name + '?make-public', |
74 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 | 78 | expectedStatus: HttpStatusCode.TEMPORARY_REDIRECT_307 |
75 | }) | 79 | }) |
76 | } | 80 | } |
81 | |||
82 | // --------------------------------------------------------------------------- | ||
83 | |||
84 | static getDefaultScalewayConfig (options: { | ||
85 | serverNumber: number | ||
86 | enablePrivateProxy?: boolean // default true | ||
87 | privateACL?: 'private' | 'public-read' // default 'private' | ||
88 | }) { | ||
89 | const { serverNumber, enablePrivateProxy = true, privateACL = 'private' } = options | ||
90 | |||
91 | return { | ||
92 | object_storage: { | ||
93 | enabled: true, | ||
94 | endpoint: this.getScalewayEndpointHost(), | ||
95 | region: this.getScalewayRegion(), | ||
96 | |||
97 | credentials: this.getScalewayCredentialsConfig(), | ||
98 | |||
99 | upload_acl: { | ||
100 | private: privateACL | ||
101 | }, | ||
102 | |||
103 | proxy: { | ||
104 | proxify_private_files: enablePrivateProxy | ||
105 | }, | ||
106 | |||
107 | streaming_playlists: { | ||
108 | bucket_name: this.DEFAULT_SCALEWAY_BUCKET, | ||
109 | prefix: `test:server-${serverNumber}-streaming-playlists:` | ||
110 | }, | ||
111 | |||
112 | videos: { | ||
113 | bucket_name: this.DEFAULT_SCALEWAY_BUCKET, | ||
114 | prefix: `test:server-${serverNumber}-videos:` | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | |||
120 | static getScalewayCredentialsConfig () { | ||
121 | return { | ||
122 | access_key_id: process.env.OBJECT_STORAGE_SCALEWAY_KEY_ID, | ||
123 | secret_access_key: process.env.OBJECT_STORAGE_SCALEWAY_ACCESS_KEY | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static getScalewayEndpointHost () { | ||
128 | return 's3.fr-par.scw.cloud' | ||
129 | } | ||
130 | |||
131 | static getScalewayRegion () { | ||
132 | return 'fr-par' | ||
133 | } | ||
134 | |||
135 | static getScalewayBaseUrl () { | ||
136 | return `https://${this.DEFAULT_SCALEWAY_BUCKET}.${this.getScalewayEndpointHost()}/` | ||
137 | } | ||
77 | } | 138 | } |
diff --git a/shared/server-commands/server/server.ts b/shared/server-commands/server/server.ts index 2b4c9c9f8..c062e6986 100644 --- a/shared/server-commands/server/server.ts +++ b/shared/server-commands/server/server.ts | |||
@@ -13,7 +13,15 @@ import { AbusesCommand } from '../moderation' | |||
13 | import { OverviewsCommand } from '../overviews' | 13 | import { OverviewsCommand } from '../overviews' |
14 | import { SearchCommand } from '../search' | 14 | import { SearchCommand } from '../search' |
15 | import { SocketIOCommand } from '../socket' | 15 | import { SocketIOCommand } from '../socket' |
16 | import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand, UsersCommand } from '../users' | 16 | import { |
17 | AccountsCommand, | ||
18 | BlocklistCommand, | ||
19 | LoginCommand, | ||
20 | NotificationsCommand, | ||
21 | SubscriptionsCommand, | ||
22 | TwoFactorCommand, | ||
23 | UsersCommand | ||
24 | } from '../users' | ||
17 | import { | 25 | import { |
18 | BlacklistCommand, | 26 | BlacklistCommand, |
19 | CaptionsCommand, | 27 | CaptionsCommand, |
@@ -28,6 +36,7 @@ import { | |||
28 | StreamingPlaylistsCommand, | 36 | StreamingPlaylistsCommand, |
29 | VideosCommand, | 37 | VideosCommand, |
30 | VideoStudioCommand, | 38 | VideoStudioCommand, |
39 | VideoTokenCommand, | ||
31 | ViewsCommand | 40 | ViewsCommand |
32 | } from '../videos' | 41 | } from '../videos' |
33 | import { CommentsCommand } from '../videos/comments-command' | 42 | import { CommentsCommand } from '../videos/comments-command' |
@@ -136,6 +145,8 @@ export class PeerTubeServer { | |||
136 | videos?: VideosCommand | 145 | videos?: VideosCommand |
137 | videoStats?: VideoStatsCommand | 146 | videoStats?: VideoStatsCommand |
138 | views?: ViewsCommand | 147 | views?: ViewsCommand |
148 | twoFactor?: TwoFactorCommand | ||
149 | videoToken?: VideoTokenCommand | ||
139 | 150 | ||
140 | constructor (options: { serverNumber: number } | { url: string }) { | 151 | constructor (options: { serverNumber: number } | { url: string }) { |
141 | if ((options as any).url) { | 152 | if ((options as any).url) { |
@@ -182,6 +193,12 @@ export class PeerTubeServer { | |||
182 | this.port = parseInt(parsed.port) | 193 | this.port = parseInt(parsed.port) |
183 | } | 194 | } |
184 | 195 | ||
196 | getDirectoryPath (directoryName: string) { | ||
197 | const testDirectory = 'test' + this.internalServerNumber | ||
198 | |||
199 | return join(root(), testDirectory, directoryName) | ||
200 | } | ||
201 | |||
185 | async flushAndRun (configOverride?: Object, options: RunServerOptions = {}) { | 202 | async flushAndRun (configOverride?: Object, options: RunServerOptions = {}) { |
186 | await ServersCommand.flushTests(this.internalServerNumber) | 203 | await ServersCommand.flushTests(this.internalServerNumber) |
187 | 204 | ||
@@ -341,19 +358,20 @@ export class PeerTubeServer { | |||
341 | suffix: '_test' + this.internalServerNumber | 358 | suffix: '_test' + this.internalServerNumber |
342 | }, | 359 | }, |
343 | storage: { | 360 | storage: { |
344 | tmp: `test${this.internalServerNumber}/tmp/`, | 361 | tmp: this.getDirectoryPath('tmp') + '/', |
345 | bin: `test${this.internalServerNumber}/bin/`, | 362 | bin: this.getDirectoryPath('bin') + '/', |
346 | avatars: `test${this.internalServerNumber}/avatars/`, | 363 | avatars: this.getDirectoryPath('avatars') + '/', |
347 | videos: `test${this.internalServerNumber}/videos/`, | 364 | videos: this.getDirectoryPath('videos') + '/', |
348 | streaming_playlists: `test${this.internalServerNumber}/streaming-playlists/`, | 365 | streaming_playlists: this.getDirectoryPath('streaming-playlists') + '/', |
349 | redundancy: `test${this.internalServerNumber}/redundancy/`, | 366 | redundancy: this.getDirectoryPath('redundancy') + '/', |
350 | logs: `test${this.internalServerNumber}/logs/`, | 367 | logs: this.getDirectoryPath('logs') + '/', |
351 | previews: `test${this.internalServerNumber}/previews/`, | 368 | previews: this.getDirectoryPath('previews') + '/', |
352 | thumbnails: `test${this.internalServerNumber}/thumbnails/`, | 369 | thumbnails: this.getDirectoryPath('thumbnails') + '/', |
353 | torrents: `test${this.internalServerNumber}/torrents/`, | 370 | torrents: this.getDirectoryPath('torrents') + '/', |
354 | captions: `test${this.internalServerNumber}/captions/`, | 371 | captions: this.getDirectoryPath('captions') + '/', |
355 | cache: `test${this.internalServerNumber}/cache/`, | 372 | cache: this.getDirectoryPath('cache') + '/', |
356 | plugins: `test${this.internalServerNumber}/plugins/` | 373 | plugins: this.getDirectoryPath('plugins') + '/', |
374 | well_known: this.getDirectoryPath('well-known') + '/' | ||
357 | }, | 375 | }, |
358 | admin: { | 376 | admin: { |
359 | email: `admin${this.internalServerNumber}@example.com` | 377 | email: `admin${this.internalServerNumber}@example.com` |
@@ -410,5 +428,7 @@ export class PeerTubeServer { | |||
410 | this.videoStudio = new VideoStudioCommand(this) | 428 | this.videoStudio = new VideoStudioCommand(this) |
411 | this.videoStats = new VideoStatsCommand(this) | 429 | this.videoStats = new VideoStatsCommand(this) |
412 | this.views = new ViewsCommand(this) | 430 | this.views = new ViewsCommand(this) |
431 | this.twoFactor = new TwoFactorCommand(this) | ||
432 | this.videoToken = new VideoTokenCommand(this) | ||
413 | } | 433 | } |
414 | } | 434 | } |
diff --git a/shared/server-commands/users/index.ts b/shared/server-commands/users/index.ts index f6f93b4d2..1afc02dc1 100644 --- a/shared/server-commands/users/index.ts +++ b/shared/server-commands/users/index.ts | |||
@@ -5,4 +5,5 @@ export * from './login' | |||
5 | export * from './login-command' | 5 | export * from './login-command' |
6 | export * from './notifications-command' | 6 | export * from './notifications-command' |
7 | export * from './subscriptions-command' | 7 | export * from './subscriptions-command' |
8 | export * from './two-factor-command' | ||
8 | export * from './users-command' | 9 | export * from './users-command' |
diff --git a/shared/server-commands/users/login-command.ts b/shared/server-commands/users/login-command.ts index 54070e426..f2fc6d1c5 100644 --- a/shared/server-commands/users/login-command.ts +++ b/shared/server-commands/users/login-command.ts | |||
@@ -2,34 +2,27 @@ import { HttpStatusCode, PeerTubeProblemDocument } from '@shared/models' | |||
2 | import { unwrapBody } from '../requests' | 2 | import { unwrapBody } from '../requests' |
3 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | 3 | import { AbstractCommand, OverrideCommandOptions } from '../shared' |
4 | 4 | ||
5 | type LoginOptions = OverrideCommandOptions & { | ||
6 | client?: { id?: string, secret?: string } | ||
7 | user?: { username: string, password?: string } | ||
8 | otpToken?: string | ||
9 | } | ||
10 | |||
5 | export class LoginCommand extends AbstractCommand { | 11 | export class LoginCommand extends AbstractCommand { |
6 | 12 | ||
7 | login (options: OverrideCommandOptions & { | 13 | async login (options: LoginOptions = {}) { |
8 | client?: { id?: string, secret?: string } | 14 | const res = await this._login(options) |
9 | user?: { username: string, password?: string } | ||
10 | } = {}) { | ||
11 | const { client = this.server.store.client, user = this.server.store.user } = options | ||
12 | const path = '/api/v1/users/token' | ||
13 | 15 | ||
14 | const body = { | 16 | return this.unwrapLoginBody(res.body) |
15 | client_id: client.id, | 17 | } |
16 | client_secret: client.secret, | ||
17 | username: user.username, | ||
18 | password: user.password ?? 'password', | ||
19 | response_type: 'code', | ||
20 | grant_type: 'password', | ||
21 | scope: 'upload' | ||
22 | } | ||
23 | 18 | ||
24 | return unwrapBody<{ access_token: string, refresh_token: string } & PeerTubeProblemDocument>(this.postBodyRequest({ | 19 | async loginAndGetResponse (options: LoginOptions = {}) { |
25 | ...options, | 20 | const res = await this._login(options) |
26 | 21 | ||
27 | path, | 22 | return { |
28 | requestType: 'form', | 23 | res, |
29 | fields: body, | 24 | body: this.unwrapLoginBody(res.body) |
30 | implicitToken: false, | 25 | } |
31 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
32 | })) | ||
33 | } | 26 | } |
34 | 27 | ||
35 | getAccessToken (arg1?: { username: string, password?: string }): Promise<string> | 28 | getAccessToken (arg1?: { username: string, password?: string }): Promise<string> |
@@ -129,4 +122,38 @@ export class LoginCommand extends AbstractCommand { | |||
129 | defaultExpectedStatus: HttpStatusCode.OK_200 | 122 | defaultExpectedStatus: HttpStatusCode.OK_200 |
130 | }) | 123 | }) |
131 | } | 124 | } |
125 | |||
126 | private _login (options: LoginOptions) { | ||
127 | const { client = this.server.store.client, user = this.server.store.user, otpToken } = options | ||
128 | const path = '/api/v1/users/token' | ||
129 | |||
130 | const body = { | ||
131 | client_id: client.id, | ||
132 | client_secret: client.secret, | ||
133 | username: user.username, | ||
134 | password: user.password ?? 'password', | ||
135 | response_type: 'code', | ||
136 | grant_type: 'password', | ||
137 | scope: 'upload' | ||
138 | } | ||
139 | |||
140 | const headers = otpToken | ||
141 | ? { 'x-peertube-otp': otpToken } | ||
142 | : {} | ||
143 | |||
144 | return this.postBodyRequest({ | ||
145 | ...options, | ||
146 | |||
147 | path, | ||
148 | headers, | ||
149 | requestType: 'form', | ||
150 | fields: body, | ||
151 | implicitToken: false, | ||
152 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
153 | }) | ||
154 | } | ||
155 | |||
156 | private unwrapLoginBody (body: any) { | ||
157 | return body as { access_token: string, refresh_token: string } & PeerTubeProblemDocument | ||
158 | } | ||
132 | } | 159 | } |
diff --git a/shared/server-commands/users/two-factor-command.ts b/shared/server-commands/users/two-factor-command.ts new file mode 100644 index 000000000..5542acfda --- /dev/null +++ b/shared/server-commands/users/two-factor-command.ts | |||
@@ -0,0 +1,92 @@ | |||
1 | import { TOTP } from 'otpauth' | ||
2 | import { HttpStatusCode, TwoFactorEnableResult } from '@shared/models' | ||
3 | import { unwrapBody } from '../requests' | ||
4 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
5 | |||
6 | export class TwoFactorCommand extends AbstractCommand { | ||
7 | |||
8 | static buildOTP (options: { | ||
9 | secret: string | ||
10 | }) { | ||
11 | const { secret } = options | ||
12 | |||
13 | return new TOTP({ | ||
14 | issuer: 'PeerTube', | ||
15 | algorithm: 'SHA1', | ||
16 | digits: 6, | ||
17 | period: 30, | ||
18 | secret | ||
19 | }) | ||
20 | } | ||
21 | |||
22 | request (options: OverrideCommandOptions & { | ||
23 | userId: number | ||
24 | currentPassword?: string | ||
25 | }) { | ||
26 | const { currentPassword, userId } = options | ||
27 | |||
28 | const path = '/api/v1/users/' + userId + '/two-factor/request' | ||
29 | |||
30 | return unwrapBody<TwoFactorEnableResult>(this.postBodyRequest({ | ||
31 | ...options, | ||
32 | |||
33 | path, | ||
34 | fields: { currentPassword }, | ||
35 | implicitToken: true, | ||
36 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
37 | })) | ||
38 | } | ||
39 | |||
40 | confirmRequest (options: OverrideCommandOptions & { | ||
41 | userId: number | ||
42 | requestToken: string | ||
43 | otpToken: string | ||
44 | }) { | ||
45 | const { userId, requestToken, otpToken } = options | ||
46 | |||
47 | const path = '/api/v1/users/' + userId + '/two-factor/confirm-request' | ||
48 | |||
49 | return this.postBodyRequest({ | ||
50 | ...options, | ||
51 | |||
52 | path, | ||
53 | fields: { requestToken, otpToken }, | ||
54 | implicitToken: true, | ||
55 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
56 | }) | ||
57 | } | ||
58 | |||
59 | disable (options: OverrideCommandOptions & { | ||
60 | userId: number | ||
61 | currentPassword?: string | ||
62 | }) { | ||
63 | const { userId, currentPassword } = options | ||
64 | const path = '/api/v1/users/' + userId + '/two-factor/disable' | ||
65 | |||
66 | return this.postBodyRequest({ | ||
67 | ...options, | ||
68 | |||
69 | path, | ||
70 | fields: { currentPassword }, | ||
71 | implicitToken: true, | ||
72 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
73 | }) | ||
74 | } | ||
75 | |||
76 | async requestAndConfirm (options: OverrideCommandOptions & { | ||
77 | userId: number | ||
78 | currentPassword?: string | ||
79 | }) { | ||
80 | const { userId, currentPassword } = options | ||
81 | |||
82 | const { otpRequest } = await this.request({ userId, currentPassword }) | ||
83 | |||
84 | await this.confirmRequest({ | ||
85 | userId, | ||
86 | requestToken: otpRequest.requestToken, | ||
87 | otpToken: TwoFactorCommand.buildOTP({ secret: otpRequest.secret }).generate() | ||
88 | }) | ||
89 | |||
90 | return otpRequest | ||
91 | } | ||
92 | } | ||
diff --git a/shared/server-commands/users/users-command.ts b/shared/server-commands/users/users-command.ts index d8303848d..811b9685b 100644 --- a/shared/server-commands/users/users-command.ts +++ b/shared/server-commands/users/users-command.ts | |||
@@ -202,7 +202,8 @@ export class UsersCommand extends AbstractCommand { | |||
202 | token, | 202 | token, |
203 | userId: user.id, | 203 | userId: user.id, |
204 | userChannelId: me.videoChannels[0].id, | 204 | userChannelId: me.videoChannels[0].id, |
205 | userChannelName: me.videoChannels[0].name | 205 | userChannelName: me.videoChannels[0].name, |
206 | password | ||
206 | } | 207 | } |
207 | } | 208 | } |
208 | 209 | ||
@@ -217,12 +218,13 @@ export class UsersCommand extends AbstractCommand { | |||
217 | username: string | 218 | username: string |
218 | password?: string | 219 | password?: string |
219 | displayName?: string | 220 | displayName?: string |
221 | email?: string | ||
220 | channel?: { | 222 | channel?: { |
221 | name: string | 223 | name: string |
222 | displayName: string | 224 | displayName: string |
223 | } | 225 | } |
224 | }) { | 226 | }) { |
225 | const { username, password = 'password', displayName, channel } = options | 227 | const { username, password = 'password', displayName, channel, email = username + '@example.com' } = options |
226 | const path = '/api/v1/users/register' | 228 | const path = '/api/v1/users/register' |
227 | 229 | ||
228 | return this.postBodyRequest({ | 230 | return this.postBodyRequest({ |
@@ -232,7 +234,7 @@ export class UsersCommand extends AbstractCommand { | |||
232 | fields: { | 234 | fields: { |
233 | username, | 235 | username, |
234 | password, | 236 | password, |
235 | email: username + '@example.com', | 237 | email, |
236 | displayName, | 238 | displayName, |
237 | channel | 239 | channel |
238 | }, | 240 | }, |
diff --git a/shared/server-commands/videos/index.ts b/shared/server-commands/videos/index.ts index b4d6fa37b..c17f6ef20 100644 --- a/shared/server-commands/videos/index.ts +++ b/shared/server-commands/videos/index.ts | |||
@@ -14,5 +14,6 @@ export * from './services-command' | |||
14 | export * from './streaming-playlists-command' | 14 | export * from './streaming-playlists-command' |
15 | export * from './comments-command' | 15 | export * from './comments-command' |
16 | export * from './video-studio-command' | 16 | export * from './video-studio-command' |
17 | export * from './video-token-command' | ||
17 | export * from './views-command' | 18 | export * from './views-command' |
18 | export * from './videos-command' | 19 | export * from './videos-command' |
diff --git a/shared/server-commands/videos/live-command.ts b/shared/server-commands/videos/live-command.ts index d804fd883..cc9502c6f 100644 --- a/shared/server-commands/videos/live-command.ts +++ b/shared/server-commands/videos/live-command.ts | |||
@@ -12,9 +12,11 @@ import { | |||
12 | ResultList, | 12 | ResultList, |
13 | VideoCreateResult, | 13 | VideoCreateResult, |
14 | VideoDetails, | 14 | VideoDetails, |
15 | VideoPrivacy, | ||
15 | VideoState | 16 | VideoState |
16 | } from '@shared/models' | 17 | } from '@shared/models' |
17 | import { unwrapBody } from '../requests' | 18 | import { unwrapBody } from '../requests' |
19 | import { ObjectStorageCommand, PeerTubeServer } from '../server' | ||
18 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | 20 | import { AbstractCommand, OverrideCommandOptions } from '../shared' |
19 | import { sendRTMPStream, testFfmpegStreamError } from './live' | 21 | import { sendRTMPStream, testFfmpegStreamError } from './live' |
20 | 22 | ||
@@ -34,6 +36,8 @@ export class LiveCommand extends AbstractCommand { | |||
34 | }) | 36 | }) |
35 | } | 37 | } |
36 | 38 | ||
39 | // --------------------------------------------------------------------------- | ||
40 | |||
37 | listSessions (options: OverrideCommandOptions & { | 41 | listSessions (options: OverrideCommandOptions & { |
38 | videoId: number | string | 42 | videoId: number | string |
39 | }) { | 43 | }) { |
@@ -70,6 +74,8 @@ export class LiveCommand extends AbstractCommand { | |||
70 | }) | 74 | }) |
71 | } | 75 | } |
72 | 76 | ||
77 | // --------------------------------------------------------------------------- | ||
78 | |||
73 | update (options: OverrideCommandOptions & { | 79 | update (options: OverrideCommandOptions & { |
74 | videoId: number | string | 80 | videoId: number | string |
75 | fields: LiveVideoUpdate | 81 | fields: LiveVideoUpdate |
@@ -110,6 +116,33 @@ export class LiveCommand extends AbstractCommand { | |||
110 | return body.video | 116 | return body.video |
111 | } | 117 | } |
112 | 118 | ||
119 | async quickCreate (options: OverrideCommandOptions & { | ||
120 | saveReplay: boolean | ||
121 | permanentLive: boolean | ||
122 | privacy?: VideoPrivacy | ||
123 | }) { | ||
124 | const { saveReplay, permanentLive, privacy } = options | ||
125 | |||
126 | const { uuid } = await this.create({ | ||
127 | ...options, | ||
128 | |||
129 | fields: { | ||
130 | name: 'live', | ||
131 | permanentLive, | ||
132 | saveReplay, | ||
133 | channelId: this.server.store.channel.id, | ||
134 | privacy | ||
135 | } | ||
136 | }) | ||
137 | |||
138 | const video = await this.server.videos.getWithToken({ id: uuid }) | ||
139 | const live = await this.get({ videoId: uuid }) | ||
140 | |||
141 | return { video, live } | ||
142 | } | ||
143 | |||
144 | // --------------------------------------------------------------------------- | ||
145 | |||
113 | async sendRTMPStreamInVideo (options: OverrideCommandOptions & { | 146 | async sendRTMPStreamInVideo (options: OverrideCommandOptions & { |
114 | videoId: number | string | 147 | videoId: number | string |
115 | fixtureName?: string | 148 | fixtureName?: string |
@@ -130,6 +163,8 @@ export class LiveCommand extends AbstractCommand { | |||
130 | return testFfmpegStreamError(command, options.shouldHaveError) | 163 | return testFfmpegStreamError(command, options.shouldHaveError) |
131 | } | 164 | } |
132 | 165 | ||
166 | // --------------------------------------------------------------------------- | ||
167 | |||
133 | waitUntilPublished (options: OverrideCommandOptions & { | 168 | waitUntilPublished (options: OverrideCommandOptions & { |
134 | videoId: number | string | 169 | videoId: number | string |
135 | }) { | 170 | }) { |
@@ -151,27 +186,77 @@ export class LiveCommand extends AbstractCommand { | |||
151 | return this.waitUntilState({ videoId, state: VideoState.LIVE_ENDED }) | 186 | return this.waitUntilState({ videoId, state: VideoState.LIVE_ENDED }) |
152 | } | 187 | } |
153 | 188 | ||
154 | waitUntilSegmentGeneration (options: OverrideCommandOptions & { | 189 | async waitUntilSegmentGeneration (options: OverrideCommandOptions & { |
190 | server: PeerTubeServer | ||
155 | videoUUID: string | 191 | videoUUID: string |
156 | playlistNumber: number | 192 | playlistNumber: number |
157 | segment: number | 193 | segment: number |
158 | totalSessions?: number | 194 | objectStorage: boolean |
159 | }) { | 195 | }) { |
160 | const { playlistNumber, segment, videoUUID, totalSessions = 1 } = options | 196 | const { server, objectStorage, playlistNumber, segment, videoUUID } = options |
197 | |||
161 | const segmentName = `${playlistNumber}-00000${segment}.ts` | 198 | const segmentName = `${playlistNumber}-00000${segment}.ts` |
199 | const baseUrl = objectStorage | ||
200 | ? ObjectStorageCommand.getMockPlaylistBaseUrl() + 'hls' | ||
201 | : server.url + '/static/streaming-playlists/hls' | ||
202 | |||
203 | let error = true | ||
204 | |||
205 | while (error) { | ||
206 | try { | ||
207 | await this.getRawRequest({ | ||
208 | ...options, | ||
209 | |||
210 | url: `${baseUrl}/${videoUUID}/${segmentName}`, | ||
211 | implicitToken: false, | ||
212 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
213 | }) | ||
214 | |||
215 | const video = await server.videos.get({ id: videoUUID }) | ||
216 | const hlsPlaylist = video.streamingPlaylists[0] | ||
217 | |||
218 | const shaBody = await server.streamingPlaylists.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) | ||
219 | |||
220 | if (!shaBody[segmentName]) { | ||
221 | throw new Error('Segment SHA does not exist') | ||
222 | } | ||
162 | 223 | ||
163 | return this.server.servers.waitUntilLog(`${videoUUID}/${segmentName}`, totalSessions * 2, false) | 224 | error = false |
225 | } catch { | ||
226 | error = true | ||
227 | await wait(100) | ||
228 | } | ||
229 | } | ||
164 | } | 230 | } |
165 | 231 | ||
166 | getSegment (options: OverrideCommandOptions & { | 232 | async waitUntilReplacedByReplay (options: OverrideCommandOptions & { |
233 | videoId: number | string | ||
234 | }) { | ||
235 | let video: VideoDetails | ||
236 | |||
237 | do { | ||
238 | video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) | ||
239 | |||
240 | await wait(500) | ||
241 | } while (video.isLive === true || video.state.id !== VideoState.PUBLISHED) | ||
242 | } | ||
243 | |||
244 | // --------------------------------------------------------------------------- | ||
245 | |||
246 | getSegmentFile (options: OverrideCommandOptions & { | ||
167 | videoUUID: string | 247 | videoUUID: string |
168 | playlistNumber: number | 248 | playlistNumber: number |
169 | segment: number | 249 | segment: number |
250 | objectStorage?: boolean // default false | ||
170 | }) { | 251 | }) { |
171 | const { playlistNumber, segment, videoUUID } = options | 252 | const { playlistNumber, segment, videoUUID, objectStorage = false } = options |
172 | 253 | ||
173 | const segmentName = `${playlistNumber}-00000${segment}.ts` | 254 | const segmentName = `${playlistNumber}-00000${segment}.ts` |
174 | const url = `${this.server.url}/static/streaming-playlists/hls/${videoUUID}/${segmentName}` | 255 | const baseUrl = objectStorage |
256 | ? ObjectStorageCommand.getMockPlaylistBaseUrl() | ||
257 | : `${this.server.url}/static/streaming-playlists/hls` | ||
258 | |||
259 | const url = `${baseUrl}/${videoUUID}/${segmentName}` | ||
175 | 260 | ||
176 | return this.getRawRequest({ | 261 | return this.getRawRequest({ |
177 | ...options, | 262 | ...options, |
@@ -182,18 +267,30 @@ export class LiveCommand extends AbstractCommand { | |||
182 | }) | 267 | }) |
183 | } | 268 | } |
184 | 269 | ||
185 | async waitUntilReplacedByReplay (options: OverrideCommandOptions & { | 270 | getPlaylistFile (options: OverrideCommandOptions & { |
186 | videoId: number | string | 271 | videoUUID: string |
272 | playlistName: string | ||
273 | objectStorage?: boolean // default false | ||
187 | }) { | 274 | }) { |
188 | let video: VideoDetails | 275 | const { playlistName, videoUUID, objectStorage = false } = options |
189 | 276 | ||
190 | do { | 277 | const baseUrl = objectStorage |
191 | video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) | 278 | ? ObjectStorageCommand.getMockPlaylistBaseUrl() |
279 | : `${this.server.url}/static/streaming-playlists/hls` | ||
192 | 280 | ||
193 | await wait(500) | 281 | const url = `${baseUrl}/${videoUUID}/${playlistName}` |
194 | } while (video.isLive === true || video.state.id !== VideoState.PUBLISHED) | 282 | |
283 | return this.getRawRequest({ | ||
284 | ...options, | ||
285 | |||
286 | url, | ||
287 | implicitToken: false, | ||
288 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
289 | }) | ||
195 | } | 290 | } |
196 | 291 | ||
292 | // --------------------------------------------------------------------------- | ||
293 | |||
197 | async countPlaylists (options: OverrideCommandOptions & { | 294 | async countPlaylists (options: OverrideCommandOptions & { |
198 | videoUUID: string | 295 | videoUUID: string |
199 | }) { | 296 | }) { |
diff --git a/shared/server-commands/videos/live.ts b/shared/server-commands/videos/live.ts index 6f180b05f..ee7444b64 100644 --- a/shared/server-commands/videos/live.ts +++ b/shared/server-commands/videos/live.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import ffmpeg, { FfmpegCommand } from 'fluent-ffmpeg' | 1 | import ffmpeg, { FfmpegCommand } from 'fluent-ffmpeg' |
2 | import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' | 2 | import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' |
3 | import { VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models' | ||
3 | import { PeerTubeServer } from '../server/server' | 4 | import { PeerTubeServer } from '../server/server' |
4 | import { VideoDetails, VideoInclude } from '@shared/models' | ||
5 | 5 | ||
6 | function sendRTMPStream (options: { | 6 | function sendRTMPStream (options: { |
7 | rtmpBaseUrl: string | 7 | rtmpBaseUrl: string |
@@ -98,7 +98,10 @@ async function waitUntilLiveReplacedByReplayOnAllServers (servers: PeerTubeServe | |||
98 | } | 98 | } |
99 | 99 | ||
100 | async function findExternalSavedVideo (server: PeerTubeServer, liveDetails: VideoDetails) { | 100 | async function findExternalSavedVideo (server: PeerTubeServer, liveDetails: VideoDetails) { |
101 | const { data } = await server.videos.list({ token: server.accessToken, sort: '-publishedAt', include: VideoInclude.BLACKLISTED }) | 101 | const include = VideoInclude.BLACKLISTED |
102 | const privacyOneOf = [ VideoPrivacy.INTERNAL, VideoPrivacy.PRIVATE, VideoPrivacy.PUBLIC, VideoPrivacy.UNLISTED ] | ||
103 | |||
104 | const { data } = await server.videos.list({ token: server.accessToken, sort: '-publishedAt', include, privacyOneOf }) | ||
102 | 105 | ||
103 | return data.find(v => v.name === liveDetails.name + ' - ' + new Date(liveDetails.publishedAt).toLocaleString()) | 106 | return data.find(v => v.name === liveDetails.name + ' - ' + new Date(liveDetails.publishedAt).toLocaleString()) |
104 | } | 107 | } |
diff --git a/shared/server-commands/videos/streaming-playlists-command.ts b/shared/server-commands/videos/streaming-playlists-command.ts index 5d40d35cb..25e446e72 100644 --- a/shared/server-commands/videos/streaming-playlists-command.ts +++ b/shared/server-commands/videos/streaming-playlists-command.ts | |||
@@ -1,22 +1,42 @@ | |||
1 | import { wait } from '@shared/core-utils' | ||
1 | import { HttpStatusCode } from '@shared/models' | 2 | import { HttpStatusCode } from '@shared/models' |
2 | import { unwrapBody, unwrapTextOrDecode, unwrapBodyOrDecodeToJSON } from '../requests' | 3 | import { unwrapBody, unwrapBodyOrDecodeToJSON, unwrapTextOrDecode } from '../requests' |
3 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | 4 | import { AbstractCommand, OverrideCommandOptions } from '../shared' |
4 | 5 | ||
5 | export class StreamingPlaylistsCommand extends AbstractCommand { | 6 | export class StreamingPlaylistsCommand extends AbstractCommand { |
6 | 7 | ||
7 | get (options: OverrideCommandOptions & { | 8 | async get (options: OverrideCommandOptions & { |
8 | url: string | 9 | url: string |
10 | withRetry?: boolean // default false | ||
11 | currentRetry?: number | ||
9 | }) { | 12 | }) { |
10 | return unwrapTextOrDecode(this.getRawRequest({ | 13 | const { withRetry, currentRetry = 1 } = options |
11 | ...options, | ||
12 | 14 | ||
13 | url: options.url, | 15 | try { |
14 | implicitToken: false, | 16 | const result = await unwrapTextOrDecode(this.getRawRequest({ |
15 | defaultExpectedStatus: HttpStatusCode.OK_200 | 17 | ...options, |
16 | })) | 18 | |
19 | url: options.url, | ||
20 | implicitToken: false, | ||
21 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
22 | })) | ||
23 | |||
24 | return result | ||
25 | } catch (err) { | ||
26 | if (!withRetry || currentRetry > 5) throw err | ||
27 | |||
28 | await wait(100) | ||
29 | |||
30 | return this.get({ | ||
31 | ...options, | ||
32 | |||
33 | withRetry, | ||
34 | currentRetry: currentRetry + 1 | ||
35 | }) | ||
36 | } | ||
17 | } | 37 | } |
18 | 38 | ||
19 | getSegment (options: OverrideCommandOptions & { | 39 | getFragmentedSegment (options: OverrideCommandOptions & { |
20 | url: string | 40 | url: string |
21 | range?: string | 41 | range?: string |
22 | }) { | 42 | }) { |
diff --git a/shared/server-commands/videos/video-token-command.ts b/shared/server-commands/videos/video-token-command.ts new file mode 100644 index 000000000..0531bee65 --- /dev/null +++ b/shared/server-commands/videos/video-token-command.ts | |||
@@ -0,0 +1,31 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ | ||
2 | |||
3 | import { HttpStatusCode, VideoToken } from '@shared/models' | ||
4 | import { unwrapBody } from '../requests' | ||
5 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
6 | |||
7 | export class VideoTokenCommand extends AbstractCommand { | ||
8 | |||
9 | create (options: OverrideCommandOptions & { | ||
10 | videoId: number | string | ||
11 | }) { | ||
12 | const { videoId } = options | ||
13 | const path = '/api/v1/videos/' + videoId + '/token' | ||
14 | |||
15 | return unwrapBody<VideoToken>(this.postBodyRequest({ | ||
16 | ...options, | ||
17 | |||
18 | path, | ||
19 | implicitToken: true, | ||
20 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
21 | })) | ||
22 | } | ||
23 | |||
24 | async getVideoFileToken (options: OverrideCommandOptions & { | ||
25 | videoId: number | string | ||
26 | }) { | ||
27 | const { files } = await this.create(options) | ||
28 | |||
29 | return files.token | ||
30 | } | ||
31 | } | ||
diff --git a/shared/server-commands/videos/videos-command.ts b/shared/server-commands/videos/videos-command.ts index 168391523..590244484 100644 --- a/shared/server-commands/videos/videos-command.ts +++ b/shared/server-commands/videos/videos-command.ts | |||
@@ -4,7 +4,7 @@ import { expect } from 'chai' | |||
4 | import { createReadStream, stat } from 'fs-extra' | 4 | import { createReadStream, stat } from 'fs-extra' |
5 | import got, { Response as GotResponse } from 'got' | 5 | import got, { Response as GotResponse } from 'got' |
6 | import validator from 'validator' | 6 | import validator from 'validator' |
7 | import { buildAbsoluteFixturePath, omit, pick, wait } from '@shared/core-utils' | 7 | import { buildAbsoluteFixturePath, getAllPrivacies, omit, pick, wait } from '@shared/core-utils' |
8 | import { buildUUID } from '@shared/extra-utils' | 8 | import { buildUUID } from '@shared/extra-utils' |
9 | import { | 9 | import { |
10 | HttpStatusCode, | 10 | HttpStatusCode, |
@@ -15,6 +15,7 @@ import { | |||
15 | VideoCreateResult, | 15 | VideoCreateResult, |
16 | VideoDetails, | 16 | VideoDetails, |
17 | VideoFileMetadata, | 17 | VideoFileMetadata, |
18 | VideoInclude, | ||
18 | VideoPrivacy, | 19 | VideoPrivacy, |
19 | VideosCommonQuery, | 20 | VideosCommonQuery, |
20 | VideoTranscodingCreate | 21 | VideoTranscodingCreate |
@@ -234,6 +235,22 @@ export class VideosCommand extends AbstractCommand { | |||
234 | }) | 235 | }) |
235 | } | 236 | } |
236 | 237 | ||
238 | listAllForAdmin (options: OverrideCommandOptions & VideosCommonQuery = {}) { | ||
239 | const include = VideoInclude.NOT_PUBLISHED_STATE | VideoInclude.BLACKLISTED | VideoInclude.BLOCKED_OWNER | ||
240 | const nsfw = 'both' | ||
241 | const privacyOneOf = getAllPrivacies() | ||
242 | |||
243 | return this.list({ | ||
244 | ...options, | ||
245 | |||
246 | include, | ||
247 | nsfw, | ||
248 | privacyOneOf, | ||
249 | |||
250 | token: this.buildCommonRequestToken({ ...options, implicitToken: true }) | ||
251 | }) | ||
252 | } | ||
253 | |||
237 | listByAccount (options: OverrideCommandOptions & VideosCommonQuery & { | 254 | listByAccount (options: OverrideCommandOptions & VideosCommonQuery & { |
238 | handle: string | 255 | handle: string |
239 | }) { | 256 | }) { |
@@ -342,8 +359,9 @@ export class VideosCommand extends AbstractCommand { | |||
342 | async upload (options: OverrideCommandOptions & { | 359 | async upload (options: OverrideCommandOptions & { |
343 | attributes?: VideoEdit | 360 | attributes?: VideoEdit |
344 | mode?: 'legacy' | 'resumable' // default legacy | 361 | mode?: 'legacy' | 'resumable' // default legacy |
362 | waitTorrentGeneration?: boolean // default true | ||
345 | } = {}) { | 363 | } = {}) { |
346 | const { mode = 'legacy' } = options | 364 | const { mode = 'legacy', waitTorrentGeneration = true } = options |
347 | let defaultChannelId = 1 | 365 | let defaultChannelId = 1 |
348 | 366 | ||
349 | try { | 367 | try { |
@@ -377,7 +395,7 @@ export class VideosCommand extends AbstractCommand { | |||
377 | 395 | ||
378 | // Wait torrent generation | 396 | // Wait torrent generation |
379 | const expectedStatus = this.buildExpectedStatus({ ...options, defaultExpectedStatus: HttpStatusCode.OK_200 }) | 397 | const expectedStatus = this.buildExpectedStatus({ ...options, defaultExpectedStatus: HttpStatusCode.OK_200 }) |
380 | if (expectedStatus === HttpStatusCode.OK_200) { | 398 | if (expectedStatus === HttpStatusCode.OK_200 && waitTorrentGeneration) { |
381 | let video: VideoDetails | 399 | let video: VideoDetails |
382 | 400 | ||
383 | do { | 401 | do { |
@@ -692,6 +710,7 @@ export class VideosCommand extends AbstractCommand { | |||
692 | 'categoryOneOf', | 710 | 'categoryOneOf', |
693 | 'licenceOneOf', | 711 | 'licenceOneOf', |
694 | 'languageOneOf', | 712 | 'languageOneOf', |
713 | 'privacyOneOf', | ||
695 | 'tagsOneOf', | 714 | 'tagsOneOf', |
696 | 'tagsAllOf', | 715 | 'tagsAllOf', |
697 | 'isLocal', | 716 | 'isLocal', |