From a6a79eae0d8564099b6957e76d7a18528d9ef124 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 5 Jul 2021 14:57:03 +0200 Subject: Introduce bulk command --- shared/extra-utils/bulk/bulk.ts | 35 ++++++++++---------- shared/extra-utils/shared/abstract-command.ts | 47 +++++++++++++++++++++++++++ shared/extra-utils/shared/index.ts | 1 + 3 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 shared/extra-utils/shared/abstract-command.ts create mode 100644 shared/extra-utils/shared/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/bulk.ts b/shared/extra-utils/bulk/bulk.ts index b6f437b8b..c102383e3 100644 --- a/shared/extra-utils/bulk/bulk.ts +++ b/shared/extra-utils/bulk/bulk.ts @@ -1,25 +1,24 @@ -import { BulkRemoveCommentsOfBody } from "@shared/models/bulk/bulk-remove-comments-of-body.model" -import { makePostBodyRequest } from "../requests/requests" + +import { BulkRemoveCommentsOfBody } from '@shared/models/bulk/bulk-remove-comments-of-body.model' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { AbstractCommand, CommonCommandOptions } from '../shared' + +class BulkCommand extends AbstractCommand { -function bulkRemoveCommentsOf (options: { - url: string - token: string - attributes: BulkRemoveCommentsOfBody - expectedStatus?: number -}) { - const { url, token, attributes, expectedStatus } = options - const path = '/api/v1/bulk/remove-comments-of' + removeCommentsOf (options: CommonCommandOptions & { + attributes: BulkRemoveCommentsOfBody + }) { + const { attributes } = options - return makePostBodyRequest({ - url, - path, - token, - fields: attributes, - statusCodeExpected: expectedStatus || HttpStatusCode.NO_CONTENT_204 - }) + return this.postBodyRequest({ + ...options, + path: '/api/v1/bulk/remove-comments-of', + fields: attributes, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } } export { - bulkRemoveCommentsOf + BulkCommand } diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts new file mode 100644 index 000000000..bb06b6bdb --- /dev/null +++ b/shared/extra-utils/shared/abstract-command.ts @@ -0,0 +1,47 @@ +import { HttpStatusCode } from '@shared/core-utils' +import { makePostBodyRequest } from '../requests/requests' +import { ServerInfo } from '../server/servers' + +export interface CommonCommandOptions { + token?: string + expectedStatus?: number +} + +abstract class AbstractCommand { + + private expectedStatus = HttpStatusCode.OK_200 + + constructor ( + protected server: ServerInfo + ) { + + } + + setServer (server: ServerInfo) { + this.server = server + } + + setExpectedStatus (status: HttpStatusCode) { + this.expectedStatus = status + } + + protected postBodyRequest (options: CommonCommandOptions & { + path: string + defaultExpectedStatus: number + fields?: { [ fieldName: string ]: any } + }) { + const { token, fields, expectedStatus, defaultExpectedStatus, path } = options + + return makePostBodyRequest({ + url: this.server.url, + path, + token: token ?? this.server.accessToken, + fields, + statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus + }) + } +} + +export { + AbstractCommand +} diff --git a/shared/extra-utils/shared/index.ts b/shared/extra-utils/shared/index.ts new file mode 100644 index 000000000..e807ab4f7 --- /dev/null +++ b/shared/extra-utils/shared/index.ts @@ -0,0 +1 @@ +export * from './abstract-command' -- cgit v1.2.3 From 329619b3453479f76c049816b7403b86e9d45cb5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 5 Jul 2021 16:37:50 +0200 Subject: Introduce CLI command --- shared/extra-utils/bulk/index.ts | 1 + shared/extra-utils/cli/cli.ts | 33 ++++++++++++++++++--------------- shared/extra-utils/cli/index.ts | 1 + shared/extra-utils/index.ts | 4 ++-- shared/extra-utils/server/servers.ts | 8 ++++++++ 5 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 shared/extra-utils/bulk/index.ts create mode 100644 shared/extra-utils/cli/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/index.ts b/shared/extra-utils/bulk/index.ts new file mode 100644 index 000000000..5d2f9d3ad --- /dev/null +++ b/shared/extra-utils/bulk/index.ts @@ -0,0 +1 @@ +export * from './bulk' diff --git a/shared/extra-utils/cli/cli.ts b/shared/extra-utils/cli/cli.ts index c62e170bb..1bf100869 100644 --- a/shared/extra-utils/cli/cli.ts +++ b/shared/extra-utils/cli/cli.ts @@ -1,24 +1,27 @@ import { exec } from 'child_process' +import { AbstractCommand } from '../shared' -import { ServerInfo } from '../server/servers' +class CLICommand extends AbstractCommand { -function getEnvCli (server?: ServerInfo) { - return `NODE_ENV=test NODE_APP_INSTANCE=${server.internalServerNumber}` -} - -async function execCLI (command: string) { - return new Promise((res, rej) => { - exec(command, (err, stdout, stderr) => { - if (err) return rej(err) + static exec (command: string) { + return new Promise((res, rej) => { + exec(command, (err, stdout, _stderr) => { + if (err) return rej(err) - return res(stdout) + return res(stdout) + }) }) - }) -} + } -// --------------------------------------------------------------------------- + getEnv () { + return `NODE_ENV=test NODE_APP_INSTANCE=${this.server.internalServerNumber}` + } + + async execWithEnv (command: string) { + return CLICommand.exec(`${this.getEnv()} ${command}`) + } +} export { - execCLI, - getEnvCli + CLICommand } diff --git a/shared/extra-utils/cli/index.ts b/shared/extra-utils/cli/index.ts new file mode 100644 index 000000000..8a3f31e2f --- /dev/null +++ b/shared/extra-utils/cli/index.ts @@ -0,0 +1 @@ +export * from './cli' diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 87ee8abba..4bf057492 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -1,6 +1,6 @@ -export * from './bulk/bulk' +export * from './bulk' -export * from './cli/cli' +export * from './cli' export * from './custom-pages/custom-pages' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 28e431e94..1b0775421 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -6,6 +6,8 @@ import { copy, ensureDir, pathExists, readdir, readFile, remove } from 'fs-extra import { join } from 'path' import { randomInt } from '../../core-utils/miscs/miscs' import { VideoChannel } from '../../models/videos' +import { BulkCommand } from '../bulk' +import { CLICommand } from '../cli' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { makeGetRequest } from '../requests/requests' @@ -60,6 +62,9 @@ interface ServerInfo { } videos?: { id: number, uuid: string }[] + + bulkCommand?: BulkCommand + cliCommand?: CLICommand } function parallelTests () { @@ -265,6 +270,9 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] } catch { /* empty */ } }) + server.bulkCommand = new BulkCommand(server) + server.cliCommand = new CLICommand(server) + res(server) }) }) -- cgit v1.2.3 From e8bd7ce7ccafe3e064b03978e9b512c1a4cc99e6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 09:55:05 +0200 Subject: Introduce CustomPage command --- shared/extra-utils/bulk/bulk.ts | 10 ++---- shared/extra-utils/cli/cli.ts | 6 +--- shared/extra-utils/custom-pages/custom-pages.ts | 47 ++++++++++++------------- shared/extra-utils/custom-pages/index.ts | 1 + shared/extra-utils/index.ts | 2 +- shared/extra-utils/requests/requests.ts | 5 +++ shared/extra-utils/server/servers.ts | 3 ++ shared/extra-utils/shared/abstract-command.ts | 44 ++++++++++++++++++----- 8 files changed, 73 insertions(+), 45 deletions(-) create mode 100644 shared/extra-utils/custom-pages/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/bulk.ts b/shared/extra-utils/bulk/bulk.ts index c102383e3..a58fb3fbb 100644 --- a/shared/extra-utils/bulk/bulk.ts +++ b/shared/extra-utils/bulk/bulk.ts @@ -1,11 +1,11 @@ import { BulkRemoveCommentsOfBody } from '@shared/models/bulk/bulk-remove-comments-of-body.model' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { AbstractCommand, CommonCommandOptions } from '../shared' +import { AbstractCommand, OverrideCommandOptions } from '../shared' -class BulkCommand extends AbstractCommand { +export class BulkCommand extends AbstractCommand { - removeCommentsOf (options: CommonCommandOptions & { + removeCommentsOf (options: OverrideCommandOptions & { attributes: BulkRemoveCommentsOfBody }) { const { attributes } = options @@ -18,7 +18,3 @@ class BulkCommand extends AbstractCommand { }) } } - -export { - BulkCommand -} diff --git a/shared/extra-utils/cli/cli.ts b/shared/extra-utils/cli/cli.ts index 1bf100869..bc1dddc68 100644 --- a/shared/extra-utils/cli/cli.ts +++ b/shared/extra-utils/cli/cli.ts @@ -1,7 +1,7 @@ import { exec } from 'child_process' import { AbstractCommand } from '../shared' -class CLICommand extends AbstractCommand { +export class CLICommand extends AbstractCommand { static exec (command: string) { return new Promise((res, rej) => { @@ -21,7 +21,3 @@ class CLICommand extends AbstractCommand { return CLICommand.exec(`${this.getEnv()} ${command}`) } } - -export { - CLICommand -} diff --git a/shared/extra-utils/custom-pages/custom-pages.ts b/shared/extra-utils/custom-pages/custom-pages.ts index bf2d16c70..56dabdc0f 100644 --- a/shared/extra-utils/custom-pages/custom-pages.ts +++ b/shared/extra-utils/custom-pages/custom-pages.ts @@ -1,31 +1,30 @@ +import { CustomPage } from '@shared/models' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { makeGetRequest, makePutBodyRequest } from '../requests/requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' -function getInstanceHomepage (url: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/custom-pages/homepage/instance' +export class CustomPagesCommand extends AbstractCommand { - return makeGetRequest({ - url, - path, - statusCodeExpected - }) -} - -function updateInstanceHomepage (url: string, token: string, content: string) { - const path = '/api/v1/custom-pages/homepage/instance' + getInstanceHomepage (options: OverrideCommandOptions = {}) { + const path = '/api/v1/custom-pages/homepage/instance' - return makePutBodyRequest({ - url, - path, - token, - fields: { content }, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} + return this.getRequestBody({ + ...options, + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } -// --------------------------------------------------------------------------- + updateInstanceHomepage (options: OverrideCommandOptions & { + content: string + }) { + const { content } = options + const path = '/api/v1/custom-pages/homepage/instance' -export { - getInstanceHomepage, - updateInstanceHomepage + return this.putBodyRequest({ + ...options, + path, + fields: { content }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } } diff --git a/shared/extra-utils/custom-pages/index.ts b/shared/extra-utils/custom-pages/index.ts new file mode 100644 index 000000000..5e70778f8 --- /dev/null +++ b/shared/extra-utils/custom-pages/index.ts @@ -0,0 +1 @@ +export * from './custom-pages' diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 4bf057492..10781d049 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -2,7 +2,7 @@ export * from './bulk' export * from './cli' -export * from './custom-pages/custom-pages' +export * from './custom-pages' export * from './feeds/feeds' diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 38e24d897..eb59ca600 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -182,6 +182,10 @@ function decodeQueryString (path: string) { return decode(path.split('?')[1]) } +function unwrap (test: request.Test): Promise { + return test.then(res => res.body) +} + // --------------------------------------------------------------------------- export { @@ -194,5 +198,6 @@ export { makePutBodyRequest, makeDeleteRequest, makeRawRequest, + unwrap, updateImageRequest } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 1b0775421..e07926065 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -8,6 +8,7 @@ import { randomInt } from '../../core-utils/miscs/miscs' import { VideoChannel } from '../../models/videos' import { BulkCommand } from '../bulk' import { CLICommand } from '../cli' +import { CustomPagesCommand } from '../custom-pages' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { makeGetRequest } from '../requests/requests' @@ -65,6 +66,7 @@ interface ServerInfo { bulkCommand?: BulkCommand cliCommand?: CLICommand + customPageCommand?: CustomPagesCommand } function parallelTests () { @@ -272,6 +274,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.bulkCommand = new BulkCommand(server) server.cliCommand = new CLICommand(server) + server.customPageCommand = new CustomPagesCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index bb06b6bdb..d8eba373d 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,15 +1,20 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makePostBodyRequest } from '../requests/requests' +import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap } from '../requests/requests' import { ServerInfo } from '../server/servers' -export interface CommonCommandOptions { +export interface OverrideCommandOptions { token?: string expectedStatus?: number } +interface CommonCommandOptions extends OverrideCommandOptions { + path: string + defaultExpectedStatus: number +} + abstract class AbstractCommand { - private expectedStatus = HttpStatusCode.OK_200 + private expectedStatus: HttpStatusCode constructor ( protected server: ServerInfo @@ -25,20 +30,43 @@ abstract class AbstractCommand { this.expectedStatus = status } + protected getRequestBody (options: CommonCommandOptions) { + return unwrap(makeGetRequest(this.buildCommonRequestOptions(options))) + } + + protected putBodyRequest (options: CommonCommandOptions & { + fields?: { [ fieldName: string ]: any } + }) { + const { fields } = options + + return makePutBodyRequest({ + ...this.buildCommonRequestOptions(options), + + fields + }) + } + protected postBodyRequest (options: CommonCommandOptions & { - path: string - defaultExpectedStatus: number fields?: { [ fieldName: string ]: any } }) { - const { token, fields, expectedStatus, defaultExpectedStatus, path } = options + const { fields } = options return makePostBodyRequest({ + ...this.buildCommonRequestOptions(options), + + fields + }) + } + + private buildCommonRequestOptions (options: CommonCommandOptions) { + const { token, expectedStatus, defaultExpectedStatus, path } = options + + return { url: this.server.url, path, token: token ?? this.server.accessToken, - fields, statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus - }) + } } } -- cgit v1.2.3 From c1bc8ee4783d6ce3102524e6c2a02b2f0f6aab6d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 10:21:35 +0200 Subject: Introduce feed command --- shared/extra-utils/feeds/feeds.ts | 55 ++++++++++++++++----------- shared/extra-utils/feeds/index.ts | 1 + shared/extra-utils/requests/requests.ts | 9 ++++- shared/extra-utils/server/servers.ts | 3 ++ shared/extra-utils/shared/abstract-command.ts | 28 ++++++++++++-- 5 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 shared/extra-utils/feeds/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/feeds/feeds.ts b/shared/extra-utils/feeds/feeds.ts index ce0a98c6d..012ce6cfe 100644 --- a/shared/extra-utils/feeds/feeds.ts +++ b/shared/extra-utils/feeds/feeds.ts @@ -1,33 +1,42 @@ -import * as request from 'supertest' + import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' type FeedType = 'videos' | 'video-comments' | 'subscriptions' -function getXMLfeed (url: string, feed: FeedType, format?: string) { - const path = '/feeds/' + feed + '.xml' +export class FeedCommand extends AbstractCommand { - return request(url) - .get(path) - .query((format) ? { format: format } : {}) - .set('Accept', 'application/xml') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /xml/) -} + getXML (options: OverrideCommandOptions & { + feed: FeedType + format?: string + }) { + const { feed, format } = options + const path = '/feeds/' + feed + '.xml' -function getJSONfeed (url: string, feed: FeedType, query: any = {}, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/feeds/' + feed + '.json' + return this.getRequestText({ + ...options, - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(statusCodeExpected) - .expect('Content-Type', /json/) -} + path, + query: format ? { format } : undefined, + accept: 'application/xml', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getJSON (options: OverrideCommandOptions & { + feed: FeedType + query?: { [ id: string ]: any } + }) { + const { feed, query } = options + const path = '/feeds/' + feed + '.json' -// --------------------------------------------------------------------------- + return this.getRequestText({ + ...options, -export { - getXMLfeed, - getJSONfeed + path, + query, + accept: 'application/json', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } } diff --git a/shared/extra-utils/feeds/index.ts b/shared/extra-utils/feeds/index.ts new file mode 100644 index 000000000..4634cb163 --- /dev/null +++ b/shared/extra-utils/feeds/index.ts @@ -0,0 +1 @@ +export * from './feeds' diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index eb59ca600..8c26a3699 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -182,10 +182,14 @@ function decodeQueryString (path: string) { return decode(path.split('?')[1]) } -function unwrap (test: request.Test): Promise { +function unwrapBody (test: request.Test): Promise { return test.then(res => res.body) } +function unwrapText (test: request.Test): Promise { + return test.then(res => res.text) +} + // --------------------------------------------------------------------------- export { @@ -198,6 +202,7 @@ export { makePutBodyRequest, makeDeleteRequest, makeRawRequest, - unwrap, + unwrapBody, + unwrapText, updateImageRequest } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index e07926065..b64c9eec6 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -9,6 +9,7 @@ import { VideoChannel } from '../../models/videos' import { BulkCommand } from '../bulk' import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' +import { FeedCommand } from '../feeds' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { makeGetRequest } from '../requests/requests' @@ -67,6 +68,7 @@ interface ServerInfo { bulkCommand?: BulkCommand cliCommand?: CLICommand customPageCommand?: CustomPagesCommand + feedCommand?: FeedCommand } function parallelTests () { @@ -275,6 +277,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.bulkCommand = new BulkCommand(server) server.cliCommand = new CLICommand(server) server.customPageCommand = new CustomPagesCommand(server) + server.feedCommand = new FeedCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index d8eba373d..53c644124 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,5 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap } from '../requests/requests' +import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap, unwrapBody, unwrapText } from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { @@ -12,6 +12,12 @@ interface CommonCommandOptions extends OverrideCommandOptions { defaultExpectedStatus: number } +interface GetCommandOptions extends CommonCommandOptions { + query?: { [ id: string ]: string } + contentType?: string + accept?: string +} + abstract class AbstractCommand { private expectedStatus: HttpStatusCode @@ -30,8 +36,12 @@ abstract class AbstractCommand { this.expectedStatus = status } - protected getRequestBody (options: CommonCommandOptions) { - return unwrap(makeGetRequest(this.buildCommonRequestOptions(options))) + protected getRequestBody (options: GetCommandOptions) { + return unwrapBody(this.getRequest(options)) + } + + protected getRequestText (options: GetCommandOptions) { + return unwrapText(this.getRequest(options)) } protected putBodyRequest (options: CommonCommandOptions & { @@ -68,6 +78,18 @@ abstract class AbstractCommand { statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } } + + private getRequest (options: GetCommandOptions) { + const { query, contentType, accept } = options + + return makeGetRequest({ + ...this.buildCommonRequestOptions(options), + + query, + contentType, + accept + }) + } } export { -- cgit v1.2.3 From f59545d97a80bf06025bf6343a80d834c7eb237f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 10:22:37 +0200 Subject: Rename command files --- shared/extra-utils/bulk/bulk-command.ts | 20 +++++++++++ shared/extra-utils/bulk/bulk.ts | 20 ----------- shared/extra-utils/bulk/index.ts | 2 +- shared/extra-utils/cli/cli-command.ts | 23 ++++++++++++ shared/extra-utils/cli/cli.ts | 23 ------------ shared/extra-utils/cli/index.ts | 2 +- .../custom-pages/custom-pages-command.ts | 30 ++++++++++++++++ shared/extra-utils/custom-pages/custom-pages.ts | 30 ---------------- shared/extra-utils/custom-pages/index.ts | 2 +- shared/extra-utils/feeds/feeds-command.ts | 42 ++++++++++++++++++++++ shared/extra-utils/feeds/feeds.ts | 42 ---------------------- shared/extra-utils/feeds/index.ts | 2 +- shared/extra-utils/index.ts | 2 +- shared/extra-utils/shared/abstract-command.ts | 2 +- 14 files changed, 121 insertions(+), 121 deletions(-) create mode 100644 shared/extra-utils/bulk/bulk-command.ts delete mode 100644 shared/extra-utils/bulk/bulk.ts create mode 100644 shared/extra-utils/cli/cli-command.ts delete mode 100644 shared/extra-utils/cli/cli.ts create mode 100644 shared/extra-utils/custom-pages/custom-pages-command.ts delete mode 100644 shared/extra-utils/custom-pages/custom-pages.ts create mode 100644 shared/extra-utils/feeds/feeds-command.ts delete mode 100644 shared/extra-utils/feeds/feeds.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/bulk-command.ts b/shared/extra-utils/bulk/bulk-command.ts new file mode 100644 index 000000000..fcbf04164 --- /dev/null +++ b/shared/extra-utils/bulk/bulk-command.ts @@ -0,0 +1,20 @@ + +import { BulkRemoveCommentsOfBody } from '@shared/models/bulk/bulk-remove-comments-of-body.model' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class BulkCommand extends AbstractCommand { + + removeCommentsOf (options: OverrideCommandOptions & { + attributes: BulkRemoveCommentsOfBody + }) { + const { attributes } = options + + return this.postBodyRequest({ + ...options, + path: '/api/v1/bulk/remove-comments-of', + fields: attributes, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/bulk/bulk.ts b/shared/extra-utils/bulk/bulk.ts deleted file mode 100644 index a58fb3fbb..000000000 --- a/shared/extra-utils/bulk/bulk.ts +++ /dev/null @@ -1,20 +0,0 @@ - -import { BulkRemoveCommentsOfBody } from '@shared/models/bulk/bulk-remove-comments-of-body.model' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class BulkCommand extends AbstractCommand { - - removeCommentsOf (options: OverrideCommandOptions & { - attributes: BulkRemoveCommentsOfBody - }) { - const { attributes } = options - - return this.postBodyRequest({ - ...options, - path: '/api/v1/bulk/remove-comments-of', - fields: attributes, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/bulk/index.ts b/shared/extra-utils/bulk/index.ts index 5d2f9d3ad..391597243 100644 --- a/shared/extra-utils/bulk/index.ts +++ b/shared/extra-utils/bulk/index.ts @@ -1 +1 @@ -export * from './bulk' +export * from './bulk-command' diff --git a/shared/extra-utils/cli/cli-command.ts b/shared/extra-utils/cli/cli-command.ts new file mode 100644 index 000000000..bc1dddc68 --- /dev/null +++ b/shared/extra-utils/cli/cli-command.ts @@ -0,0 +1,23 @@ +import { exec } from 'child_process' +import { AbstractCommand } from '../shared' + +export class CLICommand extends AbstractCommand { + + static exec (command: string) { + return new Promise((res, rej) => { + exec(command, (err, stdout, _stderr) => { + if (err) return rej(err) + + return res(stdout) + }) + }) + } + + getEnv () { + return `NODE_ENV=test NODE_APP_INSTANCE=${this.server.internalServerNumber}` + } + + async execWithEnv (command: string) { + return CLICommand.exec(`${this.getEnv()} ${command}`) + } +} diff --git a/shared/extra-utils/cli/cli.ts b/shared/extra-utils/cli/cli.ts deleted file mode 100644 index bc1dddc68..000000000 --- a/shared/extra-utils/cli/cli.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { exec } from 'child_process' -import { AbstractCommand } from '../shared' - -export class CLICommand extends AbstractCommand { - - static exec (command: string) { - return new Promise((res, rej) => { - exec(command, (err, stdout, _stderr) => { - if (err) return rej(err) - - return res(stdout) - }) - }) - } - - getEnv () { - return `NODE_ENV=test NODE_APP_INSTANCE=${this.server.internalServerNumber}` - } - - async execWithEnv (command: string) { - return CLICommand.exec(`${this.getEnv()} ${command}`) - } -} diff --git a/shared/extra-utils/cli/index.ts b/shared/extra-utils/cli/index.ts index 8a3f31e2f..91b5abfbe 100644 --- a/shared/extra-utils/cli/index.ts +++ b/shared/extra-utils/cli/index.ts @@ -1 +1 @@ -export * from './cli' +export * from './cli-command' diff --git a/shared/extra-utils/custom-pages/custom-pages-command.ts b/shared/extra-utils/custom-pages/custom-pages-command.ts new file mode 100644 index 000000000..a062c9774 --- /dev/null +++ b/shared/extra-utils/custom-pages/custom-pages-command.ts @@ -0,0 +1,30 @@ +import { CustomPage } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class CustomPagesCommand extends AbstractCommand { + + getInstanceHomepage (options: OverrideCommandOptions = {}) { + const path = '/api/v1/custom-pages/homepage/instance' + + return this.getRequestBody({ + ...options, + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateInstanceHomepage (options: OverrideCommandOptions & { + content: string + }) { + const { content } = options + const path = '/api/v1/custom-pages/homepage/instance' + + return this.putBodyRequest({ + ...options, + path, + fields: { content }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/custom-pages/custom-pages.ts b/shared/extra-utils/custom-pages/custom-pages.ts deleted file mode 100644 index 56dabdc0f..000000000 --- a/shared/extra-utils/custom-pages/custom-pages.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { CustomPage } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class CustomPagesCommand extends AbstractCommand { - - getInstanceHomepage (options: OverrideCommandOptions = {}) { - const path = '/api/v1/custom-pages/homepage/instance' - - return this.getRequestBody({ - ...options, - path, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - updateInstanceHomepage (options: OverrideCommandOptions & { - content: string - }) { - const { content } = options - const path = '/api/v1/custom-pages/homepage/instance' - - return this.putBodyRequest({ - ...options, - path, - fields: { content }, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/custom-pages/index.ts b/shared/extra-utils/custom-pages/index.ts index 5e70778f8..58aed04f2 100644 --- a/shared/extra-utils/custom-pages/index.ts +++ b/shared/extra-utils/custom-pages/index.ts @@ -1 +1 @@ -export * from './custom-pages' +export * from './custom-pages-command' diff --git a/shared/extra-utils/feeds/feeds-command.ts b/shared/extra-utils/feeds/feeds-command.ts new file mode 100644 index 000000000..8031adf92 --- /dev/null +++ b/shared/extra-utils/feeds/feeds-command.ts @@ -0,0 +1,42 @@ + +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +type FeedType = 'videos' | 'video-comments' | 'subscriptions' + +export class FeedCommand extends AbstractCommand { + + getXML (options: OverrideCommandOptions & { + feed: FeedType + format?: string + }) { + const { feed, format } = options + const path = '/feeds/' + feed + '.xml' + + return this.getRequestText({ + ...options, + + path, + query: format ? { format } : undefined, + accept: 'application/xml', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getJSON (options: OverrideCommandOptions & { + feed: FeedType + query?: { [ id: string ]: any } + }) { + const { feed, query } = options + const path = '/feeds/' + feed + '.json' + + return this.getRequestText({ + ...options, + + path, + query, + accept: 'application/json', + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/feeds/feeds.ts b/shared/extra-utils/feeds/feeds.ts deleted file mode 100644 index 012ce6cfe..000000000 --- a/shared/extra-utils/feeds/feeds.ts +++ /dev/null @@ -1,42 +0,0 @@ - -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -type FeedType = 'videos' | 'video-comments' | 'subscriptions' - -export class FeedCommand extends AbstractCommand { - - getXML (options: OverrideCommandOptions & { - feed: FeedType - format?: string - }) { - const { feed, format } = options - const path = '/feeds/' + feed + '.xml' - - return this.getRequestText({ - ...options, - - path, - query: format ? { format } : undefined, - accept: 'application/xml', - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getJSON (options: OverrideCommandOptions & { - feed: FeedType - query?: { [ id: string ]: any } - }) { - const { feed, query } = options - const path = '/feeds/' + feed + '.json' - - return this.getRequestText({ - ...options, - - path, - query, - accept: 'application/json', - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/feeds/index.ts b/shared/extra-utils/feeds/index.ts index 4634cb163..662a22b6f 100644 --- a/shared/extra-utils/feeds/index.ts +++ b/shared/extra-utils/feeds/index.ts @@ -1 +1 @@ -export * from './feeds' +export * from './feeds-command' diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 10781d049..c4f0afdc4 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -4,7 +4,7 @@ export * from './cli' export * from './custom-pages' -export * from './feeds/feeds' +export * from './feeds' export * from './mock-servers/mock-instances-index' diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 53c644124..7f812daa8 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,5 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrap, unwrapBody, unwrapText } from '../requests/requests' +import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrapBody, unwrapText } from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { -- cgit v1.2.3 From a92ddacb38a4a17e117ca9ed41680a03580fb81d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 10:34:29 +0200 Subject: Introduce logs command --- shared/extra-utils/index.ts | 2 ++ shared/extra-utils/logs/index.ts | 1 + shared/extra-utils/logs/logs-command.ts | 41 +++++++++++++++++++++++++++ shared/extra-utils/logs/logs.ts | 32 --------------------- shared/extra-utils/server/servers.ts | 3 ++ shared/extra-utils/shared/abstract-command.ts | 2 +- 6 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 shared/extra-utils/logs/index.ts create mode 100644 shared/extra-utils/logs/logs-command.ts delete mode 100644 shared/extra-utils/logs/logs.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index c4f0afdc4..a3d3970af 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -6,6 +6,8 @@ export * from './custom-pages' export * from './feeds' +export * from './logs' + export * from './mock-servers/mock-instances-index' export * from './miscs/email' diff --git a/shared/extra-utils/logs/index.ts b/shared/extra-utils/logs/index.ts new file mode 100644 index 000000000..69452d7f0 --- /dev/null +++ b/shared/extra-utils/logs/index.ts @@ -0,0 +1 @@ +export * from './logs-command' diff --git a/shared/extra-utils/logs/logs-command.ts b/shared/extra-utils/logs/logs-command.ts new file mode 100644 index 000000000..f7594734d --- /dev/null +++ b/shared/extra-utils/logs/logs-command.ts @@ -0,0 +1,41 @@ +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { LogLevel } from '../../models/server/log-level.type' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class LogsCommand extends AbstractCommand { + + getLogs (options: OverrideCommandOptions & { + startDate: Date + endDate?: Date + level?: LogLevel + }) { + const { startDate, endDate, level } = options + const path = '/api/v1/server/logs' + + return this.getRequestBody({ + ...options, + + path, + query: { startDate, endDate, level }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getAuditLogs (options: OverrideCommandOptions & { + startDate: Date + endDate?: Date + }) { + const { startDate, endDate } = options + + const path = '/api/v1/server/audit-logs' + + return this.getRequestBody({ + ...options, + + path, + query: { startDate, endDate }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + +} diff --git a/shared/extra-utils/logs/logs.ts b/shared/extra-utils/logs/logs.ts deleted file mode 100644 index 8d741276c..000000000 --- a/shared/extra-utils/logs/logs.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { makeGetRequest } from '../requests/requests' -import { LogLevel } from '../../models/server/log-level.type' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getLogs (url: string, accessToken: string, startDate: Date, endDate?: Date, level?: LogLevel) { - const path = '/api/v1/server/logs' - - return makeGetRequest({ - url, - path, - token: accessToken, - query: { startDate, endDate, level }, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getAuditLogs (url: string, accessToken: string, startDate: Date, endDate?: Date) { - const path = '/api/v1/server/audit-logs' - - return makeGetRequest({ - url, - path, - token: accessToken, - query: { startDate, endDate }, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -export { - getLogs, - getAuditLogs -} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index b64c9eec6..4343eab93 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -10,6 +10,7 @@ import { BulkCommand } from '../bulk' import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' import { FeedCommand } from '../feeds' +import { LogsCommand } from '../logs' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { makeGetRequest } from '../requests/requests' @@ -69,6 +70,7 @@ interface ServerInfo { cliCommand?: CLICommand customPageCommand?: CustomPagesCommand feedCommand?: FeedCommand + logsCommand?: LogsCommand } function parallelTests () { @@ -278,6 +280,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.cliCommand = new CLICommand(server) server.customPageCommand = new CustomPagesCommand(server) server.feedCommand = new FeedCommand(server) + server.logsCommand = new LogsCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 7f812daa8..a57222216 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -13,7 +13,7 @@ interface CommonCommandOptions extends OverrideCommandOptions { } interface GetCommandOptions extends CommonCommandOptions { - query?: { [ id: string ]: string } + query?: { [ id: string ]: any } contentType?: string accept?: string } -- cgit v1.2.3 From c8fc9b47188b33cfc33184b1ee7e680a093244f1 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 10:35:35 +0200 Subject: Rename mock server files --- shared/extra-utils/index.ts | 2 +- shared/extra-utils/mock-servers/index.ts | 2 ++ .../mock-servers/joinpeertube-versions.ts | 33 ---------------------- .../mock-servers/mock-joinpeertube-versions.ts | 33 ++++++++++++++++++++++ 4 files changed, 36 insertions(+), 34 deletions(-) create mode 100644 shared/extra-utils/mock-servers/index.ts delete mode 100644 shared/extra-utils/mock-servers/joinpeertube-versions.ts create mode 100644 shared/extra-utils/mock-servers/mock-joinpeertube-versions.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index a3d3970af..30f44dfc2 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -8,7 +8,7 @@ export * from './feeds' export * from './logs' -export * from './mock-servers/mock-instances-index' +export * from './mock-servers' export * from './miscs/email' export * from './miscs/sql' diff --git a/shared/extra-utils/mock-servers/index.ts b/shared/extra-utils/mock-servers/index.ts new file mode 100644 index 000000000..47679c818 --- /dev/null +++ b/shared/extra-utils/mock-servers/index.ts @@ -0,0 +1,2 @@ +export * from './mock-instances-index' +export * from './mock-joinpeertube-versions' diff --git a/shared/extra-utils/mock-servers/joinpeertube-versions.ts b/shared/extra-utils/mock-servers/joinpeertube-versions.ts deleted file mode 100644 index 5ea432ecf..000000000 --- a/shared/extra-utils/mock-servers/joinpeertube-versions.ts +++ /dev/null @@ -1,33 +0,0 @@ -import * as express from 'express' -import { randomInt } from '@shared/core-utils' - -export class MockJoinPeerTubeVersions { - private latestVersion: string - - initialize () { - return new Promise(res => { - const app = express() - - app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { - if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) - - return next() - }) - - app.get('/versions.json', (req: express.Request, res: express.Response) => { - return res.json({ - peertube: { - latestVersion: this.latestVersion - } - }) - }) - - const port = 42201 + randomInt(1, 100) - app.listen(port, () => res(port)) - }) - } - - setLatestVersion (latestVersion: string) { - this.latestVersion = latestVersion - } -} diff --git a/shared/extra-utils/mock-servers/mock-joinpeertube-versions.ts b/shared/extra-utils/mock-servers/mock-joinpeertube-versions.ts new file mode 100644 index 000000000..5ea432ecf --- /dev/null +++ b/shared/extra-utils/mock-servers/mock-joinpeertube-versions.ts @@ -0,0 +1,33 @@ +import * as express from 'express' +import { randomInt } from '@shared/core-utils' + +export class MockJoinPeerTubeVersions { + private latestVersion: string + + initialize () { + return new Promise(res => { + const app = express() + + app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { + if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) + + return next() + }) + + app.get('/versions.json', (req: express.Request, res: express.Response) => { + return res.json({ + peertube: { + latestVersion: this.latestVersion + } + }) + }) + + const port = 42201 + randomInt(1, 100) + app.listen(port, () => res(port)) + }) + } + + setLatestVersion (latestVersion: string) { + this.latestVersion = latestVersion + } +} -- cgit v1.2.3 From 8ef9457fdee7812b1a8cc3b3bdeff94130819003 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 10:36:54 +0200 Subject: Correctly export misc files --- shared/extra-utils/index.ts | 11 +---- shared/extra-utils/miscs/email.ts | 64 -------------------------- shared/extra-utils/miscs/index.ts | 3 ++ shared/extra-utils/mock-servers/index.ts | 1 + shared/extra-utils/mock-servers/mock-email.ts | 64 ++++++++++++++++++++++++++ shared/extra-utils/users/user-notifications.ts | 2 +- 6 files changed, 70 insertions(+), 75 deletions(-) delete mode 100644 shared/extra-utils/miscs/email.ts create mode 100644 shared/extra-utils/miscs/index.ts create mode 100644 shared/extra-utils/mock-servers/mock-email.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 30f44dfc2..7d2887209 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -1,20 +1,11 @@ export * from './bulk' - export * from './cli' - export * from './custom-pages' - export * from './feeds' - export * from './logs' - +export * from './miscs' export * from './mock-servers' -export * from './miscs/email' -export * from './miscs/sql' -export * from './miscs/miscs' -export * from './miscs/stubs' - export * from './moderation/abuses' export * from './plugins/mock-blocklist' diff --git a/shared/extra-utils/miscs/email.ts b/shared/extra-utils/miscs/email.ts deleted file mode 100644 index 9fc9a5ad0..000000000 --- a/shared/extra-utils/miscs/email.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { ChildProcess } from 'child_process' -import { randomInt } from '../../core-utils/miscs/miscs' -import { parallelTests } from '../server/servers' - -const MailDev = require('maildev') - -class MockSmtpServer { - - private static instance: MockSmtpServer - private started = false - private emailChildProcess: ChildProcess - private emails: object[] - - private constructor () { } - - collectEmails (emailsCollection: object[]) { - return new Promise((res, rej) => { - const port = parallelTests() ? randomInt(1000, 2000) : 1025 - this.emails = emailsCollection - - if (this.started) { - return res(undefined) - } - - const maildev = new MailDev({ - ip: '127.0.0.1', - smtp: port, - disableWeb: true, - silent: true - }) - - maildev.on('new', email => { - this.emails.push(email) - }) - - maildev.listen(err => { - if (err) return rej(err) - - this.started = true - - return res(port) - }) - }) - } - - kill () { - if (!this.emailChildProcess) return - - process.kill(this.emailChildProcess.pid) - - this.emailChildProcess = null - MockSmtpServer.instance = null - } - - static get Instance () { - return this.instance || (this.instance = new this()) - } -} - -// --------------------------------------------------------------------------- - -export { - MockSmtpServer -} diff --git a/shared/extra-utils/miscs/index.ts b/shared/extra-utils/miscs/index.ts new file mode 100644 index 000000000..ccacd4c79 --- /dev/null +++ b/shared/extra-utils/miscs/index.ts @@ -0,0 +1,3 @@ +export * from './miscs' +export * from './sql' +export * from './stubs' diff --git a/shared/extra-utils/mock-servers/index.ts b/shared/extra-utils/mock-servers/index.ts index 47679c818..485757843 100644 --- a/shared/extra-utils/mock-servers/index.ts +++ b/shared/extra-utils/mock-servers/index.ts @@ -1,2 +1,3 @@ +export * from './mock-email' export * from './mock-instances-index' export * from './mock-joinpeertube-versions' diff --git a/shared/extra-utils/mock-servers/mock-email.ts b/shared/extra-utils/mock-servers/mock-email.ts new file mode 100644 index 000000000..9fc9a5ad0 --- /dev/null +++ b/shared/extra-utils/mock-servers/mock-email.ts @@ -0,0 +1,64 @@ +import { ChildProcess } from 'child_process' +import { randomInt } from '../../core-utils/miscs/miscs' +import { parallelTests } from '../server/servers' + +const MailDev = require('maildev') + +class MockSmtpServer { + + private static instance: MockSmtpServer + private started = false + private emailChildProcess: ChildProcess + private emails: object[] + + private constructor () { } + + collectEmails (emailsCollection: object[]) { + return new Promise((res, rej) => { + const port = parallelTests() ? randomInt(1000, 2000) : 1025 + this.emails = emailsCollection + + if (this.started) { + return res(undefined) + } + + const maildev = new MailDev({ + ip: '127.0.0.1', + smtp: port, + disableWeb: true, + silent: true + }) + + maildev.on('new', email => { + this.emails.push(email) + }) + + maildev.listen(err => { + if (err) return rej(err) + + this.started = true + + return res(port) + }) + }) + } + + kill () { + if (!this.emailChildProcess) return + + process.kill(this.emailChildProcess.pid) + + this.emailChildProcess = null + MockSmtpServer.instance = null + } + + static get Instance () { + return this.instance || (this.instance = new this()) + } +} + +// --------------------------------------------------------------------------- + +export { + MockSmtpServer +} diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts index 844f4442d..e75946eec 100644 --- a/shared/extra-utils/users/user-notifications.ts +++ b/shared/extra-utils/users/user-notifications.ts @@ -5,7 +5,7 @@ import { inspect } from 'util' import { AbuseState, PluginType } from '@shared/models' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' -import { MockSmtpServer } from '../miscs/email' +import { MockSmtpServer } from '../mock-servers/mock-email' import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' import { doubleFollow } from '../server/follows' import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' -- cgit v1.2.3 From 0c1a77e9ccf915184c431145a8b326d4ce271b46 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 12:01:59 +0200 Subject: Introduce abuse command --- shared/extra-utils/index.ts | 2 +- shared/extra-utils/moderation/abuses-command.ts | 205 ++++++++++++++++++++ shared/extra-utils/moderation/abuses.ts | 244 ------------------------ shared/extra-utils/moderation/index.ts | 1 + shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/shared/abstract-command.ts | 6 +- 6 files changed, 215 insertions(+), 246 deletions(-) create mode 100644 shared/extra-utils/moderation/abuses-command.ts delete mode 100644 shared/extra-utils/moderation/abuses.ts create mode 100644 shared/extra-utils/moderation/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 7d2887209..bde269052 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -5,8 +5,8 @@ export * from './feeds' export * from './logs' export * from './miscs' export * from './mock-servers' +export * from './moderation' -export * from './moderation/abuses' export * from './plugins/mock-blocklist' export * from './requests/check-api-params' diff --git a/shared/extra-utils/moderation/abuses-command.ts b/shared/extra-utils/moderation/abuses-command.ts new file mode 100644 index 000000000..59126d0a9 --- /dev/null +++ b/shared/extra-utils/moderation/abuses-command.ts @@ -0,0 +1,205 @@ +import { pick } from 'lodash' +import { + AbuseFilter, + AbuseMessage, + AbusePredefinedReasonsString, + AbuseState, + AbuseUpdate, + AbuseVideoIs, + AdminAbuse, + ResultList, + UserAbuse +} from '@shared/models' +import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' +import { unwrapBody } from '../requests/requests' + +export class AbusesCommand extends AbstractCommand { + + report (options: OverrideCommandOptions & { + reason: string + + accountId?: number + videoId?: number + commentId?: number + + predefinedReasons?: AbusePredefinedReasonsString[] + + startAt?: number + endAt?: number + }) { + const path = '/api/v1/abuses' + + const video = options.videoId + ? { + id: options.videoId, + startAt: options.startAt, + endAt: options.endAt + } + : undefined + + const comment = options.commentId + ? { id: options.commentId } + : undefined + + const account = options.accountId + ? { id: options.accountId } + : undefined + + const body = { + account, + video, + comment, + + reason: options.reason, + predefinedReasons: options.predefinedReasons + } + + return unwrapBody<{ abuse: { id: number } }>(this.postBodyRequest({ + ...options, + + path, + fields: body, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + getAdminList (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + + id?: number + predefinedReason?: AbusePredefinedReasonsString + search?: string + filter?: AbuseFilter + state?: AbuseState + videoIs?: AbuseVideoIs + searchReporter?: string + searchReportee?: string + searchVideo?: string + searchVideoChannel?: string + } = {}) { + const toPick = [ + 'count', + 'filter', + 'id', + 'predefinedReason', + 'search', + 'searchReportee', + 'searchReporter', + 'searchVideo', + 'searchVideoChannel', + 'sort', + 'start', + 'state', + 'videoIs' + ] + + const path = '/api/v1/abuses' + + const defaultQuery = { sort: 'createdAt' } + const query = { ...defaultQuery, ...pick(options, toPick) } + + return this.getRequestBody>({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getUserList (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + + id?: number + search?: string + state?: AbuseState + }) { + const toPick = [ + 'id', + 'search', + 'state', + 'start', + 'count', + 'sort' + ] + + const path = '/api/v1/users/me/abuses' + + const defaultQuery = { sort: 'createdAt' } + const query = { ...defaultQuery, ...pick(options, toPick) } + + return this.getRequestBody>({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + update (options: OverrideCommandOptions & { + abuseId: number + body: AbuseUpdate + }) { + const { abuseId, body } = options + const path = '/api/v1/abuses/' + abuseId + + return this.putBodyRequest({ + ...options, + + path, + fields: body, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + delete (options: OverrideCommandOptions & { + abuseId: number + }) { + const { abuseId } = options + const path = '/api/v1/abuses/' + abuseId + + return this.deleteRequest({ ...options, path, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) + } + + listMessages (options: OverrideCommandOptions & { + abuseId: number + }) { + const { abuseId } = options + const path = '/api/v1/abuses/' + abuseId + '/messages' + + return this.getRequestBody>({ ...options, path, defaultExpectedStatus: HttpStatusCode.OK_200 }) + } + + deleteMessage (options: OverrideCommandOptions & { + abuseId: number + messageId: number + }) { + const { abuseId, messageId } = options + const path = '/api/v1/abuses/' + abuseId + '/messages/' + messageId + + return this.deleteRequest({ ...options, path, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) + } + + addMessage (options: OverrideCommandOptions & { + abuseId: number + message: string + }) { + const { abuseId, message } = options + const path = '/api/v1/abuses/' + abuseId + '/messages' + + return this.postBodyRequest({ + ...options, + + path, + fields: { message }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + +} diff --git a/shared/extra-utils/moderation/abuses.ts b/shared/extra-utils/moderation/abuses.ts deleted file mode 100644 index c0fda722f..000000000 --- a/shared/extra-utils/moderation/abuses.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { AbuseFilter, AbusePredefinedReasonsString, AbuseState, AbuseUpdate, AbuseVideoIs } from '@shared/models' -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function reportAbuse (options: { - url: string - token: string - - reason: string - - accountId?: number - videoId?: number - commentId?: number - - predefinedReasons?: AbusePredefinedReasonsString[] - - startAt?: number - endAt?: number - - statusCodeExpected?: number -}) { - const path = '/api/v1/abuses' - - const video = options.videoId - ? { - id: options.videoId, - startAt: options.startAt, - endAt: options.endAt - } - : undefined - - const comment = options.commentId - ? { id: options.commentId } - : undefined - - const account = options.accountId - ? { id: options.accountId } - : undefined - - const body = { - account, - video, - comment, - - reason: options.reason, - predefinedReasons: options.predefinedReasons - } - - return makePostBodyRequest({ - url: options.url, - path, - token: options.token, - - fields: body, - statusCodeExpected: options.statusCodeExpected || HttpStatusCode.OK_200 - }) -} - -function getAdminAbusesList (options: { - url: string - token: string - - start?: number - count?: number - sort?: string - - id?: number - predefinedReason?: AbusePredefinedReasonsString - search?: string - filter?: AbuseFilter - state?: AbuseState - videoIs?: AbuseVideoIs - searchReporter?: string - searchReportee?: string - searchVideo?: string - searchVideoChannel?: string -}) { - const { - url, - token, - start, - count, - sort, - id, - predefinedReason, - search, - filter, - state, - videoIs, - searchReporter, - searchReportee, - searchVideo, - searchVideoChannel - } = options - const path = '/api/v1/abuses' - - const query = { - id, - predefinedReason, - search, - state, - filter, - videoIs, - start, - count, - sort: sort || 'createdAt', - searchReporter, - searchReportee, - searchVideo, - searchVideoChannel - } - - return makeGetRequest({ - url, - path, - token, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getUserAbusesList (options: { - url: string - token: string - - start?: number - count?: number - sort?: string - - id?: number - search?: string - state?: AbuseState -}) { - const { - url, - token, - start, - count, - sort, - id, - search, - state - } = options - const path = '/api/v1/users/me/abuses' - - const query = { - id, - search, - state, - start, - count, - sort: sort || 'createdAt' - } - - return makeGetRequest({ - url, - path, - token, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function updateAbuse ( - url: string, - token: string, - abuseId: number, - body: AbuseUpdate, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/abuses/' + abuseId - - return makePutBodyRequest({ - url, - token, - path, - fields: body, - statusCodeExpected - }) -} - -function deleteAbuse (url: string, token: string, abuseId: number, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/abuses/' + abuseId - - return makeDeleteRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function listAbuseMessages (url: string, token: string, abuseId: number, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/abuses/' + abuseId + '/messages' - - return makeGetRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function deleteAbuseMessage ( - url: string, - token: string, - abuseId: number, - messageId: number, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/abuses/' + abuseId + '/messages/' + messageId - - return makeDeleteRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function addAbuseMessage (url: string, token: string, abuseId: number, message: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/abuses/' + abuseId + '/messages' - - return makePostBodyRequest({ - url, - token, - path, - fields: { message }, - statusCodeExpected - }) -} - -// --------------------------------------------------------------------------- - -export { - reportAbuse, - getAdminAbusesList, - updateAbuse, - deleteAbuse, - getUserAbusesList, - listAbuseMessages, - deleteAbuseMessage, - addAbuseMessage -} diff --git a/shared/extra-utils/moderation/index.ts b/shared/extra-utils/moderation/index.ts new file mode 100644 index 000000000..b37643956 --- /dev/null +++ b/shared/extra-utils/moderation/index.ts @@ -0,0 +1 @@ +export * from './abuses-command' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 4343eab93..f05f0dbbe 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -12,6 +12,7 @@ import { CustomPagesCommand } from '../custom-pages' import { FeedCommand } from '../feeds' import { LogsCommand } from '../logs' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' +import { AbusesCommand } from '../moderation' import { makeGetRequest } from '../requests/requests' interface ServerInfo { @@ -71,6 +72,7 @@ interface ServerInfo { customPageCommand?: CustomPagesCommand feedCommand?: FeedCommand logsCommand?: LogsCommand + abusesCommand?: AbusesCommand } function parallelTests () { @@ -281,6 +283,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.customPageCommand = new CustomPagesCommand(server) server.feedCommand = new FeedCommand(server) server.logsCommand = new LogsCommand(server) + server.abusesCommand = new AbusesCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index a57222216..3ee5cd865 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,5 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrapBody, unwrapText } from '../requests/requests' +import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrapBody, unwrapText } from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { @@ -44,6 +44,10 @@ abstract class AbstractCommand { return unwrapText(this.getRequest(options)) } + protected deleteRequest (options: CommonCommandOptions) { + return makeDeleteRequest(this.buildCommonRequestOptions(options)) + } + protected putBodyRequest (options: CommonCommandOptions & { fields?: { [ fieldName: string ]: any } }) { -- cgit v1.2.3 From 480d6ea6791fe4100f1905af1e1e3a08173594ea Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 14:07:54 +0200 Subject: Move plugin blocklist mock --- shared/extra-utils/index.ts | 2 -- shared/extra-utils/mock-servers/index.ts | 1 + .../mock-servers/mock-plugin-blocklist.ts | 37 ++++++++++++++++++++++ shared/extra-utils/plugins/mock-blocklist.ts | 37 ---------------------- 4 files changed, 38 insertions(+), 39 deletions(-) create mode 100644 shared/extra-utils/mock-servers/mock-plugin-blocklist.ts delete mode 100644 shared/extra-utils/plugins/mock-blocklist.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index bde269052..7ca079c78 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -7,8 +7,6 @@ export * from './miscs' export * from './mock-servers' export * from './moderation' -export * from './plugins/mock-blocklist' - export * from './requests/check-api-params' export * from './requests/requests' diff --git a/shared/extra-utils/mock-servers/index.ts b/shared/extra-utils/mock-servers/index.ts index 485757843..0ec07f685 100644 --- a/shared/extra-utils/mock-servers/index.ts +++ b/shared/extra-utils/mock-servers/index.ts @@ -1,3 +1,4 @@ export * from './mock-email' export * from './mock-instances-index' export * from './mock-joinpeertube-versions' +export * from './mock-plugin-blocklist' diff --git a/shared/extra-utils/mock-servers/mock-plugin-blocklist.ts b/shared/extra-utils/mock-servers/mock-plugin-blocklist.ts new file mode 100644 index 000000000..d18f8224f --- /dev/null +++ b/shared/extra-utils/mock-servers/mock-plugin-blocklist.ts @@ -0,0 +1,37 @@ +import * as express from 'express' +import { Server } from 'http' +import { randomInt } from '@shared/core-utils' + +type BlocklistResponse = { + data: { + value: string + action?: 'add' | 'remove' + updatedAt?: string + }[] +} + +export class MockBlocklist { + private body: BlocklistResponse + private server: Server + + initialize () { + return new Promise(res => { + const app = express() + + app.get('/blocklist', (req: express.Request, res: express.Response) => { + return res.json(this.body) + }) + + const port = 42201 + randomInt(1, 100) + this.server = app.listen(port, () => res(port)) + }) + } + + replace (body: BlocklistResponse) { + this.body = body + } + + terminate () { + if (this.server) this.server.close() + } +} diff --git a/shared/extra-utils/plugins/mock-blocklist.ts b/shared/extra-utils/plugins/mock-blocklist.ts deleted file mode 100644 index d18f8224f..000000000 --- a/shared/extra-utils/plugins/mock-blocklist.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as express from 'express' -import { Server } from 'http' -import { randomInt } from '@shared/core-utils' - -type BlocklistResponse = { - data: { - value: string - action?: 'add' | 'remove' - updatedAt?: string - }[] -} - -export class MockBlocklist { - private body: BlocklistResponse - private server: Server - - initialize () { - return new Promise(res => { - const app = express() - - app.get('/blocklist', (req: express.Request, res: express.Response) => { - return res.json(this.body) - }) - - const port = 42201 + randomInt(1, 100) - this.server = app.listen(port, () => res(port)) - }) - } - - replace (body: BlocklistResponse) { - this.body = body - } - - terminate () { - if (this.server) this.server.close() - } -} -- cgit v1.2.3 From 23a3a8827cb8b862f5cc7ee2819f39918303beca Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 14:30:20 +0200 Subject: Introduce overviews command --- shared/extra-utils/index.ts | 1 + shared/extra-utils/overviews/index.ts | 1 + shared/extra-utils/overviews/overviews-command.ts | 25 +++++++++++++++++ shared/extra-utils/overviews/overviews.ts | 34 ----------------------- shared/extra-utils/server/servers.ts | 3 ++ shared/extra-utils/shared/abstract-command.ts | 5 +++- 6 files changed, 34 insertions(+), 35 deletions(-) create mode 100644 shared/extra-utils/overviews/index.ts create mode 100644 shared/extra-utils/overviews/overviews-command.ts delete mode 100644 shared/extra-utils/overviews/overviews.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 7ca079c78..38c8c4c1c 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -6,6 +6,7 @@ export * from './logs' export * from './miscs' export * from './mock-servers' export * from './moderation' +export * from './overviews' export * from './requests/check-api-params' export * from './requests/requests' diff --git a/shared/extra-utils/overviews/index.ts b/shared/extra-utils/overviews/index.ts new file mode 100644 index 000000000..e19551907 --- /dev/null +++ b/shared/extra-utils/overviews/index.ts @@ -0,0 +1 @@ +export * from './overviews-command' diff --git a/shared/extra-utils/overviews/overviews-command.ts b/shared/extra-utils/overviews/overviews-command.ts new file mode 100644 index 000000000..0ac3cbd33 --- /dev/null +++ b/shared/extra-utils/overviews/overviews-command.ts @@ -0,0 +1,25 @@ +import { HttpStatusCode } from '@shared/core-utils' +import { VideosOverview } from '@shared/models' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class OverviewsCommand extends AbstractCommand { + + getVideos (options: OverrideCommandOptions & { + page: number + token?: string + }) { + const { token, page } = options + const path = '/api/v1/overviews/videos' + + const query = { page } + + return this.getRequestBody({ + ...options, + + token: token || null, + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/overviews/overviews.ts b/shared/extra-utils/overviews/overviews.ts deleted file mode 100644 index 5e1a13e5e..000000000 --- a/shared/extra-utils/overviews/overviews.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { makeGetRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getVideosOverview (url: string, page: number, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/overviews/videos' - - const query = { page } - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected - }) -} - -function getVideosOverviewWithToken (url: string, page: number, token: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/overviews/videos' - - const query = { page } - - return makeGetRequest({ - url, - path, - query, - token, - statusCodeExpected - }) -} - -export { - getVideosOverview, - getVideosOverviewWithToken -} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index f05f0dbbe..70be96cf6 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -13,6 +13,7 @@ import { FeedCommand } from '../feeds' import { LogsCommand } from '../logs' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { AbusesCommand } from '../moderation' +import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' interface ServerInfo { @@ -73,6 +74,7 @@ interface ServerInfo { feedCommand?: FeedCommand logsCommand?: LogsCommand abusesCommand?: AbusesCommand + overviewsCommand?: OverviewsCommand } function parallelTests () { @@ -284,6 +286,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.feedCommand = new FeedCommand(server) server.logsCommand = new LogsCommand(server) server.abusesCommand = new AbusesCommand(server) + server.overviewsCommand = new OverviewsCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 3ee5cd865..3815fab0e 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -78,7 +78,10 @@ abstract class AbstractCommand { return { url: this.server.url, path, - token: token ?? this.server.accessToken, + + // Token can be null if we don't want to add it + token: token !== undefined ? token : this.server.accessToken, + statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } } -- cgit v1.2.3 From af971e06c620bd46a5aa64c8833364e7022b5e3d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 15:22:51 +0200 Subject: Introduce search command --- shared/extra-utils/index.ts | 4 +- shared/extra-utils/overviews/overviews-command.ts | 1 - shared/extra-utils/search/index.ts | 1 + shared/extra-utils/search/search-command.ts | 101 ++++++++++++++++++++++ shared/extra-utils/search/video-channels.ts | 36 -------- shared/extra-utils/search/video-playlists.ts | 36 -------- shared/extra-utils/search/videos.ts | 64 -------------- shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/videos/videos.ts | 8 +- 9 files changed, 110 insertions(+), 144 deletions(-) create mode 100644 shared/extra-utils/search/index.ts create mode 100644 shared/extra-utils/search/search-command.ts delete mode 100644 shared/extra-utils/search/video-channels.ts delete mode 100644 shared/extra-utils/search/video-playlists.ts delete mode 100644 shared/extra-utils/search/videos.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 38c8c4c1c..067e6fb65 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -11,9 +11,7 @@ export * from './overviews' export * from './requests/check-api-params' export * from './requests/requests' -export * from './search/video-channels' -export * from './search/video-playlists' -export * from './search/videos' +export * from './search' export * from './server/activitypub' export * from './server/clients' diff --git a/shared/extra-utils/overviews/overviews-command.ts b/shared/extra-utils/overviews/overviews-command.ts index 0ac3cbd33..6f56b0ce4 100644 --- a/shared/extra-utils/overviews/overviews-command.ts +++ b/shared/extra-utils/overviews/overviews-command.ts @@ -6,7 +6,6 @@ export class OverviewsCommand extends AbstractCommand { getVideos (options: OverrideCommandOptions & { page: number - token?: string }) { const { token, page } = options const path = '/api/v1/overviews/videos' diff --git a/shared/extra-utils/search/index.ts b/shared/extra-utils/search/index.ts new file mode 100644 index 000000000..48dbe8ae9 --- /dev/null +++ b/shared/extra-utils/search/index.ts @@ -0,0 +1 @@ +export * from './search-command' diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts new file mode 100644 index 000000000..d4cfab32b --- /dev/null +++ b/shared/extra-utils/search/search-command.ts @@ -0,0 +1,101 @@ +import { + ResultList, + Video, + VideoChannel, + VideoChannelsSearchQuery, + VideoPlaylist, + VideoPlaylistsSearchQuery, + VideosSearchQuery +} from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class SearchCommand extends AbstractCommand { + + searchChannels (options: OverrideCommandOptions & { + search: string + }) { + return this.advancedChannelSearch({ + ...options, + + search: { search: options.search } + }) + } + + advancedChannelSearch (options: OverrideCommandOptions & { + search: VideoChannelsSearchQuery + }) { + const { search, token } = options + const path = '/api/v1/search/video-channels' + + return this.getRequestBody>({ + ...options, + + token: token || null, + + path, + query: search, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + searchPlaylists (options: OverrideCommandOptions & { + search: string + }) { + return this.advancedPlaylistSearch({ + ...options, + + search: { search: options.search } + }) + } + + advancedPlaylistSearch (options: OverrideCommandOptions & { + search: VideoPlaylistsSearchQuery + }) { + const { search, token } = options + const path = '/api/v1/search/video-playlists' + + return this.getRequestBody>({ + ...options, + + token: token || null, + + path, + query: search, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + searchVideos (options: OverrideCommandOptions & { + search: string + sort?: string + }) { + const { search, sort } = options + + return this.advancedVideoSearch({ + ...options, + + search: { + search: search, + sort: sort ?? '-publishedAt' + } + }) + } + + advancedVideoSearch (options: OverrideCommandOptions & { + search: VideosSearchQuery + }) { + const { search, token } = options + const path = '/api/v1/search/videos' + + return this.getRequestBody>({ + ...options, + + token: token || null, + + path, + query: search, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/search/video-channels.ts b/shared/extra-utils/search/video-channels.ts deleted file mode 100644 index 8e0f42578..000000000 --- a/shared/extra-utils/search/video-channels.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { VideoChannelsSearchQuery } from '@shared/models' -import { makeGetRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function searchVideoChannel (url: string, search: string, token?: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/search/video-channels' - - return makeGetRequest({ - url, - path, - query: { - sort: '-createdAt', - search - }, - token, - statusCodeExpected - }) -} - -function advancedVideoChannelSearch (url: string, search: VideoChannelsSearchQuery) { - const path = '/api/v1/search/video-channels' - - return makeGetRequest({ - url, - path, - query: search, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -// --------------------------------------------------------------------------- - -export { - searchVideoChannel, - advancedVideoChannelSearch -} diff --git a/shared/extra-utils/search/video-playlists.ts b/shared/extra-utils/search/video-playlists.ts deleted file mode 100644 index c22831df7..000000000 --- a/shared/extra-utils/search/video-playlists.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { VideoPlaylistsSearchQuery } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { makeGetRequest } from '../requests/requests' - -function searchVideoPlaylists (url: string, search: string, token?: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/search/video-playlists' - - return makeGetRequest({ - url, - path, - query: { - sort: '-createdAt', - search - }, - token, - statusCodeExpected - }) -} - -function advancedVideoPlaylistSearch (url: string, search: VideoPlaylistsSearchQuery) { - const path = '/api/v1/search/video-playlists' - - return makeGetRequest({ - url, - path, - query: search, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -// --------------------------------------------------------------------------- - -export { - searchVideoPlaylists, - advancedVideoPlaylistSearch -} diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts deleted file mode 100644 index db6edbd58..000000000 --- a/shared/extra-utils/search/videos.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import * as request from 'supertest' -import { VideosSearchQuery } from '../../models/search' -import { immutableAssign } from '../miscs/miscs' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function searchVideo (url: string, search: string, sort = '-publishedAt') { - const path = '/api/v1/search/videos' - - const query = { sort, search: search } - const req = request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - - return req.expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function searchVideoWithToken (url: string, search: string, token: string, query: { nsfw?: boolean } = {}) { - const path = '/api/v1/search/videos' - const req = request(url) - .get(path) - .set('Authorization', 'Bearer ' + token) - .query(immutableAssign(query, { sort: '-publishedAt', search })) - .set('Accept', 'application/json') - - return req.expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function searchVideoWithSort (url: string, search: string, sort: string) { - const path = '/api/v1/search/videos' - - const query = { search, sort } - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function advancedVideosSearch (url: string, options: VideosSearchQuery) { - const path = '/api/v1/search/videos' - - return request(url) - .get(path) - .query(options) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -// --------------------------------------------------------------------------- - -export { - searchVideo, - advancedVideosSearch, - searchVideoWithToken, - searchVideoWithSort -} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 70be96cf6..8ccf790fc 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -15,6 +15,7 @@ import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../mi import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' +import { SearchCommand } from '../search' interface ServerInfo { app: ChildProcess @@ -75,6 +76,7 @@ interface ServerInfo { logsCommand?: LogsCommand abusesCommand?: AbusesCommand overviewsCommand?: OverviewsCommand + searchCommand?: SearchCommand } function parallelTests () { @@ -287,6 +289,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.logsCommand = new LogsCommand(server) server.abusesCommand = new AbusesCommand(server) server.overviewsCommand = new OverviewsCommand(server) + server.searchCommand = new SearchCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 469ea4d63..a45c0402a 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -10,7 +10,7 @@ import validator from 'validator' import { getLowercaseExtension } from '@server/helpers/core-utils' import { buildUUID } from '@server/helpers/uuid' import { HttpStatusCode } from '@shared/core-utils' -import { VideosCommonQuery } from '@shared/models' +import { BooleanBothQuery, VideosCommonQuery } from '@shared/models' import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' import { VideoDetails, VideoPrivacy } from '../../models/videos' import { @@ -159,7 +159,7 @@ function getVideosList (url: string) { .expect('Content-Type', /json/) } -function getVideosListWithToken (url: string, token: string, query: { nsfw?: boolean } = {}) { +function getVideosListWithToken (url: string, token: string, query: { nsfw?: BooleanBothQuery } = {}) { const path = '/api/v1/videos' return request(url) @@ -219,7 +219,7 @@ function getAccountVideos ( count: number, sort?: string, query: { - nsfw?: boolean + nsfw?: BooleanBothQuery search?: string } = {} ) { @@ -245,7 +245,7 @@ function getVideoChannelVideos ( start: number, count: number, sort?: string, - query: { nsfw?: boolean } = {} + query: { nsfw?: BooleanBothQuery } = {} ) { const path = '/api/v1/video-channels/' + videoChannelName + '/videos' -- cgit v1.2.3 From 2d1ad5b96063d1e430ca99128a15e2e56cb614e0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 15:33:39 +0200 Subject: Move AP request in requests file --- shared/extra-utils/index.ts | 1 - shared/extra-utils/requests/requests.ts | 16 +++++++++++++--- shared/extra-utils/server/activitypub.ts | 15 --------------- 3 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 shared/extra-utils/server/activitypub.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 067e6fb65..9e0f6374a 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -13,7 +13,6 @@ export * from './requests/requests' export * from './search' -export * from './server/activitypub' export * from './server/clients' export * from './server/config' export * from './server/debug' diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 8c26a3699..3fbaa31d6 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ -import * as request from 'supertest' -import { buildAbsoluteFixturePath, root } from '../miscs/miscs' import { isAbsolute, join } from 'path' -import { URL } from 'url' import { decode } from 'querystring' +import * as request from 'supertest' +import { URL } from 'url' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { buildAbsoluteFixturePath, root } from '../miscs/miscs' function get4KFileUrl () { return 'https://download.cpy.re/peertube/4k_file.txt' @@ -154,6 +154,15 @@ function makeHTMLRequest (url: string, path: string) { .expect(HttpStatusCode.OK_200) } +function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) { + return makeGetRequest({ + url, + path, + statusCodeExpected: expectedStatus, + accept: 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8' + }) +} + function updateImageRequest (options: { url: string path: string @@ -202,6 +211,7 @@ export { makePutBodyRequest, makeDeleteRequest, makeRawRequest, + makeActivityPubGetRequest, unwrapBody, unwrapText, updateImageRequest diff --git a/shared/extra-utils/server/activitypub.ts b/shared/extra-utils/server/activitypub.ts deleted file mode 100644 index cf967ed7d..000000000 --- a/shared/extra-utils/server/activitypub.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as request from 'supertest' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) { - return request(url) - .get(path) - .set('Accept', 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8') - .expect(expectedStatus) -} - -// --------------------------------------------------------------------------- - -export { - makeActivityPubGetRequest -} -- cgit v1.2.3 From a9c58393d36d221197b48884a1960e6126ab31d7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 15:53:25 +0200 Subject: Introduce contact form command --- shared/extra-utils/server/contact-form-command.ts | 31 +++++++++++++++++++++++ shared/extra-utils/server/contact-form.ts | 31 ----------------------- shared/extra-utils/server/index.ts | 1 + shared/extra-utils/server/servers.ts | 3 +++ 4 files changed, 35 insertions(+), 31 deletions(-) create mode 100644 shared/extra-utils/server/contact-form-command.ts delete mode 100644 shared/extra-utils/server/contact-form.ts create mode 100644 shared/extra-utils/server/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/contact-form-command.ts b/shared/extra-utils/server/contact-form-command.ts new file mode 100644 index 000000000..943e5ccbb --- /dev/null +++ b/shared/extra-utils/server/contact-form-command.ts @@ -0,0 +1,31 @@ +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { ContactForm } from '../../models/server' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ContactFormCommand extends AbstractCommand { + + send (options: OverrideCommandOptions & { + fromEmail: string + fromName: string + subject: string + body: string + }) { + const path = '/api/v1/server/contact' + + const body: ContactForm = { + fromEmail: options.fromEmail, + fromName: options.fromName, + subject: options.subject, + body: options.body + } + + return this.postBodyRequest({ + ...options, + + path, + token: null, + fields: body, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts deleted file mode 100644 index 6c9232cc6..000000000 --- a/shared/extra-utils/server/contact-form.ts +++ /dev/null @@ -1,31 +0,0 @@ -import * as request from 'supertest' -import { ContactForm } from '../../models/server' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function sendContactForm (options: { - url: string - fromEmail: string - fromName: string - subject: string - body: string - expectedStatus?: number -}) { - const path = '/api/v1/server/contact' - - const body: ContactForm = { - fromEmail: options.fromEmail, - fromName: options.fromName, - subject: options.subject, - body: options.body - } - return request(options.url) - .post(path) - .send(body) - .expect(options.expectedStatus || HttpStatusCode.NO_CONTENT_204) -} - -// --------------------------------------------------------------------------- - -export { - sendContactForm -} diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts new file mode 100644 index 000000000..4121c8828 --- /dev/null +++ b/shared/extra-utils/server/index.ts @@ -0,0 +1 @@ +export * from './contact-form-command' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 8ccf790fc..b58639ba6 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -16,6 +16,7 @@ import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' +import { ContactFormCommand } from './contact-form-command' interface ServerInfo { app: ChildProcess @@ -77,6 +78,7 @@ interface ServerInfo { abusesCommand?: AbusesCommand overviewsCommand?: OverviewsCommand searchCommand?: SearchCommand + contactFormCommand?: ContactFormCommand } function parallelTests () { @@ -290,6 +292,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.abusesCommand = new AbusesCommand(server) server.overviewsCommand = new OverviewsCommand(server) server.searchCommand = new SearchCommand(server) + server.contactFormCommand = new ContactFormCommand(server) res(server) }) -- cgit v1.2.3 From 883a9019085ff9013079d6b1539b86f2f519175a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 6 Jul 2021 16:02:11 +0200 Subject: Introduce debug command --- shared/extra-utils/index.ts | 1 - shared/extra-utils/server/debug-command.ts | 32 +++++++++++++++++++++++++++++ shared/extra-utils/server/debug.ts | 33 ------------------------------ shared/extra-utils/server/index.ts | 1 + shared/extra-utils/server/jobs.ts | 9 ++++---- shared/extra-utils/server/servers.ts | 3 +++ 6 files changed, 40 insertions(+), 39 deletions(-) create mode 100644 shared/extra-utils/server/debug-command.ts delete mode 100644 shared/extra-utils/server/debug.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 9e0f6374a..7b5835e47 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -15,7 +15,6 @@ export * from './search' export * from './server/clients' export * from './server/config' -export * from './server/debug' export * from './server/follows' export * from './server/jobs' export * from './server/plugins' diff --git a/shared/extra-utils/server/debug-command.ts b/shared/extra-utils/server/debug-command.ts new file mode 100644 index 000000000..eecbb1711 --- /dev/null +++ b/shared/extra-utils/server/debug-command.ts @@ -0,0 +1,32 @@ +import { Debug, SendDebugCommand } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class DebugCommand extends AbstractCommand { + + getDebug (options: OverrideCommandOptions = {}) { + const path = '/api/v1/server/debug' + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + sendCommand (options: OverrideCommandOptions & { + body: SendDebugCommand + }) { + const { body } = options + const path = '/api/v1/server/debug/run-command' + + return this.postBodyRequest({ + ...options, + + path, + fields: body, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/server/debug.ts b/shared/extra-utils/server/debug.ts deleted file mode 100644 index f196812b7..000000000 --- a/shared/extra-utils/server/debug.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { makeGetRequest, makePostBodyRequest } from '../requests/requests' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { SendDebugCommand } from '@shared/models' - -function getDebug (url: string, token: string) { - const path = '/api/v1/server/debug' - - return makeGetRequest({ - url, - path, - token, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function sendDebugCommand (url: string, token: string, body: SendDebugCommand) { - const path = '/api/v1/server/debug/run-command' - - return makePostBodyRequest({ - url, - path, - token, - fields: body, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -// --------------------------------------------------------------------------- - -export { - getDebug, - sendDebugCommand -} diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 4121c8828..f0071ba72 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1 +1,2 @@ export * from './contact-form-command' +export * from './debug-command' diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index 763374e03..a3683913a 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -1,7 +1,7 @@ import * as request from 'supertest' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { getDebug, makeGetRequest } from '../../../shared/extra-utils' -import { Job, JobState, JobType, ServerDebug } from '../../models' +import { makeGetRequest } from '../../../shared/extra-utils' +import { Job, JobState, JobType } from '../../models' import { wait } from '../miscs/miscs' import { ServerInfo } from './servers' @@ -90,9 +90,8 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { tasks.push(p) } - const p = getDebug(server.url, server.accessToken) - .then(res => res.body) - .then((obj: ServerDebug) => { + const p = server.debugCommand.getDebug() + .then(obj => { if (obj.activityPubMessagesWaiting !== 0) { pendingRequests = true } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index b58639ba6..30e712ab8 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -17,6 +17,7 @@ import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { ContactFormCommand } from './contact-form-command' +import { DebugCommand } from './debug-command' interface ServerInfo { app: ChildProcess @@ -79,6 +80,7 @@ interface ServerInfo { overviewsCommand?: OverviewsCommand searchCommand?: SearchCommand contactFormCommand?: ContactFormCommand + debugCommand?: DebugCommand } function parallelTests () { @@ -293,6 +295,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.overviewsCommand = new OverviewsCommand(server) server.searchCommand = new SearchCommand(server) server.contactFormCommand = new ContactFormCommand(server) + server.debugCommand = new DebugCommand(server) res(server) }) -- cgit v1.2.3 From c3d29f694bf8c910f917be655626d0f80871124f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 09:16:40 +0200 Subject: Introduce follows command --- shared/extra-utils/index.ts | 5 +- shared/extra-utils/server/follows-command.ts | 124 +++++++++++++++++++++++++ shared/extra-utils/server/follows.ts | 131 +-------------------------- shared/extra-utils/server/index.ts | 2 + shared/extra-utils/server/servers.ts | 3 + 5 files changed, 135 insertions(+), 130 deletions(-) create mode 100644 shared/extra-utils/server/follows-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 7b5835e47..48431ed83 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -7,15 +7,14 @@ export * from './miscs' export * from './mock-servers' export * from './moderation' export * from './overviews' +export * from './search' +export * from './server' export * from './requests/check-api-params' export * from './requests/requests' -export * from './search' - export * from './server/clients' export * from './server/config' -export * from './server/follows' export * from './server/jobs' export * from './server/plugins' export * from './server/servers' diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts new file mode 100644 index 000000000..aba7bce82 --- /dev/null +++ b/shared/extra-utils/server/follows-command.ts @@ -0,0 +1,124 @@ +import { pick } from 'lodash' +import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' +import { ServerInfo } from './servers' + +export class FollowsCommand extends AbstractCommand { + + getFollowers (options: OverrideCommandOptions & { + start: number + count: number + sort: string + search?: string + actorType?: ActivityPubActorType + state?: FollowState + }) { + const path = '/api/v1/server/followers' + + const toPick = [ 'start', 'count', 'sort', 'search', 'state', 'actorType' ] + const query = pick(options, toPick) + + return this.getRequestBody>({ + ...options, + + token: null, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getFollowings (options: OverrideCommandOptions & { + start: number + count: number + sort: string + search?: string + actorType?: ActivityPubActorType + state?: FollowState + }) { + const path = '/api/v1/server/following' + + const toPick = [ 'start', 'count', 'sort', 'search', 'state', 'actorType' ] + const query = pick(options, toPick) + + return this.getRequestBody>({ + ...options, + + token: null, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + follow (options: OverrideCommandOptions & { + targets: string[] + }) { + const path = '/api/v1/server/following' + + const hosts = options.targets.map(f => f.replace(/^http:\/\//, '')) + + return this.postBodyRequest({ + ...options, + + path, + fields: { hosts }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async unfollow (options: OverrideCommandOptions & { + target: ServerInfo + }) { + const path = '/api/v1/server/following/' + options.target.host + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + acceptFollower (options: OverrideCommandOptions & { + follower: string + }) { + const path = '/api/v1/server/followers/' + options.follower + '/accept' + + return this.postBodyRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + rejectFollower (options: OverrideCommandOptions & { + follower: string + }) { + const path = '/api/v1/server/followers/' + options.follower + '/reject' + + return this.postBodyRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + removeFollower (options: OverrideCommandOptions & { + follower: ServerInfo + }) { + const path = '/api/v1/server/followers/peertube@' + options.follower.host + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts index 6aae4a31d..c23cebd81 100644 --- a/shared/extra-utils/server/follows.ts +++ b/shared/extra-utils/server/follows.ts @@ -1,126 +1,10 @@ -import * as request from 'supertest' -import { ServerInfo } from './servers' import { waitJobs } from './jobs' -import { makePostBodyRequest } from '../requests/requests' -import { ActivityPubActorType, FollowState } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getFollowersListPaginationAndSort (options: { - url: string - start: number - count: number - sort: string - search?: string - actorType?: ActivityPubActorType - state?: FollowState -}) { - const { url, start, count, sort, search, state, actorType } = options - const path = '/api/v1/server/followers' - - const query = { - start, - count, - sort, - search, - state, - actorType - } - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function acceptFollower (url: string, token: string, follower: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/server/followers/' + follower + '/accept' - - return makePostBodyRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function rejectFollower (url: string, token: string, follower: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/server/followers/' + follower + '/reject' - - return makePostBodyRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function getFollowingListPaginationAndSort (options: { - url: string - start: number - count: number - sort: string - search?: string - actorType?: ActivityPubActorType - state?: FollowState -}) { - const { url, start, count, sort, search, state, actorType } = options - const path = '/api/v1/server/following' - - const query = { - start, - count, - sort, - search, - state, - actorType - } - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function follow (follower: string, following: string[], accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/server/following' - - const followingHosts = following.map(f => f.replace(/^http:\/\//, '')) - return request(follower) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .send({ hosts: followingHosts }) - .expect(expectedStatus) -} - -async function unfollow (url: string, accessToken: string, target: ServerInfo, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/server/following/' + target.host - - return request(url) - .delete(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(expectedStatus) -} - -function removeFollower (url: string, accessToken: string, follower: ServerInfo, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/server/followers/peertube@' + follower.host - - return request(url) - .delete(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(expectedStatus) -} +import { ServerInfo } from './servers' async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { await Promise.all([ - follow(server1.url, [ server2.url ], server1.accessToken), - follow(server2.url, [ server1.url ], server2.accessToken) + server1.followsCommand.follow({ targets: [ server2.url ] }), + server2.followsCommand.follow({ targets: [ server1.url ] }) ]) // Wait request propagation @@ -132,12 +16,5 @@ async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { // --------------------------------------------------------------------------- export { - getFollowersListPaginationAndSort, - getFollowingListPaginationAndSort, - unfollow, - removeFollower, - follow, - doubleFollow, - acceptFollower, - rejectFollower + doubleFollow } diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index f0071ba72..258084623 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1,2 +1,4 @@ export * from './contact-form-command' export * from './debug-command' +export * from './follows-command' +export * from './follows' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 30e712ab8..7ac80cea0 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,6 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' +import { FollowsCommand } from './follows-command' interface ServerInfo { app: ChildProcess @@ -81,6 +82,7 @@ interface ServerInfo { searchCommand?: SearchCommand contactFormCommand?: ContactFormCommand debugCommand?: DebugCommand + followsCommand?: FollowsCommand } function parallelTests () { @@ -296,6 +298,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.searchCommand = new SearchCommand(server) server.contactFormCommand = new ContactFormCommand(server) server.debugCommand = new DebugCommand(server) + server.followsCommand = new FollowsCommand(server) res(server) }) -- cgit v1.2.3 From 9c6327f803aaf4200672f1fc40b2f43786daca47 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 09:34:56 +0200 Subject: Introduce jobs command --- shared/extra-utils/index.ts | 1 - shared/extra-utils/server/index.ts | 2 + shared/extra-utils/server/jobs-command.ts | 35 ++++++++++++++++ shared/extra-utils/server/jobs.ts | 67 ++++--------------------------- shared/extra-utils/server/servers.ts | 3 ++ 5 files changed, 47 insertions(+), 61 deletions(-) create mode 100644 shared/extra-utils/server/jobs-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 48431ed83..652779eea 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -15,7 +15,6 @@ export * from './requests/requests' export * from './server/clients' export * from './server/config' -export * from './server/jobs' export * from './server/plugins' export * from './server/servers' diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 258084623..b5b6b2116 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -2,3 +2,5 @@ export * from './contact-form-command' export * from './debug-command' export * from './follows-command' export * from './follows' +export * from './jobs' +export * from './jobs-command' diff --git a/shared/extra-utils/server/jobs-command.ts b/shared/extra-utils/server/jobs-command.ts new file mode 100644 index 000000000..758b4a4af --- /dev/null +++ b/shared/extra-utils/server/jobs-command.ts @@ -0,0 +1,35 @@ +import { pick } from 'lodash' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { Job, JobState, JobType, ResultList } from '../../models' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class JobsCommand extends AbstractCommand { + + getJobsList (options: OverrideCommandOptions & { + state?: JobState + jobType?: JobType + start?: number + count?: number + sort?: string + } = {}) { + const path = this.buildJobsUrl(options.state) + + const query = pick(options, [ 'start', 'count', 'sort', 'jobType' ]) + + return this.getRequestBody>({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + private buildJobsUrl (state?: JobState) { + let path = '/api/v1/jobs' + + if (state) path += '/' + state + + return path + } +} diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index a3683913a..b4b3d52e7 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -1,57 +1,8 @@ -import * as request from 'supertest' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { makeGetRequest } from '../../../shared/extra-utils' -import { Job, JobState, JobType } from '../../models' + +import { JobState } from '../../models' import { wait } from '../miscs/miscs' import { ServerInfo } from './servers' -function buildJobsUrl (state?: JobState) { - let path = '/api/v1/jobs' - - if (state) path += '/' + state - - return path -} - -function getJobsList (url: string, accessToken: string, state?: JobState) { - const path = buildJobsUrl(state) - - return request(url) - .get(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getJobsListPaginationAndSort (options: { - url: string - accessToken: string - start: number - count: number - sort: string - state?: JobState - jobType?: JobType -}) { - const { url, accessToken, state, start, count, sort, jobType } = options - const path = buildJobsUrl(state) - - const query = { - start, - count, - sort, - jobType - } - - return makeGetRequest({ - url, - path, - token: accessToken, - statusCodeExpected: HttpStatusCode.OK_200, - query - }) -} - async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) @@ -72,15 +23,13 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { // Check if each server has pending request for (const server of servers) { for (const state of states) { - const p = getJobsListPaginationAndSort({ - url: server.url, - accessToken: server.accessToken, - state: state, + const p = server.jobsCommand.getJobsList({ + state, start: 0, count: 10, sort: '-createdAt' - }).then(res => res.body.data) - .then((jobs: Job[]) => jobs.filter(j => !repeatableJobs.includes(j.type))) + }).then(body => body.data) + .then(jobs => jobs.filter(j => !repeatableJobs.includes(j.type))) .then(jobs => { if (jobs.length !== 0) { pendingRequests = true @@ -122,7 +71,5 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { // --------------------------------------------------------------------------- export { - getJobsList, - waitJobs, - getJobsListPaginationAndSort + waitJobs } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 7ac80cea0..5511ce0b0 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -19,6 +19,7 @@ import { SearchCommand } from '../search' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' import { FollowsCommand } from './follows-command' +import { JobsCommand } from './jobs-command' interface ServerInfo { app: ChildProcess @@ -83,6 +84,7 @@ interface ServerInfo { contactFormCommand?: ContactFormCommand debugCommand?: DebugCommand followsCommand?: FollowsCommand + jobsCommand?: JobsCommand } function parallelTests () { @@ -299,6 +301,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.contactFormCommand = new ContactFormCommand(server) server.debugCommand = new DebugCommand(server) server.followsCommand = new FollowsCommand(server) + server.jobsCommand = new JobsCommand(server) res(server) }) -- cgit v1.2.3 From ae2abfd3aed3e75d39a316b49b914d187faa7475 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 10:33:49 +0200 Subject: Introduce plugins command --- shared/extra-utils/index.ts | 1 - shared/extra-utils/server/index.ts | 2 + shared/extra-utils/server/plugins-command.ts | 245 +++++++++++++++++++++ shared/extra-utils/server/plugins.ts | 297 +------------------------- shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/shared/abstract-command.ts | 26 +-- 6 files changed, 268 insertions(+), 306 deletions(-) create mode 100644 shared/extra-utils/server/plugins-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 652779eea..cf6418249 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -15,7 +15,6 @@ export * from './requests/requests' export * from './server/clients' export * from './server/config' -export * from './server/plugins' export * from './server/servers' export * from './users/accounts' diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index b5b6b2116..e602fec7e 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -4,3 +4,5 @@ export * from './follows-command' export * from './follows' export * from './jobs' export * from './jobs-command' +export * from './plugins-command' +export * from './plugins' diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts new file mode 100644 index 000000000..f06e58a22 --- /dev/null +++ b/shared/extra-utils/server/plugins-command.ts @@ -0,0 +1,245 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { readJSON, writeJSON } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { + PeerTubePlugin, + PeerTubePluginIndex, + PeertubePluginIndexList, + PluginPackageJson, + PluginTranslation, + PluginType, + PublicServerSetting, + RegisteredServerSettings, + ResultList +} from '@shared/models' +import { buildServerDirectory } from '../miscs' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class PluginsCommand extends AbstractCommand { + + static getPluginTestPath (suffix = '') { + return join(root(), 'server', 'tests', 'fixtures', 'peertube-plugin-test' + suffix) + } + + list (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + pluginType?: PluginType + uninstalled?: boolean + }) { + const { start, count, sort, pluginType, uninstalled } = options + const path = '/api/v1/plugins' + + return this.getRequestBody>({ + ...options, + + path, + query: { + start, + count, + sort, + pluginType, + uninstalled + }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listAvailable (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + pluginType?: PluginType + currentPeerTubeEngine?: string + search?: string + expectedStatus?: HttpStatusCode + }) { + const { start, count, sort, pluginType, search, currentPeerTubeEngine } = options + const path = '/api/v1/plugins/available' + + const query: PeertubePluginIndexList = { + start, + count, + sort, + pluginType, + currentPeerTubeEngine, + search + } + + return this.getRequestBody>({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + get (options: OverrideCommandOptions & { + npmName: string + }) { + const path = '/api/v1/plugins/' + options.npmName + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateSettings (options: OverrideCommandOptions & { + npmName: string + settings: any + }) { + const { npmName, settings } = options + const path = '/api/v1/plugins/' + npmName + '/settings' + + return this.putBodyRequest({ + ...options, + + path, + fields: { settings }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + getRegisteredSettings (options: OverrideCommandOptions & { + npmName: string + }) { + const path = '/api/v1/plugins/' + options.npmName + '/registered-settings' + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getPublicSettings (options: OverrideCommandOptions & { + npmName: string + }) { + const { npmName } = options + const path = '/api/v1/plugins/' + npmName + '/public-settings' + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getTranslations (options: OverrideCommandOptions & { + locale: string + }) { + const { locale } = options + const path = '/plugins/translations/' + locale + '.json' + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + install (options: OverrideCommandOptions & { + path?: string + npmName?: string + }) { + const { npmName, path } = options + const apiPath = '/api/v1/plugins/install' + + return this.postBodyRequest({ + ...options, + + path: apiPath, + fields: { npmName, path }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + update (options: OverrideCommandOptions & { + path?: string + npmName?: string + }) { + const { npmName, path } = options + const apiPath = '/api/v1/plugins/update' + + return this.postBodyRequest({ + ...options, + + path: apiPath, + fields: { npmName, path }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + uninstall (options: OverrideCommandOptions & { + npmName: string + }) { + const { npmName } = options + const apiPath = '/api/v1/plugins/uninstall' + + return this.postBodyRequest({ + ...options, + + path: apiPath, + fields: { npmName }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + getCSS (options: OverrideCommandOptions = {}) { + const path = '/plugins/global.css' + + return this.getRequestText({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getExternalAuth (options: OverrideCommandOptions & { + npmName: string + npmVersion: string + authName: string + query?: any + }) { + const { npmName, npmVersion, authName, query } = options + + const path = '/plugins/' + npmName + '/' + npmVersion + '/auth/' + authName + + return this.getRequest({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200, + redirects: 0 + }) + } + + updatePackageJSON (npmName: string, json: any) { + const path = this.getPackageJSONPath(npmName) + + return writeJSON(path, json) + } + + getPackageJSON (npmName: string): Promise { + const path = this.getPackageJSONPath(npmName) + + return readJSON(path) + } + + private getPackageJSONPath (npmName: string) { + return buildServerDirectory(this.server, join('plugins', 'node_modules', npmName, 'package.json')) + } +} diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts index d53e5b382..1084ea4f4 100644 --- a/shared/extra-utils/server/plugins.ts +++ b/shared/extra-utils/server/plugins.ts @@ -1,307 +1,18 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ import { expect } from 'chai' -import { readJSON, writeJSON } from 'fs-extra' -import { join } from 'path' -import { RegisteredServerSettings } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { PeertubePluginIndexList } from '../../models/plugins/plugin-index/peertube-plugin-index-list.model' -import { PluginType } from '../../models/plugins/plugin.type' -import { buildServerDirectory, root } from '../miscs/miscs' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' -import { ServerInfo } from './servers' - -function listPlugins (parameters: { - url: string - accessToken: string - start?: number - count?: number - sort?: string - pluginType?: PluginType - uninstalled?: boolean - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/plugins' - - return makeGetRequest({ - url, - path, - token: accessToken, - query: { - start, - count, - sort, - pluginType, - uninstalled - }, - statusCodeExpected: expectedStatus - }) -} - -function listAvailablePlugins (parameters: { - url: string - accessToken: string - start?: number - count?: number - sort?: string - pluginType?: PluginType - currentPeerTubeEngine?: string - search?: string - expectedStatus?: HttpStatusCode -}) { - const { - url, - accessToken, - start, - count, - sort, - pluginType, - search, - currentPeerTubeEngine, - expectedStatus = HttpStatusCode.OK_200 - } = parameters - const path = '/api/v1/plugins/available' - - const query: PeertubePluginIndexList = { - start, - count, - sort, - pluginType, - currentPeerTubeEngine, - search - } - - return makeGetRequest({ - url, - path, - token: accessToken, - query, - statusCodeExpected: expectedStatus - }) -} - -function getPlugin (parameters: { - url: string - accessToken: string - npmName: string - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, expectedStatus = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/plugins/' + npmName - - return makeGetRequest({ - url, - path, - token: accessToken, - statusCodeExpected: expectedStatus - }) -} - -function updatePluginSettings (parameters: { - url: string - accessToken: string - npmName: string - settings: any - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, settings, expectedStatus = HttpStatusCode.NO_CONTENT_204 } = parameters - const path = '/api/v1/plugins/' + npmName + '/settings' - - return makePutBodyRequest({ - url, - path, - token: accessToken, - fields: { settings }, - statusCodeExpected: expectedStatus - }) -} - -function getPluginRegisteredSettings (parameters: { - url: string - accessToken: string - npmName: string - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, expectedStatus = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/plugins/' + npmName + '/registered-settings' - - return makeGetRequest({ - url, - path, - token: accessToken, - statusCodeExpected: expectedStatus - }) -} +import { ServerInfo } from '../server/servers' async function testHelloWorldRegisteredSettings (server: ServerInfo) { - const res = await getPluginRegisteredSettings({ - url: server.url, - accessToken: server.accessToken, - npmName: 'peertube-plugin-hello-world' - }) - - const registeredSettings = (res.body as RegisteredServerSettings).registeredSettings + const body = await server.pluginsCommand.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) + const registeredSettings = body.registeredSettings expect(registeredSettings).to.have.length.at.least(1) const adminNameSettings = registeredSettings.find(s => s.name === 'admin-name') expect(adminNameSettings).to.not.be.undefined } -function getPublicSettings (parameters: { - url: string - npmName: string - expectedStatus?: HttpStatusCode -}) { - const { url, npmName, expectedStatus = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/plugins/' + npmName + '/public-settings' - - return makeGetRequest({ - url, - path, - statusCodeExpected: expectedStatus - }) -} - -function getPluginTranslations (parameters: { - url: string - locale: string - expectedStatus?: HttpStatusCode -}) { - const { url, locale, expectedStatus = HttpStatusCode.OK_200 } = parameters - const path = '/plugins/translations/' + locale + '.json' - - return makeGetRequest({ - url, - path, - statusCodeExpected: expectedStatus - }) -} - -function installPlugin (parameters: { - url: string - accessToken: string - path?: string - npmName?: string - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, path, expectedStatus = HttpStatusCode.OK_200 } = parameters - const apiPath = '/api/v1/plugins/install' - - return makePostBodyRequest({ - url, - path: apiPath, - token: accessToken, - fields: { npmName, path }, - statusCodeExpected: expectedStatus - }) -} - -function updatePlugin (parameters: { - url: string - accessToken: string - path?: string - npmName?: string - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, path, expectedStatus = HttpStatusCode.OK_200 } = parameters - const apiPath = '/api/v1/plugins/update' - - return makePostBodyRequest({ - url, - path: apiPath, - token: accessToken, - fields: { npmName, path }, - statusCodeExpected: expectedStatus - }) -} - -function uninstallPlugin (parameters: { - url: string - accessToken: string - npmName: string - expectedStatus?: HttpStatusCode -}) { - const { url, accessToken, npmName, expectedStatus = HttpStatusCode.NO_CONTENT_204 } = parameters - const apiPath = '/api/v1/plugins/uninstall' - - return makePostBodyRequest({ - url, - path: apiPath, - token: accessToken, - fields: { npmName }, - statusCodeExpected: expectedStatus - }) -} - -function getPluginsCSS (url: string) { - const path = '/plugins/global.css' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getPackageJSONPath (server: ServerInfo, npmName: string) { - return buildServerDirectory(server, join('plugins', 'node_modules', npmName, 'package.json')) -} - -function updatePluginPackageJSON (server: ServerInfo, npmName: string, json: any) { - const path = getPackageJSONPath(server, npmName) - - return writeJSON(path, json) -} - -function getPluginPackageJSON (server: ServerInfo, npmName: string) { - const path = getPackageJSONPath(server, npmName) - - return readJSON(path) -} - -function getPluginTestPath (suffix = '') { - return join(root(), 'server', 'tests', 'fixtures', 'peertube-plugin-test' + suffix) -} - -function getExternalAuth (options: { - url: string - npmName: string - npmVersion: string - authName: string - query?: any - statusCodeExpected?: HttpStatusCode -}) { - const { url, npmName, npmVersion, authName, statusCodeExpected, query } = options - - const path = '/plugins/' + npmName + '/' + npmVersion + '/auth/' + authName - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected: statusCodeExpected || HttpStatusCode.OK_200, - redirects: 0 - }) -} - export { - listPlugins, - listAvailablePlugins, - installPlugin, - getPluginTranslations, - getPluginsCSS, - updatePlugin, - getPlugin, - uninstallPlugin, - testHelloWorldRegisteredSettings, - updatePluginSettings, - getPluginRegisteredSettings, - getPackageJSONPath, - updatePluginPackageJSON, - getPluginPackageJSON, - getPluginTestPath, - getPublicSettings, - getExternalAuth + testHelloWorldRegisteredSettings } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 5511ce0b0..79d6b7b1a 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -20,6 +20,7 @@ import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' import { FollowsCommand } from './follows-command' import { JobsCommand } from './jobs-command' +import { PluginsCommand } from './plugins-command' interface ServerInfo { app: ChildProcess @@ -85,6 +86,7 @@ interface ServerInfo { debugCommand?: DebugCommand followsCommand?: FollowsCommand jobsCommand?: JobsCommand + pluginsCommand?: PluginsCommand } function parallelTests () { @@ -302,6 +304,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.debugCommand = new DebugCommand(server) server.followsCommand = new FollowsCommand(server) server.jobsCommand = new JobsCommand(server) + server.pluginsCommand = new PluginsCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 3815fab0e..dd4598a91 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -16,6 +16,7 @@ interface GetCommandOptions extends CommonCommandOptions { query?: { [ id: string ]: any } contentType?: string accept?: string + redirects?: number } abstract class AbstractCommand { @@ -44,6 +45,19 @@ abstract class AbstractCommand { return unwrapText(this.getRequest(options)) } + protected getRequest (options: GetCommandOptions) { + const { redirects, query, contentType, accept } = options + + return makeGetRequest({ + ...this.buildCommonRequestOptions(options), + + redirects, + query, + contentType, + accept + }) + } + protected deleteRequest (options: CommonCommandOptions) { return makeDeleteRequest(this.buildCommonRequestOptions(options)) } @@ -85,18 +99,6 @@ abstract class AbstractCommand { statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } } - - private getRequest (options: GetCommandOptions) { - const { query, contentType, accept } = options - - return makeGetRequest({ - ...this.buildCommonRequestOptions(options), - - query, - contentType, - accept - }) - } } export { -- cgit v1.2.3 From dab047092b51b453f175069573d8865fb17acdfc Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 10:56:45 +0200 Subject: Introduce redundancy command --- shared/extra-utils/server/index.ts | 1 + shared/extra-utils/server/redundancy-command.ts | 77 ++++++++++++++++++++++ shared/extra-utils/server/redundancy.ts | 88 ------------------------- shared/extra-utils/server/servers.ts | 3 + 4 files changed, 81 insertions(+), 88 deletions(-) create mode 100644 shared/extra-utils/server/redundancy-command.ts delete mode 100644 shared/extra-utils/server/redundancy.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index e602fec7e..3ee70f0cf 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -6,3 +6,4 @@ export * from './jobs' export * from './jobs-command' export * from './plugins-command' export * from './plugins' +export * from './redundancy-command' diff --git a/shared/extra-utils/server/redundancy-command.ts b/shared/extra-utils/server/redundancy-command.ts new file mode 100644 index 000000000..d717d35f8 --- /dev/null +++ b/shared/extra-utils/server/redundancy-command.ts @@ -0,0 +1,77 @@ +import { ResultList, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class RedundancyCommand extends AbstractCommand { + + updateRedundancy (options: OverrideCommandOptions & { + host: string + redundancyAllowed: boolean + }) { + const { host, redundancyAllowed } = options + const path = '/api/v1/server/redundancy/' + host + + return this.putBodyRequest({ + ...options, + + path, + fields: { redundancyAllowed }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + listVideos (options: OverrideCommandOptions & { + target: VideoRedundanciesTarget + start?: number + count?: number + sort?: string + }) { + const path = '/api/v1/server/redundancy/videos' + + const { target, start, count, sort } = options + + return this.getRequestBody>({ + ...options, + + path, + + query: { + start: start ?? 0, + count: count ?? 5, + sort: sort ?? 'name', + target + }, + + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + addVideo (options: OverrideCommandOptions & { + videoId: number + }) { + const path = '/api/v1/server/redundancy/videos' + const { videoId } = options + + return this.postBodyRequest({ + ...options, + + path, + fields: { videoId }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + removeVideo (options: OverrideCommandOptions & { + redundancyId: number + }) { + const { redundancyId } = options + const path = '/api/v1/server/redundancy/videos/' + redundancyId + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts deleted file mode 100644 index b83815a37..000000000 --- a/shared/extra-utils/server/redundancy.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' -import { VideoRedundanciesTarget } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function updateRedundancy ( - url: string, - accessToken: string, - host: string, - redundancyAllowed: boolean, - expectedStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/server/redundancy/' + host - - return makePutBodyRequest({ - url, - path, - token: accessToken, - fields: { redundancyAllowed }, - statusCodeExpected: expectedStatus - }) -} - -function listVideoRedundancies (options: { - url: string - accessToken: string - target: VideoRedundanciesTarget - start?: number - count?: number - sort?: string - statusCodeExpected?: HttpStatusCode -}) { - const path = '/api/v1/server/redundancy/videos' - - const { url, accessToken, target, statusCodeExpected, start, count, sort } = options - - return makeGetRequest({ - url, - token: accessToken, - path, - query: { - start: start ?? 0, - count: count ?? 5, - sort: sort ?? 'name', - target - }, - statusCodeExpected: statusCodeExpected || HttpStatusCode.OK_200 - }) -} - -function addVideoRedundancy (options: { - url: string - accessToken: string - videoId: number -}) { - const path = '/api/v1/server/redundancy/videos' - const { url, accessToken, videoId } = options - - return makePostBodyRequest({ - url, - token: accessToken, - path, - fields: { videoId }, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -function removeVideoRedundancy (options: { - url: string - accessToken: string - redundancyId: number -}) { - const { url, accessToken, redundancyId } = options - const path = '/api/v1/server/redundancy/videos/' + redundancyId - - return makeDeleteRequest({ - url, - token: accessToken, - path, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -export { - updateRedundancy, - listVideoRedundancies, - addVideoRedundancy, - removeVideoRedundancy -} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 79d6b7b1a..eaf39ecea 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -21,6 +21,7 @@ import { DebugCommand } from './debug-command' import { FollowsCommand } from './follows-command' import { JobsCommand } from './jobs-command' import { PluginsCommand } from './plugins-command' +import { RedundancyCommand } from './redundancy-command' interface ServerInfo { app: ChildProcess @@ -87,6 +88,7 @@ interface ServerInfo { followsCommand?: FollowsCommand jobsCommand?: JobsCommand pluginsCommand?: PluginsCommand + redundancyCommand?: RedundancyCommand } function parallelTests () { @@ -305,6 +307,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.followsCommand = new FollowsCommand(server) server.jobsCommand = new JobsCommand(server) server.pluginsCommand = new PluginsCommand(server) + server.redundancyCommand = new RedundancyCommand(server) res(server) }) -- cgit v1.2.3 From bc8090411ddaa8d742ce4de3c83f9dba7bc18e2a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 11:07:12 +0200 Subject: Introduce stats command --- shared/extra-utils/index.ts | 4 ---- shared/extra-utils/server/index.ts | 3 +++ shared/extra-utils/server/servers.ts | 3 +++ shared/extra-utils/server/stats-command.ts | 25 +++++++++++++++++++++++++ shared/extra-utils/server/stats.ts | 23 ----------------------- 5 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 shared/extra-utils/server/stats-command.ts delete mode 100644 shared/extra-utils/server/stats.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index cf6418249..f69d7241e 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -13,10 +13,6 @@ export * from './server' export * from './requests/check-api-params' export * from './requests/requests' -export * from './server/clients' -export * from './server/config' -export * from './server/servers' - export * from './users/accounts' export * from './users/blocklist' export * from './users/login' diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 3ee70f0cf..d37f46321 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1,3 +1,4 @@ +export * from './config' export * from './contact-form-command' export * from './debug-command' export * from './follows-command' @@ -7,3 +8,5 @@ export * from './jobs-command' export * from './plugins-command' export * from './plugins' export * from './redundancy-command' +export * from './servers' +export * from './stats-command' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index eaf39ecea..4603cf62e 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -22,6 +22,7 @@ import { FollowsCommand } from './follows-command' import { JobsCommand } from './jobs-command' import { PluginsCommand } from './plugins-command' import { RedundancyCommand } from './redundancy-command' +import { StatsCommand } from './stats-command' interface ServerInfo { app: ChildProcess @@ -89,6 +90,7 @@ interface ServerInfo { jobsCommand?: JobsCommand pluginsCommand?: PluginsCommand redundancyCommand?: RedundancyCommand + statsCommand?: StatsCommand } function parallelTests () { @@ -308,6 +310,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.jobsCommand = new JobsCommand(server) server.pluginsCommand = new PluginsCommand(server) server.redundancyCommand = new RedundancyCommand(server) + server.statsCommand = new StatsCommand(server) res(server) }) diff --git a/shared/extra-utils/server/stats-command.ts b/shared/extra-utils/server/stats-command.ts new file mode 100644 index 000000000..b51d9ceef --- /dev/null +++ b/shared/extra-utils/server/stats-command.ts @@ -0,0 +1,25 @@ +import { ServerStats } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class StatsCommand extends AbstractCommand { + + get (options: OverrideCommandOptions & { + useCache?: boolean // default false + } = {}) { + const { useCache = false } = options + const path = '/api/v1/server/stats' + + const query = { + t: useCache ? undefined : new Date().getTime() + } + + return this.getRequestBody({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/server/stats.ts b/shared/extra-utils/server/stats.ts deleted file mode 100644 index b9dae24e2..000000000 --- a/shared/extra-utils/server/stats.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { makeGetRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getStats (url: string, useCache = false) { - const path = '/api/v1/server/stats' - - const query = { - t: useCache ? undefined : new Date().getTime() - } - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -// --------------------------------------------------------------------------- - -export { - getStats -} -- cgit v1.2.3 From 65e6e2602c0d5521f3a6740f7469bb92830ecb53 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 11:51:09 +0200 Subject: Introduce config command --- shared/extra-utils/server/config-command.ts | 260 ++++++++++++++++++++++++++++ shared/extra-utils/server/config.ts | 260 ---------------------------- shared/extra-utils/server/index.ts | 2 +- shared/extra-utils/server/servers.ts | 3 + 4 files changed, 264 insertions(+), 261 deletions(-) create mode 100644 shared/extra-utils/server/config-command.ts delete mode 100644 shared/extra-utils/server/config.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/config-command.ts b/shared/extra-utils/server/config-command.ts new file mode 100644 index 000000000..959848706 --- /dev/null +++ b/shared/extra-utils/server/config-command.ts @@ -0,0 +1,260 @@ +import { merge } from 'lodash' +import { DeepPartial, HttpStatusCode } from '@shared/core-utils' +import { About, ServerConfig } from '@shared/models' +import { CustomConfig } from '../../models/server/custom-config.model' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ConfigCommand extends AbstractCommand { + + static getCustomConfigResolutions (enabled: boolean) { + return { + '240p': enabled, + '360p': enabled, + '480p': enabled, + '720p': enabled, + '1080p': enabled, + '1440p': enabled, + '2160p': enabled + } + } + + getConfig (options: OverrideCommandOptions = {}) { + const path = '/api/v1/config' + + return this.getRequestBody({ + ...options, + + token: null, + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getAbout (options: OverrideCommandOptions = {}) { + const path = '/api/v1/config/about' + + return this.getRequestBody({ + ...options, + + token: null, + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getCustomConfig (options: OverrideCommandOptions = {}) { + const path = '/api/v1/config/custom' + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateCustomConfig (options: OverrideCommandOptions & { + newCustomConfig: CustomConfig + }) { + const path = '/api/v1/config/custom' + + return this.putBodyRequest({ + ...options, + + path, + fields: options.newCustomConfig, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + deleteCustomConfig (options: OverrideCommandOptions = {}) { + const path = '/api/v1/config/custom' + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateCustomSubConfig (options: OverrideCommandOptions & { + newConfig: DeepPartial + }) { + const newCustomConfig: CustomConfig = { + instance: { + name: 'PeerTube updated', + shortDescription: 'my short description', + description: 'my super description', + terms: 'my super terms', + codeOfConduct: 'my super coc', + + creationReason: 'my super creation reason', + moderationInformation: 'my super moderation information', + administrator: 'Kuja', + maintenanceLifetime: 'forever', + businessModel: 'my super business model', + hardwareInformation: '2vCore 3GB RAM', + + languages: [ 'en', 'es' ], + categories: [ 1, 2 ], + + isNSFW: true, + defaultNSFWPolicy: 'blur', + + defaultClientRoute: '/videos/recently-added', + + customizations: { + javascript: 'alert("coucou")', + css: 'body { background-color: red; }' + } + }, + theme: { + default: 'default' + }, + services: { + twitter: { + username: '@MySuperUsername', + whitelisted: true + } + }, + cache: { + previews: { + size: 2 + }, + captions: { + size: 3 + }, + torrents: { + size: 4 + } + }, + signup: { + enabled: false, + limit: 5, + requiresEmailVerification: false, + minimumAge: 16 + }, + admin: { + email: 'superadmin1@example.com' + }, + contactForm: { + enabled: true + }, + user: { + videoQuota: 5242881, + videoQuotaDaily: 318742 + }, + transcoding: { + enabled: true, + allowAdditionalExtensions: true, + allowAudioFiles: true, + threads: 1, + concurrency: 3, + profile: 'default', + resolutions: { + '0p': false, + '240p': false, + '360p': true, + '480p': true, + '720p': false, + '1080p': false, + '1440p': false, + '2160p': false + }, + webtorrent: { + enabled: true + }, + hls: { + enabled: false + } + }, + live: { + enabled: true, + allowReplay: false, + maxDuration: -1, + maxInstanceLives: -1, + maxUserLives: 50, + transcoding: { + enabled: true, + threads: 4, + profile: 'default', + resolutions: { + '240p': true, + '360p': true, + '480p': true, + '720p': true, + '1080p': true, + '1440p': true, + '2160p': true + } + } + }, + import: { + videos: { + concurrency: 3, + http: { + enabled: false + }, + torrent: { + enabled: false + } + } + }, + trending: { + videos: { + algorithms: { + enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ], + default: 'hot' + } + } + }, + autoBlacklist: { + videos: { + ofUsers: { + enabled: false + } + } + }, + followers: { + instance: { + enabled: true, + manualApproval: false + } + }, + followings: { + instance: { + autoFollowBack: { + enabled: false + }, + autoFollowIndex: { + indexUrl: 'https://instances.joinpeertube.org/api/v1/instances/hosts', + enabled: false + } + } + }, + broadcastMessage: { + enabled: true, + level: 'warning', + message: 'hello', + dismissable: true + }, + search: { + remoteUri: { + users: true, + anonymous: true + }, + searchIndex: { + enabled: true, + url: 'https://search.joinpeertube.org', + disableLocalSearch: true, + isDefaultSearch: true + } + } + } + + merge(newCustomConfig, options.newConfig) + + return this.updateCustomConfig({ ...options, newCustomConfig }) + } +} diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts deleted file mode 100644 index 9fcfb31fd..000000000 --- a/shared/extra-utils/server/config.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { makeDeleteRequest, makeGetRequest, makePutBodyRequest } from '../requests/requests' -import { CustomConfig } from '../../models/server/custom-config.model' -import { DeepPartial, HttpStatusCode } from '@shared/core-utils' -import { merge } from 'lodash' - -function getConfig (url: string) { - const path = '/api/v1/config' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getAbout (url: string) { - const path = '/api/v1/config/about' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getCustomConfig (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/config/custom' - - return makeGetRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function updateCustomConfig (url: string, token: string, newCustomConfig: CustomConfig, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/config/custom' - - return makePutBodyRequest({ - url, - token, - path, - fields: newCustomConfig, - statusCodeExpected - }) -} - -function updateCustomSubConfig (url: string, token: string, newConfig: DeepPartial) { - const updateParams: CustomConfig = { - instance: { - name: 'PeerTube updated', - shortDescription: 'my short description', - description: 'my super description', - terms: 'my super terms', - codeOfConduct: 'my super coc', - - creationReason: 'my super creation reason', - moderationInformation: 'my super moderation information', - administrator: 'Kuja', - maintenanceLifetime: 'forever', - businessModel: 'my super business model', - hardwareInformation: '2vCore 3GB RAM', - - languages: [ 'en', 'es' ], - categories: [ 1, 2 ], - - isNSFW: true, - defaultNSFWPolicy: 'blur', - - defaultClientRoute: '/videos/recently-added', - - customizations: { - javascript: 'alert("coucou")', - css: 'body { background-color: red; }' - } - }, - theme: { - default: 'default' - }, - services: { - twitter: { - username: '@MySuperUsername', - whitelisted: true - } - }, - cache: { - previews: { - size: 2 - }, - captions: { - size: 3 - }, - torrents: { - size: 4 - } - }, - signup: { - enabled: false, - limit: 5, - requiresEmailVerification: false, - minimumAge: 16 - }, - admin: { - email: 'superadmin1@example.com' - }, - contactForm: { - enabled: true - }, - user: { - videoQuota: 5242881, - videoQuotaDaily: 318742 - }, - transcoding: { - enabled: true, - allowAdditionalExtensions: true, - allowAudioFiles: true, - threads: 1, - concurrency: 3, - profile: 'default', - resolutions: { - '0p': false, - '240p': false, - '360p': true, - '480p': true, - '720p': false, - '1080p': false, - '1440p': false, - '2160p': false - }, - webtorrent: { - enabled: true - }, - hls: { - enabled: false - } - }, - live: { - enabled: true, - allowReplay: false, - maxDuration: -1, - maxInstanceLives: -1, - maxUserLives: 50, - transcoding: { - enabled: true, - threads: 4, - profile: 'default', - resolutions: { - '240p': true, - '360p': true, - '480p': true, - '720p': true, - '1080p': true, - '1440p': true, - '2160p': true - } - } - }, - import: { - videos: { - concurrency: 3, - http: { - enabled: false - }, - torrent: { - enabled: false - } - } - }, - trending: { - videos: { - algorithms: { - enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ], - default: 'hot' - } - } - }, - autoBlacklist: { - videos: { - ofUsers: { - enabled: false - } - } - }, - followers: { - instance: { - enabled: true, - manualApproval: false - } - }, - followings: { - instance: { - autoFollowBack: { - enabled: false - }, - autoFollowIndex: { - indexUrl: 'https://instances.joinpeertube.org/api/v1/instances/hosts', - enabled: false - } - } - }, - broadcastMessage: { - enabled: true, - level: 'warning', - message: 'hello', - dismissable: true - }, - search: { - remoteUri: { - users: true, - anonymous: true - }, - searchIndex: { - enabled: true, - url: 'https://search.joinpeertube.org', - disableLocalSearch: true, - isDefaultSearch: true - } - } - } - - merge(updateParams, newConfig) - - return updateCustomConfig(url, token, updateParams) -} - -function getCustomConfigResolutions (enabled: boolean) { - return { - '240p': enabled, - '360p': enabled, - '480p': enabled, - '720p': enabled, - '1080p': enabled, - '1440p': enabled, - '2160p': enabled - } -} - -function deleteCustomConfig (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/config/custom' - - return makeDeleteRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -// --------------------------------------------------------------------------- - -export { - getConfig, - getCustomConfig, - updateCustomConfig, - getAbout, - deleteCustomConfig, - updateCustomSubConfig, - getCustomConfigResolutions -} diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index d37f46321..03c3b0123 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1,4 +1,4 @@ -export * from './config' +export * from './config-command' export * from './contact-form-command' export * from './debug-command' export * from './follows-command' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 4603cf62e..c33b68316 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -16,6 +16,7 @@ import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' +import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' import { FollowsCommand } from './follows-command' @@ -91,6 +92,7 @@ interface ServerInfo { pluginsCommand?: PluginsCommand redundancyCommand?: RedundancyCommand statsCommand?: StatsCommand + configCommand?: ConfigCommand } function parallelTests () { @@ -311,6 +313,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.pluginsCommand = new PluginsCommand(server) server.redundancyCommand = new RedundancyCommand(server) server.statsCommand = new StatsCommand(server) + server.configCommand = new ConfigCommand(server) res(server) }) -- cgit v1.2.3 From 87e2635a50ac2decb1c330e55c2ff7b6d07a85de Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 11:55:16 +0200 Subject: Introduce socket io command --- shared/extra-utils/index.ts | 1 + shared/extra-utils/server/servers.ts | 3 +++ shared/extra-utils/socket/index.ts | 1 + shared/extra-utils/socket/socket-io-command.ts | 15 +++++++++++++++ shared/extra-utils/socket/socket-io.ts | 18 ------------------ shared/extra-utils/users/user-notifications.ts | 7 +++---- 6 files changed, 23 insertions(+), 22 deletions(-) create mode 100644 shared/extra-utils/socket/index.ts create mode 100644 shared/extra-utils/socket/socket-io-command.ts delete mode 100644 shared/extra-utils/socket/socket-io.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index f69d7241e..ed7d7ab04 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -9,6 +9,7 @@ export * from './moderation' export * from './overviews' export * from './search' export * from './server' +export * from './socket' export * from './requests/check-api-params' export * from './requests/requests' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index c33b68316..8bd4446be 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -16,6 +16,7 @@ import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' +import { SocketIOCommand } from '../socket' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -93,6 +94,7 @@ interface ServerInfo { redundancyCommand?: RedundancyCommand statsCommand?: StatsCommand configCommand?: ConfigCommand + socketIOCommand?: SocketIOCommand } function parallelTests () { @@ -314,6 +316,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.redundancyCommand = new RedundancyCommand(server) server.statsCommand = new StatsCommand(server) server.configCommand = new ConfigCommand(server) + server.socketIOCommand = new SocketIOCommand(server) res(server) }) diff --git a/shared/extra-utils/socket/index.ts b/shared/extra-utils/socket/index.ts new file mode 100644 index 000000000..594329b2f --- /dev/null +++ b/shared/extra-utils/socket/index.ts @@ -0,0 +1 @@ +export * from './socket-io-command' diff --git a/shared/extra-utils/socket/socket-io-command.ts b/shared/extra-utils/socket/socket-io-command.ts new file mode 100644 index 000000000..545561bed --- /dev/null +++ b/shared/extra-utils/socket/socket-io-command.ts @@ -0,0 +1,15 @@ +import { io } from 'socket.io-client' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class SocketIOCommand extends AbstractCommand { + + getUserNotificationSocket (options: OverrideCommandOptions = {}) { + return io(this.server.url + '/user-notifications', { + query: { accessToken: this.server.accessToken } + }) + } + + getLiveNotificationSocket () { + return io(this.server.url + '/live-videos') + } +} diff --git a/shared/extra-utils/socket/socket-io.ts b/shared/extra-utils/socket/socket-io.ts deleted file mode 100644 index 4ca93f453..000000000 --- a/shared/extra-utils/socket/socket-io.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { io } from 'socket.io-client' - -function getUserNotificationSocket (serverUrl: string, accessToken: string) { - return io(serverUrl + '/user-notifications', { - query: { accessToken } - }) -} - -function getLiveNotificationSocket (serverUrl: string) { - return io(serverUrl + '/live-videos') -} - -// --------------------------------------------------------------------------- - -export { - getUserNotificationSocket, - getLiveNotificationSocket -} diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts index e75946eec..961cfcc0f 100644 --- a/shared/extra-utils/users/user-notifications.ts +++ b/shared/extra-utils/users/user-notifications.ts @@ -9,7 +9,6 @@ import { MockSmtpServer } from '../mock-servers/mock-email' import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' import { doubleFollow } from '../server/follows' import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' -import { getUserNotificationSocket } from '../socket/socket-io' import { setAccessTokensToServers, userLogin } from './login' import { createUser, getMyUserInformation } from './users' @@ -748,16 +747,16 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an } { - const socket = getUserNotificationSocket(servers[0].url, userAccessToken) + const socket = servers[0].socketIOCommand.getUserNotificationSocket({ token: userAccessToken }) socket.on('new-notification', n => userNotifications.push(n)) } { - const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken) + const socket = servers[0].socketIOCommand.getUserNotificationSocket() socket.on('new-notification', n => adminNotifications.push(n)) } if (serversCount > 1) { - const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken) + const socket = servers[1].socketIOCommand.getUserNotificationSocket() socket.on('new-notification', n => adminNotificationsServer2.push(n)) } -- cgit v1.2.3 From 9fff08cf83f34339df7ed4ac770e1dee536adf9d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 13:38:26 +0200 Subject: Introduce accounts command --- shared/extra-utils/index.ts | 8 +-- shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/users/accounts-command.ts | 54 ++++++++++++++++++ shared/extra-utils/users/accounts.ts | 83 +++++++--------------------- shared/extra-utils/users/index.ts | 8 +++ 5 files changed, 86 insertions(+), 70 deletions(-) create mode 100644 shared/extra-utils/users/accounts-command.ts create mode 100644 shared/extra-utils/users/index.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index ed7d7ab04..68900af26 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -10,17 +10,11 @@ export * from './overviews' export * from './search' export * from './server' export * from './socket' +export * from './users' export * from './requests/check-api-params' export * from './requests/requests' -export * from './users/accounts' -export * from './users/blocklist' -export * from './users/login' -export * from './users/user-notifications' -export * from './users/user-subscriptions' -export * from './users/users' - export * from './videos/live' export * from './videos/services' export * from './videos/video-blacklist' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 8bd4446be..c2cab9818 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -17,6 +17,7 @@ import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' +import { AccountsCommand } from '../users' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -95,6 +96,7 @@ interface ServerInfo { statsCommand?: StatsCommand configCommand?: ConfigCommand socketIOCommand?: SocketIOCommand + accountsCommand?: AccountsCommand } function parallelTests () { @@ -317,6 +319,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.statsCommand = new StatsCommand(server) server.configCommand = new ConfigCommand(server) server.socketIOCommand = new SocketIOCommand(server) + server.accountsCommand = new AccountsCommand(server) res(server) }) diff --git a/shared/extra-utils/users/accounts-command.ts b/shared/extra-utils/users/accounts-command.ts new file mode 100644 index 000000000..89c080e93 --- /dev/null +++ b/shared/extra-utils/users/accounts-command.ts @@ -0,0 +1,54 @@ +import { ResultList } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { Account } from '../../models/actors' +import { AccountVideoRate, VideoRateType } from '../../models/videos' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class AccountsCommand extends AbstractCommand { + + list (options: OverrideCommandOptions & { + sort?: string // default -createdAt + } = {}) { + const { sort = '-createdAt' } = options + const path = '/api/v1/accounts' + + return this.getRequestBody>({ + ...options, + + path, + query: { sort }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + get (options: OverrideCommandOptions & { + accountName: string + }) { + const path = '/api/v1/accounts/' + options.accountName + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listRatings (options: OverrideCommandOptions & { + accountName: string + rating?: VideoRateType + }) { + const { rating, accountName } = options + const path = '/api/v1/accounts/' + accountName + '/ratings' + + const query = { rating } + + return this.getRequestBody>({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts index 4ea7f1402..ee94351e8 100644 --- a/shared/extra-utils/users/accounts.ts +++ b/shared/extra-utils/users/accounts.ts @@ -1,43 +1,25 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import * as request from 'supertest' import { expect } from 'chai' -import { existsSync, readdir } from 'fs-extra' +import { pathExists, readdir } from 'fs-extra' import { join } from 'path' -import { Account } from '../../models/actors' -import { root } from '../miscs/miscs' -import { makeGetRequest } from '../requests/requests' -import { VideoRateType } from '../../models/videos' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/accounts' - - return makeGetRequest({ - url, - query: { sort }, - path, - statusCodeExpected - }) -} - -function getAccount (url: string, accountName: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/accounts/' + accountName - - return makeGetRequest({ - url, - path, - statusCodeExpected - }) -} - -async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) { - const res = await getAccountsList(url) - const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain) - - const message = `${nameWithDomain} on ${url}` - expect(account.followersCount).to.equal(followersCount, message) - expect(account.followingCount).to.equal(followingCount, message) +import { root } from '@server/helpers/core-utils' +import { ServerInfo } from '../server' + +async function expectAccountFollows (options: { + server: ServerInfo + handle: string + followers: number + following: number +}) { + const { server, handle, followers, following } = options + + const body = await server.accountsCommand.list() + const account = body.data.find(a => a.name + '@' + a.host === handle) + + const message = `${handle} on ${server.url}` + expect(account.followersCount).to.equal(followers, message) + expect(account.followingCount).to.equal(following, message) } async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { @@ -46,7 +28,7 @@ async function checkActorFilesWereRemoved (filename: string, serverNumber: numbe for (const directory of [ 'avatars' ]) { const directoryPath = join(root(), testDirectory, directory) - const directoryExists = existsSync(directoryPath) + const directoryExists = await pathExists(directoryPath) expect(directoryExists).to.be.true const files = await readdir(directoryPath) @@ -56,32 +38,7 @@ async function checkActorFilesWereRemoved (filename: string, serverNumber: numbe } } -function getAccountRatings ( - url: string, - accountName: string, - accessToken: string, - rating?: VideoRateType, - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/accounts/' + accountName + '/ratings' - - const query = rating ? { rating } : {} - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(statusCodeExpected) - .expect('Content-Type', /json/) -} - -// --------------------------------------------------------------------------- - export { - getAccount, expectAccountFollows, - getAccountsList, - checkActorFilesWereRemoved, - getAccountRatings + checkActorFilesWereRemoved } diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts new file mode 100644 index 000000000..b3387ed8a --- /dev/null +++ b/shared/extra-utils/users/index.ts @@ -0,0 +1,8 @@ +export * from './accounts' +export * from './accounts-command' + +export * from './blocklist' +export * from './login' +export * from './user-notifications' +export * from './user-subscriptions' +export * from './users' -- cgit v1.2.3 From 5f8bd4cbb178290da7d8f81e996f19f0eccc8e4c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 16:02:46 +0200 Subject: Introduce blocklist command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/socket/socket-io-command.ts | 2 +- shared/extra-utils/users/blocklist-command.ts | 135 ++++++++++++++ shared/extra-utils/users/blocklist.ts | 238 ------------------------- shared/extra-utils/users/index.ts | 4 +- 5 files changed, 141 insertions(+), 242 deletions(-) create mode 100644 shared/extra-utils/users/blocklist-command.ts delete mode 100644 shared/extra-utils/users/blocklist.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index c2cab9818..3c709666d 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -17,7 +17,7 @@ import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' -import { AccountsCommand } from '../users' +import { AccountsCommand, BlocklistCommand } from '../users' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -97,6 +97,7 @@ interface ServerInfo { configCommand?: ConfigCommand socketIOCommand?: SocketIOCommand accountsCommand?: AccountsCommand + blocklistCommand?: BlocklistCommand } function parallelTests () { @@ -320,6 +321,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.configCommand = new ConfigCommand(server) server.socketIOCommand = new SocketIOCommand(server) server.accountsCommand = new AccountsCommand(server) + server.blocklistCommand = new BlocklistCommand(server) res(server) }) diff --git a/shared/extra-utils/socket/socket-io-command.ts b/shared/extra-utils/socket/socket-io-command.ts index 545561bed..c277ead28 100644 --- a/shared/extra-utils/socket/socket-io-command.ts +++ b/shared/extra-utils/socket/socket-io-command.ts @@ -5,7 +5,7 @@ export class SocketIOCommand extends AbstractCommand { getUserNotificationSocket (options: OverrideCommandOptions = {}) { return io(this.server.url + '/user-notifications', { - query: { accessToken: this.server.accessToken } + query: { accessToken: options.token ?? this.server.accessToken } }) } diff --git a/shared/extra-utils/users/blocklist-command.ts b/shared/extra-utils/users/blocklist-command.ts new file mode 100644 index 000000000..96afdc3fd --- /dev/null +++ b/shared/extra-utils/users/blocklist-command.ts @@ -0,0 +1,135 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { HttpStatusCode } from '@shared/core-utils' +import { AccountBlock, ResultList, ServerBlock } from '@shared/models' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +type ListBlocklistOptions = OverrideCommandOptions & { + start: number + count: number + sort: string // default -createdAt +} + +export class BlocklistCommand extends AbstractCommand { + + listMyAccountBlocklist (options: ListBlocklistOptions) { + const path = '/api/v1/users/me/blocklist/accounts' + + return this.listBlocklist(options, path) + } + + listMyServerBlocklist (options: ListBlocklistOptions) { + const path = '/api/v1/users/me/blocklist/servers' + + return this.listBlocklist(options, path) + } + + listServerAccountBlocklist (options: ListBlocklistOptions) { + const path = '/api/v1/server/blocklist/accounts' + + return this.listBlocklist(options, path) + } + + listServerServerBlocklist (options: ListBlocklistOptions) { + const path = '/api/v1/server/blocklist/servers' + + return this.listBlocklist(options, path) + } + + // --------------------------------------------------------------------------- + + addToMyBlocklist (options: OverrideCommandOptions & { + account?: string + server?: string + }) { + const { account, server } = options + + const path = account + ? '/api/v1/users/me/blocklist/accounts' + : '/api/v1/users/me/blocklist/servers' + + return this.postBodyRequest({ + ...options, + + path, + fields: { + accountName: account, + host: server + }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + addToServerBlocklist (options: OverrideCommandOptions & { + account?: string + server?: string + }) { + const { account, server } = options + + const path = account + ? '/api/v1/server/blocklist/accounts' + : '/api/v1/server/blocklist/servers' + + return this.postBodyRequest({ + ...options, + + path, + fields: { + accountName: account, + host: server + }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + removeFromMyBlocklist (options: OverrideCommandOptions & { + account?: string + server?: string + }) { + const { account, server } = options + + const path = account + ? '/api/v1/users/me/blocklist/accounts/' + account + : '/api/v1/users/me/blocklist/servers/' + server + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + removeFromServerBlocklist (options: OverrideCommandOptions & { + account?: string + server?: string + }) { + const { account, server } = options + + const path = account + ? '/api/v1/server/blocklist/accounts/' + account + : '/api/v1/server/blocklist/servers/' + server + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + private listBlocklist (options: ListBlocklistOptions, path: string) { + const { start, count, sort = '-createdAt' } = options + + return this.getRequestBody>({ + ...options, + + path, + query: { start, count, sort }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + +} diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts deleted file mode 100644 index bdf7ee58a..000000000 --- a/shared/extra-utils/users/blocklist.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getAccountBlocklistByAccount ( - url: string, - token: string, - start: number, - count: number, - sort = '-createdAt', - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/users/me/blocklist/accounts' - - return makeGetRequest({ - url, - token, - query: { start, count, sort }, - path, - statusCodeExpected - }) -} - -function addAccountToAccountBlocklist ( - url: string, - token: string, - accountToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/me/blocklist/accounts' - - return makePostBodyRequest({ - url, - path, - token, - fields: { - accountName: accountToBlock - }, - statusCodeExpected - }) -} - -function removeAccountFromAccountBlocklist ( - url: string, - token: string, - accountToUnblock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/me/blocklist/accounts/' + accountToUnblock - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function getServerBlocklistByAccount ( - url: string, - token: string, - start: number, - count: number, - sort = '-createdAt', - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/users/me/blocklist/servers' - - return makeGetRequest({ - url, - token, - query: { start, count, sort }, - path, - statusCodeExpected - }) -} - -function addServerToAccountBlocklist ( - url: string, - token: string, - serverToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/me/blocklist/servers' - - return makePostBodyRequest({ - url, - path, - token, - fields: { - host: serverToBlock - }, - statusCodeExpected - }) -} - -function removeServerFromAccountBlocklist ( - url: string, - token: string, - serverToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/me/blocklist/servers/' + serverToBlock - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function getAccountBlocklistByServer ( - url: string, - token: string, - start: number, - count: number, - sort = '-createdAt', - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/server/blocklist/accounts' - - return makeGetRequest({ - url, - token, - query: { start, count, sort }, - path, - statusCodeExpected - }) -} - -function addAccountToServerBlocklist ( - url: string, - token: string, - accountToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/server/blocklist/accounts' - - return makePostBodyRequest({ - url, - path, - token, - fields: { - accountName: accountToBlock - }, - statusCodeExpected - }) -} - -function removeAccountFromServerBlocklist ( - url: string, - token: string, - accountToUnblock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/server/blocklist/accounts/' + accountToUnblock - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function getServerBlocklistByServer ( - url: string, - token: string, - start: number, - count: number, - sort = '-createdAt', - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/server/blocklist/servers' - - return makeGetRequest({ - url, - token, - query: { start, count, sort }, - path, - statusCodeExpected - }) -} - -function addServerToServerBlocklist ( - url: string, - token: string, - serverToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/server/blocklist/servers' - - return makePostBodyRequest({ - url, - path, - token, - fields: { - host: serverToBlock - }, - statusCodeExpected - }) -} - -function removeServerFromServerBlocklist ( - url: string, - token: string, - serverToBlock: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/server/blocklist/servers/' + serverToBlock - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -// --------------------------------------------------------------------------- - -export { - getAccountBlocklistByAccount, - addAccountToAccountBlocklist, - removeAccountFromAccountBlocklist, - getServerBlocklistByAccount, - addServerToAccountBlocklist, - removeServerFromAccountBlocklist, - - getAccountBlocklistByServer, - addAccountToServerBlocklist, - removeAccountFromServerBlocklist, - getServerBlocklistByServer, - addServerToServerBlocklist, - removeServerFromServerBlocklist -} diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index b3387ed8a..ea5dbbf14 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -1,7 +1,7 @@ -export * from './accounts' export * from './accounts-command' +export * from './accounts' +export * from './blocklist-command' -export * from './blocklist' export * from './login' export * from './user-notifications' export * from './user-subscriptions' -- cgit v1.2.3 From 2c27e70471120c92e0bc8c8114141fbb31ff98ac Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 7 Jul 2021 16:40:49 +0200 Subject: Introduce subscriptions command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/users/index.ts | 2 +- shared/extra-utils/users/subscriptions-command.ts | 94 +++++++++++++++++++++++ shared/extra-utils/users/user-subscriptions.ts | 93 ---------------------- 4 files changed, 98 insertions(+), 95 deletions(-) create mode 100644 shared/extra-utils/users/subscriptions-command.ts delete mode 100644 shared/extra-utils/users/user-subscriptions.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 3c709666d..57b37728a 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -17,7 +17,7 @@ import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' -import { AccountsCommand, BlocklistCommand } from '../users' +import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -98,6 +98,7 @@ interface ServerInfo { socketIOCommand?: SocketIOCommand accountsCommand?: AccountsCommand blocklistCommand?: BlocklistCommand + subscriptionsCommand?: SubscriptionsCommand } function parallelTests () { @@ -322,6 +323,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.socketIOCommand = new SocketIOCommand(server) server.accountsCommand = new AccountsCommand(server) server.blocklistCommand = new BlocklistCommand(server) + server.subscriptionsCommand = new SubscriptionsCommand(server) res(server) }) diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index ea5dbbf14..94ad37242 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -4,5 +4,5 @@ export * from './blocklist-command' export * from './login' export * from './user-notifications' -export * from './user-subscriptions' +export * from './subscriptions-command' export * from './users' diff --git a/shared/extra-utils/users/subscriptions-command.ts b/shared/extra-utils/users/subscriptions-command.ts new file mode 100644 index 000000000..94d2af67a --- /dev/null +++ b/shared/extra-utils/users/subscriptions-command.ts @@ -0,0 +1,94 @@ +import { ResultList, Video, VideoChannel } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class SubscriptionsCommand extends AbstractCommand { + + add (options: OverrideCommandOptions & { + targetUri: string + }) { + const path = '/api/v1/users/me/subscriptions' + + return this.postBodyRequest({ + ...options, + + path, + fields: { uri: options.targetUri }, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + list (options: OverrideCommandOptions & { + sort?: string // default -createdAt + search?: string + } = {}) { + const { sort = '-createdAt', search } = options + const path = '/api/v1/users/me/subscriptions' + + return this.getRequestBody>({ + ...options, + + path, + query: { + sort, + search + }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listVideos (options: OverrideCommandOptions & { + sort?: string // default -createdAt + } = {}) { + const { sort = '-createdAt' } = options + const path = '/api/v1/users/me/subscriptions/videos' + + return this.getRequestBody>({ + ...options, + + path, + query: { sort }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + get (options: OverrideCommandOptions & { + uri: string + }) { + const path = '/api/v1/users/me/subscriptions/' + options.uri + + return this.getRequestBody({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + remove (options: OverrideCommandOptions & { + uri: string + }) { + const path = '/api/v1/users/me/subscriptions/' + options.uri + + return this.deleteRequest({ + ...options, + + path, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + exist (options: OverrideCommandOptions & { + uris: string[] + }) { + const path = '/api/v1/users/me/subscriptions/exist' + + return this.getRequestBody<{ [id: string ]: boolean }>({ + ...options, + + path, + query: { 'uris[]': options.uris }, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/users/user-subscriptions.ts b/shared/extra-utils/users/user-subscriptions.ts deleted file mode 100644 index edc7a3562..000000000 --- a/shared/extra-utils/users/user-subscriptions.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function addUserSubscription (url: string, token: string, targetUri: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/me/subscriptions' - - return makePostBodyRequest({ - url, - path, - token, - statusCodeExpected, - fields: { uri: targetUri } - }) -} - -function listUserSubscriptions (parameters: { - url: string - token: string - sort?: string - search?: string - statusCodeExpected?: number -}) { - const { url, token, sort = '-createdAt', search, statusCodeExpected = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/users/me/subscriptions' - - return makeGetRequest({ - url, - path, - token, - statusCodeExpected, - query: { - sort, - search - } - }) -} - -function listUserSubscriptionVideos (url: string, token: string, sort = '-createdAt', statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me/subscriptions/videos' - - return makeGetRequest({ - url, - path, - token, - statusCodeExpected, - query: { sort } - }) -} - -function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me/subscriptions/' + uri - - return makeGetRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/me/subscriptions/' + uri - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function areSubscriptionsExist (url: string, token: string, uris: string[], statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me/subscriptions/exist' - - return makeGetRequest({ - url, - path, - query: { 'uris[]': uris }, - token, - statusCodeExpected - }) -} - -// --------------------------------------------------------------------------- - -export { - areSubscriptionsExist, - addUserSubscription, - listUserSubscriptions, - getUserSubscription, - listUserSubscriptionVideos, - removeUserSubscription -} -- cgit v1.2.3 From 4f2199144e428c16460750305f737b890c1ac322 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 10:18:40 +0200 Subject: Introduce live command --- shared/extra-utils/index.ts | 16 +-- shared/extra-utils/requests/index.ts | 3 + shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/shared/abstract-command.ts | 32 +++++- shared/extra-utils/users/index.ts | 1 - shared/extra-utils/videos/index.ts | 13 +++ shared/extra-utils/videos/live-command.ts | 156 ++++++++++++++++++++++++++ shared/extra-utils/videos/live.ts | 139 +---------------------- 8 files changed, 214 insertions(+), 149 deletions(-) create mode 100644 shared/extra-utils/requests/index.ts create mode 100644 shared/extra-utils/videos/index.ts create mode 100644 shared/extra-utils/videos/live-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts index 68900af26..4b3636d06 100644 --- a/shared/extra-utils/index.ts +++ b/shared/extra-utils/index.ts @@ -7,21 +7,9 @@ export * from './miscs' export * from './mock-servers' export * from './moderation' export * from './overviews' +export * from './requests' export * from './search' export * from './server' export * from './socket' export * from './users' - -export * from './requests/check-api-params' -export * from './requests/requests' - -export * from './videos/live' -export * from './videos/services' -export * from './videos/video-blacklist' -export * from './videos/video-captions' -export * from './videos/video-change-ownership' -export * from './videos/video-channels' -export * from './videos/video-comments' -export * from './videos/video-playlists' -export * from './videos/video-streaming-playlists' -export * from './videos/videos' +export * from './videos' diff --git a/shared/extra-utils/requests/index.ts b/shared/extra-utils/requests/index.ts new file mode 100644 index 000000000..501163f92 --- /dev/null +++ b/shared/extra-utils/requests/index.ts @@ -0,0 +1,3 @@ +// Don't include activitypub that import stuff from server +export * from './check-api-params' +export * from './requests' diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 57b37728a..eca0689aa 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,6 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' +import { LiveCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -99,6 +100,7 @@ interface ServerInfo { accountsCommand?: AccountsCommand blocklistCommand?: BlocklistCommand subscriptionsCommand?: SubscriptionsCommand + liveCommand?: LiveCommand } function parallelTests () { @@ -324,6 +326,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.accountsCommand = new AccountsCommand(server) server.blocklistCommand = new BlocklistCommand(server) server.subscriptionsCommand = new SubscriptionsCommand(server) + server.liveCommand = new LiveCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index dd4598a91..38129d559 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,5 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, unwrapBody, unwrapText } from '../requests/requests' +import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest, unwrapBody, unwrapText } from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { @@ -86,6 +86,36 @@ abstract class AbstractCommand { }) } + protected postUploadRequest (options: CommonCommandOptions & { + fields?: { [ fieldName: string ]: any } + attaches?: any + }) { + const { fields, attaches } = options + + return makeUploadRequest({ + ...this.buildCommonRequestOptions(options), + + method: 'POST', + fields, + attaches + }) + } + + protected putUploadRequest (options: CommonCommandOptions & { + fields?: { [ fieldName: string ]: any } + attaches?: any + }) { + const { fields, attaches } = options + + return makeUploadRequest({ + ...this.buildCommonRequestOptions(options), + + method: 'PUT', + fields, + attaches + }) + } + private buildCommonRequestOptions (options: CommonCommandOptions) { const { token, expectedStatus, defaultExpectedStatus, path } = options diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index 94ad37242..9f760d7fd 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -1,7 +1,6 @@ export * from './accounts-command' export * from './accounts' export * from './blocklist-command' - export * from './login' export * from './user-notifications' export * from './subscriptions-command' diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts new file mode 100644 index 000000000..c9c884285 --- /dev/null +++ b/shared/extra-utils/videos/index.ts @@ -0,0 +1,13 @@ +export * from './live-command' +export * from './live' +export * from './services' +export * from './video-blacklist' +export * from './video-captions' +export * from './video-change-ownership' +export * from './video-channels' +export * from './video-comments' +export * from './video-history' +export * from './video-imports' +export * from './video-playlists' +export * from './video-streaming-playlists' +export * from './videos' diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts new file mode 100644 index 000000000..55811b8ba --- /dev/null +++ b/shared/extra-utils/videos/live-command.ts @@ -0,0 +1,156 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { readdir } from 'fs-extra' +import { omit } from 'lodash' +import { join } from 'path' +import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { buildServerDirectory, wait } from '../miscs/miscs' +import { unwrapBody } from '../requests' +import { waitUntilLog } from '../server/servers' +import { AbstractCommand, OverrideCommandOptions } from '../shared' +import { sendRTMPStream, testFfmpegStreamError } from './live' +import { getVideoWithToken } from './videos' + +export class LiveCommand extends AbstractCommand { + + getLive (options: OverrideCommandOptions & { + videoId: number | string + }) { + const path = '/api/v1/videos/live' + + return this.getRequestBody({ + ...options, + + path: path + '/' + options.videoId, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateLive (options: OverrideCommandOptions & { + videoId: number | string + fields: LiveVideoUpdate + }) { + const { videoId, fields } = options + const path = '/api/v1/videos/live' + + return this.putBodyRequest({ + ...options, + + path: path + '/' + videoId, + fields, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async createLive (options: OverrideCommandOptions & { + fields: LiveVideoCreate + }) { + const { fields } = options + const path = '/api/v1/videos/live' + + const attaches: any = {} + if (fields.thumbnailfile) attaches.thumbnailfile = fields.thumbnailfile + if (fields.previewfile) attaches.previewfile = fields.previewfile + + const body = await unwrapBody<{ video: VideoCreateResult }>(this.postUploadRequest({ + ...options, + + path, + attaches, + fields: omit(fields, 'thumbnailfile', 'previewfile'), + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.video + } + + async sendRTMPStreamInVideo (options: OverrideCommandOptions & { + videoId: number | string + fixtureName?: string + }) { + const { videoId, fixtureName } = options + const videoLive = await this.getLive({ videoId }) + + return sendRTMPStream(videoLive.rtmpUrl, videoLive.streamKey, fixtureName) + } + + async runAndTestFfmpegStreamError (options: OverrideCommandOptions & { + videoId: number | string + shouldHaveError: boolean + }) { + const command = await this.sendRTMPStreamInVideo(options) + + return testFfmpegStreamError(command, options.shouldHaveError) + } + + waitUntilLivePublished (options: OverrideCommandOptions & { + videoId: number | string + }) { + const { videoId } = options + return this.waitUntilLiveState({ videoId, state: VideoState.PUBLISHED }) + } + + waitUntilLiveWaiting (options: OverrideCommandOptions & { + videoId: number | string + }) { + const { videoId } = options + return this.waitUntilLiveState({ videoId, state: VideoState.WAITING_FOR_LIVE }) + } + + waitUntilLiveEnded (options: OverrideCommandOptions & { + videoId: number | string + }) { + const { videoId } = options + return this.waitUntilLiveState({ videoId, state: VideoState.LIVE_ENDED }) + } + + waitUntilLiveSegmentGeneration (options: OverrideCommandOptions & { + videoUUID: string + resolution: number + segment: number + }) { + const { resolution, segment, videoUUID } = options + const segmentName = `${resolution}-00000${segment}.ts` + + return waitUntilLog(this.server, `${videoUUID}/${segmentName}`, 2, false) + } + + async waitUntilLiveSaved (options: OverrideCommandOptions & { + videoId: number | string + }) { + let video: VideoDetails + + do { + const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId) + video = res.body + + await wait(500) + } while (video.isLive === true && video.state.id !== VideoState.PUBLISHED) + } + + async getPlaylistsCount (options: OverrideCommandOptions & { + videoUUID: string + }) { + const basePath = buildServerDirectory(this.server, 'streaming-playlists') + const hlsPath = join(basePath, 'hls', options.videoUUID) + + const files = await readdir(hlsPath) + + return files.filter(f => f.endsWith('.m3u8')).length + } + + private async waitUntilLiveState (options: OverrideCommandOptions & { + videoId: number | string + state: VideoState + }) { + let video: VideoDetails + + do { + const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId) + video = res.body + + await wait(500) + } while (video.state.id !== options.state) + } +} diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index c0384769b..285a39c7e 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -3,69 +3,9 @@ import { expect } from 'chai' import * as ffmpeg from 'fluent-ffmpeg' import { pathExists, readdir } from 'fs-extra' -import { omit } from 'lodash' import { join } from 'path' -import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoDetails, VideoState } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' import { buildAbsoluteFixturePath, buildServerDirectory, wait } from '../miscs/miscs' -import { makeGetRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests' -import { ServerInfo, waitUntilLog } from '../server/servers' -import { getVideoWithToken } from './videos' - -function getLive (url: string, token: string, videoId: number | string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/videos/live' - - return makeGetRequest({ - url, - token, - path: path + '/' + videoId, - statusCodeExpected - }) -} - -function updateLive ( - url: string, - token: string, - videoId: number | string, - fields: LiveVideoUpdate, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/live' - - return makePutBodyRequest({ - url, - token, - path: path + '/' + videoId, - fields, - statusCodeExpected - }) -} - -function createLive (url: string, token: string, fields: LiveVideoCreate, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/videos/live' - - const attaches: any = {} - if (fields.thumbnailfile) attaches.thumbnailfile = fields.thumbnailfile - if (fields.previewfile) attaches.previewfile = fields.previewfile - - const updatedFields = omit(fields, 'thumbnailfile', 'previewfile') - - return makeUploadRequest({ - url, - path, - token, - attaches, - fields: updatedFields, - statusCodeExpected - }) -} - -async function sendRTMPStreamInVideo (url: string, token: string, videoId: number | string, fixtureName?: string) { - const res = await getLive(url, token, videoId) - const videoLive = res.body as LiveVideo - - return sendRTMPStream(videoLive.rtmpUrl, videoLive.streamKey, fixtureName) -} +import { ServerInfo } from '../server/servers' function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') { const fixture = buildAbsoluteFixturePath(fixtureName) @@ -109,12 +49,6 @@ function waitFfmpegUntilError (command: ffmpeg.FfmpegCommand, successAfterMS = 1 }) } -async function runAndTestFfmpegStreamError (url: string, token: string, videoId: number | string, shouldHaveError: boolean) { - const command = await sendRTMPStreamInVideo(url, token, videoId) - - return testFfmpegStreamError(command, shouldHaveError) -} - async function testFfmpegStreamError (command: ffmpeg.FfmpegCommand, shouldHaveError: boolean) { let error: Error @@ -136,48 +70,9 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) { await wait(500) } -function waitUntilLivePublished (url: string, token: string, videoId: number | string) { - return waitUntilLiveState(url, token, videoId, VideoState.PUBLISHED) -} - -function waitUntilLiveWaiting (url: string, token: string, videoId: number | string) { - return waitUntilLiveState(url, token, videoId, VideoState.WAITING_FOR_LIVE) -} - -function waitUntilLiveEnded (url: string, token: string, videoId: number | string) { - return waitUntilLiveState(url, token, videoId, VideoState.LIVE_ENDED) -} - -function waitUntilLiveSegmentGeneration (server: ServerInfo, videoUUID: string, resolutionNum: number, segmentNum: number) { - const segmentName = `${resolutionNum}-00000${segmentNum}.ts` - return waitUntilLog(server, `${videoUUID}/${segmentName}`, 2, false) -} - -async function waitUntilLiveState (url: string, token: string, videoId: number | string, state: VideoState) { - let video: VideoDetails - - do { - const res = await getVideoWithToken(url, token, videoId) - video = res.body - - await wait(500) - } while (video.state.id !== state) -} - -async function waitUntilLiveSaved (url: string, token: string, videoId: number | string) { - let video: VideoDetails - - do { - const res = await getVideoWithToken(url, token, videoId) - video = res.body - - await wait(500) - } while (video.isLive === true && video.state.id !== VideoState.PUBLISHED) -} - async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) { for (const server of servers) { - await waitUntilLivePublished(server.url, server.accessToken, videoId) + await server.liveCommand.waitUntilLivePublished({ videoId }) } } @@ -206,33 +101,11 @@ async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resoluti expect(files).to.contain('segments-sha256.json') } -async function getPlaylistsCount (server: ServerInfo, videoUUID: string) { - const basePath = buildServerDirectory(server, 'streaming-playlists') - const hlsPath = join(basePath, 'hls', videoUUID) - - const files = await readdir(hlsPath) - - return files.filter(f => f.endsWith('.m3u8')).length -} - -// --------------------------------------------------------------------------- - export { - getLive, - getPlaylistsCount, - waitUntilLiveSaved, - waitUntilLivePublished, - updateLive, - createLive, - runAndTestFfmpegStreamError, - checkLiveCleanup, - waitUntilLiveSegmentGeneration, - stopFfmpeg, - waitUntilLiveWaiting, - sendRTMPStreamInVideo, - waitUntilLiveEnded, + sendRTMPStream, waitFfmpegUntilError, + testFfmpegStreamError, + stopFfmpeg, waitUntilLivePublishedOnAllServers, - sendRTMPStream, - testFfmpegStreamError + checkLiveCleanup } -- cgit v1.2.3 From d897210c2db1ca2acc1e7b28a13127647ab2222c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 10:23:21 +0200 Subject: Introduce services command --- shared/extra-utils/server/servers.ts | 4 +++- shared/extra-utils/videos/index.ts | 2 +- shared/extra-utils/videos/services-command.ts | 28 +++++++++++++++++++++++++++ shared/extra-utils/videos/services.ts | 24 ----------------------- 4 files changed, 32 insertions(+), 26 deletions(-) create mode 100644 shared/extra-utils/videos/services-command.ts delete mode 100644 shared/extra-utils/videos/services.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index eca0689aa..cb2a8814b 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { LiveCommand } from '../videos' +import { LiveCommand, ServicesCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -101,6 +101,7 @@ interface ServerInfo { blocklistCommand?: BlocklistCommand subscriptionsCommand?: SubscriptionsCommand liveCommand?: LiveCommand + servicesCommand?: ServicesCommand } function parallelTests () { @@ -327,6 +328,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.blocklistCommand = new BlocklistCommand(server) server.subscriptionsCommand = new SubscriptionsCommand(server) server.liveCommand = new LiveCommand(server) + server.servicesCommand = new ServicesCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index c9c884285..fe5dc6655 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -1,6 +1,6 @@ export * from './live-command' export * from './live' -export * from './services' +export * from './services-command' export * from './video-blacklist' export * from './video-captions' export * from './video-change-ownership' diff --git a/shared/extra-utils/videos/services-command.ts b/shared/extra-utils/videos/services-command.ts new file mode 100644 index 000000000..3b618ef66 --- /dev/null +++ b/shared/extra-utils/videos/services-command.ts @@ -0,0 +1,28 @@ +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ServicesCommand extends AbstractCommand { + + getOEmbed (options: OverrideCommandOptions & { + oembedUrl: string + format?: string + maxHeight?: number + maxWidth?: number + }) { + const path = '/services/oembed' + const query = { + url: options.oembedUrl, + format: options.format, + maxheight: options.maxHeight, + maxwidth: options.maxWidth + } + + return this.getRequest({ + ...options, + + path, + query, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/videos/services.ts b/shared/extra-utils/videos/services.ts deleted file mode 100644 index e13a788bd..000000000 --- a/shared/extra-utils/videos/services.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as request from 'supertest' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getOEmbed (url: string, oembedUrl: string, format?: string, maxHeight?: number, maxWidth?: number) { - const path = '/services/oembed' - const query = { - url: oembedUrl, - format, - maxheight: maxHeight, - maxwidth: maxWidth - } - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) -} - -// --------------------------------------------------------------------------- - -export { - getOEmbed -} -- cgit v1.2.3 From 04aed76711909507e74905bde3a7fa024d3585c9 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 10:25:50 +0200 Subject: Shorter live methods --- shared/extra-utils/videos/live-command.ts | 30 +++++++++++++++--------------- shared/extra-utils/videos/live.ts | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index 55811b8ba..e36c632ee 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -14,7 +14,7 @@ import { getVideoWithToken } from './videos' export class LiveCommand extends AbstractCommand { - getLive (options: OverrideCommandOptions & { + get (options: OverrideCommandOptions & { videoId: number | string }) { const path = '/api/v1/videos/live' @@ -27,7 +27,7 @@ export class LiveCommand extends AbstractCommand { }) } - updateLive (options: OverrideCommandOptions & { + update (options: OverrideCommandOptions & { videoId: number | string fields: LiveVideoUpdate }) { @@ -43,7 +43,7 @@ export class LiveCommand extends AbstractCommand { }) } - async createLive (options: OverrideCommandOptions & { + async create (options: OverrideCommandOptions & { fields: LiveVideoCreate }) { const { fields } = options @@ -70,12 +70,12 @@ export class LiveCommand extends AbstractCommand { fixtureName?: string }) { const { videoId, fixtureName } = options - const videoLive = await this.getLive({ videoId }) + const videoLive = await this.get({ videoId }) return sendRTMPStream(videoLive.rtmpUrl, videoLive.streamKey, fixtureName) } - async runAndTestFfmpegStreamError (options: OverrideCommandOptions & { + async runAndTestStreamError (options: OverrideCommandOptions & { videoId: number | string shouldHaveError: boolean }) { @@ -84,28 +84,28 @@ export class LiveCommand extends AbstractCommand { return testFfmpegStreamError(command, options.shouldHaveError) } - waitUntilLivePublished (options: OverrideCommandOptions & { + waitUntilPublished (options: OverrideCommandOptions & { videoId: number | string }) { const { videoId } = options - return this.waitUntilLiveState({ videoId, state: VideoState.PUBLISHED }) + return this.waitUntilState({ videoId, state: VideoState.PUBLISHED }) } - waitUntilLiveWaiting (options: OverrideCommandOptions & { + waitUntilWaiting (options: OverrideCommandOptions & { videoId: number | string }) { const { videoId } = options - return this.waitUntilLiveState({ videoId, state: VideoState.WAITING_FOR_LIVE }) + return this.waitUntilState({ videoId, state: VideoState.WAITING_FOR_LIVE }) } - waitUntilLiveEnded (options: OverrideCommandOptions & { + waitUntilEnded (options: OverrideCommandOptions & { videoId: number | string }) { const { videoId } = options - return this.waitUntilLiveState({ videoId, state: VideoState.LIVE_ENDED }) + return this.waitUntilState({ videoId, state: VideoState.LIVE_ENDED }) } - waitUntilLiveSegmentGeneration (options: OverrideCommandOptions & { + waitUntilSegmentGeneration (options: OverrideCommandOptions & { videoUUID: string resolution: number segment: number @@ -116,7 +116,7 @@ export class LiveCommand extends AbstractCommand { return waitUntilLog(this.server, `${videoUUID}/${segmentName}`, 2, false) } - async waitUntilLiveSaved (options: OverrideCommandOptions & { + async waitUntilSaved (options: OverrideCommandOptions & { videoId: number | string }) { let video: VideoDetails @@ -129,7 +129,7 @@ export class LiveCommand extends AbstractCommand { } while (video.isLive === true && video.state.id !== VideoState.PUBLISHED) } - async getPlaylistsCount (options: OverrideCommandOptions & { + async countPlaylists (options: OverrideCommandOptions & { videoUUID: string }) { const basePath = buildServerDirectory(this.server, 'streaming-playlists') @@ -140,7 +140,7 @@ export class LiveCommand extends AbstractCommand { return files.filter(f => f.endsWith('.m3u8')).length } - private async waitUntilLiveState (options: OverrideCommandOptions & { + private async waitUntilState (options: OverrideCommandOptions & { videoId: number | string state: VideoState }) { diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index 285a39c7e..92cb9104c 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -72,7 +72,7 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) { async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) { for (const server of servers) { - await server.liveCommand.waitUntilLivePublished({ videoId }) + await server.liveCommand.waitUntilPublished({ videoId }) } } -- cgit v1.2.3 From a1637fa1e25b60a88f7cfe50aac8953f50d55761 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 10:55:16 +0200 Subject: Specify if we want to fallback to the server token --- shared/extra-utils/bulk/bulk-command.ts | 2 ++ .../custom-pages/custom-pages-command.ts | 4 +++ shared/extra-utils/feeds/feeds-command.ts | 2 ++ shared/extra-utils/logs/logs-command.ts | 2 ++ shared/extra-utils/moderation/abuses-command.ts | 29 +++++++++++++-- shared/extra-utils/overviews/overviews-command.ts | 4 +-- shared/extra-utils/search/search-command.ts | 15 ++++---- shared/extra-utils/server/config-command.ts | 7 ++-- shared/extra-utils/server/contact-form-command.ts | 2 +- shared/extra-utils/server/debug-command.ts | 2 ++ shared/extra-utils/server/follows-command.ts | 11 +++--- shared/extra-utils/server/jobs-command.ts | 1 + shared/extra-utils/server/plugins-command.ts | 12 +++++++ shared/extra-utils/server/redundancy-command.ts | 4 +++ shared/extra-utils/server/stats-command.ts | 1 + shared/extra-utils/shared/abstract-command.ts | 41 ++++++++++++++-------- shared/extra-utils/users/accounts-command.ts | 3 ++ shared/extra-utils/users/blocklist-command.ts | 5 +++ shared/extra-utils/users/subscriptions-command.ts | 6 ++++ shared/extra-utils/videos/live-command.ts | 3 ++ shared/extra-utils/videos/services-command.ts | 1 + 21 files changed, 122 insertions(+), 35 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/bulk-command.ts b/shared/extra-utils/bulk/bulk-command.ts index fcbf04164..6dac6034f 100644 --- a/shared/extra-utils/bulk/bulk-command.ts +++ b/shared/extra-utils/bulk/bulk-command.ts @@ -12,8 +12,10 @@ export class BulkCommand extends AbstractCommand { return this.postBodyRequest({ ...options, + path: '/api/v1/bulk/remove-comments-of', fields: attributes, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/custom-pages/custom-pages-command.ts b/shared/extra-utils/custom-pages/custom-pages-command.ts index a062c9774..0dd77503e 100644 --- a/shared/extra-utils/custom-pages/custom-pages-command.ts +++ b/shared/extra-utils/custom-pages/custom-pages-command.ts @@ -9,7 +9,9 @@ export class CustomPagesCommand extends AbstractCommand { return this.getRequestBody({ ...options, + path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -22,8 +24,10 @@ export class CustomPagesCommand extends AbstractCommand { return this.putBodyRequest({ ...options, + path, fields: { content }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/feeds/feeds-command.ts b/shared/extra-utils/feeds/feeds-command.ts index 8031adf92..2da4110a7 100644 --- a/shared/extra-utils/feeds/feeds-command.ts +++ b/shared/extra-utils/feeds/feeds-command.ts @@ -19,6 +19,7 @@ export class FeedCommand extends AbstractCommand { path, query: format ? { format } : undefined, accept: 'application/xml', + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -36,6 +37,7 @@ export class FeedCommand extends AbstractCommand { path, query, accept: 'application/json', + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/logs/logs-command.ts b/shared/extra-utils/logs/logs-command.ts index f7594734d..f34c58c47 100644 --- a/shared/extra-utils/logs/logs-command.ts +++ b/shared/extra-utils/logs/logs-command.ts @@ -17,6 +17,7 @@ export class LogsCommand extends AbstractCommand { path, query: { startDate, endDate, level }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -34,6 +35,7 @@ export class LogsCommand extends AbstractCommand { path, query: { startDate, endDate }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/moderation/abuses-command.ts b/shared/extra-utils/moderation/abuses-command.ts index 59126d0a9..03da0c85a 100644 --- a/shared/extra-utils/moderation/abuses-command.ts +++ b/shared/extra-utils/moderation/abuses-command.ts @@ -60,6 +60,7 @@ export class AbusesCommand extends AbstractCommand { path, fields: body, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 })) } @@ -106,6 +107,7 @@ export class AbusesCommand extends AbstractCommand { path, query, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -138,6 +140,7 @@ export class AbusesCommand extends AbstractCommand { path, query, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -154,6 +157,7 @@ export class AbusesCommand extends AbstractCommand { path, fields: body, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -164,7 +168,13 @@ export class AbusesCommand extends AbstractCommand { const { abuseId } = options const path = '/api/v1/abuses/' + abuseId - return this.deleteRequest({ ...options, path, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) } listMessages (options: OverrideCommandOptions & { @@ -173,7 +183,13 @@ export class AbusesCommand extends AbstractCommand { const { abuseId } = options const path = '/api/v1/abuses/' + abuseId + '/messages' - return this.getRequestBody>({ ...options, path, defaultExpectedStatus: HttpStatusCode.OK_200 }) + return this.getRequestBody>({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) } deleteMessage (options: OverrideCommandOptions & { @@ -183,7 +199,13 @@ export class AbusesCommand extends AbstractCommand { const { abuseId, messageId } = options const path = '/api/v1/abuses/' + abuseId + '/messages/' + messageId - return this.deleteRequest({ ...options, path, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) } addMessage (options: OverrideCommandOptions & { @@ -198,6 +220,7 @@ export class AbusesCommand extends AbstractCommand { path, fields: { message }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/overviews/overviews-command.ts b/shared/extra-utils/overviews/overviews-command.ts index 6f56b0ce4..e15644d94 100644 --- a/shared/extra-utils/overviews/overviews-command.ts +++ b/shared/extra-utils/overviews/overviews-command.ts @@ -7,7 +7,7 @@ export class OverviewsCommand extends AbstractCommand { getVideos (options: OverrideCommandOptions & { page: number }) { - const { token, page } = options + const { page } = options const path = '/api/v1/overviews/videos' const query = { page } @@ -15,9 +15,9 @@ export class OverviewsCommand extends AbstractCommand { return this.getRequestBody({ ...options, - token: token || null, path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts index d4cfab32b..7539a21ec 100644 --- a/shared/extra-utils/search/search-command.ts +++ b/shared/extra-utils/search/search-command.ts @@ -25,16 +25,15 @@ export class SearchCommand extends AbstractCommand { advancedChannelSearch (options: OverrideCommandOptions & { search: VideoChannelsSearchQuery }) { - const { search, token } = options + const { search } = options const path = '/api/v1/search/video-channels' return this.getRequestBody>({ ...options, - token: token || null, - path, query: search, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -52,16 +51,15 @@ export class SearchCommand extends AbstractCommand { advancedPlaylistSearch (options: OverrideCommandOptions & { search: VideoPlaylistsSearchQuery }) { - const { search, token } = options + const { search } = options const path = '/api/v1/search/video-playlists' return this.getRequestBody>({ ...options, - token: token || null, - path, query: search, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -85,16 +83,15 @@ export class SearchCommand extends AbstractCommand { advancedVideoSearch (options: OverrideCommandOptions & { search: VideosSearchQuery }) { - const { search, token } = options + const { search } = options const path = '/api/v1/search/videos' return this.getRequestBody>({ ...options, - token: token || null, - path, query: search, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/server/config-command.ts b/shared/extra-utils/server/config-command.ts index 959848706..f5d7fc5e3 100644 --- a/shared/extra-utils/server/config-command.ts +++ b/shared/extra-utils/server/config-command.ts @@ -24,8 +24,8 @@ export class ConfigCommand extends AbstractCommand { return this.getRequestBody({ ...options, - token: null, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -36,8 +36,8 @@ export class ConfigCommand extends AbstractCommand { return this.getRequestBody({ ...options, - token: null, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -49,6 +49,7 @@ export class ConfigCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -63,6 +64,7 @@ export class ConfigCommand extends AbstractCommand { path, fields: options.newCustomConfig, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -74,6 +76,7 @@ export class ConfigCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/server/contact-form-command.ts b/shared/extra-utils/server/contact-form-command.ts index 943e5ccbb..8d034552b 100644 --- a/shared/extra-utils/server/contact-form-command.ts +++ b/shared/extra-utils/server/contact-form-command.ts @@ -23,8 +23,8 @@ export class ContactFormCommand extends AbstractCommand { ...options, path, - token: null, fields: body, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/server/debug-command.ts b/shared/extra-utils/server/debug-command.ts index eecbb1711..8b24b3067 100644 --- a/shared/extra-utils/server/debug-command.ts +++ b/shared/extra-utils/server/debug-command.ts @@ -11,6 +11,7 @@ export class DebugCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -26,6 +27,7 @@ export class DebugCommand extends AbstractCommand { path, fields: body, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts index aba7bce82..4e1e56d7a 100644 --- a/shared/extra-utils/server/follows-command.ts +++ b/shared/extra-utils/server/follows-command.ts @@ -22,10 +22,9 @@ export class FollowsCommand extends AbstractCommand { return this.getRequestBody>({ ...options, - token: null, - path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -46,10 +45,9 @@ export class FollowsCommand extends AbstractCommand { return this.getRequestBody>({ ...options, - token: null, - path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -66,6 +64,7 @@ export class FollowsCommand extends AbstractCommand { path, fields: { hosts }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -79,6 +78,7 @@ export class FollowsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -92,6 +92,7 @@ export class FollowsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -105,6 +106,7 @@ export class FollowsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -118,6 +120,7 @@ export class FollowsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/server/jobs-command.ts b/shared/extra-utils/server/jobs-command.ts index 758b4a4af..392b868c1 100644 --- a/shared/extra-utils/server/jobs-command.ts +++ b/shared/extra-utils/server/jobs-command.ts @@ -21,6 +21,7 @@ export class JobsCommand extends AbstractCommand { path, query, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index f06e58a22..ff49d58c4 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -45,6 +45,7 @@ export class PluginsCommand extends AbstractCommand { pluginType, uninstalled }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -75,6 +76,7 @@ export class PluginsCommand extends AbstractCommand { path, query, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -88,6 +90,7 @@ export class PluginsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -104,6 +107,7 @@ export class PluginsCommand extends AbstractCommand { path, fields: { settings }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -117,6 +121,7 @@ export class PluginsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -131,6 +136,7 @@ export class PluginsCommand extends AbstractCommand { ...options, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -145,6 +151,7 @@ export class PluginsCommand extends AbstractCommand { ...options, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -161,6 +168,7 @@ export class PluginsCommand extends AbstractCommand { path: apiPath, fields: { npmName, path }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -177,6 +185,7 @@ export class PluginsCommand extends AbstractCommand { path: apiPath, fields: { npmName, path }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -192,6 +201,7 @@ export class PluginsCommand extends AbstractCommand { path: apiPath, fields: { npmName }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -203,6 +213,7 @@ export class PluginsCommand extends AbstractCommand { ...options, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -222,6 +233,7 @@ export class PluginsCommand extends AbstractCommand { path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200, redirects: 0 }) diff --git a/shared/extra-utils/server/redundancy-command.ts b/shared/extra-utils/server/redundancy-command.ts index d717d35f8..728332fdd 100644 --- a/shared/extra-utils/server/redundancy-command.ts +++ b/shared/extra-utils/server/redundancy-command.ts @@ -16,6 +16,7 @@ export class RedundancyCommand extends AbstractCommand { path, fields: { redundancyAllowed }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -42,6 +43,7 @@ export class RedundancyCommand extends AbstractCommand { target }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -57,6 +59,7 @@ export class RedundancyCommand extends AbstractCommand { path, fields: { videoId }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -71,6 +74,7 @@ export class RedundancyCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } diff --git a/shared/extra-utils/server/stats-command.ts b/shared/extra-utils/server/stats-command.ts index b51d9ceef..f0f02ca08 100644 --- a/shared/extra-utils/server/stats-command.ts +++ b/shared/extra-utils/server/stats-command.ts @@ -19,6 +19,7 @@ export class StatsCommand extends AbstractCommand { path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 38129d559..1e07e9469 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,13 @@ import { HttpStatusCode } from '@shared/core-utils' -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest, unwrapBody, unwrapText } from '../requests/requests' +import { + makeDeleteRequest, + makeGetRequest, + makePostBodyRequest, + makePutBodyRequest, + makeUploadRequest, + unwrapBody, + unwrapText +} from '../requests/requests' import { ServerInfo } from '../server/servers' export interface OverrideCommandOptions { @@ -7,12 +15,14 @@ export interface OverrideCommandOptions { expectedStatus?: number } -interface CommonCommandOptions extends OverrideCommandOptions { +interface InternalCommonCommandOptions extends OverrideCommandOptions { path: string + // If we automatically send the server token if the token is not provided + implicitToken: boolean defaultExpectedStatus: number } -interface GetCommandOptions extends CommonCommandOptions { +interface InternalGetCommandOptions extends InternalCommonCommandOptions { query?: { [ id: string ]: any } contentType?: string accept?: string @@ -37,15 +47,15 @@ abstract class AbstractCommand { this.expectedStatus = status } - protected getRequestBody (options: GetCommandOptions) { + protected getRequestBody (options: InternalGetCommandOptions) { return unwrapBody(this.getRequest(options)) } - protected getRequestText (options: GetCommandOptions) { + protected getRequestText (options: InternalGetCommandOptions) { return unwrapText(this.getRequest(options)) } - protected getRequest (options: GetCommandOptions) { + protected getRequest (options: InternalGetCommandOptions) { const { redirects, query, contentType, accept } = options return makeGetRequest({ @@ -58,11 +68,11 @@ abstract class AbstractCommand { }) } - protected deleteRequest (options: CommonCommandOptions) { + protected deleteRequest (options: InternalCommonCommandOptions) { return makeDeleteRequest(this.buildCommonRequestOptions(options)) } - protected putBodyRequest (options: CommonCommandOptions & { + protected putBodyRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } }) { const { fields } = options @@ -74,7 +84,7 @@ abstract class AbstractCommand { }) } - protected postBodyRequest (options: CommonCommandOptions & { + protected postBodyRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } }) { const { fields } = options @@ -86,7 +96,7 @@ abstract class AbstractCommand { }) } - protected postUploadRequest (options: CommonCommandOptions & { + protected postUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } attaches?: any }) { @@ -101,7 +111,7 @@ abstract class AbstractCommand { }) } - protected putUploadRequest (options: CommonCommandOptions & { + protected putUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } attaches?: any }) { @@ -116,15 +126,18 @@ abstract class AbstractCommand { }) } - private buildCommonRequestOptions (options: CommonCommandOptions) { + private buildCommonRequestOptions (options: InternalCommonCommandOptions) { const { token, expectedStatus, defaultExpectedStatus, path } = options + const fallbackToken = options.implicitToken + ? this.server.accessToken + : undefined + return { url: this.server.url, path, - // Token can be null if we don't want to add it - token: token !== undefined ? token : this.server.accessToken, + token: token !== undefined ? token : fallbackToken, statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } diff --git a/shared/extra-utils/users/accounts-command.ts b/shared/extra-utils/users/accounts-command.ts index 89c080e93..4cd1d2158 100644 --- a/shared/extra-utils/users/accounts-command.ts +++ b/shared/extra-utils/users/accounts-command.ts @@ -17,6 +17,7 @@ export class AccountsCommand extends AbstractCommand { path, query: { sort }, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -30,6 +31,7 @@ export class AccountsCommand extends AbstractCommand { ...options, path, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -48,6 +50,7 @@ export class AccountsCommand extends AbstractCommand { path, query, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/users/blocklist-command.ts b/shared/extra-utils/users/blocklist-command.ts index 96afdc3fd..089b5a579 100644 --- a/shared/extra-utils/users/blocklist-command.ts +++ b/shared/extra-utils/users/blocklist-command.ts @@ -56,6 +56,7 @@ export class BlocklistCommand extends AbstractCommand { accountName: account, host: server }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -78,6 +79,7 @@ export class BlocklistCommand extends AbstractCommand { accountName: account, host: server }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -98,6 +100,7 @@ export class BlocklistCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -116,6 +119,7 @@ export class BlocklistCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -128,6 +132,7 @@ export class BlocklistCommand extends AbstractCommand { path, query: { start, count, sort }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/users/subscriptions-command.ts b/shared/extra-utils/users/subscriptions-command.ts index 94d2af67a..e998eb426 100644 --- a/shared/extra-utils/users/subscriptions-command.ts +++ b/shared/extra-utils/users/subscriptions-command.ts @@ -14,6 +14,7 @@ export class SubscriptionsCommand extends AbstractCommand { path, fields: { uri: options.targetUri }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -33,6 +34,7 @@ export class SubscriptionsCommand extends AbstractCommand { sort, search }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -48,6 +50,7 @@ export class SubscriptionsCommand extends AbstractCommand { path, query: { sort }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -61,6 +64,7 @@ export class SubscriptionsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -74,6 +78,7 @@ export class SubscriptionsCommand extends AbstractCommand { ...options, path, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -88,6 +93,7 @@ export class SubscriptionsCommand extends AbstractCommand { path, query: { 'uris[]': options.uris }, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index e36c632ee..4f03c9127 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -23,6 +23,7 @@ export class LiveCommand extends AbstractCommand { ...options, path: path + '/' + options.videoId, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 }) } @@ -39,6 +40,7 @@ export class LiveCommand extends AbstractCommand { path: path + '/' + videoId, fields, + implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } @@ -59,6 +61,7 @@ export class LiveCommand extends AbstractCommand { path, attaches, fields: omit(fields, 'thumbnailfile', 'previewfile'), + implicitToken: true, defaultExpectedStatus: HttpStatusCode.OK_200 })) diff --git a/shared/extra-utils/videos/services-command.ts b/shared/extra-utils/videos/services-command.ts index 3b618ef66..313b7878c 100644 --- a/shared/extra-utils/videos/services-command.ts +++ b/shared/extra-utils/videos/services-command.ts @@ -22,6 +22,7 @@ export class ServicesCommand extends AbstractCommand { path, query, + implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) } -- cgit v1.2.3 From e3d15a6a9aed97a004d9dac1b7a6499d794e080a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 11:17:55 +0200 Subject: Introduce blacklist command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/videos/blacklist-command.ts | 77 +++++++++++++++++++++++++ shared/extra-utils/videos/index.ts | 2 +- shared/extra-utils/videos/video-blacklist.ts | 79 -------------------------- 4 files changed, 81 insertions(+), 81 deletions(-) create mode 100644 shared/extra-utils/videos/blacklist-command.ts delete mode 100644 shared/extra-utils/videos/video-blacklist.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index cb2a8814b..a4432902f 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { LiveCommand, ServicesCommand } from '../videos' +import { LiveCommand, ServicesCommand, BlacklistCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -102,6 +102,7 @@ interface ServerInfo { subscriptionsCommand?: SubscriptionsCommand liveCommand?: LiveCommand servicesCommand?: ServicesCommand + blacklistCommand?: BlacklistCommand } function parallelTests () { @@ -329,6 +330,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.subscriptionsCommand = new SubscriptionsCommand(server) server.liveCommand = new LiveCommand(server) server.servicesCommand = new ServicesCommand(server) + server.blacklistCommand = new BlacklistCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/blacklist-command.ts b/shared/extra-utils/videos/blacklist-command.ts new file mode 100644 index 000000000..fdae6b469 --- /dev/null +++ b/shared/extra-utils/videos/blacklist-command.ts @@ -0,0 +1,77 @@ + +import { ResultList } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { VideoBlacklist, VideoBlacklistType } from '../../models/videos' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class BlacklistCommand extends AbstractCommand { + + add (options: OverrideCommandOptions & { + videoId: number | string + reason?: string + unfederate?: boolean + }) { + const { videoId, reason, unfederate } = options + const path = '/api/v1/videos/' + videoId + '/blacklist' + + return this.postBodyRequest({ + ...options, + + path, + fields: { reason, unfederate }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + update (options: OverrideCommandOptions & { + videoId: number | string + reason?: string + }) { + const { videoId, reason } = options + const path = '/api/v1/videos/' + videoId + '/blacklist' + + return this.putBodyRequest({ + ...options, + + path, + fields: { reason }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + remove (options: OverrideCommandOptions & { + videoId: number | string + }) { + const { videoId } = options + const path = '/api/v1/videos/' + videoId + '/blacklist' + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + list (options: OverrideCommandOptions & { + sort?: string + type?: VideoBlacklistType + } = {}) { + const { sort, type } = options + const path = '/api/v1/videos/blacklist/' + + const query = { sort, type } + + return this.getRequestBody>({ + ...options, + + path, + query, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index fe5dc6655..67f5faf54 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -1,7 +1,7 @@ +export * from './blacklist-command' export * from './live-command' export * from './live' export * from './services-command' -export * from './video-blacklist' export * from './video-captions' export * from './video-change-ownership' export * from './video-channels' diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts deleted file mode 100644 index aa1548537..000000000 --- a/shared/extra-utils/videos/video-blacklist.ts +++ /dev/null @@ -1,79 +0,0 @@ -import * as request from 'supertest' -import { VideoBlacklistType } from '../../models/videos' -import { makeGetRequest } from '..' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function addVideoToBlacklist ( - url: string, - token: string, - videoId: number | string, - reason?: string, - unfederate?: boolean, - specialStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return request(url) - .post(path) - .send({ reason, unfederate }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(specialStatus) -} - -function updateVideoBlacklist ( - url: string, - token: string, - videoId: number, - reason?: string, - specialStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return request(url) - .put(path) - .send({ reason }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(specialStatus) -} - -function removeVideoFromBlacklist (url: string, token: string, videoId: number | string, specialStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return request(url) - .delete(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(specialStatus) -} - -function getBlacklistedVideosList (parameters: { - url: string - token: string - sort?: string - type?: VideoBlacklistType - specialStatus?: HttpStatusCode -}) { - const { url, token, sort, type, specialStatus = HttpStatusCode.OK_200 } = parameters - const path = '/api/v1/videos/blacklist/' - - const query = { sort, type } - - return makeGetRequest({ - url, - path, - query, - token, - statusCodeExpected: specialStatus - }) -} - -// --------------------------------------------------------------------------- - -export { - addVideoToBlacklist, - removeVideoFromBlacklist, - getBlacklistedVideosList, - updateVideoBlacklist -} -- cgit v1.2.3 From a2470c9f4bfc7f49f4b94de935bacdd53fd54f29 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 11:49:38 +0200 Subject: Introduce captions command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/videos/captions-command.ts | 66 ++++++++++++++++++++++++ shared/extra-utils/videos/captions.ts | 17 +++++++ shared/extra-utils/videos/index.ts | 3 +- shared/extra-utils/videos/video-captions.ts | 72 --------------------------- 5 files changed, 88 insertions(+), 74 deletions(-) create mode 100644 shared/extra-utils/videos/captions-command.ts create mode 100644 shared/extra-utils/videos/captions.ts delete mode 100644 shared/extra-utils/videos/video-captions.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index a4432902f..170360341 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { LiveCommand, ServicesCommand, BlacklistCommand } from '../videos' +import { LiveCommand, ServicesCommand, BlacklistCommand, CaptionsCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -103,6 +103,7 @@ interface ServerInfo { liveCommand?: LiveCommand servicesCommand?: ServicesCommand blacklistCommand?: BlacklistCommand + captionsCommand?: CaptionsCommand } function parallelTests () { @@ -331,6 +332,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.liveCommand = new LiveCommand(server) server.servicesCommand = new ServicesCommand(server) server.blacklistCommand = new BlacklistCommand(server) + server.captionsCommand = new CaptionsCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts new file mode 100644 index 000000000..908b6dae6 --- /dev/null +++ b/shared/extra-utils/videos/captions-command.ts @@ -0,0 +1,66 @@ +import { ResultList, VideoCaption } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { buildAbsoluteFixturePath } from '../miscs/miscs' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class CaptionsCommand extends AbstractCommand { + + createVideoCaption (options: OverrideCommandOptions & { + videoId: string | number + language: string + fixture: string + mimeType?: string + }) { + const { videoId, language, fixture, mimeType } = options + + const path = '/api/v1/videos/' + videoId + '/captions/' + language + + const captionfile = buildAbsoluteFixturePath(fixture) + const captionfileAttach = mimeType + ? [ captionfile, { contentType: mimeType } ] + : captionfile + + return this.putUploadRequest({ + ...options, + + path, + fields: {}, + attaches: { + captionfile: captionfileAttach + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + listVideoCaptions (options: OverrideCommandOptions & { + videoId: string | number + }) { + const { videoId } = options + const path = '/api/v1/videos/' + videoId + '/captions' + + return this.getRequestBody>({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + deleteVideoCaption (options: OverrideCommandOptions & { + videoId: string | number + language: string + }) { + const { videoId, language } = options + const path = '/api/v1/videos/' + videoId + '/captions/' + language + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/videos/captions.ts b/shared/extra-utils/videos/captions.ts new file mode 100644 index 000000000..2246bd133 --- /dev/null +++ b/shared/extra-utils/videos/captions.ts @@ -0,0 +1,17 @@ +import { expect } from 'chai' +import * as request from 'supertest' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' + +async function testCaptionFile (url: string, captionPath: string, containsString: string) { + const res = await request(url) + .get(captionPath) + .expect(HttpStatusCode.OK_200) + + expect(res.text).to.contain(containsString) +} + +// --------------------------------------------------------------------------- + +export { + testCaptionFile +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 67f5faf54..03b4756d5 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -1,8 +1,9 @@ export * from './blacklist-command' +export * from './captions' +export * from './captions-command' export * from './live-command' export * from './live' export * from './services-command' -export * from './video-captions' export * from './video-change-ownership' export * from './video-channels' export * from './video-comments' diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts deleted file mode 100644 index 62eec7b90..000000000 --- a/shared/extra-utils/videos/video-captions.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { makeDeleteRequest, makeGetRequest, makeUploadRequest } from '../requests/requests' -import * as request from 'supertest' -import * as chai from 'chai' -import { buildAbsoluteFixturePath } from '../miscs/miscs' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -const expect = chai.expect - -function createVideoCaption (args: { - url: string - accessToken: string - videoId: string | number - language: string - fixture: string - mimeType?: string - statusCodeExpected?: number -}) { - const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language - - const captionfile = buildAbsoluteFixturePath(args.fixture) - const captionfileAttach = args.mimeType ? [ captionfile, { contentType: args.mimeType } ] : captionfile - - return makeUploadRequest({ - method: 'PUT', - url: args.url, - path, - token: args.accessToken, - fields: {}, - attaches: { - captionfile: captionfileAttach - }, - statusCodeExpected: args.statusCodeExpected || HttpStatusCode.NO_CONTENT_204 - }) -} - -function listVideoCaptions (url: string, videoId: string | number) { - const path = '/api/v1/videos/' + videoId + '/captions' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function deleteVideoCaption (url: string, token: string, videoId: string | number, language: string) { - const path = '/api/v1/videos/' + videoId + '/captions/' + language - - return makeDeleteRequest({ - url, - token, - path, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -async function testCaptionFile (url: string, captionPath: string, containsString: string) { - const res = await request(url) - .get(captionPath) - .expect(HttpStatusCode.OK_200) - - expect(res.text).to.contain(containsString) -} - -// --------------------------------------------------------------------------- - -export { - createVideoCaption, - listVideoCaptions, - testCaptionFile, - deleteVideoCaption -} -- cgit v1.2.3 From 72cbfc5695ec5ebdb9721d3648218f63feeaeac5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 13:56:04 +0200 Subject: Introduce change ownership command --- shared/extra-utils/server/servers.ts | 4 +- .../extra-utils/videos/change-ownership-command.ts | 69 +++++++++++++++++++++ shared/extra-utils/videos/index.ts | 2 +- .../extra-utils/videos/video-change-ownership.ts | 72 ---------------------- 4 files changed, 73 insertions(+), 74 deletions(-) create mode 100644 shared/extra-utils/videos/change-ownership-command.ts delete mode 100644 shared/extra-utils/videos/video-change-ownership.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 170360341..33f558414 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { LiveCommand, ServicesCommand, BlacklistCommand, CaptionsCommand } from '../videos' +import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, LiveCommand, ServicesCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -104,6 +104,7 @@ interface ServerInfo { servicesCommand?: ServicesCommand blacklistCommand?: BlacklistCommand captionsCommand?: CaptionsCommand + changeOwnershipCommand?: ChangeOwnershipCommand } function parallelTests () { @@ -333,6 +334,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.servicesCommand = new ServicesCommand(server) server.blacklistCommand = new BlacklistCommand(server) server.captionsCommand = new CaptionsCommand(server) + server.changeOwnershipCommand = new ChangeOwnershipCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/change-ownership-command.ts b/shared/extra-utils/videos/change-ownership-command.ts new file mode 100644 index 000000000..03f77a95f --- /dev/null +++ b/shared/extra-utils/videos/change-ownership-command.ts @@ -0,0 +1,69 @@ + +import { ResultList, VideoChangeOwnership } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ChangeOwnershipCommand extends AbstractCommand { + + create (options: OverrideCommandOptions & { + videoId: number | string + username: string + }) { + const { videoId, username } = options + const path = '/api/v1/videos/' + videoId + '/give-ownership' + + return this.postBodyRequest({ + ...options, + + path, + fields: { username }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + list (options: OverrideCommandOptions = {}) { + const path = '/api/v1/videos/ownership' + + return this.getRequestBody>({ + ...options, + + path, + query: { sort: '-createdAt' }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + accept (options: OverrideCommandOptions & { + ownershipId: number + channelId: number + }) { + const { ownershipId, channelId } = options + const path = '/api/v1/videos/ownership/' + ownershipId + '/accept' + + return this.postBodyRequest({ + ...options, + + path, + fields: { channelId }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + refuse (options: OverrideCommandOptions & { + ownershipId: number + }) { + const { ownershipId } = options + const path = '/api/v1/videos/ownership/' + ownershipId + '/refuse' + + return this.postBodyRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 03b4756d5..815c7f944 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -1,10 +1,10 @@ export * from './blacklist-command' export * from './captions' export * from './captions-command' +export * from './change-ownership-command' export * from './live-command' export * from './live' export * from './services-command' -export * from './video-change-ownership' export * from './video-channels' export * from './video-comments' export * from './video-history' diff --git a/shared/extra-utils/videos/video-change-ownership.ts b/shared/extra-utils/videos/video-change-ownership.ts deleted file mode 100644 index ef82a7636..000000000 --- a/shared/extra-utils/videos/video-change-ownership.ts +++ /dev/null @@ -1,72 +0,0 @@ -import * as request from 'supertest' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function changeVideoOwnership ( - url: string, - token: string, - videoId: number | string, - username, - expectedStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + videoId + '/give-ownership' - - return request(url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .send({ username }) - .expect(expectedStatus) -} - -function getVideoChangeOwnershipList (url: string, token: string) { - const path = '/api/v1/videos/ownership' - - return request(url) - .get(path) - .query({ sort: '-createdAt' }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function acceptChangeOwnership ( - url: string, - token: string, - ownershipId: string, - channelId: number, - expectedStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/ownership/' + ownershipId + '/accept' - - return request(url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .send({ channelId }) - .expect(expectedStatus) -} - -function refuseChangeOwnership ( - url: string, - token: string, - ownershipId: string, - expectedStatus = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/ownership/' + ownershipId + '/refuse' - - return request(url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -// --------------------------------------------------------------------------- - -export { - changeVideoOwnership, - getVideoChangeOwnershipList, - acceptChangeOwnership, - refuseChangeOwnership -} -- cgit v1.2.3 From e6346d59e63135cf012ed18c102d3b0179ef565f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 15:54:39 +0200 Subject: Introduce playlist command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/videos/index.ts | 3 +- shared/extra-utils/videos/playlists-command.ts | 280 ++++++++++++++++++++++ shared/extra-utils/videos/playlists.ts | 25 ++ shared/extra-utils/videos/video-playlists.ts | 320 ------------------------- shared/extra-utils/videos/videos.ts | 23 -- 6 files changed, 310 insertions(+), 345 deletions(-) create mode 100644 shared/extra-utils/videos/playlists-command.ts create mode 100644 shared/extra-utils/videos/playlists.ts delete mode 100644 shared/extra-utils/videos/video-playlists.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 33f558414..78b3be9c7 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, LiveCommand, ServicesCommand } from '../videos' +import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, LiveCommand, PlaylistsCommand, ServicesCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -105,6 +105,7 @@ interface ServerInfo { blacklistCommand?: BlacklistCommand captionsCommand?: CaptionsCommand changeOwnershipCommand?: ChangeOwnershipCommand + playlistsCommand?: PlaylistsCommand } function parallelTests () { @@ -335,6 +336,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.blacklistCommand = new BlacklistCommand(server) server.captionsCommand = new CaptionsCommand(server) server.changeOwnershipCommand = new ChangeOwnershipCommand(server) + server.playlistsCommand = new PlaylistsCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 815c7f944..1f6241d7e 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -4,11 +4,12 @@ export * from './captions-command' export * from './change-ownership-command' export * from './live-command' export * from './live' +export * from './playlists-command' +export * from './playlists' export * from './services-command' export * from './video-channels' export * from './video-comments' export * from './video-history' export * from './video-imports' -export * from './video-playlists' export * from './video-streaming-playlists' export * from './videos' diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts new file mode 100644 index 000000000..f77decc1a --- /dev/null +++ b/shared/extra-utils/videos/playlists-command.ts @@ -0,0 +1,280 @@ +import { omit, pick } from 'lodash' +import { + BooleanBothQuery, + ResultList, + VideoExistInPlaylist, + VideoPlaylist, + VideoPlaylistCreateResult, + VideoPlaylistElement, + VideoPlaylistElementCreateResult, + VideoPlaylistReorder +} from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model' +import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model' +import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model' +import { VideoPlaylistType } from '../../models/videos/playlist/video-playlist-type.model' +import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' +import { videoUUIDToId } from './videos' + +export class PlaylistsCommand extends AbstractCommand { + + list (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + }) { + const path = '/api/v1/video-playlists' + const query = pick(options, [ 'start', 'count', 'sort' ]) + + return this.getRequestBody>({ + ...options, + + path, + query, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listByChannel (options: OverrideCommandOptions & { + handle: string + start?: number + count?: number + sort?: string + }) { + const path = '/api/v1/video-channels/' + options.handle + '/video-playlists' + const query = pick(options, [ 'start', 'count', 'sort' ]) + + return this.getRequestBody>({ + ...options, + + path, + query, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listByAccount (options: OverrideCommandOptions & { + handle: string + start?: number + count?: number + sort?: string + search?: string + playlistType?: VideoPlaylistType + }) { + const path = '/api/v1/accounts/' + options.handle + '/video-playlists' + const query = pick(options, [ 'start', 'count', 'sort', 'search', 'playlistType' ]) + + return this.getRequestBody>({ + ...options, + + path, + query, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + get (options: OverrideCommandOptions & { + playlistId: number | string + }) { + const { playlistId } = options + const path = '/api/v1/video-playlists/' + playlistId + + return this.getRequestBody({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listVideos (options: OverrideCommandOptions & { + playlistId: number | string + start?: number + count?: number + query?: { nsfw?: BooleanBothQuery } + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' + const query = options.query ?? {} + + return this.getRequestBody>({ + ...options, + + path, + query: { + ...query, + start: options.start, + count: options.count + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + delete (options: OverrideCommandOptions & { + playlistId: number | string + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async create (options: OverrideCommandOptions & { + attributes: VideoPlaylistCreate + }) { + const path = '/api/v1/video-playlists' + + const fields = omit(options.attributes, 'thumbnailfile') + + const attaches = options.attributes.thumbnailfile + ? { thumbnailfile: options.attributes.thumbnailfile } + : {} + + const body = await unwrapBody<{ videoPlaylist: VideoPlaylistCreateResult }>(this.postUploadRequest({ + ...options, + + path, + fields, + attaches, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.videoPlaylist + } + + update (options: OverrideCommandOptions & { + attributes: VideoPlaylistUpdate + playlistId: number | string + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + + const fields = omit(options.attributes, 'thumbnailfile') + + const attaches = options.attributes.thumbnailfile + ? { thumbnailfile: options.attributes.thumbnailfile } + : {} + + return this.putUploadRequest({ + ...options, + + path, + fields, + attaches, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async addElement (options: OverrideCommandOptions & { + playlistId: number | string + attributes: VideoPlaylistElementCreate | { videoId: string } + }) { + const attributes = { + ...options.attributes, + + videoId: await videoUUIDToId(this.server.url, options.attributes.videoId) + } + + const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' + + const body = await unwrapBody<{ videoPlaylistElement: VideoPlaylistElementCreateResult }>(this.postBodyRequest({ + ...options, + + path, + fields: attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.videoPlaylistElement + } + + updateElement (options: OverrideCommandOptions & { + playlistId: number | string + elementId: number | string + attributes: VideoPlaylistElementUpdate + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.elementId + + return this.putBodyRequest({ + ...options, + + path, + fields: options.attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + removeElement (options: OverrideCommandOptions & { + playlistId: number | string + elementId: number + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.elementId + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + reorderElements (options: OverrideCommandOptions & { + playlistId: number | string + attributes: VideoPlaylistReorder + }) { + const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' + + return this.postBodyRequest({ + ...options, + + path, + fields: options.attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + getPrivacies (options: OverrideCommandOptions = {}) { + const path = '/api/v1/video-playlists/privacies' + + return this.getRequestBody<{ [ id: number ]: string }>({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + videosExist (options: OverrideCommandOptions & { + videoIds: number[] + }) { + const { videoIds } = options + const path = '/api/v1/users/me/video-playlists/videos-exist' + + return this.getRequestBody({ + ...options, + + path, + query: { videoIds }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/videos/playlists.ts b/shared/extra-utils/videos/playlists.ts new file mode 100644 index 000000000..023333c87 --- /dev/null +++ b/shared/extra-utils/videos/playlists.ts @@ -0,0 +1,25 @@ +import { expect } from 'chai' +import { readdir } from 'fs-extra' +import { join } from 'path' +import { root } from '../' + +async function checkPlaylistFilesWereRemoved ( + playlistUUID: string, + internalServerNumber: number, + directories = [ 'thumbnails' ] +) { + const testDirectory = 'test' + internalServerNumber + + for (const directory of directories) { + const directoryPath = join(root(), testDirectory, directory) + + const files = await readdir(directoryPath) + for (const file of files) { + expect(file).to.not.contain(playlistUUID) + } + } +} + +export { + checkPlaylistFilesWereRemoved +} diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts deleted file mode 100644 index c6f799e5d..000000000 --- a/shared/extra-utils/videos/video-playlists.ts +++ /dev/null @@ -1,320 +0,0 @@ -import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests' -import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model' -import { omit } from 'lodash' -import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model' -import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model' -import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model' -import { videoUUIDToId } from './videos' -import { join } from 'path' -import { root } from '..' -import { readdir } from 'fs-extra' -import { expect } from 'chai' -import { VideoPlaylistType } from '../../models/videos/playlist/video-playlist-type.model' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getVideoPlaylistsList (url: string, start: number, count: number, sort?: string) { - const path = '/api/v1/video-playlists' - - const query = { - start, - count, - sort - } - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoChannelPlaylistsList (url: string, videoChannelName: string, start: number, count: number, sort?: string) { - const path = '/api/v1/video-channels/' + videoChannelName + '/video-playlists' - - const query = { - start, - count, - sort - } - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getAccountPlaylistsList (url: string, accountName: string, start: number, count: number, sort?: string, search?: string) { - const path = '/api/v1/accounts/' + accountName + '/video-playlists' - - const query = { - start, - count, - sort, - search - } - - return makeGetRequest({ - url, - path, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getAccountPlaylistsListWithToken ( - url: string, - token: string, - accountName: string, - start: number, - count: number, - playlistType?: VideoPlaylistType, - sort?: string -) { - const path = '/api/v1/accounts/' + accountName + '/video-playlists' - - const query = { - start, - count, - playlistType, - sort - } - - return makeGetRequest({ - url, - token, - path, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoPlaylist (url: string, playlistId: number | string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/video-playlists/' + playlistId - - return makeGetRequest({ - url, - path, - statusCodeExpected - }) -} - -function getVideoPlaylistWithToken (url: string, token: string, playlistId: number | string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/video-playlists/' + playlistId - - return makeGetRequest({ - url, - token, - path, - statusCodeExpected - }) -} - -function deleteVideoPlaylist (url: string, token: string, playlistId: number | string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/video-playlists/' + playlistId - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function createVideoPlaylist (options: { - url: string - token: string - playlistAttrs: VideoPlaylistCreate - expectedStatus?: number -}) { - const path = '/api/v1/video-playlists' - - const fields = omit(options.playlistAttrs, 'thumbnailfile') - - const attaches = options.playlistAttrs.thumbnailfile - ? { thumbnailfile: options.playlistAttrs.thumbnailfile } - : {} - - return makeUploadRequest({ - method: 'POST', - url: options.url, - path, - token: options.token, - fields, - attaches, - statusCodeExpected: options.expectedStatus || HttpStatusCode.OK_200 - }) -} - -function updateVideoPlaylist (options: { - url: string - token: string - playlistAttrs: VideoPlaylistUpdate - playlistId: number | string - expectedStatus?: number -}) { - const path = '/api/v1/video-playlists/' + options.playlistId - - const fields = omit(options.playlistAttrs, 'thumbnailfile') - - const attaches = options.playlistAttrs.thumbnailfile - ? { thumbnailfile: options.playlistAttrs.thumbnailfile } - : {} - - return makeUploadRequest({ - method: 'PUT', - url: options.url, - path, - token: options.token, - fields, - attaches, - statusCodeExpected: options.expectedStatus || HttpStatusCode.NO_CONTENT_204 - }) -} - -async function addVideoInPlaylist (options: { - url: string - token: string - playlistId: number | string - elementAttrs: VideoPlaylistElementCreate | { videoId: string } - expectedStatus?: number -}) { - options.elementAttrs.videoId = await videoUUIDToId(options.url, options.elementAttrs.videoId) - - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' - - return makePostBodyRequest({ - url: options.url, - path, - token: options.token, - fields: options.elementAttrs, - statusCodeExpected: options.expectedStatus || HttpStatusCode.OK_200 - }) -} - -function updateVideoPlaylistElement (options: { - url: string - token: string - playlistId: number | string - playlistElementId: number | string - elementAttrs: VideoPlaylistElementUpdate - expectedStatus?: number -}) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId - - return makePutBodyRequest({ - url: options.url, - path, - token: options.token, - fields: options.elementAttrs, - statusCodeExpected: options.expectedStatus || HttpStatusCode.NO_CONTENT_204 - }) -} - -function removeVideoFromPlaylist (options: { - url: string - token: string - playlistId: number | string - playlistElementId: number - expectedStatus?: number -}) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId - - return makeDeleteRequest({ - url: options.url, - path, - token: options.token, - statusCodeExpected: options.expectedStatus || HttpStatusCode.NO_CONTENT_204 - }) -} - -function reorderVideosPlaylist (options: { - url: string - token: string - playlistId: number | string - elementAttrs: { - startPosition: number - insertAfterPosition: number - reorderLength?: number - } - expectedStatus?: number -}) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' - - return makePostBodyRequest({ - url: options.url, - path, - token: options.token, - fields: options.elementAttrs, - statusCodeExpected: options.expectedStatus || HttpStatusCode.NO_CONTENT_204 - }) -} - -async function checkPlaylistFilesWereRemoved ( - playlistUUID: string, - internalServerNumber: number, - directories = [ 'thumbnails' ] -) { - const testDirectory = 'test' + internalServerNumber - - for (const directory of directories) { - const directoryPath = join(root(), testDirectory, directory) - - const files = await readdir(directoryPath) - for (const file of files) { - expect(file).to.not.contain(playlistUUID) - } - } -} - -function getVideoPlaylistPrivacies (url: string) { - const path = '/api/v1/video-playlists/privacies' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function doVideosExistInMyPlaylist (url: string, token: string, videoIds: number[]) { - const path = '/api/v1/users/me/video-playlists/videos-exist' - - return makeGetRequest({ - url, - token, - path, - query: { videoIds }, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -// --------------------------------------------------------------------------- - -export { - getVideoPlaylistPrivacies, - - getVideoPlaylistsList, - getVideoChannelPlaylistsList, - getAccountPlaylistsList, - getAccountPlaylistsListWithToken, - - getVideoPlaylist, - getVideoPlaylistWithToken, - - createVideoPlaylist, - updateVideoPlaylist, - deleteVideoPlaylist, - - addVideoInPlaylist, - updateVideoPlaylistElement, - removeVideoFromPlaylist, - - reorderVideosPlaylist, - - checkPlaylistFilesWereRemoved, - - doVideosExistInMyPlaylist -} diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index a45c0402a..920c93072 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -262,28 +262,6 @@ function getVideoChannelVideos ( }) } -function getPlaylistVideos ( - url: string, - accessToken: string, - playlistId: number | string, - start: number, - count: number, - query: { nsfw?: boolean } = {} -) { - const path = '/api/v1/video-playlists/' + playlistId + '/videos' - - return makeGetRequest({ - url, - path, - query: immutableAssign(query, { - start, - count - }), - token: accessToken, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - function getVideosListPagination (url: string, start: number, count: number, sort?: string, skipCount?: boolean) { const path = '/api/v1/videos' @@ -871,7 +849,6 @@ export { getLocalVideos, completeVideoCheck, checkVideoFilesWereRemoved, - getPlaylistVideos, getMyVideosWithFilter, uploadVideoAndGetId, getLocalIdByUUID, -- cgit v1.2.3 From 313228e9c3b5bcef5391228c9b949d05d32ad7bb Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 16:21:42 +0200 Subject: Introduce history command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/videos/history-command.ts | 59 ++++++++++++++++++++++++++++ shared/extra-utils/videos/index.ts | 2 +- shared/extra-utils/videos/video-history.ts | 49 ----------------------- 4 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 shared/extra-utils/videos/history-command.ts delete mode 100644 shared/extra-utils/videos/video-history.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 78b3be9c7..bd5c29e51 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,7 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, LiveCommand, PlaylistsCommand, ServicesCommand } from '../videos' +import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, HistoryCommand, LiveCommand, PlaylistsCommand, ServicesCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -106,6 +106,7 @@ interface ServerInfo { captionsCommand?: CaptionsCommand changeOwnershipCommand?: ChangeOwnershipCommand playlistsCommand?: PlaylistsCommand + historyCommand?: HistoryCommand } function parallelTests () { @@ -337,6 +338,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.captionsCommand = new CaptionsCommand(server) server.changeOwnershipCommand = new ChangeOwnershipCommand(server) server.playlistsCommand = new PlaylistsCommand(server) + server.historyCommand = new HistoryCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/history-command.ts b/shared/extra-utils/videos/history-command.ts new file mode 100644 index 000000000..8a144a312 --- /dev/null +++ b/shared/extra-utils/videos/history-command.ts @@ -0,0 +1,59 @@ +import { ResultList, Video } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class HistoryCommand extends AbstractCommand { + + wathVideo (options: OverrideCommandOptions & { + videoId: number | string + currentTime: number + }) { + const { videoId, currentTime } = options + + const path = '/api/v1/videos/' + videoId + '/watching' + const fields = { currentTime } + + return this.putBodyRequest({ + ...options, + + path, + fields, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + list (options: OverrideCommandOptions & { + search?: string + } = {}) { + const { search } = options + const path = '/api/v1/users/me/history/videos' + + return this.getRequestBody>({ + ...options, + + path, + query: { + search + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + remove (options: OverrideCommandOptions & { + beforeDate?: string + } = {}) { + const { beforeDate } = options + const path = '/api/v1/users/me/history/videos/remove' + + return this.postBodyRequest({ + ...options, + + path, + fields: { beforeDate }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 1f6241d7e..74667fc06 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -2,6 +2,7 @@ export * from './blacklist-command' export * from './captions' export * from './captions-command' export * from './change-ownership-command' +export * from './history-command' export * from './live-command' export * from './live' export * from './playlists-command' @@ -9,7 +10,6 @@ export * from './playlists' export * from './services-command' export * from './video-channels' export * from './video-comments' -export * from './video-history' export * from './video-imports' export * from './video-streaming-playlists' export * from './videos' diff --git a/shared/extra-utils/videos/video-history.ts b/shared/extra-utils/videos/video-history.ts deleted file mode 100644 index b989e14dc..000000000 --- a/shared/extra-utils/videos/video-history.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function userWatchVideo ( - url: string, - token: string, - videoId: number | string, - currentTime: number, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + videoId + '/watching' - const fields = { currentTime } - - return makePutBodyRequest({ url, path, token, fields, statusCodeExpected }) -} - -function listMyVideosHistory (url: string, token: string, search?: string) { - const path = '/api/v1/users/me/history/videos' - - return makeGetRequest({ - url, - path, - token, - query: { - search - }, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function removeMyVideosHistory (url: string, token: string, beforeDate?: string) { - const path = '/api/v1/users/me/history/videos/remove' - - return makePostBodyRequest({ - url, - path, - token, - fields: beforeDate ? { beforeDate } : {}, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -// --------------------------------------------------------------------------- - -export { - userWatchVideo, - listMyVideosHistory, - removeMyVideosHistory -} -- cgit v1.2.3 From 6910f20f114b5bd020258a3a9a3f2117819a60c2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 8 Jul 2021 16:49:51 +0200 Subject: Introduce import command --- shared/extra-utils/server/servers.ts | 13 +++- shared/extra-utils/videos/imports-command.ts | 86 ++++++++++++++++++++++++++ shared/extra-utils/videos/index.ts | 2 +- shared/extra-utils/videos/video-imports.ts | 90 ---------------------------- 4 files changed, 99 insertions(+), 92 deletions(-) create mode 100644 shared/extra-utils/videos/imports-command.ts delete mode 100644 shared/extra-utils/videos/video-imports.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index bd5c29e51..95c876110 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -18,7 +18,16 @@ import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' -import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, HistoryCommand, LiveCommand, PlaylistsCommand, ServicesCommand } from '../videos' +import { + BlacklistCommand, + CaptionsCommand, + ChangeOwnershipCommand, + HistoryCommand, + ImportsCommand, + LiveCommand, + PlaylistsCommand, + ServicesCommand +} from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -107,6 +116,7 @@ interface ServerInfo { changeOwnershipCommand?: ChangeOwnershipCommand playlistsCommand?: PlaylistsCommand historyCommand?: HistoryCommand + importsCommand?: ImportsCommand } function parallelTests () { @@ -339,6 +349,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.changeOwnershipCommand = new ChangeOwnershipCommand(server) server.playlistsCommand = new PlaylistsCommand(server) server.historyCommand = new HistoryCommand(server) + server.importsCommand = new ImportsCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/imports-command.ts b/shared/extra-utils/videos/imports-command.ts new file mode 100644 index 000000000..024aa363f --- /dev/null +++ b/shared/extra-utils/videos/imports-command.ts @@ -0,0 +1,86 @@ + +import { ResultList } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { VideoImport, VideoImportCreate } from '../../models/videos' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ImportsCommand extends AbstractCommand { + + static getYoutubeVideoUrl () { + return 'https://www.youtube.com/watch?v=msX3jv1XdvM' + } + + static getYoutubeHDRVideoUrl () { + /** + * The video is used to check format-selection correctness wrt. HDR, + * which brings its own set of oddities outside of a MediaSource. + * FIXME: refactor once HDR is supported at playback + * + * The video needs to have the following format_ids: + * (which you can check by using `youtube-dl -F`): + * - 303 (1080p webm vp9) + * - 299 (1080p mp4 avc1) + * - 335 (1080p webm vp9.2 HDR) + * + * 15 jan. 2021: TEST VIDEO NOT CURRENTLY PROVIDING + * - 400 (1080p mp4 av01) + * - 315 (2160p webm vp9 HDR) + * - 337 (2160p webm vp9.2 HDR) + * - 401 (2160p mp4 av01 HDR) + */ + return 'https://www.youtube.com/watch?v=qR5vOXbZsI4' + } + + static getMagnetURI () { + // eslint-disable-next-line max-len + 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' + } + + static getBadVideoUrl () { + return 'https://download.cpy.re/peertube/bad_video.mp4' + } + + static getGoodVideoUrl () { + return 'https://download.cpy.re/peertube/good_video.mp4' + } + + importVideo (options: OverrideCommandOptions & { + attributes: VideoImportCreate & { torrentfile?: string } + }) { + const { attributes } = options + const path = '/api/v1/videos/imports' + + let attaches: any = {} + if (attributes.torrentfile) attaches = { torrentfile: attributes.torrentfile } + + return unwrapBody(this.postUploadRequest({ + ...options, + + path, + attaches, + fields: options.attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + getMyVideoImports (options: OverrideCommandOptions & { + sort?: string + } = {}) { + const { sort } = options + const path = '/api/v1/users/me/videos/imports' + + const query = {} + if (sort) query['sort'] = sort + + return this.getRequestBody>({ + ...options, + + path, + query: { sort }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 74667fc06..372cf7a90 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -3,6 +3,7 @@ export * from './captions' export * from './captions-command' export * from './change-ownership-command' export * from './history-command' +export * from './imports-command' export * from './live-command' export * from './live' export * from './playlists-command' @@ -10,6 +11,5 @@ export * from './playlists' export * from './services-command' export * from './video-channels' export * from './video-comments' -export * from './video-imports' export * from './video-streaming-playlists' export * from './videos' diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts deleted file mode 100644 index 81c0163cb..000000000 --- a/shared/extra-utils/videos/video-imports.ts +++ /dev/null @@ -1,90 +0,0 @@ - -import { VideoImportCreate } from '../../models/videos' -import { makeGetRequest, makeUploadRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getYoutubeVideoUrl () { - return 'https://www.youtube.com/watch?v=msX3jv1XdvM' -} - -function getYoutubeHDRVideoUrl () { - /** - * The video is used to check format-selection correctness wrt. HDR, - * which brings its own set of oddities outside of a MediaSource. - * FIXME: refactor once HDR is supported at playback - * - * The video needs to have the following format_ids: - * (which you can check by using `youtube-dl -F`): - * - 303 (1080p webm vp9) - * - 299 (1080p mp4 avc1) - * - 335 (1080p webm vp9.2 HDR) - * - * 15 jan. 2021: TEST VIDEO NOT CURRENTLY PROVIDING - * - 400 (1080p mp4 av01) - * - 315 (2160p webm vp9 HDR) - * - 337 (2160p webm vp9.2 HDR) - * - 401 (2160p mp4 av01 HDR) - */ - return 'https://www.youtube.com/watch?v=qR5vOXbZsI4' -} - -function getMagnetURI () { - // eslint-disable-next-line max-len - 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' -} - -function getBadVideoUrl () { - return 'https://download.cpy.re/peertube/bad_video.mp4' -} - -function getGoodVideoUrl () { - return 'https://download.cpy.re/peertube/good_video.mp4' -} - -function importVideo ( - url: string, - token: string, - attributes: VideoImportCreate & { torrentfile?: string }, - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/videos/imports' - - let attaches: any = {} - if (attributes.torrentfile) attaches = { torrentfile: attributes.torrentfile } - - return makeUploadRequest({ - url, - path, - token, - attaches, - fields: attributes, - statusCodeExpected - }) -} - -function getMyVideoImports (url: string, token: string, sort?: string) { - const path = '/api/v1/users/me/videos/imports' - - const query = {} - if (sort) query['sort'] = sort - - return makeGetRequest({ - url, - query, - path, - token, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -// --------------------------------------------------------------------------- - -export { - getBadVideoUrl, - getYoutubeVideoUrl, - getYoutubeHDRVideoUrl, - importVideo, - getMagnetURI, - getMyVideoImports, - getGoodVideoUrl -} -- cgit v1.2.3 From 57f879a540551c3b958b0991c8e1e3657a4481d8 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 10:21:10 +0200 Subject: Introduce streaming playlists command --- shared/extra-utils/server/servers.ts | 5 +- shared/extra-utils/shared/abstract-command.ts | 45 ++++++++++-- shared/extra-utils/videos/index.ts | 3 +- .../videos/streaming-playlists-command.ts | 45 ++++++++++++ shared/extra-utils/videos/streaming-playlists.ts | 76 ++++++++++++++++++++ .../videos/video-streaming-playlists.ts | 82 ---------------------- 6 files changed, 165 insertions(+), 91 deletions(-) create mode 100644 shared/extra-utils/videos/streaming-playlists-command.ts create mode 100644 shared/extra-utils/videos/streaming-playlists.ts delete mode 100644 shared/extra-utils/videos/video-streaming-playlists.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 95c876110..6a1dadbcc 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -26,7 +26,8 @@ import { ImportsCommand, LiveCommand, PlaylistsCommand, - ServicesCommand + ServicesCommand, + StreamingPlaylistsCommand } from '../videos' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' @@ -117,6 +118,7 @@ interface ServerInfo { playlistsCommand?: PlaylistsCommand historyCommand?: HistoryCommand importsCommand?: ImportsCommand + streamingPlaylistsCommand?: StreamingPlaylistsCommand } function parallelTests () { @@ -350,6 +352,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.playlistsCommand = new PlaylistsCommand(server) server.historyCommand = new HistoryCommand(server) server.importsCommand = new ImportsCommand(server) + server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 1e07e9469..be368376f 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -16,6 +16,9 @@ export interface OverrideCommandOptions { } interface InternalCommonCommandOptions extends OverrideCommandOptions { + // Default to server.url + url?: string + path: string // If we automatically send the server token if the token is not provided implicitToken: boolean @@ -27,6 +30,7 @@ interface InternalGetCommandOptions extends InternalCommonCommandOptions { contentType?: string accept?: string redirects?: number + range?: string } abstract class AbstractCommand { @@ -55,6 +59,22 @@ abstract class AbstractCommand { return unwrapText(this.getRequest(options)) } + protected getRawRequest (options: Omit) { + const { url, range } = options + const { host, protocol, pathname } = new URL(url) + + return this.getRequest({ + ...options, + + token: this.buildCommonRequestToken(options), + defaultExpectedStatus: this.buildStatusCodeExpected(options), + + url: `${protocol}//${host}`, + path: pathname, + range + }) + } + protected getRequest (options: InternalGetCommandOptions) { const { redirects, query, contentType, accept } = options @@ -127,20 +147,31 @@ abstract class AbstractCommand { } private buildCommonRequestOptions (options: InternalCommonCommandOptions) { - const { token, expectedStatus, defaultExpectedStatus, path } = options + const { path } = options + + return { + url: this.server.url, + path, + + token: this.buildCommonRequestToken(options), + statusCodeExpected: this.buildStatusCodeExpected(options) + } + } + + private buildCommonRequestToken (options: Pick) { + const { token } = options const fallbackToken = options.implicitToken ? this.server.accessToken : undefined - return { - url: this.server.url, - path, + return token !== undefined ? token : fallbackToken + } - token: token !== undefined ? token : fallbackToken, + private buildStatusCodeExpected (options: Pick) { + const { expectedStatus, defaultExpectedStatus } = options - statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus - } + return expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus } } diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 372cf7a90..f87ae8eea 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -9,7 +9,8 @@ export * from './live' export * from './playlists-command' export * from './playlists' export * from './services-command' +export * from './streaming-playlists-command' +export * from './streaming-playlists' export * from './video-channels' export * from './video-comments' -export * from './video-streaming-playlists' export * from './videos' diff --git a/shared/extra-utils/videos/streaming-playlists-command.ts b/shared/extra-utils/videos/streaming-playlists-command.ts new file mode 100644 index 000000000..4caec7137 --- /dev/null +++ b/shared/extra-utils/videos/streaming-playlists-command.ts @@ -0,0 +1,45 @@ + +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { unwrapBody, unwrapText } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class StreamingPlaylistsCommand extends AbstractCommand { + + get (options: OverrideCommandOptions & { + url: string + }) { + return unwrapText(this.getRawRequest({ + ...options, + + url: options.url, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + getSegment (options: OverrideCommandOptions & { + url: string + range?: string + }) { + return unwrapText(this.getRawRequest({ + ...options, + + url: options.url, + range: options.range, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200, + })) + } + + getSegmentSha256 (options: OverrideCommandOptions & { + url: string + }) { + return unwrapBody<{ [ id: string ]: string }>(this.getRawRequest({ + ...options, + + url: options.url, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } +} diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts new file mode 100644 index 000000000..0324c739a --- /dev/null +++ b/shared/extra-utils/videos/streaming-playlists.ts @@ -0,0 +1,76 @@ +import { expect } from 'chai' +import { sha256 } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { VideoStreamingPlaylist } from '@shared/models' +import { ServerInfo } from '../server' + +async function checkSegmentHash (options: { + server: ServerInfo + baseUrlPlaylist: string + baseUrlSegment: string + videoUUID: string + resolution: number + hlsPlaylist: VideoStreamingPlaylist +}) { + const { server, baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist } = options + const command = server.streamingPlaylistsCommand + + const playlist = await command.get({ url: `${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8` }) + + const videoName = `${videoUUID}-${resolution}-fragmented.mp4` + + const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) + + const length = parseInt(matches[1], 10) + const offset = parseInt(matches[2], 10) + const range = `${offset}-${offset + length - 1}` + + const segmentBody = await command.getSegment({ + url: `${baseUrlSegment}/${videoUUID}/${videoName}`, + expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, + range: `bytes=${range}` + }) + + const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) + expect(sha256(segmentBody)).to.equal(shaBody[videoName][range]) +} + +async function checkLiveSegmentHash (options: { + server: ServerInfo + baseUrlSegment: string + videoUUID: string + segmentName: string + hlsPlaylist: VideoStreamingPlaylist +}) { + const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options + const command = server.streamingPlaylistsCommand + + const segmentBody = await command.getSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` }) + const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) + + expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) +} + +async function checkResolutionsInMasterPlaylist (options: { + server: ServerInfo + playlistUrl: string + resolutions: number[] +}) { + const { server, playlistUrl, resolutions } = options + + const masterPlaylist = await server.streamingPlaylistsCommand.get({ url: playlistUrl }) + + for (const resolution of resolutions) { + const reg = new RegExp( + '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"' + ) + + expect(masterPlaylist).to.match(reg) + } +} + +export { + checkSegmentHash, + checkLiveSegmentHash, + checkResolutionsInMasterPlaylist +} diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts deleted file mode 100644 index 99c2e1880..000000000 --- a/shared/extra-utils/videos/video-streaming-playlists.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { makeRawRequest } from '../requests/requests' -import { sha256 } from '../../../server/helpers/core-utils' -import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model' -import { expect } from 'chai' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getPlaylist (url: string, statusCodeExpected = HttpStatusCode.OK_200) { - return makeRawRequest(url, statusCodeExpected) -} - -function getSegment (url: string, statusCodeExpected = HttpStatusCode.OK_200, range?: string) { - return makeRawRequest(url, statusCodeExpected, range) -} - -function getSegmentSha256 (url: string, statusCodeExpected = HttpStatusCode.OK_200) { - return makeRawRequest(url, statusCodeExpected) -} - -async function checkSegmentHash ( - baseUrlPlaylist: string, - baseUrlSegment: string, - videoUUID: string, - resolution: number, - hlsPlaylist: VideoStreamingPlaylist -) { - const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`) - const playlist = res.text - - const videoName = `${videoUUID}-${resolution}-fragmented.mp4` - - const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) - - const length = parseInt(matches[1], 10) - const offset = parseInt(matches[2], 10) - const range = `${offset}-${offset + length - 1}` - - const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, HttpStatusCode.PARTIAL_CONTENT_206, `bytes=${range}`) - - const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) - - const sha256Server = resSha.body[videoName][range] - expect(sha256(res2.body)).to.equal(sha256Server) -} - -async function checkLiveSegmentHash ( - baseUrlSegment: string, - videoUUID: string, - segmentName: string, - hlsPlaylist: VideoStreamingPlaylist -) { - const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${segmentName}`) - - const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) - - const sha256Server = resSha.body[segmentName] - expect(sha256(res2.body)).to.equal(sha256Server) -} - -async function checkResolutionsInMasterPlaylist (playlistUrl: string, resolutions: number[]) { - const res = await getPlaylist(playlistUrl) - - const masterPlaylist = res.text - - for (const resolution of resolutions) { - const reg = new RegExp( - '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"' - ) - - expect(masterPlaylist).to.match(reg) - } -} - -// --------------------------------------------------------------------------- - -export { - getPlaylist, - getSegment, - checkResolutionsInMasterPlaylist, - getSegmentSha256, - checkLiveSegmentHash, - checkSegmentHash -} -- cgit v1.2.3 From a54618880c394ad7571f3f3222dc96ec2dd10d9a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 11:21:30 +0200 Subject: Introduce channels command --- shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/shared/abstract-command.ts | 21 +++ shared/extra-utils/videos/channels-command.ts | 157 +++++++++++++++++++++ shared/extra-utils/videos/channels.ts | 20 +++ shared/extra-utils/videos/index.ts | 5 +- shared/extra-utils/videos/video-channels.ts | 192 -------------------------- 6 files changed, 204 insertions(+), 194 deletions(-) create mode 100644 shared/extra-utils/videos/channels-command.ts create mode 100644 shared/extra-utils/videos/channels.ts delete mode 100644 shared/extra-utils/videos/video-channels.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 6a1dadbcc..68e10af5f 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -22,6 +22,7 @@ import { BlacklistCommand, CaptionsCommand, ChangeOwnershipCommand, + ChannelsCommand, HistoryCommand, ImportsCommand, LiveCommand, @@ -119,6 +120,7 @@ interface ServerInfo { historyCommand?: HistoryCommand importsCommand?: ImportsCommand streamingPlaylistsCommand?: StreamingPlaylistsCommand + channelsCommand?: ChannelsCommand } function parallelTests () { @@ -353,6 +355,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.historyCommand = new HistoryCommand(server) server.importsCommand = new ImportsCommand(server) server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) + server.channelsCommand = new ChannelsCommand(server) res(server) }) diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index be368376f..6a9ab1348 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,4 +1,6 @@ +import { isAbsolute, join } from 'path' import { HttpStatusCode } from '@shared/core-utils' +import { root } from '../miscs' import { makeDeleteRequest, makeGetRequest, @@ -146,6 +148,25 @@ abstract class AbstractCommand { }) } + protected updateImageRequest (options: InternalCommonCommandOptions & { + fixture: string + fieldname: string + }) { + let filePath = '' + if (isAbsolute(options.fixture)) { + filePath = options.fixture + } else { + filePath = join(root(), 'server', 'tests', 'fixtures', options.fixture) + } + + return this.postUploadRequest({ + ...options, + + fields: {}, + attaches: { [options.fieldname]: filePath } + }) + } + private buildCommonRequestOptions (options: InternalCommonCommandOptions) { const { path } = options diff --git a/shared/extra-utils/videos/channels-command.ts b/shared/extra-utils/videos/channels-command.ts new file mode 100644 index 000000000..a98c5cc93 --- /dev/null +++ b/shared/extra-utils/videos/channels-command.ts @@ -0,0 +1,157 @@ +import { pick } from 'lodash' +import { ResultList, VideoChannel, VideoChannelCreateResult } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' +import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ChannelsCommand extends AbstractCommand { + + list (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + withStats?: boolean + } = {}) { + const path = '/api/v1/video-channels' + + return this.getRequestBody>({ + ...options, + + path, + query: pick(options, [ 'start', 'count', 'sort', 'withStats' ]), + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listByAccount (options: OverrideCommandOptions & { + accountName: string + start?: number + count?: number + sort?: string + withStats?: boolean + search?: string + }) { + const { accountName, sort = 'createdAt' } = options + const path = '/api/v1/accounts/' + accountName + '/video-channels' + + return this.getRequestBody>({ + ...options, + + path, + query: { sort, ...pick(options, [ 'start', 'count', 'withStats', 'search' ]) }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + async create (options: OverrideCommandOptions & { + attributes: VideoChannelCreate + }) { + const path = '/api/v1/video-channels/' + + // Default attributes + const defaultAttributes = { + displayName: 'my super video channel', + description: 'my super channel description', + support: 'my super channel support' + } + const attributes = { ...defaultAttributes, ...options.attributes } + + const body = await unwrapBody<{ videoChannel: VideoChannelCreateResult }>(this.postBodyRequest({ + ...options, + + path, + fields: attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.videoChannel + } + + update (options: OverrideCommandOptions & { + channelName: string + attributes: VideoChannelUpdate + }) { + const { channelName, attributes } = options + const path = '/api/v1/video-channels/' + channelName + + return this.putBodyRequest({ + ...options, + + path, + fields: attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + delete (options: OverrideCommandOptions & { + channelName: string + }) { + const path = '/api/v1/video-channels/' + options.channelName + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + get (options: OverrideCommandOptions & { + channelName: string + }) { + const path = '/api/v1/video-channels/' + options.channelName + + return this.getRequestBody({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + updateImage (options: OverrideCommandOptions & { + fixture: string + channelName: string | number + type: 'avatar' | 'banner' + }) { + const { channelName, fixture, type } = options + + const path = `/api/v1/video-channels/${channelName}/${type}/pick` + + return this.updateImageRequest({ + ...options, + + path, + fixture, + fieldname: type + 'file', + + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + deleteImage (options: OverrideCommandOptions & { + channelName: string | number + type: 'avatar' | 'banner' + }) { + const { channelName, type } = options + + const path = `/api/v1/video-channels/${channelName}/${type}` + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/videos/channels.ts b/shared/extra-utils/videos/channels.ts new file mode 100644 index 000000000..a77543c92 --- /dev/null +++ b/shared/extra-utils/videos/channels.ts @@ -0,0 +1,20 @@ +import { User } from '../../models/users/user.model' +import { ServerInfo } from '../server/servers' +import { getMyUserInformation } from '../users/users' + +function setDefaultVideoChannel (servers: ServerInfo[]) { + const tasks: Promise[] = [] + + for (const server of servers) { + const p = getMyUserInformation(server.url, server.accessToken) + .then(res => { server.videoChannel = (res.body as User).videoChannels[0] }) + + tasks.push(p) + } + + return Promise.all(tasks) +} + +export { + setDefaultVideoChannel +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index f87ae8eea..3bc219281 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -1,7 +1,9 @@ export * from './blacklist-command' -export * from './captions' export * from './captions-command' +export * from './captions' export * from './change-ownership-command' +export * from './channels' +export * from './channels-command' export * from './history-command' export * from './imports-command' export * from './live-command' @@ -11,6 +13,5 @@ export * from './playlists' export * from './services-command' export * from './streaming-playlists-command' export * from './streaming-playlists' -export * from './video-channels' export * from './video-comments' export * from './videos' diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts deleted file mode 100644 index 0aab93e52..000000000 --- a/shared/extra-utils/videos/video-channels.ts +++ /dev/null @@ -1,192 +0,0 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ - -import * as request from 'supertest' -import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' -import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' -import { makeDeleteRequest, makeGetRequest, updateImageRequest } from '../requests/requests' -import { ServerInfo } from '../server/servers' -import { MyUser, User } from '../../models/users/user.model' -import { getMyUserInformation } from '../users/users' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getVideoChannelsList (url: string, start: number, count: number, sort?: string, withStats?: boolean) { - const path = '/api/v1/video-channels' - - const req = request(url) - .get(path) - .query({ start: start }) - .query({ count: count }) - - if (sort) req.query({ sort }) - if (withStats) req.query({ withStats }) - - return req.set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getAccountVideoChannelsList (parameters: { - url: string - accountName: string - start?: number - count?: number - sort?: string - specialStatus?: HttpStatusCode - withStats?: boolean - search?: string -}) { - const { - url, - accountName, - start, - count, - sort = 'createdAt', - specialStatus = HttpStatusCode.OK_200, - withStats = false, - search - } = parameters - - const path = '/api/v1/accounts/' + accountName + '/video-channels' - - return makeGetRequest({ - url, - path, - query: { - start, - count, - sort, - withStats, - search - }, - statusCodeExpected: specialStatus - }) -} - -function addVideoChannel ( - url: string, - token: string, - videoChannelAttributesArg: VideoChannelCreate, - expectedStatus = HttpStatusCode.OK_200 -) { - const path = '/api/v1/video-channels/' - - // Default attributes - let attributes = { - displayName: 'my super video channel', - description: 'my super channel description', - support: 'my super channel support' - } - attributes = Object.assign(attributes, videoChannelAttributesArg) - - return request(url) - .post(path) - .send(attributes) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -function updateVideoChannel ( - url: string, - token: string, - channelName: string, - attributes: VideoChannelUpdate, - expectedStatus = HttpStatusCode.NO_CONTENT_204 -) { - const body: any = {} - const path = '/api/v1/video-channels/' + channelName - - if (attributes.displayName) body.displayName = attributes.displayName - if (attributes.description) body.description = attributes.description - if (attributes.support) body.support = attributes.support - if (attributes.bulkVideosSupportUpdate) body.bulkVideosSupportUpdate = attributes.bulkVideosSupportUpdate - - return request(url) - .put(path) - .send(body) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -function deleteVideoChannel (url: string, token: string, channelName: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/video-channels/' + channelName - - return request(url) - .delete(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -function getVideoChannel (url: string, channelName: string) { - const path = '/api/v1/video-channels/' + channelName - - return request(url) - .get(path) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function updateVideoChannelImage (options: { - url: string - accessToken: string - fixture: string - videoChannelName: string | number - type: 'avatar' | 'banner' -}) { - const path = `/api/v1/video-channels/${options.videoChannelName}/${options.type}/pick` - - return updateImageRequest({ ...options, path, fieldname: options.type + 'file' }) -} - -function deleteVideoChannelImage (options: { - url: string - accessToken: string - videoChannelName: string | number - type: 'avatar' | 'banner' -}) { - const path = `/api/v1/video-channels/${options.videoChannelName}/${options.type}` - - return makeDeleteRequest({ - url: options.url, - token: options.accessToken, - path, - statusCodeExpected: 204 - }) -} - -function setDefaultVideoChannel (servers: ServerInfo[]) { - const tasks: Promise[] = [] - - for (const server of servers) { - const p = getMyUserInformation(server.url, server.accessToken) - .then(res => { server.videoChannel = (res.body as User).videoChannels[0] }) - - tasks.push(p) - } - - return Promise.all(tasks) -} - -async function getDefaultVideoChannel (url: string, token: string) { - const res = await getMyUserInformation(url, token) - - return (res.body as MyUser).videoChannels[0].id -} - -// --------------------------------------------------------------------------- - -export { - updateVideoChannelImage, - getVideoChannelsList, - getAccountVideoChannelsList, - addVideoChannel, - updateVideoChannel, - deleteVideoChannel, - getVideoChannel, - setDefaultVideoChannel, - deleteVideoChannelImage, - getDefaultVideoChannel -} -- cgit v1.2.3 From 12edc1495a36b2199f1bf1ba37f50c7b694be382 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 14:15:11 +0200 Subject: Introduce comments command --- shared/extra-utils/server/servers.ts | 3 + shared/extra-utils/videos/comments-command.ts | 132 ++++++++++++++++++++ shared/extra-utils/videos/index.ts | 3 +- .../videos/streaming-playlists-command.ts | 2 +- shared/extra-utils/videos/video-comments.ts | 138 --------------------- 5 files changed, 138 insertions(+), 140 deletions(-) create mode 100644 shared/extra-utils/videos/comments-command.ts delete mode 100644 shared/extra-utils/videos/video-comments.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 68e10af5f..8e80a9842 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -30,6 +30,7 @@ import { ServicesCommand, StreamingPlaylistsCommand } from '../videos' +import { CommentsCommand } from '../videos/comments-command' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' import { DebugCommand } from './debug-command' @@ -121,6 +122,7 @@ interface ServerInfo { importsCommand?: ImportsCommand streamingPlaylistsCommand?: StreamingPlaylistsCommand channelsCommand?: ChannelsCommand + commentsCommand?: CommentsCommand } function parallelTests () { @@ -356,6 +358,7 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] server.importsCommand = new ImportsCommand(server) server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) server.channelsCommand = new ChannelsCommand(server) + server.commentsCommand = new CommentsCommand(server) res(server) }) diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts new file mode 100644 index 000000000..b31f3e2dd --- /dev/null +++ b/shared/extra-utils/videos/comments-command.ts @@ -0,0 +1,132 @@ +import { pick } from 'lodash' +import { ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class CommentsCommand extends AbstractCommand { + + listForAdmin (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + isLocal?: boolean + search?: string + searchAccount?: string + searchVideo?: string + } = {}) { + const { sort = '-createdAt' } = options + const path = '/api/v1/videos/comments' + + const query = { sort, ...pick(options, [ 'start', 'count', 'isLocal', 'search', 'searchAccount', 'searchVideo' ]) } + + return this.getRequestBody>({ + ...options, + + path, + query, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listThreads (options: OverrideCommandOptions & { + videoId: number | string + start?: number + count?: number + sort?: string + }) { + const { start, count, sort, videoId } = options + const path = '/api/v1/videos/' + videoId + '/comment-threads' + + return this.getRequestBody({ + ...options, + + path, + query: { start, count, sort }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getThread (options: OverrideCommandOptions & { + videoId: number | string + threadId: number + }) { + const { videoId, threadId } = options + const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId + + return this.getRequestBody({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + async createThread (options: OverrideCommandOptions & { + videoId: number | string + text: string + }) { + const { videoId, text } = options + const path = '/api/v1/videos/' + videoId + '/comment-threads' + + const body = await unwrapBody<{ comment: VideoComment }>(this.postBodyRequest({ + ...options, + + path, + fields: { text }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.comment + } + + async addReply (options: OverrideCommandOptions & { + videoId: number | string + toCommentId: number + text: string + }) { + const { videoId, toCommentId, text } = options + const path = '/api/v1/videos/' + videoId + '/comments/' + toCommentId + + const body = await unwrapBody<{ comment: VideoComment }>(this.postBodyRequest({ + ...options, + + path, + fields: { text }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + + return body.comment + } + + async findCommentId (options: OverrideCommandOptions & { + videoId: number | string + text: string + }) { + const { videoId, text } = options + const { data } = await this.listThreads({ videoId, count: 25, sort: '-createdAt' }) + + return data.find(c => c.text === text).id + } + + delete (options: OverrideCommandOptions & { + videoId: number | string + commentId: number + }) { + const { videoId, commentId } = options + const path = '/api/v1/videos/' + videoId + '/comments/' + commentId + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 3bc219281..652d82842 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -4,6 +4,7 @@ export * from './captions' export * from './change-ownership-command' export * from './channels' export * from './channels-command' +export * from './comments-command' export * from './history-command' export * from './imports-command' export * from './live-command' @@ -13,5 +14,5 @@ export * from './playlists' export * from './services-command' export * from './streaming-playlists-command' export * from './streaming-playlists' -export * from './video-comments' +export * from './comments-command' export * from './videos' diff --git a/shared/extra-utils/videos/streaming-playlists-command.ts b/shared/extra-utils/videos/streaming-playlists-command.ts index 4caec7137..b109597c9 100644 --- a/shared/extra-utils/videos/streaming-playlists-command.ts +++ b/shared/extra-utils/videos/streaming-playlists-command.ts @@ -27,7 +27,7 @@ export class StreamingPlaylistsCommand extends AbstractCommand { url: options.url, range: options.range, implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200, + defaultExpectedStatus: HttpStatusCode.OK_200 })) } diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts deleted file mode 100644 index 71b9f875a..000000000 --- a/shared/extra-utils/videos/video-comments.ts +++ /dev/null @@ -1,138 +0,0 @@ -/* eslint-disable @typescript-eslint/no-floating-promises */ - -import * as request from 'supertest' -import { makeDeleteRequest, makeGetRequest } from '../requests/requests' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getAdminVideoComments (options: { - url: string - token: string - start: number - count: number - sort?: string - isLocal?: boolean - search?: string - searchAccount?: string - searchVideo?: string -}) { - const { url, token, start, count, sort, isLocal, search, searchAccount, searchVideo } = options - const path = '/api/v1/videos/comments' - - const query = { - start, - count, - sort: sort || '-createdAt' - } - - if (isLocal !== undefined) Object.assign(query, { isLocal }) - if (search !== undefined) Object.assign(query, { search }) - if (searchAccount !== undefined) Object.assign(query, { searchAccount }) - if (searchVideo !== undefined) Object.assign(query, { searchVideo }) - - return makeGetRequest({ - url, - path, - token, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string, token?: string) { - const path = '/api/v1/videos/' + videoId + '/comment-threads' - - const req = request(url) - .get(path) - .query({ start: start }) - .query({ count: count }) - - if (sort) req.query({ sort }) - if (token) req.set('Authorization', 'Bearer ' + token) - - return req.set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getVideoThreadComments (url: string, videoId: number | string, threadId: number, token?: string) { - const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId - - const req = request(url) - .get(path) - .set('Accept', 'application/json') - - if (token) req.set('Authorization', 'Bearer ' + token) - - return req.expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function addVideoCommentThread ( - url: string, - token: string, - videoId: number | string, - text: string, - expectedStatus = HttpStatusCode.OK_200 -) { - const path = '/api/v1/videos/' + videoId + '/comment-threads' - - return request(url) - .post(path) - .send({ text }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -function addVideoCommentReply ( - url: string, - token: string, - videoId: number | string, - inReplyToCommentId: number, - text: string, - expectedStatus = HttpStatusCode.OK_200 -) { - const path = '/api/v1/videos/' + videoId + '/comments/' + inReplyToCommentId - - return request(url) - .post(path) - .send({ text }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -async function findCommentId (url: string, videoId: number | string, text: string) { - const res = await getVideoCommentThreads(url, videoId, 0, 25, '-createdAt') - - return res.body.data.find(c => c.text === text).id as number -} - -function deleteVideoComment ( - url: string, - token: string, - videoId: number | string, - commentId: number, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + videoId + '/comments/' + commentId - - return makeDeleteRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -// --------------------------------------------------------------------------- - -export { - getVideoCommentThreads, - getAdminVideoComments, - getVideoThreadComments, - addVideoCommentThread, - addVideoCommentReply, - findCommentId, - deleteVideoComment -} -- cgit v1.2.3 From 078f17e6d90376050f43ce639e88e11869b49ee7 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 15:03:44 +0200 Subject: Fix CLI tools --- shared/extra-utils/server/servers.ts | 89 +++++++++++++++++++----------------- shared/extra-utils/users/login.ts | 4 +- 2 files changed, 49 insertions(+), 44 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 8e80a9842..41b48a8ee 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -41,25 +41,25 @@ import { RedundancyCommand } from './redundancy-command' import { StatsCommand } from './stats-command' interface ServerInfo { - app: ChildProcess + app?: ChildProcess url: string - host: string - hostname: string - port: number + host?: string + hostname?: string + port?: number - rtmpPort: number + rtmpPort?: number - parallel: boolean + parallel?: boolean internalServerNumber: number - serverNumber: number + serverNumber?: number - client: { - id: string - secret: string + client?: { + id?: string + secret?: string } - user: { + user?: { username: string password: string email?: string @@ -328,43 +328,47 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] } catch { /* empty */ } }) - server.bulkCommand = new BulkCommand(server) - server.cliCommand = new CLICommand(server) - server.customPageCommand = new CustomPagesCommand(server) - server.feedCommand = new FeedCommand(server) - server.logsCommand = new LogsCommand(server) - server.abusesCommand = new AbusesCommand(server) - server.overviewsCommand = new OverviewsCommand(server) - server.searchCommand = new SearchCommand(server) - server.contactFormCommand = new ContactFormCommand(server) - server.debugCommand = new DebugCommand(server) - server.followsCommand = new FollowsCommand(server) - server.jobsCommand = new JobsCommand(server) - server.pluginsCommand = new PluginsCommand(server) - server.redundancyCommand = new RedundancyCommand(server) - server.statsCommand = new StatsCommand(server) - server.configCommand = new ConfigCommand(server) - server.socketIOCommand = new SocketIOCommand(server) - server.accountsCommand = new AccountsCommand(server) - server.blocklistCommand = new BlocklistCommand(server) - server.subscriptionsCommand = new SubscriptionsCommand(server) - server.liveCommand = new LiveCommand(server) - server.servicesCommand = new ServicesCommand(server) - server.blacklistCommand = new BlacklistCommand(server) - server.captionsCommand = new CaptionsCommand(server) - server.changeOwnershipCommand = new ChangeOwnershipCommand(server) - server.playlistsCommand = new PlaylistsCommand(server) - server.historyCommand = new HistoryCommand(server) - server.importsCommand = new ImportsCommand(server) - server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) - server.channelsCommand = new ChannelsCommand(server) - server.commentsCommand = new CommentsCommand(server) + assignCommands(server) res(server) }) }) } +function assignCommands (server: ServerInfo) { + server.bulkCommand = new BulkCommand(server) + server.cliCommand = new CLICommand(server) + server.customPageCommand = new CustomPagesCommand(server) + server.feedCommand = new FeedCommand(server) + server.logsCommand = new LogsCommand(server) + server.abusesCommand = new AbusesCommand(server) + server.overviewsCommand = new OverviewsCommand(server) + server.searchCommand = new SearchCommand(server) + server.contactFormCommand = new ContactFormCommand(server) + server.debugCommand = new DebugCommand(server) + server.followsCommand = new FollowsCommand(server) + server.jobsCommand = new JobsCommand(server) + server.pluginsCommand = new PluginsCommand(server) + server.redundancyCommand = new RedundancyCommand(server) + server.statsCommand = new StatsCommand(server) + server.configCommand = new ConfigCommand(server) + server.socketIOCommand = new SocketIOCommand(server) + server.accountsCommand = new AccountsCommand(server) + server.blocklistCommand = new BlocklistCommand(server) + server.subscriptionsCommand = new SubscriptionsCommand(server) + server.liveCommand = new LiveCommand(server) + server.servicesCommand = new ServicesCommand(server) + server.blacklistCommand = new BlacklistCommand(server) + server.captionsCommand = new CaptionsCommand(server) + server.changeOwnershipCommand = new ChangeOwnershipCommand(server) + server.playlistsCommand = new PlaylistsCommand(server) + server.historyCommand = new HistoryCommand(server) + server.importsCommand = new ImportsCommand(server) + server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) + server.channelsCommand = new ChannelsCommand(server) + server.commentsCommand = new CommentsCommand(server) +} + async function reRunServer (server: ServerInfo, configOverride?: any) { const newServer = await runServer(server, configOverride) server.app = newServer.app @@ -475,5 +479,6 @@ export { flushAndRunServer, killallServers, reRunServer, + assignCommands, waitUntilLog } diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index 39e1a2747..c14367542 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts @@ -4,9 +4,9 @@ import { ServerInfo } from '../server/servers' import { getClient } from '../server/clients' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -type Client = { id: string, secret: string } +type Client = { id?: string, secret?: string } type User = { username: string, password: string } -type Server = { url: string, client: Client, user: User } +type Server = { url?: string, client?: Client, user?: User } function login (url: string, client: Client, user: User, expectedStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/token' -- cgit v1.2.3 From 9293139fde7091e9badcafa9b570b83cea9a10ad Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 15:37:43 +0200 Subject: Introduce sql command --- shared/extra-utils/miscs/index.ts | 2 +- shared/extra-utils/miscs/sql-command.ts | 142 +++++++++++++++++++++++ shared/extra-utils/miscs/sql.ts | 161 -------------------------- shared/extra-utils/miscs/stubs.ts | 7 -- shared/extra-utils/server/servers.ts | 10 +- shared/extra-utils/shared/abstract-command.ts | 2 +- 6 files changed, 152 insertions(+), 172 deletions(-) create mode 100644 shared/extra-utils/miscs/sql-command.ts delete mode 100644 shared/extra-utils/miscs/sql.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/index.ts b/shared/extra-utils/miscs/index.ts index ccacd4c79..7e236c329 100644 --- a/shared/extra-utils/miscs/index.ts +++ b/shared/extra-utils/miscs/index.ts @@ -1,3 +1,3 @@ export * from './miscs' -export * from './sql' +export * from './sql-command' export * from './stubs' diff --git a/shared/extra-utils/miscs/sql-command.ts b/shared/extra-utils/miscs/sql-command.ts new file mode 100644 index 000000000..2a3e9e607 --- /dev/null +++ b/shared/extra-utils/miscs/sql-command.ts @@ -0,0 +1,142 @@ +import { QueryTypes, Sequelize } from 'sequelize' +import { AbstractCommand } from '../shared' + +export class SQLCommand extends AbstractCommand { + private sequelize: Sequelize + + deleteAll (table: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.DELETE } + + return seq.query(`DELETE FROM "${table}"`, options) + } + + async getCount (table: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } + + const [ { total } ] = await seq.query<{ total: string }>(`SELECT COUNT(*) as total FROM "${table}"`, options) + if (total === null) return 0 + + return parseInt(total, 10) + } + + setActorField (to: string, field: string, value: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) + } + + setVideoField (uuid: string, field: string, value: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) + } + + setPlaylistField (uuid: string, field: string, value: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) + } + + async countVideoViewsOf (uuid: string) { + const seq = this.getSequelize() + + // tslint:disable + const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' + + `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` + + const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } + const [ { total } ] = await seq.query<{ total: number }>(query, options) + + if (!total) return 0 + + return parseInt(total + '', 10) + } + + getActorImage (filename: string) { + return this.selectQuery(`SELECT * FROM "actorImage" WHERE filename = '${filename}'`) + .then(rows => rows[0]) + } + + selectQuery (query: string) { + const seq = this.getSequelize() + const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } + + return seq.query(query, options) + } + + updateQuery (query: string) { + const seq = this.getSequelize() + const options = { type: QueryTypes.UPDATE as QueryTypes.UPDATE } + + return seq.query(query, options) + } + + setPluginField (pluginName: string, field: string, value: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE "plugin" SET "${field}" = '${value}' WHERE "name" = '${pluginName}'`, options) + } + + setPluginVersion (pluginName: string, newVersion: string) { + return this.setPluginField(pluginName, 'version', newVersion) + } + + setPluginLatestVersion (pluginName: string, newVersion: string) { + return this.setPluginField(pluginName, 'latestVersion', newVersion) + } + + setActorFollowScores (newScore: number) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE "actorFollow" SET "score" = ${newScore}`, options) + } + + setTokenField (accessToken: string, field: string, value: string) { + const seq = this.getSequelize() + + const options = { type: QueryTypes.UPDATE } + + return seq.query(`UPDATE "oAuthToken" SET "${field}" = '${value}' WHERE "accessToken" = '${accessToken}'`, options) + } + + async cleanup () { + if (!this.sequelize) return + + await this.sequelize.close() + this.sequelize = undefined + } + + private getSequelize () { + if (this.sequelize) return this.sequelize + + const dbname = 'peertube_test' + this.server.internalServerNumber + const username = 'peertube' + const password = 'peertube' + const host = 'localhost' + const port = 5432 + + this.sequelize = new Sequelize(dbname, username, password, { + dialect: 'postgres', + host, + port, + logging: false + }) + + return this.sequelize + } + +} diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts deleted file mode 100644 index 65a0aa5fe..000000000 --- a/shared/extra-utils/miscs/sql.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { QueryTypes, Sequelize } from 'sequelize' -import { ServerInfo } from '../server/servers' - -const sequelizes: { [ id: number ]: Sequelize } = {} - -function getSequelize (internalServerNumber: number) { - if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber] - - const dbname = 'peertube_test' + internalServerNumber - const username = 'peertube' - const password = 'peertube' - const host = 'localhost' - const port = 5432 - - const seq = new Sequelize(dbname, username, password, { - dialect: 'postgres', - host, - port, - logging: false - }) - - sequelizes[internalServerNumber] = seq - - return seq -} - -function deleteAll (internalServerNumber: number, table: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.DELETE } - - return seq.query(`DELETE FROM "${table}"`, options) -} - -async function getCount (internalServerNumber: number, table: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } - - const [ { total } ] = await seq.query<{ total: string }>(`SELECT COUNT(*) as total FROM "${table}"`, options) - if (total === null) return 0 - - return parseInt(total, 10) -} - -function setActorField (internalServerNumber: number, to: string, field: string, value: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options) -} - -function setVideoField (internalServerNumber: number, uuid: string, field: string, value: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) -} - -function setPlaylistField (internalServerNumber: number, uuid: string, field: string, value: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options) -} - -async function countVideoViewsOf (internalServerNumber: number, uuid: string) { - const seq = getSequelize(internalServerNumber) - - // tslint:disable - const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' + - `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'` - - const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } - const [ { total } ] = await seq.query<{ total: number }>(query, options) - - if (!total) return 0 - - return parseInt(total + '', 10) -} - -function getActorImage (internalServerNumber: number, filename: string) { - return selectQuery(internalServerNumber, `SELECT * FROM "actorImage" WHERE filename = '${filename}'`) - .then(rows => rows[0]) -} - -function selectQuery (internalServerNumber: number, query: string) { - const seq = getSequelize(internalServerNumber) - const options = { type: QueryTypes.SELECT as QueryTypes.SELECT } - - return seq.query(query, options) -} - -function updateQuery (internalServerNumber: number, query: string) { - const seq = getSequelize(internalServerNumber) - const options = { type: QueryTypes.UPDATE as QueryTypes.UPDATE } - - return seq.query(query, options) -} - -async function closeAllSequelize (servers: ServerInfo[]) { - for (const server of servers) { - if (sequelizes[server.internalServerNumber]) { - await sequelizes[server.internalServerNumber].close() - // eslint-disable-next-line - delete sequelizes[server.internalServerNumber] - } - } -} - -function setPluginField (internalServerNumber: number, pluginName: string, field: string, value: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE "plugin" SET "${field}" = '${value}' WHERE "name" = '${pluginName}'`, options) -} - -function setPluginVersion (internalServerNumber: number, pluginName: string, newVersion: string) { - return setPluginField(internalServerNumber, pluginName, 'version', newVersion) -} - -function setPluginLatestVersion (internalServerNumber: number, pluginName: string, newVersion: string) { - return setPluginField(internalServerNumber, pluginName, 'latestVersion', newVersion) -} - -function setActorFollowScores (internalServerNumber: number, newScore: number) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE "actorFollow" SET "score" = ${newScore}`, options) -} - -function setTokenField (internalServerNumber: number, accessToken: string, field: string, value: string) { - const seq = getSequelize(internalServerNumber) - - const options = { type: QueryTypes.UPDATE } - - return seq.query(`UPDATE "oAuthToken" SET "${field}" = '${value}' WHERE "accessToken" = '${accessToken}'`, options) -} - -export { - setVideoField, - setPlaylistField, - setActorField, - countVideoViewsOf, - setPluginVersion, - setPluginLatestVersion, - selectQuery, - getActorImage, - deleteAll, - setTokenField, - updateQuery, - setActorFollowScores, - closeAllSequelize, - getCount -} diff --git a/shared/extra-utils/miscs/stubs.ts b/shared/extra-utils/miscs/stubs.ts index d1eb0e3b2..940e4bf29 100644 --- a/shared/extra-utils/miscs/stubs.ts +++ b/shared/extra-utils/miscs/stubs.ts @@ -2,13 +2,6 @@ function buildRequestStub (): any { return { } } -function buildResponseStub (): any { - return { - locals: {} - } -} - export { - buildResponseStub, buildRequestStub } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 41b48a8ee..bd3be8373 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -30,6 +30,7 @@ import { ServicesCommand, StreamingPlaylistsCommand } from '../videos' +import { SQLCommand } from '../miscs' import { CommentsCommand } from '../videos/comments-command' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' @@ -123,6 +124,7 @@ interface ServerInfo { streamingPlaylistsCommand?: StreamingPlaylistsCommand channelsCommand?: ChannelsCommand commentsCommand?: CommentsCommand + sqlCommand?: SQLCommand } function parallelTests () { @@ -367,6 +369,7 @@ function assignCommands (server: ServerInfo) { server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) server.channelsCommand = new ChannelsCommand(server) server.commentsCommand = new CommentsCommand(server) + server.sqlCommand = new SQLCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { @@ -398,17 +401,20 @@ async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exc expect(filtered).to.have.lengthOf(0) } -function killallServers (servers: ServerInfo[]) { +async function killallServers (servers: ServerInfo[]) { for (const server of servers) { if (!server.app) continue + await server.sqlCommand.cleanup() + process.kill(-server.app.pid) + server.app = null } } async function cleanupTests (servers: ServerInfo[]) { - killallServers(servers) + await killallServers(servers) if (isGithubCI()) { await ensureDir('artifacts') diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 6a9ab1348..200db90d4 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,6 +1,6 @@ import { isAbsolute, join } from 'path' import { HttpStatusCode } from '@shared/core-utils' -import { root } from '../miscs' +import { root } from '../miscs/miscs' import { makeDeleteRequest, makeGetRequest, -- cgit v1.2.3 From dd0ebb715123dfa126a82d4e4fe3a04064ae77b8 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Jul 2021 16:23:01 +0200 Subject: Introduce notifications command --- shared/extra-utils/search/search-command.ts | 2 +- shared/extra-utils/server/servers.ts | 6 +- shared/extra-utils/shared/abstract-command.ts | 7 +- shared/extra-utils/users/index.ts | 3 +- shared/extra-utils/users/notifications-command.ts | 87 +++ shared/extra-utils/users/notifications.ts | 729 +++++++++++++++++++ shared/extra-utils/users/user-notifications.ts | 808 --------------------- .../videos/streaming-playlists-command.ts | 2 +- 8 files changed, 828 insertions(+), 816 deletions(-) create mode 100644 shared/extra-utils/users/notifications-command.ts create mode 100644 shared/extra-utils/users/notifications.ts delete mode 100644 shared/extra-utils/users/user-notifications.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts index 7539a21ec..b6054f093 100644 --- a/shared/extra-utils/search/search-command.ts +++ b/shared/extra-utils/search/search-command.ts @@ -90,7 +90,7 @@ export class SearchCommand extends AbstractCommand { ...options, path, - query: search, + query: { sort: '-publishedAt', ...search }, implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index bd3be8373..e0e49d2c4 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -11,13 +11,14 @@ import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' import { FeedCommand } from '../feeds' import { LogsCommand } from '../logs' +import { SQLCommand } from '../miscs' import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' -import { AccountsCommand, BlocklistCommand, SubscriptionsCommand } from '../users' +import { AccountsCommand, BlocklistCommand, NotificationsCommand, SubscriptionsCommand } from '../users' import { BlacklistCommand, CaptionsCommand, @@ -30,7 +31,6 @@ import { ServicesCommand, StreamingPlaylistsCommand } from '../videos' -import { SQLCommand } from '../miscs' import { CommentsCommand } from '../videos/comments-command' import { ConfigCommand } from './config-command' import { ContactFormCommand } from './contact-form-command' @@ -125,6 +125,7 @@ interface ServerInfo { channelsCommand?: ChannelsCommand commentsCommand?: CommentsCommand sqlCommand?: SQLCommand + notificationsCommand?: NotificationsCommand } function parallelTests () { @@ -370,6 +371,7 @@ function assignCommands (server: ServerInfo) { server.channelsCommand = new ChannelsCommand(server) server.commentsCommand = new CommentsCommand(server) server.sqlCommand = new SQLCommand(server) + server.notificationsCommand = new NotificationsCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 200db90d4..fd2deb57e 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -78,7 +78,7 @@ abstract class AbstractCommand { } protected getRequest (options: InternalGetCommandOptions) { - const { redirects, query, contentType, accept } = options + const { redirects, query, contentType, accept, range } = options return makeGetRequest({ ...this.buildCommonRequestOptions(options), @@ -86,6 +86,7 @@ abstract class AbstractCommand { redirects, query, contentType, + range, accept }) } @@ -168,10 +169,10 @@ abstract class AbstractCommand { } private buildCommonRequestOptions (options: InternalCommonCommandOptions) { - const { path } = options + const { url, path } = options return { - url: this.server.url, + url: url ?? this.server.url, path, token: this.buildCommonRequestToken(options), diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index 9f760d7fd..ed166c756 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -2,6 +2,7 @@ export * from './accounts-command' export * from './accounts' export * from './blocklist-command' export * from './login' -export * from './user-notifications' +export * from './notifications' +export * from './notifications-command' export * from './subscriptions-command' export * from './users' diff --git a/shared/extra-utils/users/notifications-command.ts b/shared/extra-utils/users/notifications-command.ts new file mode 100644 index 000000000..dfe574ca1 --- /dev/null +++ b/shared/extra-utils/users/notifications-command.ts @@ -0,0 +1,87 @@ +import { ResultList } from '@shared/models' +import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { UserNotification, UserNotificationSetting } from '../../models/users' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class NotificationsCommand extends AbstractCommand { + + updateMySettings (options: OverrideCommandOptions & { + settings: UserNotificationSetting + }) { + const path = '/api/v1/users/me/notification-settings' + + return this.putBodyRequest({ + ...options, + + path, + fields: options.settings, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + list (options: OverrideCommandOptions & { + start?: number + count?: number + unread?: boolean + sort?: string + }) { + const { start, count, unread, sort = '-createdAt' } = options + const path = '/api/v1/users/me/notifications' + + return this.getRequestBody>({ + ...options, + + path, + query: { + start, + count, + sort, + unread + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + markAsRead (options: OverrideCommandOptions & { + ids: number[] + }) { + const { ids } = options + const path = '/api/v1/users/me/notifications/read' + + return this.postBodyRequest({ + ...options, + + path, + fields: { ids }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + markAsReadAll (options: OverrideCommandOptions) { + const path = '/api/v1/users/me/notifications/read-all' + + return this.postBodyRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async getLastest (options: OverrideCommandOptions = {}) { + const { total, data } = await this.list({ + ...options, + start: 0, + count: 1, + sort: '-createdAt' + }) + + if (total === 0) return undefined + + return data[0] + } +} diff --git a/shared/extra-utils/users/notifications.ts b/shared/extra-utils/users/notifications.ts new file mode 100644 index 000000000..81f0729fa --- /dev/null +++ b/shared/extra-utils/users/notifications.ts @@ -0,0 +1,729 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { inspect } from 'util' +import { AbuseState, PluginType } from '@shared/models' +import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' +import { MockSmtpServer } from '../mock-servers/mock-email' +import { doubleFollow } from '../server/follows' +import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' +import { setAccessTokensToServers, userLogin } from './login' +import { createUser, getMyUserInformation } from './users' + +function getAllNotificationsSettings (): UserNotificationSetting { + return { + newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, + newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL + } +} + +type CheckerBaseParams = { + server: ServerInfo + emails: any[] + socketNotifications: UserNotification[] + token: string + check?: { web: boolean, mail: boolean } +} + +type CheckerType = 'presence' | 'absence' + +async function checkNotification ( + base: CheckerBaseParams, + notificationChecker: (notification: UserNotification, type: CheckerType) => void, + emailNotificationFinder: (email: object) => boolean, + checkType: CheckerType +) { + const check = base.check || { web: true, mail: true } + + if (check.web) { + const notification = await base.server.notificationsCommand.getLastest({ token: base.token }) + + if (notification || checkType !== 'absence') { + notificationChecker(notification, checkType) + } + + const socketNotification = base.socketNotifications.find(n => { + try { + notificationChecker(n, 'presence') + return true + } catch { + return false + } + }) + + if (checkType === 'presence') { + const obj = inspect(base.socketNotifications, { depth: 5 }) + expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined + } else { + const obj = inspect(socketNotification, { depth: 5 }) + expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined + } + } + + if (check.mail) { + // Last email + const email = base.emails + .slice() + .reverse() + .find(e => emailNotificationFinder(e)) + + if (checkType === 'presence') { + const emails = base.emails.map(e => e.text) + expect(email, 'The email is absent when is should be present. ' + inspect(emails)).to.not.be.undefined + } else { + expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined + } + } +} + +function checkVideo (video: any, videoName?: string, videoUUID?: string) { + if (videoName) { + expect(video.name).to.be.a('string') + expect(video.name).to.not.be.empty + expect(video.name).to.equal(videoName) + } + + if (videoUUID) { + expect(video.uuid).to.be.a('string') + expect(video.uuid).to.not.be.empty + expect(video.uuid).to.equal(videoUUID) + } + + expect(video.id).to.be.a('number') +} + +function checkActor (actor: any) { + expect(actor.displayName).to.be.a('string') + expect(actor.displayName).to.not.be.empty + expect(actor.host).to.not.be.undefined +} + +function checkComment (comment: any, commentId: number, threadId: number) { + expect(comment.id).to.equal(commentId) + expect(comment.threadId).to.equal(threadId) +} + +async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkVideo(notification.video, videoName, videoUUID) + checkActor(notification.video.channel) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { + const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkVideo(notification.video, videoName, videoUUID) + checkActor(notification.video.channel) + } else { + expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + return text.includes(videoUUID) && text.includes('Your video') + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkMyVideoImportIsFinished ( + base: CheckerBaseParams, + videoName: string, + videoUUID: string, + url: string, + success: boolean, + type: CheckerType +) { + const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.videoImport.targetUrl).to.equal(url) + + if (success) checkVideo(notification.videoImport.video, videoName, videoUUID) + } else { + expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + const toFind = success ? ' finished' : ' error' + + return text.includes(url) && text.includes(toFind) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_USER_REGISTRATION + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkActor(notification.account) + expect(notification.account.name).to.equal(username) + } else { + expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + + return text.includes(' registered.') && text.includes(username) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewActorFollow ( + base: CheckerBaseParams, + followType: 'channel' | 'account', + followerName: string, + followerDisplayName: string, + followingDisplayName: string, + type: CheckerType +) { + const notificationType = UserNotificationType.NEW_FOLLOW + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkActor(notification.actorFollow.follower) + expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName) + expect(notification.actorFollow.follower.name).to.equal(followerName) + expect(notification.actorFollow.follower.host).to.not.be.undefined + + const following = notification.actorFollow.following + expect(following.displayName).to.equal(followingDisplayName) + expect(following.type).to.equal(followType) + } else { + expect(notification).to.satisfy(n => { + return n.type !== notificationType || + (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName) + }) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + + return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkActor(notification.actorFollow.follower) + expect(notification.actorFollow.follower.name).to.equal('peertube') + expect(notification.actorFollow.follower.host).to.equal(followerHost) + + expect(notification.actorFollow.following.name).to.equal('peertube') + } else { + expect(notification).to.satisfy(n => { + return n.type !== notificationType || n.actorFollow.follower.host !== followerHost + }) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + + return text.includes('instance has a new follower') && text.includes(followerHost) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) { + const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + const following = notification.actorFollow.following + checkActor(following) + expect(following.name).to.equal('peertube') + expect(following.host).to.equal(followingHost) + + expect(notification.actorFollow.follower.name).to.equal('peertube') + expect(notification.actorFollow.follower.host).to.equal(followerHost) + } else { + expect(notification).to.satisfy(n => { + return n.type !== notificationType || n.actorFollow.following.host !== followingHost + }) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + + return text.includes(' automatically followed a new instance') && text.includes(followingHost) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkCommentMention ( + base: CheckerBaseParams, + uuid: string, + commentId: number, + threadId: number, + byAccountDisplayName: string, + type: CheckerType +) { + const notificationType = UserNotificationType.COMMENT_MENTION + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkComment(notification.comment, commentId, threadId) + checkActor(notification.comment.account) + expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) + + checkVideo(notification.comment.video, undefined, uuid) + } else { + expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) + } + } + + function emailNotificationFinder (email: object) { + const text: string = email['text'] + + return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +let lastEmailCount = 0 + +async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { + const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + checkComment(notification.comment, commentId, threadId) + checkActor(notification.comment.account) + checkVideo(notification.comment.video, undefined, uuid) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.comment === undefined || n.comment.id !== commentId + }) + } + } + + const commentUrl = `http://localhost:${base.server.port}/w/${uuid};threadId=${threadId}` + + function emailNotificationFinder (email: object) { + return email['text'].indexOf(commentUrl) !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) + + if (type === 'presence') { + // We cannot detect email duplicates, so check we received another email + expect(base.emails).to.have.length.above(lastEmailCount) + lastEmailCount = base.emails.length + } +} + +async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.abuse.id).to.be.a('number') + checkVideo(notification.abuse.video, videoName, videoUUID) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.abuse === undefined || n.abuse.video.uuid !== videoUUID + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewAbuseMessage (base: CheckerBaseParams, abuseId: number, message: string, toEmail: string, type: CheckerType) { + const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.abuse.id).to.equal(abuseId) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + const to = email['to'].filter(t => t.address === toEmail) + + return text.indexOf(message) !== -1 && to.length !== 0 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkAbuseStateChange (base: CheckerBaseParams, abuseId: number, state: AbuseState, type: CheckerType) { + const notificationType = UserNotificationType.ABUSE_STATE_CHANGE + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.abuse.id).to.equal(abuseId) + expect(notification.abuse.state).to.equal(state) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + + const contains = state === AbuseState.ACCEPTED + ? ' accepted' + : ' rejected' + + return text.indexOf(contains) !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewCommentAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.abuse.id).to.be.a('number') + checkVideo(notification.abuse.comment.video, videoName, videoUUID) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.abuse === undefined || n.abuse.comment.video.uuid !== videoUUID + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displayName: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.abuse.id).to.be.a('number') + expect(notification.abuse.account.displayName).to.equal(displayName) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { + const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.videoBlacklist.video.id).to.be.a('number') + checkVideo(notification.videoBlacklist.video, videoName, videoUUID) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.video === undefined || n.video.uuid !== videoUUID + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewBlacklistOnMyVideo ( + base: CheckerBaseParams, + videoUUID: string, + videoName: string, + blacklistType: 'blacklist' | 'unblacklist' +) { + const notificationType = blacklistType === 'blacklist' + ? UserNotificationType.BLACKLIST_ON_MY_VIDEO + : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO + + function notificationChecker (notification: UserNotification) { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video + + checkVideo(video, videoName, videoUUID) + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, 'presence') +} + +async function checkNewPeerTubeVersion (base: CheckerBaseParams, latestVersion: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.peertube).to.exist + expect(notification.peertube.latestVersion).to.equal(latestVersion) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + + return text.includes(latestVersion) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function checkNewPluginVersion (base: CheckerBaseParams, pluginType: PluginType, pluginName: string, type: CheckerType) { + const notificationType = UserNotificationType.NEW_PLUGIN_VERSION + + function notificationChecker (notification: UserNotification, type: CheckerType) { + if (type === 'presence') { + expect(notification).to.not.be.undefined + expect(notification.type).to.equal(notificationType) + + expect(notification.plugin.name).to.equal(pluginName) + expect(notification.plugin.type).to.equal(pluginType) + } else { + expect(notification).to.satisfy((n: UserNotification) => { + return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName + }) + } + } + + function emailNotificationFinder (email: object) { + const text = email['text'] + + return text.includes(pluginName) + } + + await checkNotification(base, notificationChecker, emailNotificationFinder, type) +} + +async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { + const userNotifications: UserNotification[] = [] + const adminNotifications: UserNotification[] = [] + const adminNotificationsServer2: UserNotification[] = [] + const emails: object[] = [] + + const port = await MockSmtpServer.Instance.collectEmails(emails) + + const overrideConfig = { + smtp: { + hostname: 'localhost', + port + }, + signup: { + limit: 20 + } + } + const servers = await flushAndRunMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) + + await setAccessTokensToServers(servers) + + if (serversCount > 1) { + await doubleFollow(servers[0], servers[1]) + } + + const user = { + username: 'user_1', + password: 'super password' + } + await createUser({ + url: servers[0].url, + accessToken: servers[0].accessToken, + username: user.username, + password: user.password, + videoQuota: 10 * 1000 * 1000 + }) + const userAccessToken = await userLogin(servers[0], user) + + await servers[0].notificationsCommand.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) + await servers[0].notificationsCommand.updateMySettings({ settings: getAllNotificationsSettings() }) + + if (serversCount > 1) { + await servers[1].notificationsCommand.updateMySettings({ settings: getAllNotificationsSettings() }) + } + + { + const socket = servers[0].socketIOCommand.getUserNotificationSocket({ token: userAccessToken }) + socket.on('new-notification', n => userNotifications.push(n)) + } + { + const socket = servers[0].socketIOCommand.getUserNotificationSocket() + socket.on('new-notification', n => adminNotifications.push(n)) + } + + if (serversCount > 1) { + const socket = servers[1].socketIOCommand.getUserNotificationSocket() + socket.on('new-notification', n => adminNotificationsServer2.push(n)) + } + + const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) + const channelId = resChannel.body.videoChannels[0].id + + return { + userNotifications, + adminNotifications, + adminNotificationsServer2, + userAccessToken, + emails, + servers, + channelId + } +} + +// --------------------------------------------------------------------------- + +export { + getAllNotificationsSettings, + + CheckerBaseParams, + CheckerType, + checkNotification, + checkMyVideoImportIsFinished, + checkUserRegistered, + checkAutoInstanceFollowing, + checkVideoIsPublished, + checkNewVideoFromSubscription, + checkNewActorFollow, + checkNewCommentOnMyVideo, + checkNewBlacklistOnMyVideo, + checkCommentMention, + checkNewVideoAbuseForModerators, + checkVideoAutoBlacklistForModerators, + checkNewAbuseMessage, + checkAbuseStateChange, + checkNewInstanceFollower, + prepareNotificationsTest, + checkNewCommentAbuseForModerators, + checkNewAccountAbuseForModerators, + checkNewPeerTubeVersion, + checkNewPluginVersion +} diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts deleted file mode 100644 index 961cfcc0f..000000000 --- a/shared/extra-utils/users/user-notifications.ts +++ /dev/null @@ -1,808 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { inspect } from 'util' -import { AbuseState, PluginType } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' -import { MockSmtpServer } from '../mock-servers/mock-email' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' -import { doubleFollow } from '../server/follows' -import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' -import { setAccessTokensToServers, userLogin } from './login' -import { createUser, getMyUserInformation } from './users' - -function updateMyNotificationSettings ( - url: string, - token: string, - settings: UserNotificationSetting, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/me/notification-settings' - - return makePutBodyRequest({ - url, - path, - token, - fields: settings, - statusCodeExpected - }) -} - -async function getUserNotifications ( - url: string, - token: string, - start: number, - count: number, - unread?: boolean, - sort = '-createdAt', - statusCodeExpected = HttpStatusCode.OK_200 -) { - const path = '/api/v1/users/me/notifications' - - return makeGetRequest({ - url, - path, - token, - query: { - start, - count, - sort, - unread - }, - statusCodeExpected - }) -} - -function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/me/notifications/read' - - return makePostBodyRequest({ - url, - path, - token, - fields: { ids }, - statusCodeExpected - }) -} - -function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/me/notifications/read-all' - - return makePostBodyRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -async function getLastNotification (serverUrl: string, accessToken: string) { - const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt') - - if (res.body.total === 0) return undefined - - return res.body.data[0] as UserNotification -} - -type CheckerBaseParams = { - server: ServerInfo - emails: any[] - socketNotifications: UserNotification[] - token: string - check?: { web: boolean, mail: boolean } -} - -type CheckerType = 'presence' | 'absence' - -async function checkNotification ( - base: CheckerBaseParams, - notificationChecker: (notification: UserNotification, type: CheckerType) => void, - emailNotificationFinder: (email: object) => boolean, - checkType: CheckerType -) { - const check = base.check || { web: true, mail: true } - - if (check.web) { - const notification = await getLastNotification(base.server.url, base.token) - - if (notification || checkType !== 'absence') { - notificationChecker(notification, checkType) - } - - const socketNotification = base.socketNotifications.find(n => { - try { - notificationChecker(n, 'presence') - return true - } catch { - return false - } - }) - - if (checkType === 'presence') { - const obj = inspect(base.socketNotifications, { depth: 5 }) - expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined - } else { - const obj = inspect(socketNotification, { depth: 5 }) - expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined - } - } - - if (check.mail) { - // Last email - const email = base.emails - .slice() - .reverse() - .find(e => emailNotificationFinder(e)) - - if (checkType === 'presence') { - const emails = base.emails.map(e => e.text) - expect(email, 'The email is absent when is should be present. ' + inspect(emails)).to.not.be.undefined - } else { - expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined - } - } -} - -function checkVideo (video: any, videoName?: string, videoUUID?: string) { - if (videoName) { - expect(video.name).to.be.a('string') - expect(video.name).to.not.be.empty - expect(video.name).to.equal(videoName) - } - - if (videoUUID) { - expect(video.uuid).to.be.a('string') - expect(video.uuid).to.not.be.empty - expect(video.uuid).to.equal(videoUUID) - } - - expect(video.id).to.be.a('number') -} - -function checkActor (actor: any) { - expect(actor.displayName).to.be.a('string') - expect(actor.displayName).to.not.be.empty - expect(actor.host).to.not.be.undefined -} - -function checkComment (comment: any, commentId: number, threadId: number) { - expect(comment.id).to.equal(commentId) - expect(comment.threadId).to.equal(threadId) -} - -async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkVideo(notification.video, videoName, videoUUID) - checkActor(notification.video.channel) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { - const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkVideo(notification.video, videoName, videoUUID) - checkActor(notification.video.channel) - } else { - expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - return text.includes(videoUUID) && text.includes('Your video') - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkMyVideoImportIsFinished ( - base: CheckerBaseParams, - videoName: string, - videoUUID: string, - url: string, - success: boolean, - type: CheckerType -) { - const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.videoImport.targetUrl).to.equal(url) - - if (success) checkVideo(notification.videoImport.video, videoName, videoUUID) - } else { - expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - const toFind = success ? ' finished' : ' error' - - return text.includes(url) && text.includes(toFind) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_USER_REGISTRATION - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.account) - expect(notification.account.name).to.equal(username) - } else { - expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' registered.') && text.includes(username) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewActorFollow ( - base: CheckerBaseParams, - followType: 'channel' | 'account', - followerName: string, - followerDisplayName: string, - followingDisplayName: string, - type: CheckerType -) { - const notificationType = UserNotificationType.NEW_FOLLOW - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.actorFollow.follower) - expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName) - expect(notification.actorFollow.follower.name).to.equal(followerName) - expect(notification.actorFollow.follower.host).to.not.be.undefined - - const following = notification.actorFollow.following - expect(following.displayName).to.equal(followingDisplayName) - expect(following.type).to.equal(followType) - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || - (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName) - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkActor(notification.actorFollow.follower) - expect(notification.actorFollow.follower.name).to.equal('peertube') - expect(notification.actorFollow.follower.host).to.equal(followerHost) - - expect(notification.actorFollow.following.name).to.equal('peertube') - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || n.actorFollow.follower.host !== followerHost - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes('instance has a new follower') && text.includes(followerHost) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) { - const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - const following = notification.actorFollow.following - checkActor(following) - expect(following.name).to.equal('peertube') - expect(following.host).to.equal(followingHost) - - expect(notification.actorFollow.follower.name).to.equal('peertube') - expect(notification.actorFollow.follower.host).to.equal(followerHost) - } else { - expect(notification).to.satisfy(n => { - return n.type !== notificationType || n.actorFollow.following.host !== followingHost - }) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' automatically followed a new instance') && text.includes(followingHost) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkCommentMention ( - base: CheckerBaseParams, - uuid: string, - commentId: number, - threadId: number, - byAccountDisplayName: string, - type: CheckerType -) { - const notificationType = UserNotificationType.COMMENT_MENTION - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkComment(notification.comment, commentId, threadId) - checkActor(notification.comment.account) - expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) - - checkVideo(notification.comment.video, undefined, uuid) - } else { - expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) - } - } - - function emailNotificationFinder (email: object) { - const text: string = email['text'] - - return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -let lastEmailCount = 0 - -async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { - const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - checkComment(notification.comment, commentId, threadId) - checkActor(notification.comment.account) - checkVideo(notification.comment.video, undefined, uuid) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.comment === undefined || n.comment.id !== commentId - }) - } - } - - const commentUrl = `http://localhost:${base.server.port}/w/${uuid};threadId=${threadId}` - - function emailNotificationFinder (email: object) { - return email['text'].indexOf(commentUrl) !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) - - if (type === 'presence') { - // We cannot detect email duplicates, so check we received another email - expect(base.emails).to.have.length.above(lastEmailCount) - lastEmailCount = base.emails.length - } -} - -async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - checkVideo(notification.abuse.video, videoName, videoUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.video.uuid !== videoUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewAbuseMessage (base: CheckerBaseParams, abuseId: number, message: string, toEmail: string, type: CheckerType) { - const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.equal(abuseId) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - const to = email['to'].filter(t => t.address === toEmail) - - return text.indexOf(message) !== -1 && to.length !== 0 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkAbuseStateChange (base: CheckerBaseParams, abuseId: number, state: AbuseState, type: CheckerType) { - const notificationType = UserNotificationType.ABUSE_STATE_CHANGE - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.equal(abuseId) - expect(notification.abuse.state).to.equal(state) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - const contains = state === AbuseState.ACCEPTED - ? ' accepted' - : ' rejected' - - return text.indexOf(contains) !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewCommentAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - checkVideo(notification.abuse.comment.video, videoName, videoUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.comment.video.uuid !== videoUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displayName: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.abuse.id).to.be.a('number') - expect(notification.abuse.account.displayName).to.equal(displayName) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { - const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.videoBlacklist.video.id).to.be.a('number') - checkVideo(notification.videoBlacklist.video, videoName, videoUUID) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.video === undefined || n.video.uuid !== videoUUID - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewBlacklistOnMyVideo ( - base: CheckerBaseParams, - videoUUID: string, - videoName: string, - blacklistType: 'blacklist' | 'unblacklist' -) { - const notificationType = blacklistType === 'blacklist' - ? UserNotificationType.BLACKLIST_ON_MY_VIDEO - : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO - - function notificationChecker (notification: UserNotification) { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video - - checkVideo(video, videoName, videoUUID) - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, 'presence') -} - -async function checkNewPeerTubeVersion (base: CheckerBaseParams, latestVersion: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.peertube).to.exist - expect(notification.peertube.latestVersion).to.equal(latestVersion) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - return text.includes(latestVersion) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -async function checkNewPluginVersion (base: CheckerBaseParams, pluginType: PluginType, pluginName: string, type: CheckerType) { - const notificationType = UserNotificationType.NEW_PLUGIN_VERSION - - function notificationChecker (notification: UserNotification, type: CheckerType) { - if (type === 'presence') { - expect(notification).to.not.be.undefined - expect(notification.type).to.equal(notificationType) - - expect(notification.plugin.name).to.equal(pluginName) - expect(notification.plugin.type).to.equal(pluginType) - } else { - expect(notification).to.satisfy((n: UserNotification) => { - return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName - }) - } - } - - function emailNotificationFinder (email: object) { - const text = email['text'] - - return text.includes(pluginName) - } - - await checkNotification(base, notificationChecker, emailNotificationFinder, type) -} - -function getAllNotificationsSettings (): UserNotificationSetting { - return { - newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, - newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL - } -} - -async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { - const userNotifications: UserNotification[] = [] - const adminNotifications: UserNotification[] = [] - const adminNotificationsServer2: UserNotification[] = [] - const emails: object[] = [] - - const port = await MockSmtpServer.Instance.collectEmails(emails) - - const overrideConfig = { - smtp: { - hostname: 'localhost', - port - }, - signup: { - limit: 20 - } - } - const servers = await flushAndRunMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) - - await setAccessTokensToServers(servers) - - if (serversCount > 1) { - await doubleFollow(servers[0], servers[1]) - } - - const user = { - username: 'user_1', - password: 'super password' - } - await createUser({ - url: servers[0].url, - accessToken: servers[0].accessToken, - username: user.username, - password: user.password, - videoQuota: 10 * 1000 * 1000 - }) - const userAccessToken = await userLogin(servers[0], user) - - await updateMyNotificationSettings(servers[0].url, userAccessToken, getAllNotificationsSettings()) - await updateMyNotificationSettings(servers[0].url, servers[0].accessToken, getAllNotificationsSettings()) - - if (serversCount > 1) { - await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, getAllNotificationsSettings()) - } - - { - const socket = servers[0].socketIOCommand.getUserNotificationSocket({ token: userAccessToken }) - socket.on('new-notification', n => userNotifications.push(n)) - } - { - const socket = servers[0].socketIOCommand.getUserNotificationSocket() - socket.on('new-notification', n => adminNotifications.push(n)) - } - - if (serversCount > 1) { - const socket = servers[1].socketIOCommand.getUserNotificationSocket() - socket.on('new-notification', n => adminNotificationsServer2.push(n)) - } - - const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) - const channelId = resChannel.body.videoChannels[0].id - - return { - userNotifications, - adminNotifications, - adminNotificationsServer2, - userAccessToken, - emails, - servers, - channelId - } -} - -// --------------------------------------------------------------------------- - -export { - CheckerBaseParams, - CheckerType, - getAllNotificationsSettings, - checkNotification, - markAsReadAllNotifications, - checkMyVideoImportIsFinished, - checkUserRegistered, - checkAutoInstanceFollowing, - checkVideoIsPublished, - checkNewVideoFromSubscription, - checkNewActorFollow, - checkNewCommentOnMyVideo, - checkNewBlacklistOnMyVideo, - checkCommentMention, - updateMyNotificationSettings, - checkNewVideoAbuseForModerators, - checkVideoAutoBlacklistForModerators, - checkNewAbuseMessage, - checkAbuseStateChange, - getUserNotifications, - markAsReadNotifications, - getLastNotification, - checkNewInstanceFollower, - prepareNotificationsTest, - checkNewCommentAbuseForModerators, - checkNewAccountAbuseForModerators, - checkNewPeerTubeVersion, - checkNewPluginVersion -} diff --git a/shared/extra-utils/videos/streaming-playlists-command.ts b/shared/extra-utils/videos/streaming-playlists-command.ts index b109597c9..fab3eb556 100644 --- a/shared/extra-utils/videos/streaming-playlists-command.ts +++ b/shared/extra-utils/videos/streaming-playlists-command.ts @@ -21,7 +21,7 @@ export class StreamingPlaylistsCommand extends AbstractCommand { url: string range?: string }) { - return unwrapText(this.getRawRequest({ + return unwrapBody(this.getRawRequest({ ...options, url: options.url, -- cgit v1.2.3 From 5e2fea3ab9357c228b5d21166092f9a2368e258e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 12 Jul 2021 16:06:57 +0200 Subject: Fix search tests --- shared/extra-utils/search/search-command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts index b6054f093..7539a21ec 100644 --- a/shared/extra-utils/search/search-command.ts +++ b/shared/extra-utils/search/search-command.ts @@ -90,7 +90,7 @@ export class SearchCommand extends AbstractCommand { ...options, path, - query: { sort: '-publishedAt', ...search }, + query: search, implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 }) -- cgit v1.2.3 From 6c5065a011b099618681a37bd77eaa7bd3db752e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 13 Jul 2021 09:43:59 +0200 Subject: Introduce server commands --- shared/extra-utils/miscs/checks.ts | 46 +++++++ shared/extra-utils/miscs/generate.ts | 61 +++++++++ shared/extra-utils/miscs/index.ts | 6 +- shared/extra-utils/miscs/miscs.ts | 170 ------------------------ shared/extra-utils/miscs/sql-command.ts | 2 +- shared/extra-utils/miscs/stubs.ts | 7 - shared/extra-utils/miscs/tests.ts | 62 +++++++++ shared/extra-utils/miscs/webtorrent.ts | 16 +++ shared/extra-utils/mock-servers/mock-email.ts | 4 +- shared/extra-utils/requests/check-api-params.ts | 11 +- shared/extra-utils/requests/requests.ts | 4 +- shared/extra-utils/server/directories.ts | 34 +++++ shared/extra-utils/server/index.ts | 2 + shared/extra-utils/server/jobs.ts | 2 +- shared/extra-utils/server/plugins-command.ts | 3 +- shared/extra-utils/server/servers-command.ts | 81 +++++++++++ shared/extra-utils/server/servers.ts | 108 ++------------- shared/extra-utils/shared/abstract-command.ts | 2 +- shared/extra-utils/videos/captions-command.ts | 4 +- shared/extra-utils/videos/live-command.ts | 7 +- shared/extra-utils/videos/live.ts | 4 +- shared/extra-utils/videos/playlists.ts | 2 +- shared/extra-utils/videos/videos.ts | 30 +---- 23 files changed, 345 insertions(+), 323 deletions(-) create mode 100644 shared/extra-utils/miscs/checks.ts create mode 100644 shared/extra-utils/miscs/generate.ts delete mode 100644 shared/extra-utils/miscs/miscs.ts delete mode 100644 shared/extra-utils/miscs/stubs.ts create mode 100644 shared/extra-utils/miscs/tests.ts create mode 100644 shared/extra-utils/miscs/webtorrent.ts create mode 100644 shared/extra-utils/server/directories.ts create mode 100644 shared/extra-utils/server/servers-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/checks.ts b/shared/extra-utils/miscs/checks.ts new file mode 100644 index 000000000..86b861cd2 --- /dev/null +++ b/shared/extra-utils/miscs/checks.ts @@ -0,0 +1,46 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ + +import { expect } from 'chai' +import { pathExists, readFile } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { makeGetRequest } from '../requests' +import { ServerInfo } from '../server' + +// Default interval -> 5 minutes +function dateIsValid (dateString: string, interval = 300000) { + const dateToCheck = new Date(dateString) + const now = new Date() + + return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval +} + +async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { + const res = await makeGetRequest({ + url, + path: imagePath, + statusCodeExpected: HttpStatusCode.OK_200 + }) + + const body = res.body + + const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) + const minLength = body.length - ((30 * body.length) / 100) + const maxLength = body.length + ((30 * body.length) / 100) + + expect(data.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') + expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') +} + +async function testFileExistsOrNot (server: ServerInfo, directory: string, filePath: string, exist: boolean) { + const base = server.serversCommand.buildDirectory(directory) + + expect(await pathExists(join(base, filePath))).to.equal(exist) +} + +export { + dateIsValid, + testImage, + testFileExistsOrNot +} diff --git a/shared/extra-utils/miscs/generate.ts b/shared/extra-utils/miscs/generate.ts new file mode 100644 index 000000000..4e70ab853 --- /dev/null +++ b/shared/extra-utils/miscs/generate.ts @@ -0,0 +1,61 @@ +import { ensureDir, pathExists } from 'fs-extra' +import { dirname } from 'path' +import { buildAbsoluteFixturePath } from './tests' +import * as ffmpeg from 'fluent-ffmpeg' + +async function generateHighBitrateVideo () { + const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) + + await ensureDir(dirname(tempFixturePath)) + + const exists = await pathExists(tempFixturePath) + if (!exists) { + console.log('Generating high bitrate video.') + + // Generate a random, high bitrate video on the fly, so we don't have to include + // a large file in the repo. The video needs to have a certain minimum length so + // that FFmpeg properly applies bitrate limits. + // https://stackoverflow.com/a/15795112 + return new Promise((res, rej) => { + ffmpeg() + .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) + .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) + .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) + .output(tempFixturePath) + .on('error', rej) + .on('end', () => res(tempFixturePath)) + .run() + }) + } + + return tempFixturePath +} + +async function generateVideoWithFramerate (fps = 60) { + const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) + + await ensureDir(dirname(tempFixturePath)) + + const exists = await pathExists(tempFixturePath) + if (!exists) { + console.log('Generating video with framerate %d.', fps) + + return new Promise((res, rej) => { + ffmpeg() + .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) + .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) + .outputOptions([ `-r ${fps}` ]) + .output(tempFixturePath) + .on('error', rej) + .on('end', () => res(tempFixturePath)) + .run() + }) + } + + return tempFixturePath +} + +export { + generateHighBitrateVideo, + generateVideoWithFramerate +} diff --git a/shared/extra-utils/miscs/index.ts b/shared/extra-utils/miscs/index.ts index 7e236c329..4474661de 100644 --- a/shared/extra-utils/miscs/index.ts +++ b/shared/extra-utils/miscs/index.ts @@ -1,3 +1,5 @@ -export * from './miscs' +export * from './checks' +export * from './generate' export * from './sql-command' -export * from './stubs' +export * from './tests' +export * from './webtorrent' diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts deleted file mode 100644 index 462b914d4..000000000 --- a/shared/extra-utils/miscs/miscs.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import * as chai from 'chai' -import * as ffmpeg from 'fluent-ffmpeg' -import { ensureDir, pathExists, readFile, stat } from 'fs-extra' -import { basename, dirname, isAbsolute, join, resolve } from 'path' -import * as request from 'supertest' -import * as WebTorrent from 'webtorrent' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -const expect = chai.expect -let webtorrent: WebTorrent.Instance - -function immutableAssign (target: T, source: U) { - return Object.assign<{}, T, U>({}, target, source) -} - -// Default interval -> 5 minutes -function dateIsValid (dateString: string, interval = 300000) { - const dateToCheck = new Date(dateString) - const now = new Date() - - return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval -} - -function wait (milliseconds: number) { - return new Promise(resolve => setTimeout(resolve, milliseconds)) -} - -function webtorrentAdd (torrent: string, refreshWebTorrent = false) { - const WebTorrent = require('webtorrent') - - if (!webtorrent) webtorrent = new WebTorrent() - if (refreshWebTorrent === true) webtorrent = new WebTorrent() - - return new Promise(res => webtorrent.add(torrent, res)) -} - -function root () { - // We are in /miscs - let root = join(__dirname, '..', '..', '..') - - if (basename(root) === 'dist') root = resolve(root, '..') - - return root -} - -function buildServerDirectory (server: { internalServerNumber: number }, directory: string) { - return join(root(), 'test' + server.internalServerNumber, directory) -} - -async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { - const res = await request(url) - .get(imagePath) - .expect(HttpStatusCode.OK_200) - - const body = res.body - - const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) - const minLength = body.length - ((30 * body.length) / 100) - const maxLength = body.length + ((30 * body.length) / 100) - - expect(data.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') - expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') -} - -async function testFileExistsOrNot (server: { internalServerNumber: number }, directory: string, filePath: string, exist: boolean) { - const base = buildServerDirectory(server, directory) - - expect(await pathExists(join(base, filePath))).to.equal(exist) -} - -function isGithubCI () { - return !!process.env.GITHUB_WORKSPACE -} - -function buildAbsoluteFixturePath (path: string, customCIPath = false) { - if (isAbsolute(path)) return path - - if (customCIPath && process.env.GITHUB_WORKSPACE) { - return join(process.env.GITHUB_WORKSPACE, 'fixtures', path) - } - - return join(root(), 'server', 'tests', 'fixtures', path) -} - -function areHttpImportTestsDisabled () { - const disabled = process.env.DISABLE_HTTP_IMPORT_TESTS === 'true' - - if (disabled) console.log('Import tests are disabled') - - return disabled -} - -async function generateHighBitrateVideo () { - const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating high bitrate video.') - - // Generate a random, high bitrate video on the fly, so we don't have to include - // a large file in the repo. The video needs to have a certain minimum length so - // that FFmpeg properly applies bitrate limits. - // https://stackoverflow.com/a/15795112 - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - return tempFixturePath -} - -async function generateVideoWithFramerate (fps = 60) { - const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) - - await ensureDir(dirname(tempFixturePath)) - - const exists = await pathExists(tempFixturePath) - if (!exists) { - console.log('Generating video with framerate %d.', fps) - - return new Promise((res, rej) => { - ffmpeg() - .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) - .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) - .outputOptions([ `-r ${fps}` ]) - .output(tempFixturePath) - .on('error', rej) - .on('end', () => res(tempFixturePath)) - .run() - }) - } - - return tempFixturePath -} - -async function getFileSize (path: string) { - const stats = await stat(path) - - return stats.size -} - -// --------------------------------------------------------------------------- - -export { - dateIsValid, - wait, - areHttpImportTestsDisabled, - buildServerDirectory, - webtorrentAdd, - getFileSize, - immutableAssign, - testImage, - isGithubCI, - buildAbsoluteFixturePath, - testFileExistsOrNot, - root, - generateHighBitrateVideo, - generateVideoWithFramerate -} diff --git a/shared/extra-utils/miscs/sql-command.ts b/shared/extra-utils/miscs/sql-command.ts index 2a3e9e607..80c8cd271 100644 --- a/shared/extra-utils/miscs/sql-command.ts +++ b/shared/extra-utils/miscs/sql-command.ts @@ -1,5 +1,5 @@ import { QueryTypes, Sequelize } from 'sequelize' -import { AbstractCommand } from '../shared' +import { AbstractCommand } from '../shared/abstract-command' export class SQLCommand extends AbstractCommand { private sequelize: Sequelize diff --git a/shared/extra-utils/miscs/stubs.ts b/shared/extra-utils/miscs/stubs.ts deleted file mode 100644 index 940e4bf29..000000000 --- a/shared/extra-utils/miscs/stubs.ts +++ /dev/null @@ -1,7 +0,0 @@ -function buildRequestStub (): any { - return { } -} - -export { - buildRequestStub -} diff --git a/shared/extra-utils/miscs/tests.ts b/shared/extra-utils/miscs/tests.ts new file mode 100644 index 000000000..8f7a2f92b --- /dev/null +++ b/shared/extra-utils/miscs/tests.ts @@ -0,0 +1,62 @@ +import { stat } from 'fs-extra' +import { basename, isAbsolute, join, resolve } from 'path' + +function parallelTests () { + return process.env.MOCHA_PARALLEL === 'true' +} + +function isGithubCI () { + return !!process.env.GITHUB_WORKSPACE +} + +function areHttpImportTestsDisabled () { + const disabled = process.env.DISABLE_HTTP_IMPORT_TESTS === 'true' + + if (disabled) console.log('Import tests are disabled') + + return disabled +} + +function buildAbsoluteFixturePath (path: string, customCIPath = false) { + if (isAbsolute(path)) return path + + if (customCIPath && process.env.GITHUB_WORKSPACE) { + return join(process.env.GITHUB_WORKSPACE, 'fixtures', path) + } + + return join(root(), 'server', 'tests', 'fixtures', path) +} + +function root () { + // We are in /miscs + let root = join(__dirname, '..', '..', '..') + + if (basename(root) === 'dist') root = resolve(root, '..') + + return root +} + +function wait (milliseconds: number) { + return new Promise(resolve => setTimeout(resolve, milliseconds)) +} + +async function getFileSize (path: string) { + const stats = await stat(path) + + return stats.size +} + +function buildRequestStub (): any { + return { } +} + +export { + parallelTests, + isGithubCI, + areHttpImportTestsDisabled, + buildAbsoluteFixturePath, + getFileSize, + buildRequestStub, + wait, + root +} diff --git a/shared/extra-utils/miscs/webtorrent.ts b/shared/extra-utils/miscs/webtorrent.ts new file mode 100644 index 000000000..82548946d --- /dev/null +++ b/shared/extra-utils/miscs/webtorrent.ts @@ -0,0 +1,16 @@ +import * as WebTorrent from 'webtorrent' + +let webtorrent: WebTorrent.Instance + +function webtorrentAdd (torrent: string, refreshWebTorrent = false) { + const WebTorrent = require('webtorrent') + + if (!webtorrent) webtorrent = new WebTorrent() + if (refreshWebTorrent === true) webtorrent = new WebTorrent() + + return new Promise(res => webtorrent.add(torrent, res)) +} + +export { + webtorrentAdd +} diff --git a/shared/extra-utils/mock-servers/mock-email.ts b/shared/extra-utils/mock-servers/mock-email.ts index 9fc9a5ad0..ffd62e325 100644 --- a/shared/extra-utils/mock-servers/mock-email.ts +++ b/shared/extra-utils/mock-servers/mock-email.ts @@ -1,6 +1,6 @@ import { ChildProcess } from 'child_process' -import { randomInt } from '../../core-utils/miscs/miscs' -import { parallelTests } from '../server/servers' +import { randomInt } from '@shared/core-utils' +import { parallelTests } from '../miscs' const MailDev = require('maildev') diff --git a/shared/extra-utils/requests/check-api-params.ts b/shared/extra-utils/requests/check-api-params.ts index 7f5ff775c..7df63b004 100644 --- a/shared/extra-utils/requests/check-api-params.ts +++ b/shared/extra-utils/requests/check-api-params.ts @@ -1,13 +1,12 @@ +import { HttpStatusCode } from '@shared/core-utils' import { makeGetRequest } from './requests' -import { immutableAssign } from '../miscs/miscs' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' function checkBadStartPagination (url: string, path: string, token?: string, query = {}) { return makeGetRequest({ url, path, token, - query: immutableAssign(query, { start: 'hello' }), + query: { ...query, start: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } @@ -17,7 +16,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin url, path, token, - query: immutableAssign(query, { count: 'hello' }), + query: { ...query, count: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) @@ -25,7 +24,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin url, path, token, - query: immutableAssign(query, { count: 2000 }), + query: { ...query, count: 2000 }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } @@ -35,7 +34,7 @@ function checkBadSortPagination (url: string, path: string, token?: string, quer url, path, token, - query: immutableAssign(query, { sort: 'hello' }), + query: { ...query, sort: 'hello' }, statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 }) } diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 3fbaa31d6..f9d112aca 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -4,8 +4,8 @@ import { isAbsolute, join } from 'path' import { decode } from 'querystring' import * as request from 'supertest' import { URL } from 'url' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { buildAbsoluteFixturePath, root } from '../miscs/miscs' +import { HttpStatusCode } from '@shared/core-utils' +import { buildAbsoluteFixturePath, root } from '../miscs/tests' function get4KFileUrl () { return 'https://download.cpy.re/peertube/4k_file.txt' diff --git a/shared/extra-utils/server/directories.ts b/shared/extra-utils/server/directories.ts new file mode 100644 index 000000000..3cd38a561 --- /dev/null +++ b/shared/extra-utils/server/directories.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { pathExists, readdir } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { ServerInfo } from './servers' + +async function checkTmpIsEmpty (server: ServerInfo) { + await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) + + if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { + await checkDirectoryIsEmpty(server, 'tmp/hls') + } +} + +async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) { + const testDirectory = 'test' + server.internalServerNumber + + const directoryPath = join(root(), testDirectory, directory) + + const directoryExists = await pathExists(directoryPath) + expect(directoryExists).to.be.true + + const files = await readdir(directoryPath) + const filtered = files.filter(f => exceptions.includes(f) === false) + + expect(filtered).to.have.lengthOf(0) +} + +export { + checkTmpIsEmpty, + checkDirectoryIsEmpty +} diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 03c3b0123..669b004cd 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -1,6 +1,7 @@ export * from './config-command' export * from './contact-form-command' export * from './debug-command' +export * from './directories' export * from './follows-command' export * from './follows' export * from './jobs' @@ -8,5 +9,6 @@ export * from './jobs-command' export * from './plugins-command' export * from './plugins' export * from './redundancy-command' +export * from './servers-command' export * from './servers' export * from './stats-command' diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index b4b3d52e7..36ef882b3 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -1,6 +1,6 @@ import { JobState } from '../../models' -import { wait } from '../miscs/miscs' +import { wait } from '../miscs' import { ServerInfo } from './servers' async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index ff49d58c4..5bed51d1a 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -15,7 +15,6 @@ import { RegisteredServerSettings, ResultList } from '@shared/models' -import { buildServerDirectory } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class PluginsCommand extends AbstractCommand { @@ -252,6 +251,6 @@ export class PluginsCommand extends AbstractCommand { } private getPackageJSONPath (npmName: string) { - return buildServerDirectory(this.server, join('plugins', 'node_modules', npmName, 'package.json')) + return this.server.serversCommand.buildDirectory(join('plugins', 'node_modules', npmName, 'package.json')) } } diff --git a/shared/extra-utils/server/servers-command.ts b/shared/extra-utils/server/servers-command.ts new file mode 100644 index 000000000..9ef68fede --- /dev/null +++ b/shared/extra-utils/server/servers-command.ts @@ -0,0 +1,81 @@ +import { exec } from 'child_process' +import { copy, ensureDir, readFile, remove } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { HttpStatusCode } from '@shared/core-utils' +import { getFileSize } from '@uploadx/core' +import { isGithubCI, wait } from '../miscs' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class ServersCommand extends AbstractCommand { + + static flushTests (internalServerNumber: number) { + return new Promise((res, rej) => { + const suffix = ` -- ${internalServerNumber}` + + return exec('npm run clean:server:test' + suffix, (err, _stdout, stderr) => { + if (err || stderr) return rej(err || new Error(stderr)) + + return res() + }) + }) + } + + ping (options: OverrideCommandOptions = {}) { + return this.getRequestBody({ + ...options, + + path: '/api/v1/ping', + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + async cleanupTests () { + const p: Promise[] = [] + + if (isGithubCI()) { + await ensureDir('artifacts') + + const origin = this.server.serversCommand.buildDirectory('logs/peertube.log') + const destname = `peertube-${this.server.internalServerNumber}.log` + console.log('Saving logs %s.', destname) + + await copy(origin, join('artifacts', destname)) + } + + if (this.server.parallel) { + p.push(ServersCommand.flushTests(this.server.internalServerNumber)) + } + + if (this.server.customConfigFile) { + p.push(remove(this.server.customConfigFile)) + } + + return p + } + + async waitUntilLog (str: string, count = 1, strictCount = true) { + const logfile = this.server.serversCommand.buildDirectory('logs/peertube.log') + + while (true) { + const buf = await readFile(logfile) + + const matches = buf.toString().match(new RegExp(str, 'g')) + if (matches && matches.length === count) return + if (matches && strictCount === false && matches.length >= count) return + + await wait(1000) + } + } + + buildDirectory (directory: string) { + return join(root(), 'test' + this.server.internalServerNumber, directory) + } + + async getServerFileSize (subPath: string) { + const path = this.server.serversCommand.buildDirectory(subPath) + + return getFileSize(path) + } +} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index e0e49d2c4..f5dc0326f 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ -import { expect } from 'chai' -import { ChildProcess, exec, fork } from 'child_process' -import { copy, ensureDir, pathExists, readdir, readFile, remove } from 'fs-extra' +import { ChildProcess, fork } from 'child_process' +import { copy, ensureDir } from 'fs-extra' import { join } from 'path' +import { root } from '@server/helpers/core-utils' import { randomInt } from '../../core-utils/miscs/miscs' import { VideoChannel } from '../../models/videos' import { BulkCommand } from '../bulk' @@ -11,11 +11,9 @@ import { CLICommand } from '../cli' import { CustomPagesCommand } from '../custom-pages' import { FeedCommand } from '../feeds' import { LogsCommand } from '../logs' -import { SQLCommand } from '../miscs' -import { buildServerDirectory, getFileSize, isGithubCI, root, wait } from '../miscs/miscs' +import { isGithubCI, parallelTests, SQLCommand } from '../miscs' import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' -import { makeGetRequest } from '../requests/requests' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' import { AccountsCommand, BlocklistCommand, NotificationsCommand, SubscriptionsCommand } from '../users' @@ -39,6 +37,7 @@ import { FollowsCommand } from './follows-command' import { JobsCommand } from './jobs-command' import { PluginsCommand } from './plugins-command' import { RedundancyCommand } from './redundancy-command' +import { ServersCommand } from './servers-command' import { StatsCommand } from './stats-command' interface ServerInfo { @@ -126,10 +125,7 @@ interface ServerInfo { commentsCommand?: CommentsCommand sqlCommand?: SQLCommand notificationsCommand?: NotificationsCommand -} - -function parallelTests () { - return process.env.MOCHA_PARALLEL === 'true' + serversCommand?: ServersCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -151,18 +147,6 @@ function flushAndRunMultipleServers (totalServers: number, configOverride?: Obje }) } -function flushTests (serverNumber?: number) { - return new Promise((res, rej) => { - const suffix = serverNumber ? ` -- ${serverNumber}` : '' - - return exec('npm run clean:server:test' + suffix, (err, _stdout, stderr) => { - if (err || stderr) return rej(err || new Error(stderr)) - - return res() - }) - }) -} - function randomServer () { const low = 10 const high = 10000 @@ -189,7 +173,7 @@ async function flushAndRunServer (serverNumber: number, configOverride?: Object, const rtmpPort = parallel ? randomRTMP() : 1936 const port = 9000 + internalServerNumber - await flushTests(internalServerNumber) + await ServersCommand.flushTests(internalServerNumber) const server: ServerInfo = { app: null, @@ -372,6 +356,7 @@ function assignCommands (server: ServerInfo) { server.commentsCommand = new CommentsCommand(server) server.sqlCommand = new SQLCommand(server) server.notificationsCommand = new NotificationsCommand(server) + server.serversCommand = new ServersCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { @@ -381,28 +366,6 @@ async function reRunServer (server: ServerInfo, configOverride?: any) { return server } -async function checkTmpIsEmpty (server: ServerInfo) { - await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) - - if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { - await checkDirectoryIsEmpty(server, 'tmp/hls') - } -} - -async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) { - const testDirectory = 'test' + server.internalServerNumber - - const directoryPath = join(root(), testDirectory, directory) - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - const filtered = files.filter(f => exceptions.includes(f) === false) - - expect(filtered).to.have.lengthOf(0) -} - async function killallServers (servers: ServerInfo[]) { for (const server of servers) { if (!server.app) continue @@ -422,71 +385,22 @@ async function cleanupTests (servers: ServerInfo[]) { await ensureDir('artifacts') } - const p: Promise[] = [] + let p: Promise[] = [] for (const server of servers) { - if (isGithubCI()) { - const origin = await buildServerDirectory(server, 'logs/peertube.log') - const destname = `peertube-${server.internalServerNumber}.log` - console.log('Saving logs %s.', destname) - - await copy(origin, join('artifacts', destname)) - } - - if (server.parallel) { - p.push(flushTests(server.internalServerNumber)) - } - - if (server.customConfigFile) { - p.push(remove(server.customConfigFile)) - } + p = p.concat(server.serversCommand.cleanupTests()) } return Promise.all(p) } -async function waitUntilLog (server: ServerInfo, str: string, count = 1, strictCount = true) { - const logfile = buildServerDirectory(server, 'logs/peertube.log') - - while (true) { - const buf = await readFile(logfile) - - const matches = buf.toString().match(new RegExp(str, 'g')) - if (matches && matches.length === count) return - if (matches && strictCount === false && matches.length >= count) return - - await wait(1000) - } -} - -async function getServerFileSize (server: ServerInfo, subPath: string) { - const path = buildServerDirectory(server, subPath) - - return getFileSize(path) -} - -function makePingRequest (server: ServerInfo) { - return makeGetRequest({ - url: server.url, - path: '/api/v1/ping', - statusCodeExpected: 200 - }) -} - // --------------------------------------------------------------------------- export { - checkDirectoryIsEmpty, - checkTmpIsEmpty, - getServerFileSize, ServerInfo, - parallelTests, cleanupTests, flushAndRunMultipleServers, - flushTests, - makePingRequest, flushAndRunServer, killallServers, reRunServer, - assignCommands, - waitUntilLog + assignCommands } diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index fd2deb57e..4e61554a2 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,6 +1,6 @@ import { isAbsolute, join } from 'path' import { HttpStatusCode } from '@shared/core-utils' -import { root } from '../miscs/miscs' +import { root } from '../miscs/tests' import { makeDeleteRequest, makeGetRequest, diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts index 908b6dae6..ac3bde7a9 100644 --- a/shared/extra-utils/videos/captions-command.ts +++ b/shared/extra-utils/videos/captions-command.ts @@ -1,6 +1,6 @@ +import { HttpStatusCode } from '@shared/core-utils' import { ResultList, VideoCaption } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { buildAbsoluteFixturePath } from '../miscs/miscs' +import { buildAbsoluteFixturePath } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CaptionsCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index 4f03c9127..a494e60fa 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -5,9 +5,8 @@ import { omit } from 'lodash' import { join } from 'path' import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { buildServerDirectory, wait } from '../miscs/miscs' +import { wait } from '../miscs' import { unwrapBody } from '../requests' -import { waitUntilLog } from '../server/servers' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { sendRTMPStream, testFfmpegStreamError } from './live' import { getVideoWithToken } from './videos' @@ -116,7 +115,7 @@ export class LiveCommand extends AbstractCommand { const { resolution, segment, videoUUID } = options const segmentName = `${resolution}-00000${segment}.ts` - return waitUntilLog(this.server, `${videoUUID}/${segmentName}`, 2, false) + return this.server.serversCommand.waitUntilLog(`${videoUUID}/${segmentName}`, 2, false) } async waitUntilSaved (options: OverrideCommandOptions & { @@ -135,7 +134,7 @@ export class LiveCommand extends AbstractCommand { async countPlaylists (options: OverrideCommandOptions & { videoUUID: string }) { - const basePath = buildServerDirectory(this.server, 'streaming-playlists') + const basePath = this.server.serversCommand.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', options.videoUUID) const files = await readdir(hlsPath) diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index 92cb9104c..0efcc2883 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -4,7 +4,7 @@ import { expect } from 'chai' import * as ffmpeg from 'fluent-ffmpeg' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' -import { buildAbsoluteFixturePath, buildServerDirectory, wait } from '../miscs/miscs' +import { buildAbsoluteFixturePath, wait } from '../miscs' import { ServerInfo } from '../server/servers' function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') { @@ -77,7 +77,7 @@ async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoI } async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) { - const basePath = buildServerDirectory(server, 'streaming-playlists') + const basePath = server.serversCommand.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', videoUUID) if (resolutions.length === 0) { diff --git a/shared/extra-utils/videos/playlists.ts b/shared/extra-utils/videos/playlists.ts index 023333c87..3dde52bb9 100644 --- a/shared/extra-utils/videos/playlists.ts +++ b/shared/extra-utils/videos/playlists.ts @@ -1,7 +1,7 @@ import { expect } from 'chai' import { readdir } from 'fs-extra' import { join } from 'path' -import { root } from '../' +import { root } from '../miscs' async function checkPlaylistFilesWereRemoved ( playlistUUID: string, diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 920c93072..5dd71ce8b 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -13,15 +13,7 @@ import { HttpStatusCode } from '@shared/core-utils' import { BooleanBothQuery, VideosCommonQuery } from '@shared/models' import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' import { VideoDetails, VideoPrivacy } from '../../models/videos' -import { - buildAbsoluteFixturePath, - buildServerDirectory, - dateIsValid, - immutableAssign, - testImage, - wait, - webtorrentAdd -} from '../miscs/miscs' +import { buildAbsoluteFixturePath, dateIsValid, testImage, wait, webtorrentAdd } from '../miscs' import { makeGetRequest, makePutBodyRequest, makeRawRequest, makeUploadRequest } from '../requests/requests' import { waitJobs } from '../server/jobs' import { ServerInfo } from '../server/servers' @@ -165,7 +157,7 @@ function getVideosListWithToken (url: string, token: string, query: { nsfw?: Boo return request(url) .get(path) .set('Authorization', 'Bearer ' + token) - .query(immutableAssign(query, { sort: 'name' })) + .query({ sort: 'name', ...query }) .set('Accept', 'application/json') .expect(HttpStatusCode.OK_200) .expect('Content-Type', /json/) @@ -228,11 +220,7 @@ function getAccountVideos ( return makeGetRequest({ url, path, - query: immutableAssign(query, { - start, - count, - sort - }), + query: { ...query, start, count, sort }, token: accessToken, statusCodeExpected: HttpStatusCode.OK_200 }) @@ -252,11 +240,7 @@ function getVideoChannelVideos ( return makeGetRequest({ url, path, - query: immutableAssign(query, { - start, - count, - sort - }), + query: { ...query, start, count, sort }, token: accessToken, statusCodeExpected: HttpStatusCode.OK_200 }) @@ -320,7 +304,7 @@ async function removeAllVideos (server: ServerInfo) { async function checkVideoFilesWereRemoved ( videoUUID: string, - serverNumber: number, + server: ServerInfo, directories = [ 'redundancy', 'videos', @@ -333,7 +317,7 @@ async function checkVideoFilesWereRemoved ( ] ) { for (const directory of directories) { - const directoryPath = buildServerDirectory({ internalServerNumber: serverNumber }, directory) + const directoryPath = server.serversCommand.buildDirectory(directory) const directoryExists = await pathExists(directoryPath) if (directoryExists === false) continue @@ -607,7 +591,7 @@ function rateVideo (url: string, accessToken: string, id: number | string, ratin function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { return new Promise((res, rej) => { const torrentName = videoUUID + '-' + resolution + '.torrent' - const torrentPath = buildServerDirectory(server, join('torrents', torrentName)) + const torrentPath = server.serversCommand.buildDirectory(join('torrents', torrentName)) readFile(torrentPath, (err, data) => { if (err) return rej(err) -- cgit v1.2.3 From 41d1d075011174e73dccb74006181a92a618d7b4 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 13 Jul 2021 11:05:15 +0200 Subject: Introduce login command --- shared/extra-utils/requests/requests.ts | 4 + shared/extra-utils/server/clients.ts | 20 ---- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/shared/abstract-command.ts | 10 +- shared/extra-utils/users/index.ts | 1 + shared/extra-utils/users/login-command.ts | 134 ++++++++++++++++++++++++++ shared/extra-utils/users/login.ts | 120 +---------------------- shared/extra-utils/users/notifications.ts | 4 +- shared/extra-utils/users/users.ts | 5 +- 9 files changed, 156 insertions(+), 146 deletions(-) delete mode 100644 shared/extra-utils/server/clients.ts create mode 100644 shared/extra-utils/users/login-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index f9d112aca..c5ee63e05 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -27,6 +27,7 @@ function makeGetRequest (options: { range?: string redirects?: number accept?: string + host?: string }) { if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 if (options.contentType === undefined) options.contentType = 'application/json' @@ -38,6 +39,7 @@ function makeGetRequest (options: { if (options.query) req.query(options.query) if (options.range) req.set('Range', options.range) if (options.accept) req.set('Accept', options.accept) + if (options.host) req.set('Host', options.host) if (options.redirects) req.redirects(options.redirects) return req.expect(options.statusCodeExpected) @@ -113,6 +115,7 @@ function makePostBodyRequest (options: { path: string token?: string fields?: { [ fieldName: string ]: any } + type?: string statusCodeExpected?: HttpStatusCode }) { if (!options.fields) options.fields = {} @@ -123,6 +126,7 @@ function makePostBodyRequest (options: { .set('Accept', 'application/json') if (options.token) req.set('Authorization', 'Bearer ' + options.token) + if (options.type) req.type(options.type) return req.send(options.fields) .expect(options.statusCodeExpected) diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts deleted file mode 100644 index 894fe4911..000000000 --- a/shared/extra-utils/server/clients.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as request from 'supertest' -import { URL } from 'url' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -function getClient (url: string) { - const path = '/api/v1/oauth-clients/local' - - return request(url) - .get(path) - .set('Host', new URL(url).host) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -// --------------------------------------------------------------------------- - -export { - getClient -} diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index f5dc0326f..4d9599680 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -16,7 +16,7 @@ import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' -import { AccountsCommand, BlocklistCommand, NotificationsCommand, SubscriptionsCommand } from '../users' +import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand } from '../users' import { BlacklistCommand, CaptionsCommand, @@ -126,6 +126,7 @@ interface ServerInfo { sqlCommand?: SQLCommand notificationsCommand?: NotificationsCommand serversCommand?: ServersCommand + loginCommand?: LoginCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -357,6 +358,7 @@ function assignCommands (server: ServerInfo) { server.sqlCommand = new SQLCommand(server) server.notificationsCommand = new NotificationsCommand(server) server.serversCommand = new ServersCommand(server) + server.loginCommand = new LoginCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 4e61554a2..af9ecd926 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -33,6 +33,7 @@ interface InternalGetCommandOptions extends InternalCommonCommandOptions { accept?: string redirects?: number range?: string + host?: string } abstract class AbstractCommand { @@ -78,7 +79,7 @@ abstract class AbstractCommand { } protected getRequest (options: InternalGetCommandOptions) { - const { redirects, query, contentType, accept, range } = options + const { redirects, query, contentType, accept, range, host } = options return makeGetRequest({ ...this.buildCommonRequestOptions(options), @@ -87,6 +88,7 @@ abstract class AbstractCommand { query, contentType, range, + host, accept }) } @@ -109,13 +111,15 @@ abstract class AbstractCommand { protected postBodyRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } + type?: string }) { - const { fields } = options + const { type, fields } = options return makePostBodyRequest({ ...this.buildCommonRequestOptions(options), - fields + fields, + type }) } diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index ed166c756..b200ae705 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -2,6 +2,7 @@ export * from './accounts-command' export * from './accounts' export * from './blocklist-command' export * from './login' +export * from './login-command' export * from './notifications' export * from './notifications-command' export * from './subscriptions-command' diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts new file mode 100644 index 000000000..97efcb766 --- /dev/null +++ b/shared/extra-utils/users/login-command.ts @@ -0,0 +1,134 @@ +import { PeerTubeRequestError } from '@server/helpers/requests' +import { HttpStatusCode } from '@shared/core-utils' +import { PeerTubeProblemDocument } from '@shared/models' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class LoginCommand extends AbstractCommand { + + login (options: OverrideCommandOptions & { + client?: { id?: string, secret?: string } + user?: { username: string, password: string } + } = {}) { + const { client = this.server.client, user = this.server.user } = options + const path = '/api/v1/users/token' + + const body = { + client_id: client.id, + client_secret: client.secret, + username: user.username, + password: user.password, + response_type: 'code', + grant_type: 'password', + scope: 'upload' + } + + return unwrapBody<{ access_token: string, refresh_token: string } & PeerTubeProblemDocument>(this.postBodyRequest({ + ...options, + + path, + type: 'form', + fields: body, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + getAccessToken (user?: { username: string, password: string }): Promise + getAccessToken (username: string, password: string): Promise + async getAccessToken (arg1?: { username: string, password: string } | string, password?: string) { + let user: { username: string, password: string } + + if (!arg1) user = this.server.user + else if (typeof arg1 === 'object') user = arg1 + else user = { username: arg1, password } + + try { + const body = await this.login({ user }) + + return body.access_token + } catch (err) { + throw new Error('Cannot authenticate. Please check your username/password.') + } + } + + loginUsingExternalToken (options: OverrideCommandOptions & { + username: string + externalAuthToken: string + }) { + const { username, externalAuthToken } = options + const path = '/api/v1/users/token' + + const body = { + client_id: this.server.client.id, + client_secret: this.server.client.secret, + username: username, + response_type: 'code', + grant_type: 'password', + scope: 'upload', + externalAuthToken + } + + return this.postBodyRequest({ + ...options, + + path, + type: 'form', + fields: body, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + logout (options: OverrideCommandOptions & { + token: string + }) { + const path = '/api/v1/users/revoke-token' + + return unwrapBody<{ redirectUrl: string }>(this.postBodyRequest({ + ...options, + + path, + type: 'form', + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + refreshToken (options: OverrideCommandOptions & { + refreshToken: string + }) { + const path = '/api/v1/users/token' + + const body = { + client_id: this.server.client.id, + client_secret: this.server.client.secret, + refresh_token: options.refreshToken, + response_type: 'code', + grant_type: 'refresh_token' + } + + return this.postBodyRequest({ + ...options, + + path, + type: 'form', + fields: body, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getClient (options: OverrideCommandOptions = {}) { + const path = '/api/v1/oauth-clients/local' + + return this.getRequestBody<{ client_id: string, client_secret: string }>({ + ...options, + + path, + host: this.server.host, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } +} diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index c14367542..d4ee8e517 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts @@ -1,133 +1,19 @@ -import * as request from 'supertest' - import { ServerInfo } from '../server/servers' -import { getClient } from '../server/clients' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -type Client = { id?: string, secret?: string } -type User = { username: string, password: string } -type Server = { url?: string, client?: Client, user?: User } - -function login (url: string, client: Client, user: User, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/token' - - const body = { - client_id: client.id, - client_secret: client.secret, - username: user.username, - password: user.password, - response_type: 'code', - grant_type: 'password', - scope: 'upload' - } - - return request(url) - .post(path) - .type('form') - .send(body) - .expect(expectedStatus) -} - -function logout (url: string, token: string, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/revoke-token' - - return request(url) - .post(path) - .set('Authorization', 'Bearer ' + token) - .type('form') - .expect(expectedStatus) -} - -async function serverLogin (server: Server) { - const res = await login(server.url, server.client, server.user, HttpStatusCode.OK_200) - - return res.body.access_token as string -} - -function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/token' - - const body = { - client_id: server.client.id, - client_secret: server.client.secret, - refresh_token: refreshToken, - response_type: 'code', - grant_type: 'refresh_token' - } - - return request(server.url) - .post(path) - .type('form') - .send(body) - .expect(expectedStatus) -} - -async function userLogin (server: Server, user: User, expectedStatus = HttpStatusCode.OK_200) { - const res = await login(server.url, server.client, user, expectedStatus) - - return res.body.access_token as string -} - -async function getAccessToken (url: string, username: string, password: string) { - const resClient = await getClient(url) - const client = { - id: resClient.body.client_id, - secret: resClient.body.client_secret - } - - const user = { username, password } - - try { - const res = await login(url, client, user) - return res.body.access_token - } catch (err) { - throw new Error('Cannot authenticate. Please check your username/password.') - } -} function setAccessTokensToServers (servers: ServerInfo[]) { const tasks: Promise[] = [] for (const server of servers) { - const p = serverLogin(server).then(t => { server.accessToken = t }) + const p = server.loginCommand.getAccessToken() + .then(t => { server.accessToken = t }) tasks.push(p) } return Promise.all(tasks) } -function loginUsingExternalToken (server: Server, username: string, externalAuthToken: string, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/token' - - const body = { - client_id: server.client.id, - client_secret: server.client.secret, - username: username, - response_type: 'code', - grant_type: 'password', - scope: 'upload', - externalAuthToken - } - - return request(server.url) - .post(path) - .type('form') - .send(body) - .expect(expectedStatus) -} - // --------------------------------------------------------------------------- export { - login, - logout, - serverLogin, - refreshToken, - userLogin, - getAccessToken, - setAccessTokensToServers, - Server, - Client, - User, - loginUsingExternalToken + setAccessTokensToServers } diff --git a/shared/extra-utils/users/notifications.ts b/shared/extra-utils/users/notifications.ts index 81f0729fa..79cb6f617 100644 --- a/shared/extra-utils/users/notifications.ts +++ b/shared/extra-utils/users/notifications.ts @@ -7,7 +7,7 @@ import { UserNotification, UserNotificationSetting, UserNotificationSettingValue import { MockSmtpServer } from '../mock-servers/mock-email' import { doubleFollow } from '../server/follows' import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' -import { setAccessTokensToServers, userLogin } from './login' +import { setAccessTokensToServers } from './login' import { createUser, getMyUserInformation } from './users' function getAllNotificationsSettings (): UserNotificationSetting { @@ -662,7 +662,7 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an password: user.password, videoQuota: 10 * 1000 * 1000 }) - const userAccessToken = await userLogin(servers[0], user) + const userAccessToken = await servers[0].loginCommand.getAccessToken(user) await servers[0].notificationsCommand.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) await servers[0].notificationsCommand.updateMySettings({ settings: getAllNotificationsSettings() }) diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts index 0f15962ad..835ad08ba 100644 --- a/shared/extra-utils/users/users.ts +++ b/shared/extra-utils/users/users.ts @@ -7,7 +7,6 @@ import { UserRegister } from '../../models/users/user-register.model' import { UserRole } from '../../models/users/user-role' import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateImageRequest } from '../requests/requests' import { ServerInfo } from '../server/servers' -import { userLogin } from './login' function createUser (parameters: { url: string @@ -55,7 +54,7 @@ async function generateUser (server: ServerInfo, username: string) { const password = 'my super password' const resCreate = await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) - const token = await userLogin(server, { username, password }) + const token = await server.loginCommand.getAccessToken({ username, password }) const resMe = await getMyUserInformation(server.url, token) @@ -70,7 +69,7 @@ async function generateUserAccessToken (server: ServerInfo, username: string) { const password = 'my super password' await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) - return userLogin(server, { username, password }) + return server.loginCommand.getAccessToken({ username, password }) } function registerUser (url: string, username: string, password: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { -- cgit v1.2.3 From d0a0fa429d4651710ed951a3c11af0219e408964 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 13 Jul 2021 11:44:16 +0200 Subject: Adapt CLI to new commands --- shared/extra-utils/users/login-command.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts index 97efcb766..8af3531f9 100644 --- a/shared/extra-utils/users/login-command.ts +++ b/shared/extra-utils/users/login-command.ts @@ -1,4 +1,3 @@ -import { PeerTubeRequestError } from '@server/helpers/requests' import { HttpStatusCode } from '@shared/core-utils' import { PeerTubeProblemDocument } from '@shared/models' import { unwrapBody } from '../requests' @@ -34,8 +33,8 @@ export class LoginCommand extends AbstractCommand { })) } - getAccessToken (user?: { username: string, password: string }): Promise - getAccessToken (username: string, password: string): Promise + getAccessToken (arg1?: { username: string, password: string }): Promise + getAccessToken (arg1: string, password: string): Promise async getAccessToken (arg1?: { username: string, password: string } | string, password?: string) { let user: { username: string, password: string } @@ -48,7 +47,7 @@ export class LoginCommand extends AbstractCommand { return body.access_token } catch (err) { - throw new Error('Cannot authenticate. Please check your username/password.') + throw new Error(`Cannot authenticate. Please check your username/password. (${err})`) } } -- cgit v1.2.3 From 7926c5f9b3ffcabb1ffb0dcfa5e48b8e0b88fbc0 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 13 Jul 2021 14:23:01 +0200 Subject: Introduce user command --- shared/extra-utils/server/servers.ts | 4 +- shared/extra-utils/users/index.ts | 1 + shared/extra-utils/users/login-command.ts | 12 +- shared/extra-utils/users/notifications.ts | 18 +- shared/extra-utils/users/users-command.ts | 414 ++++++++++++++++++++++++++++++ shared/extra-utils/users/users.ts | 400 +---------------------------- shared/extra-utils/videos/channels.ts | 6 +- shared/extra-utils/videos/videos.ts | 4 +- 8 files changed, 435 insertions(+), 424 deletions(-) create mode 100644 shared/extra-utils/users/users-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index 4d9599680..b6d597c5d 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -16,7 +16,7 @@ import { AbusesCommand } from '../moderation' import { OverviewsCommand } from '../overviews' import { SearchCommand } from '../search' import { SocketIOCommand } from '../socket' -import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand } from '../users' +import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand, UsersCommand } from '../users' import { BlacklistCommand, CaptionsCommand, @@ -127,6 +127,7 @@ interface ServerInfo { notificationsCommand?: NotificationsCommand serversCommand?: ServersCommand loginCommand?: LoginCommand + usersCommand?: UsersCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -359,6 +360,7 @@ function assignCommands (server: ServerInfo) { server.notificationsCommand = new NotificationsCommand(server) server.serversCommand = new ServersCommand(server) server.loginCommand = new LoginCommand(server) + server.usersCommand = new UsersCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index b200ae705..e6107afa5 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -6,4 +6,5 @@ export * from './login-command' export * from './notifications' export * from './notifications-command' export * from './subscriptions-command' +export * from './users-command' export * from './users' diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts index 8af3531f9..b4e3bb602 100644 --- a/shared/extra-utils/users/login-command.ts +++ b/shared/extra-utils/users/login-command.ts @@ -7,7 +7,7 @@ export class LoginCommand extends AbstractCommand { login (options: OverrideCommandOptions & { client?: { id?: string, secret?: string } - user?: { username: string, password: string } + user?: { username: string, password?: string } } = {}) { const { client = this.server.client, user = this.server.user } = options const path = '/api/v1/users/token' @@ -16,7 +16,7 @@ export class LoginCommand extends AbstractCommand { client_id: client.id, client_secret: client.secret, username: user.username, - password: user.password, + password: user.password ?? 'password', response_type: 'code', grant_type: 'password', scope: 'upload' @@ -33,10 +33,10 @@ export class LoginCommand extends AbstractCommand { })) } - getAccessToken (arg1?: { username: string, password: string }): Promise - getAccessToken (arg1: string, password: string): Promise - async getAccessToken (arg1?: { username: string, password: string } | string, password?: string) { - let user: { username: string, password: string } + getAccessToken (arg1?: { username: string, password?: string }): Promise + getAccessToken (arg1: string, password?: string): Promise + async getAccessToken (arg1?: { username: string, password?: string } | string, password?: string) { + let user: { username: string, password?: string } if (!arg1) user = this.server.user else if (typeof arg1 === 'object') user = arg1 diff --git a/shared/extra-utils/users/notifications.ts b/shared/extra-utils/users/notifications.ts index 79cb6f617..0af7d8a18 100644 --- a/shared/extra-utils/users/notifications.ts +++ b/shared/extra-utils/users/notifications.ts @@ -8,7 +8,6 @@ import { MockSmtpServer } from '../mock-servers/mock-email' import { doubleFollow } from '../server/follows' import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' import { setAccessTokensToServers } from './login' -import { createUser, getMyUserInformation } from './users' function getAllNotificationsSettings (): UserNotificationSetting { return { @@ -651,17 +650,8 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an await doubleFollow(servers[0], servers[1]) } - const user = { - username: 'user_1', - password: 'super password' - } - await createUser({ - url: servers[0].url, - accessToken: servers[0].accessToken, - username: user.username, - password: user.password, - videoQuota: 10 * 1000 * 1000 - }) + const user = { username: 'user_1', password: 'super password' } + await servers[0].usersCommand.create({ ...user, videoQuota: 10 * 1000 * 1000 }) const userAccessToken = await servers[0].loginCommand.getAccessToken(user) await servers[0].notificationsCommand.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) @@ -685,8 +675,8 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an socket.on('new-notification', n => adminNotificationsServer2.push(n)) } - const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) - const channelId = resChannel.body.videoChannels[0].id + const { videoChannels } = await servers[0].usersCommand.getMyInfo() + const channelId = videoChannels[0].id return { userNotifications, diff --git a/shared/extra-utils/users/users-command.ts b/shared/extra-utils/users/users-command.ts new file mode 100644 index 000000000..202528b8d --- /dev/null +++ b/shared/extra-utils/users/users-command.ts @@ -0,0 +1,414 @@ +import { omit, pick } from 'lodash' +import { HttpStatusCode } from '@shared/core-utils' +import { + MyUser, + ResultList, + User, + UserAdminFlag, + UserCreateResult, + UserRole, + UserUpdate, + UserUpdateMe, + UserVideoQuota, + UserVideoRate +} from '@shared/models' +import { ScopedToken } from '@shared/models/users/user-scoped-token' +import { unwrapBody } from '../requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export class UsersCommand extends AbstractCommand { + + askResetPassword (options: OverrideCommandOptions & { + email: string + }) { + const { email } = options + const path = '/api/v1/users/ask-reset-password' + + return this.postBodyRequest({ + ...options, + + path, + fields: { email }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + resetPassword (options: OverrideCommandOptions & { + userId: number + verificationString: string + password: string + }) { + const { userId, verificationString, password } = options + const path = '/api/v1/users/' + userId + '/reset-password' + + return this.postBodyRequest({ + ...options, + + path, + fields: { password, verificationString }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + askSendVerifyEmail (options: OverrideCommandOptions & { + email: string + }) { + const { email } = options + const path = '/api/v1/users/ask-send-verify-email' + + return this.postBodyRequest({ + ...options, + + path, + fields: { email }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + verifyEmail (options: OverrideCommandOptions & { + userId: number + verificationString: string + isPendingEmail?: boolean // default false + }) { + const { userId, verificationString, isPendingEmail = false } = options + const path = '/api/v1/users/' + userId + '/verify-email' + + return this.postBodyRequest({ + ...options, + + path, + fields: { + verificationString, + isPendingEmail + }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + banUser (options: OverrideCommandOptions & { + userId: number + reason?: string + }) { + const { userId, reason } = options + const path = '/api/v1/users' + '/' + userId + '/block' + + return this.postBodyRequest({ + ...options, + + path, + fields: { reason }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + unbanUser (options: OverrideCommandOptions & { + userId: number + }) { + const { userId } = options + const path = '/api/v1/users' + '/' + userId + '/unblock' + + return this.postBodyRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + getMyScopedTokens (options: OverrideCommandOptions = {}) { + const path = '/api/v1/users/scoped-tokens' + + return this.getRequestBody({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + renewMyScopedTokens (options: OverrideCommandOptions = {}) { + const path = '/api/v1/users/scoped-tokens' + + return this.postBodyRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + // --------------------------------------------------------------------------- + + create (options: OverrideCommandOptions & { + username: string + password?: string + videoQuota?: number + videoQuotaDaily?: number + role?: UserRole + adminFlags?: UserAdminFlag + }) { + const { + username, + adminFlags, + password = 'password', + videoQuota = 42000000, + videoQuotaDaily = -1, + role = UserRole.USER + } = options + + const path = '/api/v1/users' + + return unwrapBody<{ user: UserCreateResult }>(this.postBodyRequest({ + ...options, + + path, + fields: { + username, + password, + role, + adminFlags, + email: username + '@example.com', + videoQuota, + videoQuotaDaily + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })).then(res => res.user) + } + + async generate (username: string) { + const password = 'password' + const user = await this.create({ username, password }) + + const token = await this.server.loginCommand.getAccessToken({ username, password }) + + const me = await this.getMyInfo({ token }) + + return { + token, + userId: user.id, + userChannelId: me.videoChannels[0].id + } + } + + async generateUserAndToken (username: string) { + const password = 'password' + await this.create({ username, password }) + + return this.server.loginCommand.getAccessToken({ username, password }) + } + + register (options: OverrideCommandOptions & { + username: string + password?: string + displayName?: string + channel?: { + name: string + displayName: string + } + }) { + const { username, password = 'password', displayName, channel } = options + const path = '/api/v1/users/register' + + return this.postBodyRequest({ + ...options, + + path, + fields: { + username, + password, + email: username + '@example.com', + displayName, + channel + }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + getMyInfo (options: OverrideCommandOptions = {}) { + const path = '/api/v1/users/me' + + return this.getRequestBody({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getMyQuotaUsed (options: OverrideCommandOptions = {}) { + const path = '/api/v1/users/me/video-quota-used' + + return this.getRequestBody({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getMyRating (options: OverrideCommandOptions & { + videoId: number | string + }) { + const { videoId } = options + const path = '/api/v1/users/me/videos/' + videoId + '/rating' + + return this.getRequestBody({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + deleteMe (options: OverrideCommandOptions = {}) { + const path = '/api/v1/users/me' + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + updateMe (options: OverrideCommandOptions & UserUpdateMe) { + const path = '/api/v1/users/me' + + const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') + + return this.putBodyRequest({ + ...options, + + path, + fields: toSend, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + updateMyAvatar (options: OverrideCommandOptions & { + fixture: string + }) { + const { fixture } = options + const path = '/api/v1/users/me/avatar/pick' + + return this.updateImageRequest({ + ...options, + + path, + fixture, + fieldname: 'avatarfile', + + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + // --------------------------------------------------------------------------- + + get (options: OverrideCommandOptions & { + userId: number + withStats?: boolean // default false + }) { + const { userId, withStats } = options + const path = '/api/v1/users/' + userId + + return this.getRequestBody({ + ...options, + + path, + query: { withStats }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + list (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + search?: string + blocked?: boolean + } = {}) { + const path = '/api/v1/users' + + return this.getRequestBody>({ + ...options, + + path, + query: pick(options, [ 'start', 'count', 'sort', 'search', 'blocked' ]), + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + remove (options: OverrideCommandOptions & { + userId: number + }) { + const { userId } = options + const path = '/api/v1/users/' + userId + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + update (options: OverrideCommandOptions & { + userId: number + email?: string + emailVerified?: boolean + videoQuota?: number + videoQuotaDaily?: number + password?: string + adminFlags?: UserAdminFlag + pluginAuth?: string + role?: UserRole + }) { + const path = '/api/v1/users/' + options.userId + + const toSend: UserUpdate = {} + if (options.password !== undefined && options.password !== null) toSend.password = options.password + if (options.email !== undefined && options.email !== null) toSend.email = options.email + if (options.emailVerified !== undefined && options.emailVerified !== null) toSend.emailVerified = options.emailVerified + if (options.videoQuota !== undefined && options.videoQuota !== null) toSend.videoQuota = options.videoQuota + if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend.videoQuotaDaily = options.videoQuotaDaily + if (options.role !== undefined && options.role !== null) toSend.role = options.role + if (options.adminFlags !== undefined && options.adminFlags !== null) toSend.adminFlags = options.adminFlags + if (options.pluginAuth !== undefined) toSend.pluginAuth = options.pluginAuth + + return this.putBodyRequest({ + ...options, + + path, + fields: toSend, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } +} diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts index 835ad08ba..6cf61d60e 100644 --- a/shared/extra-utils/users/users.ts +++ b/shared/extra-utils/users/users.ts @@ -1,118 +1,8 @@ -import { omit } from 'lodash' import * as request from 'supertest' import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' -import { UserUpdateMe } from '../../models/users' -import { UserAdminFlag } from '../../models/users/user-flag.model' -import { UserRegister } from '../../models/users/user-register.model' -import { UserRole } from '../../models/users/user-role' -import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateImageRequest } from '../requests/requests' -import { ServerInfo } from '../server/servers' -function createUser (parameters: { - url: string - accessToken: string - username: string - password: string - videoQuota?: number - videoQuotaDaily?: number - role?: UserRole - adminFlags?: UserAdminFlag - specialStatus?: number -}) { - const { - url, - accessToken, - username, - adminFlags, - password = 'password', - videoQuota = 1000000, - videoQuotaDaily = -1, - role = UserRole.USER, - specialStatus = HttpStatusCode.OK_200 - } = parameters - - const path = '/api/v1/users' - const body = { - username, - password, - role, - adminFlags, - email: username + '@example.com', - videoQuota, - videoQuotaDaily - } - - return request(url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .send(body) - .expect(specialStatus) -} - -async function generateUser (server: ServerInfo, username: string) { - const password = 'my super password' - const resCreate = await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) - - const token = await server.loginCommand.getAccessToken({ username, password }) - - const resMe = await getMyUserInformation(server.url, token) - - return { - token, - userId: resCreate.body.user.id, - userChannelId: resMe.body.videoChannels[0].id - } -} - -async function generateUserAccessToken (server: ServerInfo, username: string) { - const password = 'my super password' - await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) - - return server.loginCommand.getAccessToken({ username, password }) -} - -function registerUser (url: string, username: string, password: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/register' - const body = { - username, - password, - email: username + '@example.com' - } - - return request(url) - .post(path) - .set('Accept', 'application/json') - .send(body) - .expect(specialStatus) -} - -function registerUserWithChannel (options: { - url: string - user: { username: string, password: string, displayName?: string } - channel: { name: string, displayName: string } -}) { - const path = '/api/v1/users/register' - const body: UserRegister = { - username: options.user.username, - password: options.user.password, - email: options.user.username + '@example.com', - channel: options.channel - } - - if (options.user.displayName) { - Object.assign(body, { displayName: options.user.displayName }) - } - - return makePostBodyRequest({ - url: options.url, - path, - fields: body, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -function getMyUserInformation (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { +// FIXME: delete once videos does not use it anymore +function xxxgetMyUserInformation (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { const path = '/api/v1/users/me' return request(url) @@ -123,292 +13,8 @@ function getMyUserInformation (url: string, accessToken: string, specialStatus = .expect('Content-Type', /json/) } -function getUserScopedTokens (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/users/scoped-tokens' - - return makeGetRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function renewUserScopedTokens (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { - const path = '/api/v1/users/scoped-tokens' - - return makePostBodyRequest({ - url, - path, - token, - statusCodeExpected - }) -} - -function deleteMe (url: string, accessToken: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users/me' - - return request(url) - .delete(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(specialStatus) -} - -function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me/video-quota-used' - - return request(url) - .get(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(specialStatus) - .expect('Content-Type', /json/) -} - -function getUserInformation (url: string, accessToken: string, userId: number, withStats = false) { - const path = '/api/v1/users/' + userId - - return request(url) - .get(path) - .query({ withStats }) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getMyUserVideoRating (url: string, accessToken: string, videoId: number | string, specialStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me/videos/' + videoId + '/rating' - - return request(url) - .get(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(specialStatus) - .expect('Content-Type', /json/) -} - -function getUsersList (url: string, accessToken: string) { - const path = '/api/v1/users' - - return request(url) - .get(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getUsersListPaginationAndSort ( - url: string, - accessToken: string, - start: number, - count: number, - sort: string, - search?: string, - blocked?: boolean -) { - const path = '/api/v1/users' - - const query = { - start, - count, - sort, - search, - blocked - } - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function removeUser (url: string, userId: number | string, accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users' - - return request(url) - .delete(path + '/' + userId) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(expectedStatus) -} - -function blockUser ( - url: string, - userId: number | string, - accessToken: string, - expectedStatus = HttpStatusCode.NO_CONTENT_204, - reason?: string -) { - const path = '/api/v1/users' - let body: any - if (reason) body = { reason } - - return request(url) - .post(path + '/' + userId + '/block') - .send(body) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(expectedStatus) -} - -function unblockUser (url: string, userId: number | string, accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/users' - - return request(url) - .post(path + '/' + userId + '/unblock') - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(expectedStatus) -} - -function updateMyUser (options: { url: string, accessToken: string, statusCodeExpected?: HttpStatusCode } & UserUpdateMe) { - const path = '/api/v1/users/me' - - const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') - - return makePutBodyRequest({ - url: options.url, - path, - token: options.accessToken, - fields: toSend, - statusCodeExpected: options.statusCodeExpected || HttpStatusCode.NO_CONTENT_204 - }) -} - -function updateMyAvatar (options: { - url: string - accessToken: string - fixture: string -}) { - const path = '/api/v1/users/me/avatar/pick' - - return updateImageRequest({ ...options, path, fieldname: 'avatarfile' }) -} - -function updateUser (options: { - url: string - userId: number - accessToken: string - email?: string - emailVerified?: boolean - videoQuota?: number - videoQuotaDaily?: number - password?: string - adminFlags?: UserAdminFlag - pluginAuth?: string - role?: UserRole -}) { - const path = '/api/v1/users/' + options.userId - - const toSend = {} - if (options.password !== undefined && options.password !== null) toSend['password'] = options.password - if (options.email !== undefined && options.email !== null) toSend['email'] = options.email - if (options.emailVerified !== undefined && options.emailVerified !== null) toSend['emailVerified'] = options.emailVerified - if (options.videoQuota !== undefined && options.videoQuota !== null) toSend['videoQuota'] = options.videoQuota - if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend['videoQuotaDaily'] = options.videoQuotaDaily - if (options.role !== undefined && options.role !== null) toSend['role'] = options.role - if (options.adminFlags !== undefined && options.adminFlags !== null) toSend['adminFlags'] = options.adminFlags - if (options.pluginAuth !== undefined) toSend['pluginAuth'] = options.pluginAuth - - return makePutBodyRequest({ - url: options.url, - path, - token: options.accessToken, - fields: toSend, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -function askResetPassword (url: string, email: string) { - const path = '/api/v1/users/ask-reset-password' - - return makePostBodyRequest({ - url, - path, - fields: { email }, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -function resetPassword ( - url: string, - userId: number, - verificationString: string, - password: string, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/' + userId + '/reset-password' - - return makePostBodyRequest({ - url, - path, - fields: { password, verificationString }, - statusCodeExpected - }) -} - -function askSendVerifyEmail (url: string, email: string) { - const path = '/api/v1/users/ask-send-verify-email' - - return makePostBodyRequest({ - url, - path, - fields: { email }, - statusCodeExpected: HttpStatusCode.NO_CONTENT_204 - }) -} - -function verifyEmail ( - url: string, - userId: number, - verificationString: string, - isPendingEmail = false, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/users/' + userId + '/verify-email' - - return makePostBodyRequest({ - url, - path, - fields: { - verificationString, - isPendingEmail - }, - statusCodeExpected - }) -} - // --------------------------------------------------------------------------- export { - createUser, - registerUser, - getMyUserInformation, - getMyUserVideoRating, - deleteMe, - registerUserWithChannel, - getMyUserVideoQuotaUsed, - getUsersList, - getUsersListPaginationAndSort, - removeUser, - updateUser, - updateMyUser, - getUserInformation, - blockUser, - unblockUser, - askResetPassword, - resetPassword, - renewUserScopedTokens, - updateMyAvatar, - generateUser, - askSendVerifyEmail, - generateUserAccessToken, - verifyEmail, - getUserScopedTokens + xxxgetMyUserInformation } diff --git a/shared/extra-utils/videos/channels.ts b/shared/extra-utils/videos/channels.ts index a77543c92..9e7ec565d 100644 --- a/shared/extra-utils/videos/channels.ts +++ b/shared/extra-utils/videos/channels.ts @@ -1,13 +1,11 @@ -import { User } from '../../models/users/user.model' import { ServerInfo } from '../server/servers' -import { getMyUserInformation } from '../users/users' function setDefaultVideoChannel (servers: ServerInfo[]) { const tasks: Promise[] = [] for (const server of servers) { - const p = getMyUserInformation(server.url, server.accessToken) - .then(res => { server.videoChannel = (res.body as User).videoChannels[0] }) + const p = server.usersCommand.getMyInfo() + .then(user => { server.videoChannel = user.videoChannels[0] }) tasks.push(p) } diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 5dd71ce8b..5e20f8010 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -17,7 +17,7 @@ import { buildAbsoluteFixturePath, dateIsValid, testImage, wait, webtorrentAdd } import { makeGetRequest, makePutBodyRequest, makeRawRequest, makeUploadRequest } from '../requests/requests' import { waitJobs } from '../server/jobs' import { ServerInfo } from '../server/servers' -import { getMyUserInformation } from '../users/users' +import { xxxgetMyUserInformation } from '../users' loadLanguages() @@ -339,7 +339,7 @@ async function uploadVideo ( let defaultChannelId = '1' try { - const res = await getMyUserInformation(url, accessToken) + const res = await xxxgetMyUserInformation(url, accessToken) defaultChannelId = res.body.videoChannels[0].id } catch (e) { /* empty */ } -- cgit v1.2.3 From d23dd9fbfc4d26026352c10f81d2795ceaf2908a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Jul 2021 10:02:54 +0200 Subject: Introduce videos command --- shared/extra-utils/miscs/webtorrent.ts | 16 +- shared/extra-utils/requests/requests.ts | 25 +- shared/extra-utils/server/servers.ts | 5 +- shared/extra-utils/shared/abstract-command.ts | 41 +- shared/extra-utils/videos/index.ts | 1 + shared/extra-utils/videos/live-command.ts | 7 +- shared/extra-utils/videos/playlists-command.ts | 17 +- shared/extra-utils/videos/videos-command.ts | 583 ++++++++++++++++++++ shared/extra-utils/videos/videos.ts | 714 +------------------------ 9 files changed, 679 insertions(+), 730 deletions(-) create mode 100644 shared/extra-utils/videos/videos-command.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/webtorrent.ts b/shared/extra-utils/miscs/webtorrent.ts index 82548946d..63e648309 100644 --- a/shared/extra-utils/miscs/webtorrent.ts +++ b/shared/extra-utils/miscs/webtorrent.ts @@ -1,4 +1,8 @@ +import { readFile } from 'fs-extra' +import * as parseTorrent from 'parse-torrent' +import { join } from 'path' import * as WebTorrent from 'webtorrent' +import { ServerInfo } from '../server' let webtorrent: WebTorrent.Instance @@ -11,6 +15,16 @@ function webtorrentAdd (torrent: string, refreshWebTorrent = false) { return new Promise(res => webtorrent.add(torrent, res)) } +async function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { + const torrentName = videoUUID + '-' + resolution + '.torrent' + const torrentPath = server.serversCommand.buildDirectory(join('torrents', torrentName)) + + const data = await readFile(torrentPath) + + return parseTorrent(data) +} + export { - webtorrentAdd + webtorrentAdd, + parseTorrentVideo } diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index c5ee63e05..3f1ac6650 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -67,11 +67,17 @@ function makeUploadRequest (options: { method?: 'POST' | 'PUT' path: string token?: string + fields: { [ fieldName: string ]: any } attaches?: { [ attachName: string ]: any | any[] } + + headers?: { [ name: string ]: string } + statusCodeExpected?: HttpStatusCode }) { - if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 + if (options.statusCodeExpected === undefined) { + options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 + } let req: request.Test if (options.method === 'PUT') { @@ -84,6 +90,10 @@ function makeUploadRequest (options: { if (options.token) req.set('Authorization', 'Bearer ' + options.token) + Object.keys(options.headers || {}).forEach(name => { + req.set(name, options.headers[name]) + }) + Object.keys(options.fields).forEach(field => { const value = options.fields[field] @@ -107,7 +117,11 @@ function makeUploadRequest (options: { } }) - return req.expect(options.statusCodeExpected) + if (options.statusCodeExpected) { + req.expect(options.statusCodeExpected) + } + + return req } function makePostBodyRequest (options: { @@ -115,7 +129,9 @@ function makePostBodyRequest (options: { path: string token?: string fields?: { [ fieldName: string ]: any } + headers?: { [ name: string ]: string } type?: string + xForwardedFor?: string statusCodeExpected?: HttpStatusCode }) { if (!options.fields) options.fields = {} @@ -126,8 +142,13 @@ function makePostBodyRequest (options: { .set('Accept', 'application/json') if (options.token) req.set('Authorization', 'Bearer ' + options.token) + if (options.xForwardedFor) req.set('X-Forwarded-For', options.xForwardedFor) if (options.type) req.type(options.type) + Object.keys(options.headers || {}).forEach(name => { + req.set(name, options.headers[name]) + }) + return req.send(options.fields) .expect(options.statusCodeExpected) } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index b6d597c5d..fda5c3d6d 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -27,7 +27,8 @@ import { LiveCommand, PlaylistsCommand, ServicesCommand, - StreamingPlaylistsCommand + StreamingPlaylistsCommand, + VideosCommand } from '../videos' import { CommentsCommand } from '../videos/comments-command' import { ConfigCommand } from './config-command' @@ -128,6 +129,7 @@ interface ServerInfo { serversCommand?: ServersCommand loginCommand?: LoginCommand usersCommand?: UsersCommand + videosCommand?: VideosCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -361,6 +363,7 @@ function assignCommands (server: ServerInfo) { server.serversCommand = new ServersCommand(server) server.loginCommand = new LoginCommand(server) server.usersCommand = new UsersCommand(server) + server.videosCommand = new VideosCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index af9ecd926..5fddcf639 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -1,5 +1,4 @@ import { isAbsolute, join } from 'path' -import { HttpStatusCode } from '@shared/core-utils' import { root } from '../miscs/tests' import { makeDeleteRequest, @@ -38,22 +37,12 @@ interface InternalGetCommandOptions extends InternalCommonCommandOptions { abstract class AbstractCommand { - private expectedStatus: HttpStatusCode - constructor ( protected server: ServerInfo ) { } - setServer (server: ServerInfo) { - this.server = server - } - - setExpectedStatus (status: HttpStatusCode) { - this.expectedStatus = status - } - protected getRequestBody (options: InternalGetCommandOptions) { return unwrapBody(this.getRequest(options)) } @@ -111,43 +100,51 @@ abstract class AbstractCommand { protected postBodyRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } + headers?: { [ name: string ]: string } type?: string + xForwardedFor?: string }) { - const { type, fields } = options + const { type, fields, xForwardedFor, headers } = options return makePostBodyRequest({ ...this.buildCommonRequestOptions(options), fields, - type + xForwardedFor, + type, + headers }) } protected postUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } - attaches?: any + attaches?: { [ fieldName: string ]: any } + headers?: { [ name: string ]: string } }) { - const { fields, attaches } = options + const { fields, attaches, headers } = options return makeUploadRequest({ ...this.buildCommonRequestOptions(options), method: 'POST', fields, - attaches + attaches, + headers }) } protected putUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } - attaches?: any + attaches?: { [ fieldName: string ]: any } + headers?: { [ name: string ]: string } }) { - const { fields, attaches } = options + const { fields, attaches, headers } = options return makeUploadRequest({ ...this.buildCommonRequestOptions(options), method: 'PUT', + headers, fields, attaches }) @@ -172,7 +169,7 @@ abstract class AbstractCommand { }) } - private buildCommonRequestOptions (options: InternalCommonCommandOptions) { + protected buildCommonRequestOptions (options: InternalCommonCommandOptions) { const { url, path } = options return { @@ -184,7 +181,7 @@ abstract class AbstractCommand { } } - private buildCommonRequestToken (options: Pick) { + protected buildCommonRequestToken (options: Pick) { const { token } = options const fallbackToken = options.implicitToken @@ -194,10 +191,10 @@ abstract class AbstractCommand { return token !== undefined ? token : fallbackToken } - private buildStatusCodeExpected (options: Pick) { + protected buildStatusCodeExpected (options: Pick) { const { expectedStatus, defaultExpectedStatus } = options - return expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus + return expectedStatus !== undefined ? expectedStatus : defaultExpectedStatus } } diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts index 652d82842..26e663f46 100644 --- a/shared/extra-utils/videos/index.ts +++ b/shared/extra-utils/videos/index.ts @@ -15,4 +15,5 @@ export * from './services-command' export * from './streaming-playlists-command' export * from './streaming-playlists' export * from './comments-command' +export * from './videos-command' export * from './videos' diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index a494e60fa..5adf601cc 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -9,7 +9,6 @@ import { wait } from '../miscs' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { sendRTMPStream, testFfmpegStreamError } from './live' -import { getVideoWithToken } from './videos' export class LiveCommand extends AbstractCommand { @@ -124,8 +123,7 @@ export class LiveCommand extends AbstractCommand { let video: VideoDetails do { - const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId) - video = res.body + video = await this.server.videosCommand.getWithToken({ token: options.token, id: options.videoId }) await wait(500) } while (video.isLive === true && video.state.id !== VideoState.PUBLISHED) @@ -149,8 +147,7 @@ export class LiveCommand extends AbstractCommand { let video: VideoDetails do { - const res = await getVideoWithToken(this.server.url, options.token ?? this.server.accessToken, options.videoId) - video = res.body + video = await this.server.videosCommand.getWithToken({ token: options.token, id: options.videoId }) await wait(500) } while (video.state.id !== options.state) diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts index f77decc1a..75c8f2433 100644 --- a/shared/extra-utils/videos/playlists-command.ts +++ b/shared/extra-utils/videos/playlists-command.ts @@ -1,23 +1,22 @@ import { omit, pick } from 'lodash' +import { HttpStatusCode } from '@shared/core-utils' import { BooleanBothQuery, ResultList, VideoExistInPlaylist, VideoPlaylist, + VideoPlaylistCreate, VideoPlaylistCreateResult, VideoPlaylistElement, + VideoPlaylistElementCreate, VideoPlaylistElementCreateResult, - VideoPlaylistReorder + VideoPlaylistElementUpdate, + VideoPlaylistReorder, + VideoPlaylistType, + VideoPlaylistUpdate } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' -import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model' -import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model' -import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model' -import { VideoPlaylistType } from '../../models/videos/playlist/video-playlist-type.model' -import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' -import { videoUUIDToId } from './videos' export class PlaylistsCommand extends AbstractCommand { @@ -185,7 +184,7 @@ export class PlaylistsCommand extends AbstractCommand { const attributes = { ...options.attributes, - videoId: await videoUUIDToId(this.server.url, options.attributes.videoId) + videoId: await this.server.videosCommand.getId({ ...options, uuid: options.attributes.videoId }) } const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts new file mode 100644 index 000000000..574705474 --- /dev/null +++ b/shared/extra-utils/videos/videos-command.ts @@ -0,0 +1,583 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ + +import { expect } from 'chai' +import { createReadStream, stat } from 'fs-extra' +import got, { Response as GotResponse } from 'got' +import { omit, pick } from 'lodash' +import validator from 'validator' +import { buildUUID } from '@server/helpers/uuid' +import { loadLanguages } from '@server/initializers/constants' +import { HttpStatusCode } from '@shared/core-utils' +import { + ResultList, + UserVideoRateType, + Video, + VideoCreate, + VideoCreateResult, + VideoDetails, + VideoFileMetadata, + VideoPrivacy, + VideosCommonQuery, + VideosWithSearchCommonQuery +} from '@shared/models' +import { buildAbsoluteFixturePath, wait } from '../miscs' +import { unwrapBody } from '../requests' +import { ServerInfo, waitJobs } from '../server' +import { AbstractCommand, OverrideCommandOptions } from '../shared' + +export type VideoEdit = Partial> & { + fixture?: string + thumbnailfile?: string + previewfile?: string +} + +export class VideosCommand extends AbstractCommand { + + constructor (server: ServerInfo) { + super(server) + + loadLanguages() + } + + getCategories (options: OverrideCommandOptions = {}) { + const path = '/api/v1/videos/categories' + + return this.getRequestBody<{ [id: number]: string }>({ + ...options, + path, + + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getLicences (options: OverrideCommandOptions = {}) { + const path = '/api/v1/videos/licences' + + return this.getRequestBody<{ [id: number]: string }>({ + ...options, + path, + + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getLanguages (options: OverrideCommandOptions = {}) { + const path = '/api/v1/videos/languages' + + return this.getRequestBody<{ [id: string]: string }>({ + ...options, + path, + + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getPrivacies (options: OverrideCommandOptions = {}) { + const path = '/api/v1/videos/privacies' + + return this.getRequestBody<{ [id in VideoPrivacy]: string }>({ + ...options, + path, + + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + // --------------------------------------------------------------------------- + + getDescription (options: OverrideCommandOptions & { + descriptionPath: string + }) { + return this.getRequestBody<{ description: string }>({ + ...options, + path: options.descriptionPath, + + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getFileMetadata (options: OverrideCommandOptions & { + url: string + }) { + return unwrapBody(this.getRawRequest({ + ...options, + + url: options.url, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + })) + } + + // --------------------------------------------------------------------------- + + view (options: OverrideCommandOptions & { + id: number | string + xForwardedFor?: string + }) { + const { id, xForwardedFor } = options + const path = '/api/v1/videos/' + id + '/views' + + return this.postBodyRequest({ + ...options, + + path, + xForwardedFor, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + rate (options: OverrideCommandOptions & { + id: number | string + rating: UserVideoRateType + }) { + const { id, rating } = options + const path = '/api/v1/videos/' + id + '/rate' + + return this.putBodyRequest({ + ...options, + + path, + fields: { rating }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + // --------------------------------------------------------------------------- + + get (options: OverrideCommandOptions & { + id: number | string + }) { + const path = '/api/v1/videos/' + options.id + + return this.getRequestBody({ + ...options, + + path, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + getWithToken (options: OverrideCommandOptions & { + id: number | string + }) { + return this.get({ + ...options, + + token: this.buildCommonRequestToken({ ...options, implicitToken: true }) + }) + } + + async getId (options: OverrideCommandOptions & { + uuid: number | string + }) { + const { uuid } = options + + if (validator.isUUID('' + uuid) === false) return uuid as number + + const { id } = await this.get({ ...options, id: uuid }) + + return id + } + + // --------------------------------------------------------------------------- + + listMyVideos (options: OverrideCommandOptions & { + start?: number + count?: number + sort?: string + search?: string + isLive?: boolean + } = {}) { + const path = '/api/v1/users/me/videos' + + return this.getRequestBody>({ + ...options, + + path, + query: pick(options, [ 'start', 'count', 'sort', 'search', 'isLive' ]), + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + // --------------------------------------------------------------------------- + + list (options: OverrideCommandOptions & VideosCommonQuery = {}) { + const path = '/api/v1/videos' + + const query = this.buildListQuery(options) + + return this.getRequestBody>({ + ...options, + + path, + query: { sort: 'name', ...query }, + implicitToken: false, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listWithToken (options: OverrideCommandOptions & VideosCommonQuery = {}) { + return this.list({ + ...options, + + token: this.buildCommonRequestToken({ ...options, implicitToken: true }) + }) + } + + listByAccount (options: OverrideCommandOptions & VideosWithSearchCommonQuery & { + accountName: string + }) { + const { accountName, search } = options + const path = '/api/v1/accounts/' + accountName + '/videos' + + return this.getRequestBody>({ + ...options, + + path, + query: { search, ...this.buildListQuery(options) }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + listByChannel (options: OverrideCommandOptions & VideosWithSearchCommonQuery & { + videoChannelName: string + }) { + const { videoChannelName } = options + const path = '/api/v1/video-channels/' + videoChannelName + '/videos' + + return this.getRequestBody>({ + ...options, + + path, + query: this.buildListQuery(options), + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + }) + } + + // --------------------------------------------------------------------------- + + update (options: OverrideCommandOptions & { + id: number | string + attributes?: VideoEdit + }) { + const { id, attributes = {} } = options + const path = '/api/v1/videos/' + id + + // Upload request + if (attributes.thumbnailfile || attributes.previewfile) { + const attaches: any = {} + if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile + if (attributes.previewfile) attaches.previewfile = attributes.previewfile + + return this.putUploadRequest({ + ...options, + + path, + fields: options.attributes, + attaches: { + thumbnailfile: attributes.thumbnailfile, + previewfile: attributes.previewfile + }, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + return this.putBodyRequest({ + ...options, + + path, + fields: options.attributes, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + remove (options: OverrideCommandOptions & { + id: number | string + }) { + const path = '/api/v1/videos/' + options.id + + return this.deleteRequest({ + ...options, + + path, + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 + }) + } + + async removeAll () { + const { data } = await this.list() + + for (const v of data) { + await this.remove({ id: v.id }) + } + } + + // --------------------------------------------------------------------------- + + async upload (options: OverrideCommandOptions & { + attributes?: VideoEdit + mode?: 'legacy' | 'resumable' // default legacy + } = {}) { + const { mode = 'legacy', expectedStatus } = options + let defaultChannelId = 1 + + try { + const { videoChannels } = await this.server.usersCommand.getMyInfo({ token: options.token }) + defaultChannelId = videoChannels[0].id + } catch (e) { /* empty */ } + + // Override default attributes + const attributes = { + name: 'my super video', + category: 5, + licence: 4, + language: 'zh', + channelId: defaultChannelId, + nsfw: true, + waitTranscoding: false, + description: 'my super description', + support: 'my super support text', + tags: [ 'tag' ], + privacy: VideoPrivacy.PUBLIC, + commentsEnabled: true, + downloadEnabled: true, + fixture: 'video_short.webm', + + ...options.attributes + } + + const res = mode === 'legacy' + ? await this.buildLegacyUpload({ ...options, attributes }) + : await this.buildResumeUpload({ ...options, attributes }) + + // Wait torrent generation + if (expectedStatus === HttpStatusCode.OK_200) { + let video: VideoDetails + + do { + video = await this.getWithToken({ ...options, id: video.uuid }) + + await wait(50) + } while (!video.files[0].torrentUrl) + } + + return res + } + + async buildLegacyUpload (options: OverrideCommandOptions & { + attributes: VideoEdit + }): Promise { + const path = '/api/v1/videos/upload' + + return unwrapBody<{ video: VideoCreateResult }>(this.postUploadRequest({ + ...options, + + path, + fields: this.buildUploadFields(options.attributes), + attaches: this.buildUploadAttaches(options.attributes), + implicitToken: true, + defaultExpectedStatus: HttpStatusCode.OK_200 + })).then(body => body.video || body as any) + } + + async buildResumeUpload (options: OverrideCommandOptions & { + attributes: VideoEdit + }) { + const { attributes, expectedStatus } = options + + let size = 0 + let videoFilePath: string + let mimetype = 'video/mp4' + + if (attributes.fixture) { + videoFilePath = buildAbsoluteFixturePath(attributes.fixture) + size = (await stat(videoFilePath)).size + + if (videoFilePath.endsWith('.mkv')) { + mimetype = 'video/x-matroska' + } else if (videoFilePath.endsWith('.webm')) { + mimetype = 'video/webm' + } + } + + const initializeSessionRes = await this.prepareResumableUpload({ ...options, attributes, size, mimetype }) + const initStatus = initializeSessionRes.status + + if (videoFilePath && initStatus === HttpStatusCode.CREATED_201) { + const locationHeader = initializeSessionRes.header['location'] + expect(locationHeader).to.not.be.undefined + + const pathUploadId = locationHeader.split('?')[1] + + const result = await this.sendResumableChunks({ ...options, pathUploadId, videoFilePath, size }) + + return result.body.video + } + + const expectedInitStatus = expectedStatus === HttpStatusCode.OK_200 + ? HttpStatusCode.CREATED_201 + : expectedStatus + + expect(initStatus).to.equal(expectedInitStatus) + + return initializeSessionRes.body.video as VideoCreateResult + } + + async prepareResumableUpload (options: OverrideCommandOptions & { + attributes: VideoEdit + size: number + mimetype: string + }) { + const { attributes, size, mimetype } = options + + const path = '/api/v1/videos/upload-resumable' + + return this.postUploadRequest({ + ...options, + + path, + headers: { + 'X-Upload-Content-Type': mimetype, + 'X-Upload-Content-Length': size.toString() + }, + fields: { filename: attributes.fixture, ...this.buildUploadFields(options.attributes) }, + implicitToken: true, + defaultExpectedStatus: null + }) + } + + sendResumableChunks (options: OverrideCommandOptions & { + pathUploadId: string + videoFilePath: string + size: number + contentLength?: number + contentRangeBuilder?: (start: number, chunk: any) => string + }) { + const { pathUploadId, videoFilePath, size, contentLength, contentRangeBuilder, expectedStatus = HttpStatusCode.OK_200 } = options + + const path = '/api/v1/videos/upload-resumable' + let start = 0 + + const token = this.buildCommonRequestToken({ ...options, implicitToken: true }) + const url = this.server.url + + const readable = createReadStream(videoFilePath, { highWaterMark: 8 * 1024 }) + return new Promise>((resolve, reject) => { + readable.on('data', async function onData (chunk) { + readable.pause() + + const headers = { + 'Authorization': 'Bearer ' + token, + 'Content-Type': 'application/octet-stream', + 'Content-Range': contentRangeBuilder + ? contentRangeBuilder(start, chunk) + : `bytes ${start}-${start + chunk.length - 1}/${size}`, + 'Content-Length': contentLength ? contentLength + '' : chunk.length + '' + } + + const res = await got<{ video: VideoCreateResult }>({ + url, + method: 'put', + headers, + path: path + '?' + pathUploadId, + body: chunk, + responseType: 'json', + throwHttpErrors: false + }) + + start += chunk.length + + if (res.statusCode === expectedStatus) { + return resolve(res) + } + + if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) { + readable.off('data', onData) + return reject(new Error('Incorrect transient behaviour sending intermediary chunks')) + } + + readable.resume() + }) + }) + } + + quickUpload (options: OverrideCommandOptions & { + name: string + nsfw?: boolean + privacy?: VideoPrivacy + fixture?: string + }) { + const attributes: VideoEdit = { name: options.name } + if (options.nsfw) attributes.nsfw = options.nsfw + if (options.privacy) attributes.privacy = options.privacy + if (options.fixture) attributes.fixture = options.fixture + + return this.upload({ ...options, attributes }) + } + + async randomUpload (options: OverrideCommandOptions & { + wait?: boolean // default true + additionalParams?: VideoEdit & { prefixName: string } + } = {}) { + const { wait = true, additionalParams } = options + const prefixName = additionalParams?.prefixName || '' + const name = prefixName + buildUUID() + + const attributes = { name, additionalParams } + + if (wait) await waitJobs([ this.server ]) + + const result = await this.upload({ ...options, attributes }) + + return { ...result, name } + } + + // --------------------------------------------------------------------------- + + private buildListQuery (options: VideosCommonQuery) { + return pick(options, [ + 'start', + 'count', + 'sort', + 'nsfw', + 'isLive', + 'categoryOneOf', + 'licenceOneOf', + 'languageOneOf', + 'tagsOneOf', + 'tagsAllOf', + 'filter', + 'skipCount' + ]) + } + + private buildUploadFields (attributes: VideoEdit) { + return omit(attributes, [ 'thumbnailfile', 'previewfile' ]) + } + + private buildUploadAttaches (attributes: VideoEdit) { + const attaches: { [ name: string ]: string } = {} + + for (const key of [ 'thumbnailfile', 'previewfile' ]) { + if (attributes[key]) attaches[key] = buildAbsoluteFixturePath(attributes[key]) + } + + if (attributes.fixture) attaches.videofile = buildAbsoluteFixturePath(attributes.fixture) + + return attaches + } +} diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 5e20f8010..19f0df8b8 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -1,306 +1,16 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ import { expect } from 'chai' -import { createReadStream, pathExists, readdir, readFile, stat } from 'fs-extra' -import got, { Response as GotResponse } from 'got/dist/source' -import * as parseTorrent from 'parse-torrent' +import { pathExists, readdir } from 'fs-extra' import { join } from 'path' -import * as request from 'supertest' -import validator from 'validator' import { getLowercaseExtension } from '@server/helpers/core-utils' -import { buildUUID } from '@server/helpers/uuid' import { HttpStatusCode } from '@shared/core-utils' -import { BooleanBothQuery, VideosCommonQuery } from '@shared/models' -import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' -import { VideoDetails, VideoPrivacy } from '../../models/videos' -import { buildAbsoluteFixturePath, dateIsValid, testImage, wait, webtorrentAdd } from '../miscs' -import { makeGetRequest, makePutBodyRequest, makeRawRequest, makeUploadRequest } from '../requests/requests' -import { waitJobs } from '../server/jobs' +import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' +import { dateIsValid, testImage, webtorrentAdd } from '../miscs' +import { makeRawRequest } from '../requests/requests' +import { waitJobs } from '../server' import { ServerInfo } from '../server/servers' -import { xxxgetMyUserInformation } from '../users' - -loadLanguages() - -type VideoAttributes = { - name?: string - category?: number - licence?: number - language?: string - nsfw?: boolean - commentsEnabled?: boolean - downloadEnabled?: boolean - waitTranscoding?: boolean - description?: string - originallyPublishedAt?: string - tags?: string[] - channelId?: number - privacy?: VideoPrivacy - fixture?: string - support?: string - thumbnailfile?: string - previewfile?: string - scheduleUpdate?: { - updateAt: string - privacy?: VideoPrivacy - } -} - -function getVideoCategories (url: string) { - const path = '/api/v1/videos/categories' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoLicences (url: string) { - const path = '/api/v1/videos/licences' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoLanguages (url: string) { - const path = '/api/v1/videos/languages' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoPrivacies (url: string) { - const path = '/api/v1/videos/privacies' - - return makeGetRequest({ - url, - path, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideo (url: string, id: number | string, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/videos/' + id - - return request(url) - .get(path) - .set('Accept', 'application/json') - .expect(expectedStatus) -} - -async function getVideoIdFromUUID (url: string, uuid: string) { - const res = await getVideo(url, uuid) - - return res.body.id -} - -function getVideoFileMetadataUrl (url: string) { - return request(url) - .get('/') - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function viewVideo (url: string, id: number | string, expectedStatus = HttpStatusCode.NO_CONTENT_204, xForwardedFor?: string) { - const path = '/api/v1/videos/' + id + '/views' - - const req = request(url) - .post(path) - .set('Accept', 'application/json') - - if (xForwardedFor) { - req.set('X-Forwarded-For', xForwardedFor) - } - - return req.expect(expectedStatus) -} - -function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/videos/' + id - - return request(url) - .get(path) - .set('Authorization', 'Bearer ' + token) - .set('Accept', 'application/json') - .expect(expectedStatus) -} - -function getVideoDescription (url: string, descriptionPath: string) { - return request(url) - .get(descriptionPath) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getVideosList (url: string) { - const path = '/api/v1/videos' - - return request(url) - .get(path) - .query({ sort: 'name' }) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getVideosListWithToken (url: string, token: string, query: { nsfw?: BooleanBothQuery } = {}) { - const path = '/api/v1/videos' - - return request(url) - .get(path) - .set('Authorization', 'Bearer ' + token) - .query({ sort: 'name', ...query }) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getLocalVideos (url: string) { - const path = '/api/v1/videos' - - return request(url) - .get(path) - .query({ sort: 'name', filter: 'local' }) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string, search?: string) { - const path = '/api/v1/users/me/videos' - - const req = request(url) - .get(path) - .query({ start: start }) - .query({ count: count }) - .query({ search: search }) - - if (sort) req.query({ sort }) - - return req.set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getMyVideosWithFilter (url: string, accessToken: string, query: { isLive?: boolean }) { - const path = '/api/v1/users/me/videos' - - return makeGetRequest({ - url, - path, - token: accessToken, - query, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getAccountVideos ( - url: string, - accessToken: string, - accountName: string, - start: number, - count: number, - sort?: string, - query: { - nsfw?: BooleanBothQuery - search?: string - } = {} -) { - const path = '/api/v1/accounts/' + accountName + '/videos' - - return makeGetRequest({ - url, - path, - query: { ...query, start, count, sort }, - token: accessToken, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideoChannelVideos ( - url: string, - accessToken: string, - videoChannelName: string, - start: number, - count: number, - sort?: string, - query: { nsfw?: BooleanBothQuery } = {} -) { - const path = '/api/v1/video-channels/' + videoChannelName + '/videos' - - return makeGetRequest({ - url, - path, - query: { ...query, start, count, sort }, - token: accessToken, - statusCodeExpected: HttpStatusCode.OK_200 - }) -} - -function getVideosListPagination (url: string, start: number, count: number, sort?: string, skipCount?: boolean) { - const path = '/api/v1/videos' - - const req = request(url) - .get(path) - .query({ start: start }) - .query({ count: count }) - - if (sort) req.query({ sort }) - if (skipCount) req.query({ skipCount }) - - return req.set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getVideosListSort (url: string, sort: string) { - const path = '/api/v1/videos' - - return request(url) - .get(path) - .query({ sort: sort }) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function getVideosWithFilters (url: string, query: VideosCommonQuery) { - const path = '/api/v1/videos' - - return request(url) - .get(path) - .query(query) - .set('Accept', 'application/json') - .expect(HttpStatusCode.OK_200) - .expect('Content-Type', /json/) -} - -function removeVideo (url: string, token: string, id: number | string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/videos' - - return request(url) - .delete(path + '/' + id) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - .expect(expectedStatus) -} - -async function removeAllVideos (server: ServerInfo) { - const resVideos = await getVideosList(server.url) - - for (const v of resVideos.body.data) { - await removeVideo(server.url, server.accessToken, v.id) - } -} +import { VideoEdit } from './videos-command' async function checkVideoFilesWereRemoved ( videoUUID: string, @@ -329,280 +39,20 @@ async function checkVideoFilesWereRemoved ( } } -async function uploadVideo ( - url: string, - accessToken: string, - videoAttributesArg: VideoAttributes, - specialStatus = HttpStatusCode.OK_200, - mode: 'legacy' | 'resumable' = 'legacy' -) { - let defaultChannelId = '1' - - try { - const res = await xxxgetMyUserInformation(url, accessToken) - defaultChannelId = res.body.videoChannels[0].id - } catch (e) { /* empty */ } - - // Override default attributes - const attributes = Object.assign({ - name: 'my super video', - category: 5, - licence: 4, - language: 'zh', - channelId: defaultChannelId, - nsfw: true, - waitTranscoding: false, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag' ], - privacy: VideoPrivacy.PUBLIC, - commentsEnabled: true, - downloadEnabled: true, - fixture: 'video_short.webm' - }, videoAttributesArg) - - const res = mode === 'legacy' - ? await buildLegacyUpload(url, accessToken, attributes, specialStatus) - : await buildResumeUpload(url, accessToken, attributes, specialStatus) - - // Wait torrent generation - if (specialStatus === HttpStatusCode.OK_200) { - let video: VideoDetails - do { - const resVideo = await getVideoWithToken(url, accessToken, res.body.video.uuid) - video = resVideo.body - - await wait(50) - } while (!video.files[0].torrentUrl) - } - - return res -} - function checkUploadVideoParam ( - url: string, + server: ServerInfo, token: string, - attributes: Partial, - specialStatus = HttpStatusCode.OK_200, + attributes: Partial, + expectedStatus = HttpStatusCode.OK_200, mode: 'legacy' | 'resumable' = 'legacy' ) { return mode === 'legacy' - ? buildLegacyUpload(url, token, attributes, specialStatus) - : buildResumeUpload(url, token, attributes, specialStatus) -} - -async function buildLegacyUpload (url: string, token: string, attributes: VideoAttributes, specialStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/videos/upload' - const req = request(url) - .post(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + token) - - buildUploadReq(req, attributes) - - if (attributes.fixture !== undefined) { - req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture)) - } - - return req.expect(specialStatus) -} - -async function buildResumeUpload (url: string, token: string, attributes: VideoAttributes, specialStatus = HttpStatusCode.OK_200) { - let size = 0 - let videoFilePath: string - let mimetype = 'video/mp4' - - if (attributes.fixture) { - videoFilePath = buildAbsoluteFixturePath(attributes.fixture) - size = (await stat(videoFilePath)).size - - if (videoFilePath.endsWith('.mkv')) { - mimetype = 'video/x-matroska' - } else if (videoFilePath.endsWith('.webm')) { - mimetype = 'video/webm' - } - } - - const initializeSessionRes = await prepareResumableUpload({ url, token, attributes, size, mimetype }) - const initStatus = initializeSessionRes.status - - if (videoFilePath && initStatus === HttpStatusCode.CREATED_201) { - const locationHeader = initializeSessionRes.header['location'] - expect(locationHeader).to.not.be.undefined - - const pathUploadId = locationHeader.split('?')[1] - - return sendResumableChunks({ url, token, pathUploadId, videoFilePath, size, specialStatus }) - } - - const expectedInitStatus = specialStatus === HttpStatusCode.OK_200 - ? HttpStatusCode.CREATED_201 - : specialStatus - - expect(initStatus).to.equal(expectedInitStatus) - - return initializeSessionRes -} - -async function prepareResumableUpload (options: { - url: string - token: string - attributes: VideoAttributes - size: number - mimetype: string -}) { - const { url, token, attributes, size, mimetype } = options - - const path = '/api/v1/videos/upload-resumable' - - const req = request(url) - .post(path) - .set('Authorization', 'Bearer ' + token) - .set('X-Upload-Content-Type', mimetype) - .set('X-Upload-Content-Length', size.toString()) - - buildUploadReq(req, attributes) - - if (attributes.fixture) { - req.field('filename', attributes.fixture) - } - - return req -} - -function sendResumableChunks (options: { - url: string - token: string - pathUploadId: string - videoFilePath: string - size: number - specialStatus?: HttpStatusCode - contentLength?: number - contentRangeBuilder?: (start: number, chunk: any) => string -}) { - const { url, token, pathUploadId, videoFilePath, size, specialStatus, contentLength, contentRangeBuilder } = options - - const expectedStatus = specialStatus || HttpStatusCode.OK_200 - - const path = '/api/v1/videos/upload-resumable' - let start = 0 - - const readable = createReadStream(videoFilePath, { highWaterMark: 8 * 1024 }) - return new Promise((resolve, reject) => { - readable.on('data', async function onData (chunk) { - readable.pause() - - const headers = { - 'Authorization': 'Bearer ' + token, - 'Content-Type': 'application/octet-stream', - 'Content-Range': contentRangeBuilder - ? contentRangeBuilder(start, chunk) - : `bytes ${start}-${start + chunk.length - 1}/${size}`, - 'Content-Length': contentLength ? contentLength + '' : chunk.length + '' - } - - const res = await got({ - url, - method: 'put', - headers, - path: path + '?' + pathUploadId, - body: chunk, - responseType: 'json', - throwHttpErrors: false - }) - - start += chunk.length - - if (res.statusCode === expectedStatus) { - return resolve(res) - } - - if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) { - readable.off('data', onData) - return reject(new Error('Incorrect transient behaviour sending intermediary chunks')) - } - - readable.resume() - }) - }) -} - -function updateVideo ( - url: string, - accessToken: string, - id: number | string, - attributes: VideoAttributes, - statusCodeExpected = HttpStatusCode.NO_CONTENT_204 -) { - const path = '/api/v1/videos/' + id - const body = {} - - if (attributes.name) body['name'] = attributes.name - if (attributes.category) body['category'] = attributes.category - if (attributes.licence) body['licence'] = attributes.licence - if (attributes.language) body['language'] = attributes.language - if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw) - if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled) - if (attributes.downloadEnabled !== undefined) body['downloadEnabled'] = JSON.stringify(attributes.downloadEnabled) - if (attributes.originallyPublishedAt !== undefined) body['originallyPublishedAt'] = attributes.originallyPublishedAt - if (attributes.description) body['description'] = attributes.description - if (attributes.tags) body['tags'] = attributes.tags - if (attributes.privacy) body['privacy'] = attributes.privacy - if (attributes.channelId) body['channelId'] = attributes.channelId - if (attributes.scheduleUpdate) body['scheduleUpdate'] = attributes.scheduleUpdate - - // Upload request - if (attributes.thumbnailfile || attributes.previewfile) { - const attaches: any = {} - if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile - if (attributes.previewfile) attaches.previewfile = attributes.previewfile - - return makeUploadRequest({ - url, - method: 'PUT', - path, - token: accessToken, - fields: body, - attaches, - statusCodeExpected - }) - } - - return makePutBodyRequest({ - url, - path, - fields: body, - token: accessToken, - statusCodeExpected - }) -} - -function rateVideo (url: string, accessToken: string, id: number | string, rating: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { - const path = '/api/v1/videos/' + id + '/rate' - - return request(url) - .put(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .send({ rating }) - .expect(specialStatus) -} - -function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { - return new Promise((res, rej) => { - const torrentName = videoUUID + '-' + resolution + '.torrent' - const torrentPath = server.serversCommand.buildDirectory(join('torrents', torrentName)) - - readFile(torrentPath, (err, data) => { - if (err) return rej(err) - - return res(parseTorrent(data)) - }) - }) + ? server.videosCommand.buildLegacyUpload({ token, attributes, expectedStatus }) + : server.videosCommand.buildResumeUpload({ token, attributes, expectedStatus }) } async function completeVideoCheck ( - url: string, + server: ServerInfo, video: any, attributes: { name: string @@ -644,7 +94,7 @@ async function completeVideoCheck ( if (!attributes.likes) attributes.likes = 0 if (!attributes.dislikes) attributes.dislikes = 0 - const host = new URL(url).host + const host = new URL(server.url).host const originHost = attributes.account.host expect(video.name).to.equal(attributes.name) @@ -681,8 +131,7 @@ async function completeVideoCheck ( expect(video.originallyPublishedAt).to.be.null } - const res = await getVideo(url, video.uuid) - const videoDetails: VideoDetails = res.body + const videoDetails = await server.videosCommand.get({ id: video.uuid }) expect(videoDetails.files).to.have.lengthOf(attributes.files.length) expect(videoDetails.tags).to.deep.equal(attributes.tags) @@ -738,148 +187,33 @@ async function completeVideoCheck ( } expect(videoDetails.thumbnailPath).to.exist - await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) + await testImage(server.url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) if (attributes.previewfile) { expect(videoDetails.previewPath).to.exist - await testImage(url, attributes.previewfile, videoDetails.previewPath) + await testImage(server.url, attributes.previewfile, videoDetails.previewPath) } } -async function videoUUIDToId (url: string, id: number | string) { - if (validator.isUUID('' + id) === false) return id - - const res = await getVideo(url, id) - return res.body.id -} - -async function uploadVideoAndGetId (options: { - server: ServerInfo - videoName: string - nsfw?: boolean - privacy?: VideoPrivacy - token?: string - fixture?: string -}) { - const videoAttrs: any = { name: options.videoName } - if (options.nsfw) videoAttrs.nsfw = options.nsfw - if (options.privacy) videoAttrs.privacy = options.privacy - if (options.fixture) videoAttrs.fixture = options.fixture - - const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs) - - return res.body.video as { id: number, uuid: string, shortUUID: string } -} - -async function getLocalIdByUUID (url: string, uuid: string) { - const res = await getVideo(url, uuid) - - return res.body.id -} - // serverNumber starts from 1 -async function uploadRandomVideoOnServers (servers: ServerInfo[], serverNumber: number, additionalParams: any = {}) { +async function uploadRandomVideoOnServers ( + servers: ServerInfo[], + serverNumber: number, + additionalParams?: VideoEdit & { prefixName?: string } +) { const server = servers.find(s => s.serverNumber === serverNumber) - const res = await uploadRandomVideo(server, false, additionalParams) + const res = await server.videosCommand.randomUpload({ wait: false, ...additionalParams }) await waitJobs(servers) return res } -async function uploadRandomVideo (server: ServerInfo, wait = true, additionalParams: any = {}) { - const prefixName = additionalParams.prefixName || '' - const name = prefixName + buildUUID() - - const data = Object.assign({ name }, additionalParams) - const res = await uploadVideo(server.url, server.accessToken, data) - - if (wait) await waitJobs([ server ]) - - return { uuid: res.body.video.uuid, name } -} - // --------------------------------------------------------------------------- export { - getVideoDescription, - getVideoCategories, - uploadRandomVideo, - getVideoLicences, - videoUUIDToId, - getVideoPrivacies, - getVideoLanguages, - getMyVideos, - getAccountVideos, - getVideoChannelVideos, - getVideo, - getVideoFileMetadataUrl, - getVideoWithToken, - getVideosList, - removeAllVideos, checkUploadVideoParam, - getVideosListPagination, - getVideosListSort, - removeVideo, - getVideosListWithToken, - uploadVideo, - sendResumableChunks, - getVideosWithFilters, - uploadRandomVideoOnServers, - updateVideo, - rateVideo, - viewVideo, - parseTorrentVideo, - getLocalVideos, completeVideoCheck, - checkVideoFilesWereRemoved, - getMyVideosWithFilter, - uploadVideoAndGetId, - getLocalIdByUUID, - getVideoIdFromUUID, - prepareResumableUpload -} - -// --------------------------------------------------------------------------- - -function buildUploadReq (req: request.Test, attributes: VideoAttributes) { - - for (const key of [ 'name', 'support', 'channelId', 'description', 'originallyPublishedAt' ]) { - if (attributes[key] !== undefined) { - req.field(key, attributes[key]) - } - } - - for (const key of [ 'nsfw', 'commentsEnabled', 'downloadEnabled', 'waitTranscoding' ]) { - if (attributes[key] !== undefined) { - req.field(key, JSON.stringify(attributes[key])) - } - } - - for (const key of [ 'language', 'privacy', 'category', 'licence' ]) { - if (attributes[key] !== undefined) { - req.field(key, attributes[key].toString()) - } - } - - const tags = attributes.tags || [] - for (let i = 0; i < tags.length; i++) { - req.field('tags[' + i + ']', attributes.tags[i]) - } - - for (const key of [ 'thumbnailfile', 'previewfile' ]) { - if (attributes[key] !== undefined) { - req.attach(key, buildAbsoluteFixturePath(attributes[key])) - } - } - - if (attributes.scheduleUpdate) { - if (attributes.scheduleUpdate.updateAt) { - req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt) - } - - if (attributes.scheduleUpdate.privacy) { - req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy) - } - } + uploadRandomVideoOnServers, + checkVideoFilesWereRemoved } -- cgit v1.2.3 From 89d241a79c262b9775c233b73cff080043ebb5e6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 09:04:35 +0200 Subject: Shorter server command names --- shared/extra-utils/miscs/checks.ts | 2 +- shared/extra-utils/miscs/webtorrent.ts | 2 +- shared/extra-utils/server/follows.ts | 4 +- shared/extra-utils/server/jobs.ts | 4 +- shared/extra-utils/server/plugins-command.ts | 2 +- shared/extra-utils/server/plugins.ts | 2 +- shared/extra-utils/server/servers-command.ts | 6 +- shared/extra-utils/server/servers.ts | 230 +++++++++++------------ shared/extra-utils/users/accounts.ts | 2 +- shared/extra-utils/users/login-command.ts | 12 +- shared/extra-utils/users/login.ts | 2 +- shared/extra-utils/users/notifications.ts | 20 +- shared/extra-utils/users/users-command.ts | 4 +- shared/extra-utils/videos/channels.ts | 4 +- shared/extra-utils/videos/live-command.ts | 8 +- shared/extra-utils/videos/live.ts | 4 +- shared/extra-utils/videos/playlists-command.ts | 2 +- shared/extra-utils/videos/streaming-playlists.ts | 6 +- shared/extra-utils/videos/videos-command.ts | 2 +- shared/extra-utils/videos/videos.ts | 10 +- 20 files changed, 164 insertions(+), 164 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/checks.ts b/shared/extra-utils/miscs/checks.ts index 86b861cd2..8f7bdb9b5 100644 --- a/shared/extra-utils/miscs/checks.ts +++ b/shared/extra-utils/miscs/checks.ts @@ -34,7 +34,7 @@ async function testImage (url: string, imageName: string, imagePath: string, ext } async function testFileExistsOrNot (server: ServerInfo, directory: string, filePath: string, exist: boolean) { - const base = server.serversCommand.buildDirectory(directory) + const base = server.servers.buildDirectory(directory) expect(await pathExists(join(base, filePath))).to.equal(exist) } diff --git a/shared/extra-utils/miscs/webtorrent.ts b/shared/extra-utils/miscs/webtorrent.ts index 63e648309..84e390b2a 100644 --- a/shared/extra-utils/miscs/webtorrent.ts +++ b/shared/extra-utils/miscs/webtorrent.ts @@ -17,7 +17,7 @@ function webtorrentAdd (torrent: string, refreshWebTorrent = false) { async function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { const torrentName = videoUUID + '-' + resolution + '.torrent' - const torrentPath = server.serversCommand.buildDirectory(join('torrents', torrentName)) + const torrentPath = server.servers.buildDirectory(join('torrents', torrentName)) const data = await readFile(torrentPath) diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts index c23cebd81..50ae898cc 100644 --- a/shared/extra-utils/server/follows.ts +++ b/shared/extra-utils/server/follows.ts @@ -3,8 +3,8 @@ import { ServerInfo } from './servers' async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { await Promise.all([ - server1.followsCommand.follow({ targets: [ server2.url ] }), - server2.followsCommand.follow({ targets: [ server1.url ] }) + server1.follows.follow({ targets: [ server2.url ] }), + server2.follows.follow({ targets: [ server1.url ] }) ]) // Wait request propagation diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index 36ef882b3..754530977 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -23,7 +23,7 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { // Check if each server has pending request for (const server of servers) { for (const state of states) { - const p = server.jobsCommand.getJobsList({ + const p = server.jobs.getJobsList({ state, start: 0, count: 10, @@ -39,7 +39,7 @@ async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { tasks.push(p) } - const p = server.debugCommand.getDebug() + const p = server.debug.getDebug() .then(obj => { if (obj.activityPubMessagesWaiting !== 0) { pendingRequests = true diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index 5bed51d1a..98049ce19 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -251,6 +251,6 @@ export class PluginsCommand extends AbstractCommand { } private getPackageJSONPath (npmName: string) { - return this.server.serversCommand.buildDirectory(join('plugins', 'node_modules', npmName, 'package.json')) + return this.server.servers.buildDirectory(join('plugins', 'node_modules', npmName, 'package.json')) } } diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts index 1084ea4f4..d1cc7e383 100644 --- a/shared/extra-utils/server/plugins.ts +++ b/shared/extra-utils/server/plugins.ts @@ -4,7 +4,7 @@ import { expect } from 'chai' import { ServerInfo } from '../server/servers' async function testHelloWorldRegisteredSettings (server: ServerInfo) { - const body = await server.pluginsCommand.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) + const body = await server.plugins.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) const registeredSettings = body.registeredSettings expect(registeredSettings).to.have.length.at.least(1) diff --git a/shared/extra-utils/server/servers-command.ts b/shared/extra-utils/server/servers-command.ts index 9ef68fede..a7c5a868d 100644 --- a/shared/extra-utils/server/servers-command.ts +++ b/shared/extra-utils/server/servers-command.ts @@ -37,7 +37,7 @@ export class ServersCommand extends AbstractCommand { if (isGithubCI()) { await ensureDir('artifacts') - const origin = this.server.serversCommand.buildDirectory('logs/peertube.log') + const origin = this.server.servers.buildDirectory('logs/peertube.log') const destname = `peertube-${this.server.internalServerNumber}.log` console.log('Saving logs %s.', destname) @@ -56,7 +56,7 @@ export class ServersCommand extends AbstractCommand { } async waitUntilLog (str: string, count = 1, strictCount = true) { - const logfile = this.server.serversCommand.buildDirectory('logs/peertube.log') + const logfile = this.server.servers.buildDirectory('logs/peertube.log') while (true) { const buf = await readFile(logfile) @@ -74,7 +74,7 @@ export class ServersCommand extends AbstractCommand { } async getServerFileSize (subPath: string) { - const path = this.server.serversCommand.buildDirectory(subPath) + const path = this.server.servers.buildDirectory(subPath) return getFileSize(path) } diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index fda5c3d6d..ea3f19a92 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -53,83 +53,81 @@ interface ServerInfo { parallel?: boolean internalServerNumber: number + serverNumber?: number + customConfigFile?: string - client?: { - id?: string - secret?: string - } + store?: { + client?: { + id?: string + secret?: string + } - user?: { - username: string - password: string - email?: string - } + user?: { + username: string + password: string + email?: string + } - customConfigFile?: string + channel?: VideoChannel - accessToken?: string - refreshToken?: string - videoChannel?: VideoChannel + video?: { + id: number + uuid: string + shortUUID: string + name?: string + url?: string - video?: { - id: number - uuid: string - shortUUID: string - name?: string - url?: string + account?: { + name: string + } - account?: { - name: string + embedPath?: string } - embedPath?: string + videos?: { id: number, uuid: string }[] } - remoteVideo?: { - id: number - uuid: string - } + accessToken?: string + refreshToken?: string - videos?: { id: number, uuid: string }[] - - bulkCommand?: BulkCommand - cliCommand?: CLICommand - customPageCommand?: CustomPagesCommand - feedCommand?: FeedCommand - logsCommand?: LogsCommand - abusesCommand?: AbusesCommand - overviewsCommand?: OverviewsCommand - searchCommand?: SearchCommand - contactFormCommand?: ContactFormCommand - debugCommand?: DebugCommand - followsCommand?: FollowsCommand - jobsCommand?: JobsCommand - pluginsCommand?: PluginsCommand - redundancyCommand?: RedundancyCommand - statsCommand?: StatsCommand - configCommand?: ConfigCommand - socketIOCommand?: SocketIOCommand - accountsCommand?: AccountsCommand - blocklistCommand?: BlocklistCommand - subscriptionsCommand?: SubscriptionsCommand - liveCommand?: LiveCommand - servicesCommand?: ServicesCommand - blacklistCommand?: BlacklistCommand - captionsCommand?: CaptionsCommand - changeOwnershipCommand?: ChangeOwnershipCommand - playlistsCommand?: PlaylistsCommand - historyCommand?: HistoryCommand - importsCommand?: ImportsCommand - streamingPlaylistsCommand?: StreamingPlaylistsCommand - channelsCommand?: ChannelsCommand - commentsCommand?: CommentsCommand - sqlCommand?: SQLCommand - notificationsCommand?: NotificationsCommand - serversCommand?: ServersCommand - loginCommand?: LoginCommand - usersCommand?: UsersCommand - videosCommand?: VideosCommand + bulk?: BulkCommand + cli?: CLICommand + customPage?: CustomPagesCommand + feed?: FeedCommand + logs?: LogsCommand + abuses?: AbusesCommand + overviews?: OverviewsCommand + search?: SearchCommand + contactForm?: ContactFormCommand + debug?: DebugCommand + follows?: FollowsCommand + jobs?: JobsCommand + plugins?: PluginsCommand + redundancy?: RedundancyCommand + stats?: StatsCommand + config?: ConfigCommand + socketIO?: SocketIOCommand + accounts?: AccountsCommand + blocklist?: BlocklistCommand + subscriptions?: SubscriptionsCommand + live?: LiveCommand + services?: ServicesCommand + blacklist?: BlacklistCommand + captions?: CaptionsCommand + changeOwnership?: ChangeOwnershipCommand + playlists?: PlaylistsCommand + history?: HistoryCommand + imports?: ImportsCommand + streamingPlaylists?: StreamingPlaylistsCommand + channels?: ChannelsCommand + comments?: CommentsCommand + sql?: SQLCommand + notifications?: NotificationsCommand + servers?: ServersCommand + login?: LoginCommand + users?: UsersCommand + videos?: VideosCommand } function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { @@ -189,13 +187,15 @@ async function flushAndRunServer (serverNumber: number, configOverride?: Object, url: `http://localhost:${port}`, host: `localhost:${port}`, hostname: 'localhost', - client: { - id: null, - secret: null - }, - user: { - username: null, - password: null + store: { + client: { + id: null, + secret: null + }, + user: { + username: null, + password: null + } } } @@ -291,10 +291,10 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] const regexp = regexps[key] const matches = data.toString().match(regexp) if (matches !== null) { - if (key === 'client_id') server.client.id = matches[1] - else if (key === 'client_secret') server.client.secret = matches[1] - else if (key === 'user_username') server.user.username = matches[1] - else if (key === 'user_password') server.user.password = matches[1] + if (key === 'client_id') server.store.client.id = matches[1] + else if (key === 'client_secret') server.store.client.secret = matches[1] + else if (key === 'user_username') server.store.user.username = matches[1] + else if (key === 'user_password') server.store.user.password = matches[1] } } @@ -327,43 +327,43 @@ async function runServer (server: ServerInfo, configOverrideArg?: any, args = [] } function assignCommands (server: ServerInfo) { - server.bulkCommand = new BulkCommand(server) - server.cliCommand = new CLICommand(server) - server.customPageCommand = new CustomPagesCommand(server) - server.feedCommand = new FeedCommand(server) - server.logsCommand = new LogsCommand(server) - server.abusesCommand = new AbusesCommand(server) - server.overviewsCommand = new OverviewsCommand(server) - server.searchCommand = new SearchCommand(server) - server.contactFormCommand = new ContactFormCommand(server) - server.debugCommand = new DebugCommand(server) - server.followsCommand = new FollowsCommand(server) - server.jobsCommand = new JobsCommand(server) - server.pluginsCommand = new PluginsCommand(server) - server.redundancyCommand = new RedundancyCommand(server) - server.statsCommand = new StatsCommand(server) - server.configCommand = new ConfigCommand(server) - server.socketIOCommand = new SocketIOCommand(server) - server.accountsCommand = new AccountsCommand(server) - server.blocklistCommand = new BlocklistCommand(server) - server.subscriptionsCommand = new SubscriptionsCommand(server) - server.liveCommand = new LiveCommand(server) - server.servicesCommand = new ServicesCommand(server) - server.blacklistCommand = new BlacklistCommand(server) - server.captionsCommand = new CaptionsCommand(server) - server.changeOwnershipCommand = new ChangeOwnershipCommand(server) - server.playlistsCommand = new PlaylistsCommand(server) - server.historyCommand = new HistoryCommand(server) - server.importsCommand = new ImportsCommand(server) - server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server) - server.channelsCommand = new ChannelsCommand(server) - server.commentsCommand = new CommentsCommand(server) - server.sqlCommand = new SQLCommand(server) - server.notificationsCommand = new NotificationsCommand(server) - server.serversCommand = new ServersCommand(server) - server.loginCommand = new LoginCommand(server) - server.usersCommand = new UsersCommand(server) - server.videosCommand = new VideosCommand(server) + server.bulk = new BulkCommand(server) + server.cli = new CLICommand(server) + server.customPage = new CustomPagesCommand(server) + server.feed = new FeedCommand(server) + server.logs = new LogsCommand(server) + server.abuses = new AbusesCommand(server) + server.overviews = new OverviewsCommand(server) + server.search = new SearchCommand(server) + server.contactForm = new ContactFormCommand(server) + server.debug = new DebugCommand(server) + server.follows = new FollowsCommand(server) + server.jobs = new JobsCommand(server) + server.plugins = new PluginsCommand(server) + server.redundancy = new RedundancyCommand(server) + server.stats = new StatsCommand(server) + server.config = new ConfigCommand(server) + server.socketIO = new SocketIOCommand(server) + server.accounts = new AccountsCommand(server) + server.blocklist = new BlocklistCommand(server) + server.subscriptions = new SubscriptionsCommand(server) + server.live = new LiveCommand(server) + server.services = new ServicesCommand(server) + server.blacklist = new BlacklistCommand(server) + server.captions = new CaptionsCommand(server) + server.changeOwnership = new ChangeOwnershipCommand(server) + server.playlists = new PlaylistsCommand(server) + server.history = new HistoryCommand(server) + server.imports = new ImportsCommand(server) + server.streamingPlaylists = new StreamingPlaylistsCommand(server) + server.channels = new ChannelsCommand(server) + server.comments = new CommentsCommand(server) + server.sql = new SQLCommand(server) + server.notifications = new NotificationsCommand(server) + server.servers = new ServersCommand(server) + server.login = new LoginCommand(server) + server.users = new UsersCommand(server) + server.videos = new VideosCommand(server) } async function reRunServer (server: ServerInfo, configOverride?: any) { @@ -377,7 +377,7 @@ async function killallServers (servers: ServerInfo[]) { for (const server of servers) { if (!server.app) continue - await server.sqlCommand.cleanup() + await server.sql.cleanup() process.kill(-server.app.pid) @@ -394,7 +394,7 @@ async function cleanupTests (servers: ServerInfo[]) { let p: Promise[] = [] for (const server of servers) { - p = p.concat(server.serversCommand.cleanupTests()) + p = p.concat(server.servers.cleanupTests()) } return Promise.all(p) diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts index ee94351e8..2c9a4b71c 100644 --- a/shared/extra-utils/users/accounts.ts +++ b/shared/extra-utils/users/accounts.ts @@ -14,7 +14,7 @@ async function expectAccountFollows (options: { }) { const { server, handle, followers, following } = options - const body = await server.accountsCommand.list() + const body = await server.accounts.list() const account = body.data.find(a => a.name + '@' + a.host === handle) const message = `${handle} on ${server.url}` diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts index b4e3bb602..10c3db851 100644 --- a/shared/extra-utils/users/login-command.ts +++ b/shared/extra-utils/users/login-command.ts @@ -9,7 +9,7 @@ export class LoginCommand extends AbstractCommand { client?: { id?: string, secret?: string } user?: { username: string, password?: string } } = {}) { - const { client = this.server.client, user = this.server.user } = options + const { client = this.server.store.client, user = this.server.store.user } = options const path = '/api/v1/users/token' const body = { @@ -38,7 +38,7 @@ export class LoginCommand extends AbstractCommand { async getAccessToken (arg1?: { username: string, password?: string } | string, password?: string) { let user: { username: string, password?: string } - if (!arg1) user = this.server.user + if (!arg1) user = this.server.store.user else if (typeof arg1 === 'object') user = arg1 else user = { username: arg1, password } @@ -59,8 +59,8 @@ export class LoginCommand extends AbstractCommand { const path = '/api/v1/users/token' const body = { - client_id: this.server.client.id, - client_secret: this.server.client.secret, + client_id: this.server.store.client.id, + client_secret: this.server.store.client.secret, username: username, response_type: 'code', grant_type: 'password', @@ -100,8 +100,8 @@ export class LoginCommand extends AbstractCommand { const path = '/api/v1/users/token' const body = { - client_id: this.server.client.id, - client_secret: this.server.client.secret, + client_id: this.server.store.client.id, + client_secret: this.server.store.client.secret, refresh_token: options.refreshToken, response_type: 'code', grant_type: 'refresh_token' diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index d4ee8e517..d0c26a4f0 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts @@ -4,7 +4,7 @@ function setAccessTokensToServers (servers: ServerInfo[]) { const tasks: Promise[] = [] for (const server of servers) { - const p = server.loginCommand.getAccessToken() + const p = server.login.getAccessToken() .then(t => { server.accessToken = t }) tasks.push(p) } diff --git a/shared/extra-utils/users/notifications.ts b/shared/extra-utils/users/notifications.ts index 0af7d8a18..9196f0bf5 100644 --- a/shared/extra-utils/users/notifications.ts +++ b/shared/extra-utils/users/notifications.ts @@ -49,7 +49,7 @@ async function checkNotification ( const check = base.check || { web: true, mail: true } if (check.web) { - const notification = await base.server.notificationsCommand.getLastest({ token: base.token }) + const notification = await base.server.notifications.getLastest({ token: base.token }) if (notification || checkType !== 'absence') { notificationChecker(notification, checkType) @@ -651,31 +651,31 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an } const user = { username: 'user_1', password: 'super password' } - await servers[0].usersCommand.create({ ...user, videoQuota: 10 * 1000 * 1000 }) - const userAccessToken = await servers[0].loginCommand.getAccessToken(user) + await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 }) + const userAccessToken = await servers[0].login.getAccessToken(user) - await servers[0].notificationsCommand.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) - await servers[0].notificationsCommand.updateMySettings({ settings: getAllNotificationsSettings() }) + await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) + await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) if (serversCount > 1) { - await servers[1].notificationsCommand.updateMySettings({ settings: getAllNotificationsSettings() }) + await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) } { - const socket = servers[0].socketIOCommand.getUserNotificationSocket({ token: userAccessToken }) + const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken }) socket.on('new-notification', n => userNotifications.push(n)) } { - const socket = servers[0].socketIOCommand.getUserNotificationSocket() + const socket = servers[0].socketIO.getUserNotificationSocket() socket.on('new-notification', n => adminNotifications.push(n)) } if (serversCount > 1) { - const socket = servers[1].socketIOCommand.getUserNotificationSocket() + const socket = servers[1].socketIO.getUserNotificationSocket() socket.on('new-notification', n => adminNotificationsServer2.push(n)) } - const { videoChannels } = await servers[0].usersCommand.getMyInfo() + const { videoChannels } = await servers[0].users.getMyInfo() const channelId = videoChannels[0].id return { diff --git a/shared/extra-utils/users/users-command.ts b/shared/extra-utils/users/users-command.ts index 202528b8d..59dc6d018 100644 --- a/shared/extra-utils/users/users-command.ts +++ b/shared/extra-utils/users/users-command.ts @@ -194,7 +194,7 @@ export class UsersCommand extends AbstractCommand { const password = 'password' const user = await this.create({ username, password }) - const token = await this.server.loginCommand.getAccessToken({ username, password }) + const token = await this.server.login.getAccessToken({ username, password }) const me = await this.getMyInfo({ token }) @@ -209,7 +209,7 @@ export class UsersCommand extends AbstractCommand { const password = 'password' await this.create({ username, password }) - return this.server.loginCommand.getAccessToken({ username, password }) + return this.server.login.getAccessToken({ username, password }) } register (options: OverrideCommandOptions & { diff --git a/shared/extra-utils/videos/channels.ts b/shared/extra-utils/videos/channels.ts index 9e7ec565d..81e818094 100644 --- a/shared/extra-utils/videos/channels.ts +++ b/shared/extra-utils/videos/channels.ts @@ -4,8 +4,8 @@ function setDefaultVideoChannel (servers: ServerInfo[]) { const tasks: Promise[] = [] for (const server of servers) { - const p = server.usersCommand.getMyInfo() - .then(user => { server.videoChannel = user.videoChannels[0] }) + const p = server.users.getMyInfo() + .then(user => { server.store.channel = user.videoChannels[0] }) tasks.push(p) } diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index 5adf601cc..fd66c9924 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -114,7 +114,7 @@ export class LiveCommand extends AbstractCommand { const { resolution, segment, videoUUID } = options const segmentName = `${resolution}-00000${segment}.ts` - return this.server.serversCommand.waitUntilLog(`${videoUUID}/${segmentName}`, 2, false) + return this.server.servers.waitUntilLog(`${videoUUID}/${segmentName}`, 2, false) } async waitUntilSaved (options: OverrideCommandOptions & { @@ -123,7 +123,7 @@ export class LiveCommand extends AbstractCommand { let video: VideoDetails do { - video = await this.server.videosCommand.getWithToken({ token: options.token, id: options.videoId }) + video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) await wait(500) } while (video.isLive === true && video.state.id !== VideoState.PUBLISHED) @@ -132,7 +132,7 @@ export class LiveCommand extends AbstractCommand { async countPlaylists (options: OverrideCommandOptions & { videoUUID: string }) { - const basePath = this.server.serversCommand.buildDirectory('streaming-playlists') + const basePath = this.server.servers.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', options.videoUUID) const files = await readdir(hlsPath) @@ -147,7 +147,7 @@ export class LiveCommand extends AbstractCommand { let video: VideoDetails do { - video = await this.server.videosCommand.getWithToken({ token: options.token, id: options.videoId }) + video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) await wait(500) } while (video.state.id !== options.state) diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index 0efcc2883..353595811 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -72,12 +72,12 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) { async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) { for (const server of servers) { - await server.liveCommand.waitUntilPublished({ videoId }) + await server.live.waitUntilPublished({ videoId }) } } async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) { - const basePath = server.serversCommand.buildDirectory('streaming-playlists') + const basePath = server.servers.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', videoUUID) if (resolutions.length === 0) { diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts index 75c8f2433..cbfc7e10f 100644 --- a/shared/extra-utils/videos/playlists-command.ts +++ b/shared/extra-utils/videos/playlists-command.ts @@ -184,7 +184,7 @@ export class PlaylistsCommand extends AbstractCommand { const attributes = { ...options.attributes, - videoId: await this.server.videosCommand.getId({ ...options, uuid: options.attributes.videoId }) + videoId: await this.server.videos.getId({ ...options, uuid: options.attributes.videoId }) } const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts index 0324c739a..e8fd2f232 100644 --- a/shared/extra-utils/videos/streaming-playlists.ts +++ b/shared/extra-utils/videos/streaming-playlists.ts @@ -13,7 +13,7 @@ async function checkSegmentHash (options: { hlsPlaylist: VideoStreamingPlaylist }) { const { server, baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist } = options - const command = server.streamingPlaylistsCommand + const command = server.streamingPlaylists const playlist = await command.get({ url: `${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8` }) @@ -43,7 +43,7 @@ async function checkLiveSegmentHash (options: { hlsPlaylist: VideoStreamingPlaylist }) { const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options - const command = server.streamingPlaylistsCommand + const command = server.streamingPlaylists const segmentBody = await command.getSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` }) const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) @@ -58,7 +58,7 @@ async function checkResolutionsInMasterPlaylist (options: { }) { const { server, playlistUrl, resolutions } = options - const masterPlaylist = await server.streamingPlaylistsCommand.get({ url: playlistUrl }) + const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl }) for (const resolution of resolutions) { const reg = new RegExp( diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts index 574705474..5556cddf6 100644 --- a/shared/extra-utils/videos/videos-command.ts +++ b/shared/extra-utils/videos/videos-command.ts @@ -336,7 +336,7 @@ export class VideosCommand extends AbstractCommand { let defaultChannelId = 1 try { - const { videoChannels } = await this.server.usersCommand.getMyInfo({ token: options.token }) + const { videoChannels } = await this.server.users.getMyInfo({ token: options.token }) defaultChannelId = videoChannels[0].id } catch (e) { /* empty */ } diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index 19f0df8b8..86f49384d 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -27,7 +27,7 @@ async function checkVideoFilesWereRemoved ( ] ) { for (const directory of directories) { - const directoryPath = server.serversCommand.buildDirectory(directory) + const directoryPath = server.servers.buildDirectory(directory) const directoryExists = await pathExists(directoryPath) if (directoryExists === false) continue @@ -47,8 +47,8 @@ function checkUploadVideoParam ( mode: 'legacy' | 'resumable' = 'legacy' ) { return mode === 'legacy' - ? server.videosCommand.buildLegacyUpload({ token, attributes, expectedStatus }) - : server.videosCommand.buildResumeUpload({ token, attributes, expectedStatus }) + ? server.videos.buildLegacyUpload({ token, attributes, expectedStatus }) + : server.videos.buildResumeUpload({ token, attributes, expectedStatus }) } async function completeVideoCheck ( @@ -131,7 +131,7 @@ async function completeVideoCheck ( expect(video.originallyPublishedAt).to.be.null } - const videoDetails = await server.videosCommand.get({ id: video.uuid }) + const videoDetails = await server.videos.get({ id: video.uuid }) expect(videoDetails.files).to.have.lengthOf(attributes.files.length) expect(videoDetails.tags).to.deep.equal(attributes.tags) @@ -202,7 +202,7 @@ async function uploadRandomVideoOnServers ( additionalParams?: VideoEdit & { prefixName?: string } ) { const server = servers.find(s => s.serverNumber === serverNumber) - const res = await server.videosCommand.randomUpload({ wait: false, ...additionalParams }) + const res = await server.videos.randomUpload({ wait: false, ...additionalParams }) await waitJobs(servers) -- cgit v1.2.3 From 254d3579f5338f5fd775c17d15cdfc37078bcfb4 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 09:47:51 +0200 Subject: Use an object to represent a server --- shared/extra-utils/miscs/checks.ts | 4 +- shared/extra-utils/miscs/webtorrent.ts | 4 +- shared/extra-utils/server/directories.ts | 6 +- shared/extra-utils/server/follows-command.ts | 6 +- shared/extra-utils/server/follows.ts | 4 +- shared/extra-utils/server/index.ts | 1 + shared/extra-utils/server/jobs.ts | 10 +- shared/extra-utils/server/plugins.ts | 4 +- shared/extra-utils/server/server.ts | 376 +++++++++++++++++++++ shared/extra-utils/server/servers-command.ts | 2 +- shared/extra-utils/server/servers.ts | 400 +---------------------- shared/extra-utils/shared/abstract-command.ts | 4 +- shared/extra-utils/users/accounts.ts | 4 +- shared/extra-utils/users/login.ts | 4 +- shared/extra-utils/users/notifications.ts | 7 +- shared/extra-utils/videos/channels.ts | 4 +- shared/extra-utils/videos/live.ts | 6 +- shared/extra-utils/videos/streaming-playlists.ts | 8 +- shared/extra-utils/videos/videos-command.ts | 4 +- shared/extra-utils/videos/videos.ts | 10 +- 20 files changed, 441 insertions(+), 427 deletions(-) create mode 100644 shared/extra-utils/server/server.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/checks.ts b/shared/extra-utils/miscs/checks.ts index 8f7bdb9b5..c81460330 100644 --- a/shared/extra-utils/miscs/checks.ts +++ b/shared/extra-utils/miscs/checks.ts @@ -6,7 +6,7 @@ import { join } from 'path' import { root } from '@server/helpers/core-utils' import { HttpStatusCode } from '@shared/core-utils' import { makeGetRequest } from '../requests' -import { ServerInfo } from '../server' +import { PeerTubeServer } from '../server' // Default interval -> 5 minutes function dateIsValid (dateString: string, interval = 300000) { @@ -33,7 +33,7 @@ async function testImage (url: string, imageName: string, imagePath: string, ext expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') } -async function testFileExistsOrNot (server: ServerInfo, directory: string, filePath: string, exist: boolean) { +async function testFileExistsOrNot (server: PeerTubeServer, directory: string, filePath: string, exist: boolean) { const base = server.servers.buildDirectory(directory) expect(await pathExists(join(base, filePath))).to.equal(exist) diff --git a/shared/extra-utils/miscs/webtorrent.ts b/shared/extra-utils/miscs/webtorrent.ts index 84e390b2a..815ea3d56 100644 --- a/shared/extra-utils/miscs/webtorrent.ts +++ b/shared/extra-utils/miscs/webtorrent.ts @@ -2,7 +2,7 @@ import { readFile } from 'fs-extra' import * as parseTorrent from 'parse-torrent' import { join } from 'path' import * as WebTorrent from 'webtorrent' -import { ServerInfo } from '../server' +import { PeerTubeServer } from '../server' let webtorrent: WebTorrent.Instance @@ -15,7 +15,7 @@ function webtorrentAdd (torrent: string, refreshWebTorrent = false) { return new Promise(res => webtorrent.add(torrent, res)) } -async function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) { +async function parseTorrentVideo (server: PeerTubeServer, videoUUID: string, resolution: number) { const torrentName = videoUUID + '-' + resolution + '.torrent' const torrentPath = server.servers.buildDirectory(join('torrents', torrentName)) diff --git a/shared/extra-utils/server/directories.ts b/shared/extra-utils/server/directories.ts index 3cd38a561..b6465cbf4 100644 --- a/shared/extra-utils/server/directories.ts +++ b/shared/extra-utils/server/directories.ts @@ -4,9 +4,9 @@ import { expect } from 'chai' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { ServerInfo } from './servers' +import { PeerTubeServer } from './server' -async function checkTmpIsEmpty (server: ServerInfo) { +async function checkTmpIsEmpty (server: PeerTubeServer) { await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { @@ -14,7 +14,7 @@ async function checkTmpIsEmpty (server: ServerInfo) { } } -async function checkDirectoryIsEmpty (server: ServerInfo, directory: string, exceptions: string[] = []) { +async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) { const testDirectory = 'test' + server.internalServerNumber const directoryPath = join(root(), testDirectory, directory) diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts index 4e1e56d7a..4e9ed9494 100644 --- a/shared/extra-utils/server/follows-command.ts +++ b/shared/extra-utils/server/follows-command.ts @@ -2,7 +2,7 @@ import { pick } from 'lodash' import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models' import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' import { AbstractCommand, OverrideCommandOptions } from '../shared' -import { ServerInfo } from './servers' +import { PeerTubeServer } from './server' export class FollowsCommand extends AbstractCommand { @@ -70,7 +70,7 @@ export class FollowsCommand extends AbstractCommand { } async unfollow (options: OverrideCommandOptions & { - target: ServerInfo + target: PeerTubeServer }) { const path = '/api/v1/server/following/' + options.target.host @@ -112,7 +112,7 @@ export class FollowsCommand extends AbstractCommand { } removeFollower (options: OverrideCommandOptions & { - follower: ServerInfo + follower: PeerTubeServer }) { const path = '/api/v1/server/followers/peertube@' + options.follower.host diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts index 50ae898cc..0188be1aa 100644 --- a/shared/extra-utils/server/follows.ts +++ b/shared/extra-utils/server/follows.ts @@ -1,7 +1,7 @@ import { waitJobs } from './jobs' -import { ServerInfo } from './servers' +import { PeerTubeServer } from './server' -async function doubleFollow (server1: ServerInfo, server2: ServerInfo) { +async function doubleFollow (server1: PeerTubeServer, server2: PeerTubeServer) { await Promise.all([ server1.follows.follow({ targets: [ server2.url ] }), server2.follows.follow({ targets: [ server1.url ] }) diff --git a/shared/extra-utils/server/index.ts b/shared/extra-utils/server/index.ts index 669b004cd..9055dfc57 100644 --- a/shared/extra-utils/server/index.ts +++ b/shared/extra-utils/server/index.ts @@ -9,6 +9,7 @@ export * from './jobs-command' export * from './plugins-command' export * from './plugins' export * from './redundancy-command' +export * from './server' export * from './servers-command' export * from './servers' export * from './stats-command' diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts index 754530977..64a0353eb 100644 --- a/shared/extra-utils/server/jobs.ts +++ b/shared/extra-utils/server/jobs.ts @@ -1,17 +1,17 @@ import { JobState } from '../../models' import { wait } from '../miscs' -import { ServerInfo } from './servers' +import { PeerTubeServer } from './server' -async function waitJobs (serversArg: ServerInfo[] | ServerInfo) { +async function waitJobs (serversArg: PeerTubeServer[] | PeerTubeServer) { const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) : 250 - let servers: ServerInfo[] + let servers: PeerTubeServer[] - if (Array.isArray(serversArg) === false) servers = [ serversArg as ServerInfo ] - else servers = serversArg as ServerInfo[] + if (Array.isArray(serversArg) === false) servers = [ serversArg as PeerTubeServer ] + else servers = serversArg as PeerTubeServer[] const states: JobState[] = [ 'waiting', 'active', 'delayed' ] const repeatableJobs = [ 'videos-views', 'activitypub-cleaner' ] diff --git a/shared/extra-utils/server/plugins.ts b/shared/extra-utils/server/plugins.ts index d1cc7e383..0f5fabd5a 100644 --- a/shared/extra-utils/server/plugins.ts +++ b/shared/extra-utils/server/plugins.ts @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ import { expect } from 'chai' -import { ServerInfo } from '../server/servers' +import { PeerTubeServer } from '../server/server' -async function testHelloWorldRegisteredSettings (server: ServerInfo) { +async function testHelloWorldRegisteredSettings (server: PeerTubeServer) { const body = await server.plugins.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) const registeredSettings = body.registeredSettings diff --git a/shared/extra-utils/server/server.ts b/shared/extra-utils/server/server.ts new file mode 100644 index 000000000..b1347661f --- /dev/null +++ b/shared/extra-utils/server/server.ts @@ -0,0 +1,376 @@ +import { ChildProcess, fork } from 'child_process' +import { copy } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { randomInt } from '../../core-utils/miscs/miscs' +import { VideoChannel } from '../../models/videos' +import { BulkCommand } from '../bulk' +import { CLICommand } from '../cli' +import { CustomPagesCommand } from '../custom-pages' +import { FeedCommand } from '../feeds' +import { LogsCommand } from '../logs' +import { parallelTests, SQLCommand } from '../miscs' +import { AbusesCommand } from '../moderation' +import { OverviewsCommand } from '../overviews' +import { SearchCommand } from '../search' +import { SocketIOCommand } from '../socket' +import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand, UsersCommand } from '../users' +import { + BlacklistCommand, + CaptionsCommand, + ChangeOwnershipCommand, + ChannelsCommand, + HistoryCommand, + ImportsCommand, + LiveCommand, + PlaylistsCommand, + ServicesCommand, + StreamingPlaylistsCommand, + VideosCommand +} from '../videos' +import { CommentsCommand } from '../videos/comments-command' +import { ConfigCommand } from './config-command' +import { ContactFormCommand } from './contact-form-command' +import { DebugCommand } from './debug-command' +import { FollowsCommand } from './follows-command' +import { JobsCommand } from './jobs-command' +import { PluginsCommand } from './plugins-command' +import { RedundancyCommand } from './redundancy-command' +import { ServersCommand } from './servers-command' +import { StatsCommand } from './stats-command' + +export type RunServerOptions = { + hideLogs?: boolean + execArgv?: string[] +} + +export class PeerTubeServer { + app?: ChildProcess + + url: string + host?: string + hostname?: string + port?: number + + rtmpPort?: number + + parallel?: boolean + internalServerNumber: number + + serverNumber?: number + customConfigFile?: string + + store?: { + client?: { + id?: string + secret?: string + } + + user?: { + username: string + password: string + email?: string + } + + channel?: VideoChannel + + video?: { + id: number + uuid: string + shortUUID: string + name?: string + url?: string + + account?: { + name: string + } + + embedPath?: string + } + + videos?: { id: number, uuid: string }[] + } + + accessToken?: string + refreshToken?: string + + bulk?: BulkCommand + cli?: CLICommand + customPage?: CustomPagesCommand + feed?: FeedCommand + logs?: LogsCommand + abuses?: AbusesCommand + overviews?: OverviewsCommand + search?: SearchCommand + contactForm?: ContactFormCommand + debug?: DebugCommand + follows?: FollowsCommand + jobs?: JobsCommand + plugins?: PluginsCommand + redundancy?: RedundancyCommand + stats?: StatsCommand + config?: ConfigCommand + socketIO?: SocketIOCommand + accounts?: AccountsCommand + blocklist?: BlocklistCommand + subscriptions?: SubscriptionsCommand + live?: LiveCommand + services?: ServicesCommand + blacklist?: BlacklistCommand + captions?: CaptionsCommand + changeOwnership?: ChangeOwnershipCommand + playlists?: PlaylistsCommand + history?: HistoryCommand + imports?: ImportsCommand + streamingPlaylists?: StreamingPlaylistsCommand + channels?: ChannelsCommand + comments?: CommentsCommand + sql?: SQLCommand + notifications?: NotificationsCommand + servers?: ServersCommand + login?: LoginCommand + users?: UsersCommand + videos?: VideosCommand + + constructor (options: { serverNumber: number } | { url: string }) { + if ((options as any).url) { + this.setUrl((options as any).url) + } else { + this.setServerNumber((options as any).serverNumber) + } + + this.store = { + client: { + id: null, + secret: null + }, + user: { + username: null, + password: null + } + } + + this.assignCommands() + } + + setServerNumber (serverNumber: number) { + this.serverNumber = serverNumber + + this.parallel = parallelTests() + + this.internalServerNumber = this.parallel ? this.randomServer() : this.serverNumber + this.rtmpPort = this.parallel ? this.randomRTMP() : 1936 + this.port = 9000 + this.internalServerNumber + + this.url = `http://localhost:${this.port}` + this.host = `localhost:${this.port}` + this.hostname = 'localhost' + } + + setUrl (url: string) { + const parsed = new URL(url) + + this.url = url + this.host = parsed.host + this.hostname = parsed.hostname + this.port = parseInt(parsed.port) + } + + async flushAndRun (configOverride?: Object, args = [], options: RunServerOptions = {}) { + await ServersCommand.flushTests(this.internalServerNumber) + + return this.run(configOverride, args, options) + } + + async run (configOverrideArg?: any, args = [], options: RunServerOptions = {}) { + // These actions are async so we need to be sure that they have both been done + const serverRunString = { + 'HTTP server listening': false + } + const key = 'Database peertube_test' + this.internalServerNumber + ' is ready' + serverRunString[key] = false + + const regexps = { + client_id: 'Client id: (.+)', + client_secret: 'Client secret: (.+)', + user_username: 'Username: (.+)', + user_password: 'User password: (.+)' + } + + await this.assignCustomConfigFile() + + const configOverride = this.buildConfigOverride() + + if (configOverrideArg !== undefined) { + Object.assign(configOverride, configOverrideArg) + } + + // Share the environment + const env = Object.create(process.env) + env['NODE_ENV'] = 'test' + env['NODE_APP_INSTANCE'] = this.internalServerNumber.toString() + env['NODE_CONFIG'] = JSON.stringify(configOverride) + + const forkOptions = { + silent: true, + env, + detached: true, + execArgv: options.execArgv || [] + } + + return new Promise(res => { + this.app = fork(join(root(), 'dist', 'server.js'), args, forkOptions) + this.app.stdout.on('data', function onStdout (data) { + let dontContinue = false + + // Capture things if we want to + for (const key of Object.keys(regexps)) { + const regexp = regexps[key] + const matches = data.toString().match(regexp) + if (matches !== null) { + if (key === 'client_id') this.store.client.id = matches[1] + else if (key === 'client_secret') this.store.client.secret = matches[1] + else if (key === 'user_username') this.store.user.username = matches[1] + else if (key === 'user_password') this.store.user.password = matches[1] + } + } + + // Check if all required sentences are here + for (const key of Object.keys(serverRunString)) { + if (data.toString().indexOf(key) !== -1) serverRunString[key] = true + if (serverRunString[key] === false) dontContinue = true + } + + // If no, there is maybe one thing not already initialized (client/user credentials generation...) + if (dontContinue === true) return + + if (options.hideLogs === false) { + console.log(data.toString()) + } else { + this.app.stdout.removeListener('data', onStdout) + } + + process.on('exit', () => { + try { + process.kill(this.server.app.pid) + } catch { /* empty */ } + }) + + res() + }) + }) + } + + async kill () { + if (!this.app) return + + await this.sql.cleanup() + + process.kill(-this.app.pid) + + this.app = null + } + + private randomServer () { + const low = 10 + const high = 10000 + + return randomInt(low, high) + } + + private randomRTMP () { + const low = 1900 + const high = 2100 + + return randomInt(low, high) + } + + private async assignCustomConfigFile () { + if (this.internalServerNumber === this.serverNumber) return + + const basePath = join(root(), 'config') + + const tmpConfigFile = join(basePath, `test-${this.internalServerNumber}.yaml`) + await copy(join(basePath, `test-${this.serverNumber}.yaml`), tmpConfigFile) + + this.customConfigFile = tmpConfigFile + } + + private buildConfigOverride () { + if (!this.parallel) return {} + + return { + listen: { + port: this.port + }, + webserver: { + port: this.port + }, + database: { + suffix: '_test' + this.internalServerNumber + }, + storage: { + tmp: `test${this.internalServerNumber}/tmp/`, + avatars: `test${this.internalServerNumber}/avatars/`, + videos: `test${this.internalServerNumber}/videos/`, + streaming_playlists: `test${this.internalServerNumber}/streaming-playlists/`, + redundancy: `test${this.internalServerNumber}/redundancy/`, + logs: `test${this.internalServerNumber}/logs/`, + previews: `test${this.internalServerNumber}/previews/`, + thumbnails: `test${this.internalServerNumber}/thumbnails/`, + torrents: `test${this.internalServerNumber}/torrents/`, + captions: `test${this.internalServerNumber}/captions/`, + cache: `test${this.internalServerNumber}/cache/`, + plugins: `test${this.internalServerNumber}/plugins/` + }, + admin: { + email: `admin${this.internalServerNumber}@example.com` + }, + live: { + rtmp: { + port: this.rtmpPort + } + } + } + } + + private assignCommands () { + this.bulk = new BulkCommand(this) + this.cli = new CLICommand(this) + this.customPage = new CustomPagesCommand(this) + this.feed = new FeedCommand(this) + this.logs = new LogsCommand(this) + this.abuses = new AbusesCommand(this) + this.overviews = new OverviewsCommand(this) + this.search = new SearchCommand(this) + this.contactForm = new ContactFormCommand(this) + this.debug = new DebugCommand(this) + this.follows = new FollowsCommand(this) + this.jobs = new JobsCommand(this) + this.plugins = new PluginsCommand(this) + this.redundancy = new RedundancyCommand(this) + this.stats = new StatsCommand(this) + this.config = new ConfigCommand(this) + this.socketIO = new SocketIOCommand(this) + this.accounts = new AccountsCommand(this) + this.blocklist = new BlocklistCommand(this) + this.subscriptions = new SubscriptionsCommand(this) + this.live = new LiveCommand(this) + this.services = new ServicesCommand(this) + this.blacklist = new BlacklistCommand(this) + this.captions = new CaptionsCommand(this) + this.changeOwnership = new ChangeOwnershipCommand(this) + this.playlists = new PlaylistsCommand(this) + this.history = new HistoryCommand(this) + this.imports = new ImportsCommand(this) + this.streamingPlaylists = new StreamingPlaylistsCommand(this) + this.channels = new ChannelsCommand(this) + this.comments = new CommentsCommand(this) + this.sql = new SQLCommand(this) + this.notifications = new NotificationsCommand(this) + this.servers = new ServersCommand(this) + this.login = new LoginCommand(this) + this.users = new UsersCommand(this) + this.videos = new VideosCommand(this) + } +} diff --git a/shared/extra-utils/server/servers-command.ts b/shared/extra-utils/server/servers-command.ts index a7c5a868d..1a7b2aade 100644 --- a/shared/extra-utils/server/servers-command.ts +++ b/shared/extra-utils/server/servers-command.ts @@ -37,7 +37,7 @@ export class ServersCommand extends AbstractCommand { if (isGithubCI()) { await ensureDir('artifacts') - const origin = this.server.servers.buildDirectory('logs/peertube.log') + const origin = this.buildDirectory('logs/peertube.log') const destname = `peertube-${this.server.internalServerNumber}.log` console.log('Saving logs %s.', destname) diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts index ea3f19a92..87d7e9449 100644 --- a/shared/extra-utils/server/servers.ts +++ b/shared/extra-utils/server/servers.ts @@ -1,391 +1,30 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ +import { ensureDir } from 'fs-extra' +import { isGithubCI } from '../miscs' +import { PeerTubeServer, RunServerOptions } from './server' -import { ChildProcess, fork } from 'child_process' -import { copy, ensureDir } from 'fs-extra' -import { join } from 'path' -import { root } from '@server/helpers/core-utils' -import { randomInt } from '../../core-utils/miscs/miscs' -import { VideoChannel } from '../../models/videos' -import { BulkCommand } from '../bulk' -import { CLICommand } from '../cli' -import { CustomPagesCommand } from '../custom-pages' -import { FeedCommand } from '../feeds' -import { LogsCommand } from '../logs' -import { isGithubCI, parallelTests, SQLCommand } from '../miscs' -import { AbusesCommand } from '../moderation' -import { OverviewsCommand } from '../overviews' -import { SearchCommand } from '../search' -import { SocketIOCommand } from '../socket' -import { AccountsCommand, BlocklistCommand, LoginCommand, NotificationsCommand, SubscriptionsCommand, UsersCommand } from '../users' -import { - BlacklistCommand, - CaptionsCommand, - ChangeOwnershipCommand, - ChannelsCommand, - HistoryCommand, - ImportsCommand, - LiveCommand, - PlaylistsCommand, - ServicesCommand, - StreamingPlaylistsCommand, - VideosCommand -} from '../videos' -import { CommentsCommand } from '../videos/comments-command' -import { ConfigCommand } from './config-command' -import { ContactFormCommand } from './contact-form-command' -import { DebugCommand } from './debug-command' -import { FollowsCommand } from './follows-command' -import { JobsCommand } from './jobs-command' -import { PluginsCommand } from './plugins-command' -import { RedundancyCommand } from './redundancy-command' -import { ServersCommand } from './servers-command' -import { StatsCommand } from './stats-command' +async function createSingleServer (serverNumber: number, configOverride?: Object, args = [], options: RunServerOptions = {}) { + const server = new PeerTubeServer({ serverNumber }) -interface ServerInfo { - app?: ChildProcess + await server.flushAndRun(configOverride, args, options) - url: string - host?: string - hostname?: string - port?: number - - rtmpPort?: number - - parallel?: boolean - internalServerNumber: number - - serverNumber?: number - customConfigFile?: string - - store?: { - client?: { - id?: string - secret?: string - } - - user?: { - username: string - password: string - email?: string - } - - channel?: VideoChannel - - video?: { - id: number - uuid: string - shortUUID: string - name?: string - url?: string - - account?: { - name: string - } - - embedPath?: string - } - - videos?: { id: number, uuid: string }[] - } - - accessToken?: string - refreshToken?: string - - bulk?: BulkCommand - cli?: CLICommand - customPage?: CustomPagesCommand - feed?: FeedCommand - logs?: LogsCommand - abuses?: AbusesCommand - overviews?: OverviewsCommand - search?: SearchCommand - contactForm?: ContactFormCommand - debug?: DebugCommand - follows?: FollowsCommand - jobs?: JobsCommand - plugins?: PluginsCommand - redundancy?: RedundancyCommand - stats?: StatsCommand - config?: ConfigCommand - socketIO?: SocketIOCommand - accounts?: AccountsCommand - blocklist?: BlocklistCommand - subscriptions?: SubscriptionsCommand - live?: LiveCommand - services?: ServicesCommand - blacklist?: BlacklistCommand - captions?: CaptionsCommand - changeOwnership?: ChangeOwnershipCommand - playlists?: PlaylistsCommand - history?: HistoryCommand - imports?: ImportsCommand - streamingPlaylists?: StreamingPlaylistsCommand - channels?: ChannelsCommand - comments?: CommentsCommand - sql?: SQLCommand - notifications?: NotificationsCommand - servers?: ServersCommand - login?: LoginCommand - users?: UsersCommand - videos?: VideosCommand -} - -function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) { - const apps = [] - let i = 0 - - return new Promise(res => { - function anotherServerDone (serverNumber, app) { - apps[serverNumber - 1] = app - i++ - if (i === totalServers) { - return res(apps) - } - } - - for (let j = 1; j <= totalServers; j++) { - flushAndRunServer(j, configOverride).then(app => anotherServerDone(j, app)) - } - }) -} - -function randomServer () { - const low = 10 - const high = 10000 - - return randomInt(low, high) -} - -function randomRTMP () { - const low = 1900 - const high = 2100 - - return randomInt(low, high) -} - -type RunServerOptions = { - hideLogs?: boolean - execArgv?: string[] -} - -async function flushAndRunServer (serverNumber: number, configOverride?: Object, args = [], options: RunServerOptions = {}) { - const parallel = parallelTests() - - const internalServerNumber = parallel ? randomServer() : serverNumber - const rtmpPort = parallel ? randomRTMP() : 1936 - const port = 9000 + internalServerNumber - - await ServersCommand.flushTests(internalServerNumber) - - const server: ServerInfo = { - app: null, - port, - internalServerNumber, - rtmpPort, - parallel, - serverNumber, - url: `http://localhost:${port}`, - host: `localhost:${port}`, - hostname: 'localhost', - store: { - client: { - id: null, - secret: null - }, - user: { - username: null, - password: null - } - } - } - - return runServer(server, configOverride, args, options) + return server } -async function runServer (server: ServerInfo, configOverrideArg?: any, args = [], options: RunServerOptions = {}) { - // These actions are async so we need to be sure that they have both been done - const serverRunString = { - 'HTTP server listening': false - } - const key = 'Database peertube_test' + server.internalServerNumber + ' is ready' - serverRunString[key] = false - - const regexps = { - client_id: 'Client id: (.+)', - client_secret: 'Client secret: (.+)', - user_username: 'Username: (.+)', - user_password: 'User password: (.+)' - } - - if (server.internalServerNumber !== server.serverNumber) { - const basePath = join(root(), 'config') - - const tmpConfigFile = join(basePath, `test-${server.internalServerNumber}.yaml`) - await copy(join(basePath, `test-${server.serverNumber}.yaml`), tmpConfigFile) - - server.customConfigFile = tmpConfigFile - } - - const configOverride: any = {} - - if (server.parallel) { - Object.assign(configOverride, { - listen: { - port: server.port - }, - webserver: { - port: server.port - }, - database: { - suffix: '_test' + server.internalServerNumber - }, - storage: { - tmp: `test${server.internalServerNumber}/tmp/`, - avatars: `test${server.internalServerNumber}/avatars/`, - videos: `test${server.internalServerNumber}/videos/`, - streaming_playlists: `test${server.internalServerNumber}/streaming-playlists/`, - redundancy: `test${server.internalServerNumber}/redundancy/`, - logs: `test${server.internalServerNumber}/logs/`, - previews: `test${server.internalServerNumber}/previews/`, - thumbnails: `test${server.internalServerNumber}/thumbnails/`, - torrents: `test${server.internalServerNumber}/torrents/`, - captions: `test${server.internalServerNumber}/captions/`, - cache: `test${server.internalServerNumber}/cache/`, - plugins: `test${server.internalServerNumber}/plugins/` - }, - admin: { - email: `admin${server.internalServerNumber}@example.com` - }, - live: { - rtmp: { - port: server.rtmpPort - } - } - }) - } - - if (configOverrideArg !== undefined) { - Object.assign(configOverride, configOverrideArg) - } - - // Share the environment - const env = Object.create(process.env) - env['NODE_ENV'] = 'test' - env['NODE_APP_INSTANCE'] = server.internalServerNumber.toString() - env['NODE_CONFIG'] = JSON.stringify(configOverride) +function createMultipleServers (totalServers: number, configOverride?: Object) { + const serverPromises: Promise[] = [] - const forkOptions = { - silent: true, - env, - detached: true, - execArgv: options.execArgv || [] + for (let i = 1; i <= totalServers; i++) { + serverPromises.push(createSingleServer(i, configOverride)) } - return new Promise(res => { - server.app = fork(join(root(), 'dist', 'server.js'), args, forkOptions) - server.app.stdout.on('data', function onStdout (data) { - let dontContinue = false - - // Capture things if we want to - for (const key of Object.keys(regexps)) { - const regexp = regexps[key] - const matches = data.toString().match(regexp) - if (matches !== null) { - if (key === 'client_id') server.store.client.id = matches[1] - else if (key === 'client_secret') server.store.client.secret = matches[1] - else if (key === 'user_username') server.store.user.username = matches[1] - else if (key === 'user_password') server.store.user.password = matches[1] - } - } - - // Check if all required sentences are here - for (const key of Object.keys(serverRunString)) { - if (data.toString().indexOf(key) !== -1) serverRunString[key] = true - if (serverRunString[key] === false) dontContinue = true - } - - // If no, there is maybe one thing not already initialized (client/user credentials generation...) - if (dontContinue === true) return - - if (options.hideLogs === false) { - console.log(data.toString()) - } else { - server.app.stdout.removeListener('data', onStdout) - } - - process.on('exit', () => { - try { - process.kill(server.app.pid) - } catch { /* empty */ } - }) - - assignCommands(server) - - res(server) - }) - }) -} - -function assignCommands (server: ServerInfo) { - server.bulk = new BulkCommand(server) - server.cli = new CLICommand(server) - server.customPage = new CustomPagesCommand(server) - server.feed = new FeedCommand(server) - server.logs = new LogsCommand(server) - server.abuses = new AbusesCommand(server) - server.overviews = new OverviewsCommand(server) - server.search = new SearchCommand(server) - server.contactForm = new ContactFormCommand(server) - server.debug = new DebugCommand(server) - server.follows = new FollowsCommand(server) - server.jobs = new JobsCommand(server) - server.plugins = new PluginsCommand(server) - server.redundancy = new RedundancyCommand(server) - server.stats = new StatsCommand(server) - server.config = new ConfigCommand(server) - server.socketIO = new SocketIOCommand(server) - server.accounts = new AccountsCommand(server) - server.blocklist = new BlocklistCommand(server) - server.subscriptions = new SubscriptionsCommand(server) - server.live = new LiveCommand(server) - server.services = new ServicesCommand(server) - server.blacklist = new BlacklistCommand(server) - server.captions = new CaptionsCommand(server) - server.changeOwnership = new ChangeOwnershipCommand(server) - server.playlists = new PlaylistsCommand(server) - server.history = new HistoryCommand(server) - server.imports = new ImportsCommand(server) - server.streamingPlaylists = new StreamingPlaylistsCommand(server) - server.channels = new ChannelsCommand(server) - server.comments = new CommentsCommand(server) - server.sql = new SQLCommand(server) - server.notifications = new NotificationsCommand(server) - server.servers = new ServersCommand(server) - server.login = new LoginCommand(server) - server.users = new UsersCommand(server) - server.videos = new VideosCommand(server) -} - -async function reRunServer (server: ServerInfo, configOverride?: any) { - const newServer = await runServer(server, configOverride) - server.app = newServer.app - - return server + return Promise.all(serverPromises) } -async function killallServers (servers: ServerInfo[]) { - for (const server of servers) { - if (!server.app) continue - - await server.sql.cleanup() - - process.kill(-server.app.pid) - - server.app = null - } +async function killallServers (servers: PeerTubeServer[]) { + return Promise.all(servers.map(s => s.kill())) } -async function cleanupTests (servers: ServerInfo[]) { +async function cleanupTests (servers: PeerTubeServer[]) { await killallServers(servers) if (isGithubCI()) { @@ -403,11 +42,8 @@ async function cleanupTests (servers: ServerInfo[]) { // --------------------------------------------------------------------------- export { - ServerInfo, + createSingleServer, + createMultipleServers, cleanupTests, - flushAndRunMultipleServers, - flushAndRunServer, - killallServers, - reRunServer, - assignCommands + killallServers } diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 5fddcf639..967f8f2ac 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -9,7 +9,7 @@ import { unwrapBody, unwrapText } from '../requests/requests' -import { ServerInfo } from '../server/servers' +import { PeerTubeServer } from '../server/server' export interface OverrideCommandOptions { token?: string @@ -38,7 +38,7 @@ interface InternalGetCommandOptions extends InternalCommonCommandOptions { abstract class AbstractCommand { constructor ( - protected server: ServerInfo + protected server: PeerTubeServer ) { } diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts index 2c9a4b71c..9fc1bcfc4 100644 --- a/shared/extra-utils/users/accounts.ts +++ b/shared/extra-utils/users/accounts.ts @@ -4,10 +4,10 @@ import { expect } from 'chai' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { ServerInfo } from '../server' +import { PeerTubeServer } from '../server' async function expectAccountFollows (options: { - server: ServerInfo + server: PeerTubeServer handle: string followers: number following: number diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index d0c26a4f0..f1df027d3 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts @@ -1,6 +1,6 @@ -import { ServerInfo } from '../server/servers' +import { PeerTubeServer } from '../server/server' -function setAccessTokensToServers (servers: ServerInfo[]) { +function setAccessTokensToServers (servers: PeerTubeServer[]) { const tasks: Promise[] = [] for (const server of servers) { diff --git a/shared/extra-utils/users/notifications.ts b/shared/extra-utils/users/notifications.ts index 9196f0bf5..4c42fad3e 100644 --- a/shared/extra-utils/users/notifications.ts +++ b/shared/extra-utils/users/notifications.ts @@ -5,8 +5,9 @@ import { inspect } from 'util' import { AbuseState, PluginType } from '@shared/models' import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' import { MockSmtpServer } from '../mock-servers/mock-email' +import { PeerTubeServer } from '../server' import { doubleFollow } from '../server/follows' -import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' +import { createMultipleServers } from '../server/servers' import { setAccessTokensToServers } from './login' function getAllNotificationsSettings (): UserNotificationSetting { @@ -31,7 +32,7 @@ function getAllNotificationsSettings (): UserNotificationSetting { } type CheckerBaseParams = { - server: ServerInfo + server: PeerTubeServer emails: any[] socketNotifications: UserNotification[] token: string @@ -642,7 +643,7 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an limit: 20 } } - const servers = await flushAndRunMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) + const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) await setAccessTokensToServers(servers) diff --git a/shared/extra-utils/videos/channels.ts b/shared/extra-utils/videos/channels.ts index 81e818094..756c47453 100644 --- a/shared/extra-utils/videos/channels.ts +++ b/shared/extra-utils/videos/channels.ts @@ -1,6 +1,6 @@ -import { ServerInfo } from '../server/servers' +import { PeerTubeServer } from '../server/server' -function setDefaultVideoChannel (servers: ServerInfo[]) { +function setDefaultVideoChannel (servers: PeerTubeServer[]) { const tasks: Promise[] = [] for (const server of servers) { diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts index 353595811..502964b1a 100644 --- a/shared/extra-utils/videos/live.ts +++ b/shared/extra-utils/videos/live.ts @@ -5,7 +5,7 @@ import * as ffmpeg from 'fluent-ffmpeg' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' import { buildAbsoluteFixturePath, wait } from '../miscs' -import { ServerInfo } from '../server/servers' +import { PeerTubeServer } from '../server/server' function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = 'video_short.mp4') { const fixture = buildAbsoluteFixturePath(fixtureName) @@ -70,13 +70,13 @@ async function stopFfmpeg (command: ffmpeg.FfmpegCommand) { await wait(500) } -async function waitUntilLivePublishedOnAllServers (servers: ServerInfo[], videoId: string) { +async function waitUntilLivePublishedOnAllServers (servers: PeerTubeServer[], videoId: string) { for (const server of servers) { await server.live.waitUntilPublished({ videoId }) } } -async function checkLiveCleanup (server: ServerInfo, videoUUID: string, resolutions: number[] = []) { +async function checkLiveCleanup (server: PeerTubeServer, videoUUID: string, resolutions: number[] = []) { const basePath = server.servers.buildDirectory('streaming-playlists') const hlsPath = join(basePath, 'hls', videoUUID) diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts index e8fd2f232..002ae08b2 100644 --- a/shared/extra-utils/videos/streaming-playlists.ts +++ b/shared/extra-utils/videos/streaming-playlists.ts @@ -2,10 +2,10 @@ import { expect } from 'chai' import { sha256 } from '@server/helpers/core-utils' import { HttpStatusCode } from '@shared/core-utils' import { VideoStreamingPlaylist } from '@shared/models' -import { ServerInfo } from '../server' +import { PeerTubeServer } from '../server' async function checkSegmentHash (options: { - server: ServerInfo + server: PeerTubeServer baseUrlPlaylist: string baseUrlSegment: string videoUUID: string @@ -36,7 +36,7 @@ async function checkSegmentHash (options: { } async function checkLiveSegmentHash (options: { - server: ServerInfo + server: PeerTubeServer baseUrlSegment: string videoUUID: string segmentName: string @@ -52,7 +52,7 @@ async function checkLiveSegmentHash (options: { } async function checkResolutionsInMasterPlaylist (options: { - server: ServerInfo + server: PeerTubeServer playlistUrl: string resolutions: number[] }) { diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts index 5556cddf6..feef5a771 100644 --- a/shared/extra-utils/videos/videos-command.ts +++ b/shared/extra-utils/videos/videos-command.ts @@ -22,7 +22,7 @@ import { } from '@shared/models' import { buildAbsoluteFixturePath, wait } from '../miscs' import { unwrapBody } from '../requests' -import { ServerInfo, waitJobs } from '../server' +import { PeerTubeServer, waitJobs } from '../server' import { AbstractCommand, OverrideCommandOptions } from '../shared' export type VideoEdit = Partial> & { @@ -33,7 +33,7 @@ export type VideoEdit = Partial, expectedStatus = HttpStatusCode.OK_200, @@ -52,7 +52,7 @@ function checkUploadVideoParam ( } async function completeVideoCheck ( - server: ServerInfo, + server: PeerTubeServer, video: any, attributes: { name: string @@ -197,7 +197,7 @@ async function completeVideoCheck ( // serverNumber starts from 1 async function uploadRandomVideoOnServers ( - servers: ServerInfo[], + servers: PeerTubeServer[], serverNumber: number, additionalParams?: VideoEdit & { prefixName?: string } ) { -- cgit v1.2.3 From 59bbcced37005dd511daca9bd58ae2998cb931b1 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 10:19:16 +0200 Subject: Centralize test URLs --- shared/extra-utils/miscs/tests.ts | 32 +++++++++++++++++++++++ shared/extra-utils/requests/requests.ts | 5 ---- shared/extra-utils/videos/imports-command.ts | 38 ---------------------------- 3 files changed, 32 insertions(+), 43 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/miscs/tests.ts b/shared/extra-utils/miscs/tests.ts index 8f7a2f92b..3dfb2487e 100644 --- a/shared/extra-utils/miscs/tests.ts +++ b/shared/extra-utils/miscs/tests.ts @@ -1,6 +1,36 @@ import { stat } from 'fs-extra' import { basename, isAbsolute, join, resolve } from 'path' +const FIXTURE_URLS = { + youtube: 'https://www.youtube.com/watch?v=msX3jv1XdvM', + + /** + * The video is used to check format-selection correctness wrt. HDR, + * which brings its own set of oddities outside of a MediaSource. + * FIXME: refactor once HDR is supported at playback + * + * The video needs to have the following format_ids: + * (which you can check by using `youtube-dl -F`): + * - 303 (1080p webm vp9) + * - 299 (1080p mp4 avc1) + * - 335 (1080p webm vp9.2 HDR) + * + * 15 jan. 2021: TEST VIDEO NOT CURRENTLY PROVIDING + * - 400 (1080p mp4 av01) + * - 315 (2160p webm vp9 HDR) + * - 337 (2160p webm vp9.2 HDR) + * - 401 (2160p mp4 av01 HDR) + */ + youtubeHDR: 'https://www.youtube.com/watch?v=qR5vOXbZsI4', + + // eslint-disable-next-line max-len + magnet: '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', + + badVideo: 'https://download.cpy.re/peertube/bad_video.mp4', + goodVideo: 'https://download.cpy.re/peertube/good_video.mp4', + video4K: 'https://download.cpy.re/peertube/4k_file.txt' +} + function parallelTests () { return process.env.MOCHA_PARALLEL === 'true' } @@ -51,6 +81,8 @@ function buildRequestStub (): any { } export { + FIXTURE_URLS, + parallelTests, isGithubCI, areHttpImportTestsDisabled, diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 3f1ac6650..60c9b938b 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -7,10 +7,6 @@ import { URL } from 'url' import { HttpStatusCode } from '@shared/core-utils' import { buildAbsoluteFixturePath, root } from '../miscs/tests' -function get4KFileUrl () { - return 'https://download.cpy.re/peertube/4k_file.txt' -} - function makeRawRequest (url: string, statusCodeExpected?: HttpStatusCode, range?: string) { const { host, protocol, pathname } = new URL(url) @@ -227,7 +223,6 @@ function unwrapText (test: request.Test): Promise { // --------------------------------------------------------------------------- export { - get4KFileUrl, makeHTMLRequest, makeGetRequest, decodeQueryString, diff --git a/shared/extra-utils/videos/imports-command.ts b/shared/extra-utils/videos/imports-command.ts index 024aa363f..de8b65829 100644 --- a/shared/extra-utils/videos/imports-command.ts +++ b/shared/extra-utils/videos/imports-command.ts @@ -7,44 +7,6 @@ import { AbstractCommand, OverrideCommandOptions } from '../shared' export class ImportsCommand extends AbstractCommand { - static getYoutubeVideoUrl () { - return 'https://www.youtube.com/watch?v=msX3jv1XdvM' - } - - static getYoutubeHDRVideoUrl () { - /** - * The video is used to check format-selection correctness wrt. HDR, - * which brings its own set of oddities outside of a MediaSource. - * FIXME: refactor once HDR is supported at playback - * - * The video needs to have the following format_ids: - * (which you can check by using `youtube-dl -F`): - * - 303 (1080p webm vp9) - * - 299 (1080p mp4 avc1) - * - 335 (1080p webm vp9.2 HDR) - * - * 15 jan. 2021: TEST VIDEO NOT CURRENTLY PROVIDING - * - 400 (1080p mp4 av01) - * - 315 (2160p webm vp9 HDR) - * - 337 (2160p webm vp9.2 HDR) - * - 401 (2160p mp4 av01 HDR) - */ - return 'https://www.youtube.com/watch?v=qR5vOXbZsI4' - } - - static getMagnetURI () { - // eslint-disable-next-line max-len - 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' - } - - static getBadVideoUrl () { - return 'https://download.cpy.re/peertube/bad_video.mp4' - } - - static getGoodVideoUrl () { - return 'https://download.cpy.re/peertube/good_video.mp4' - } - importVideo (options: OverrideCommandOptions & { attributes: VideoImportCreate & { torrentfile?: string } }) { -- cgit v1.2.3 From 08642a765ea514a00f159db898edf14c376fbe6c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 10:20:44 +0200 Subject: Fix server run --- shared/extra-utils/server/server.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/server.ts b/shared/extra-utils/server/server.ts index b1347661f..cc6df2efe 100644 --- a/shared/extra-utils/server/server.ts +++ b/shared/extra-utils/server/server.ts @@ -219,6 +219,8 @@ export class PeerTubeServer { } return new Promise(res => { + const self = this + this.app = fork(join(root(), 'dist', 'server.js'), args, forkOptions) this.app.stdout.on('data', function onStdout (data) { let dontContinue = false @@ -228,10 +230,10 @@ export class PeerTubeServer { const regexp = regexps[key] const matches = data.toString().match(regexp) if (matches !== null) { - if (key === 'client_id') this.store.client.id = matches[1] - else if (key === 'client_secret') this.store.client.secret = matches[1] - else if (key === 'user_username') this.store.user.username = matches[1] - else if (key === 'user_password') this.store.user.password = matches[1] + if (key === 'client_id') self.store.client.id = matches[1] + else if (key === 'client_secret') self.store.client.secret = matches[1] + else if (key === 'user_username') self.store.user.username = matches[1] + else if (key === 'user_password') self.store.user.password = matches[1] } } @@ -247,12 +249,12 @@ export class PeerTubeServer { if (options.hideLogs === false) { console.log(data.toString()) } else { - this.app.stdout.removeListener('data', onStdout) + self.app.stdout.removeListener('data', onStdout) } process.on('exit', () => { try { - process.kill(this.server.app.pid) + process.kill(self.server.app.pid) } catch { /* empty */ } }) -- cgit v1.2.3 From c0e8b12e7fd554ba4d2ceb0c4900804c6a4c63ea Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 10:42:24 +0200 Subject: Refactor requests --- shared/extra-utils/bulk/bulk-command.ts | 4 +- .../custom-pages/custom-pages-command.ts | 2 +- shared/extra-utils/feeds/feeds-command.ts | 2 +- shared/extra-utils/logs/logs-command.ts | 2 +- shared/extra-utils/miscs/checks.ts | 4 +- shared/extra-utils/moderation/abuses-command.ts | 2 +- shared/extra-utils/overviews/overviews-command.ts | 2 +- shared/extra-utils/requests/check-api-params.ts | 10 +- shared/extra-utils/requests/requests.ts | 256 ++++++++------------- shared/extra-utils/search/search-command.ts | 2 +- shared/extra-utils/server/config-command.ts | 4 +- shared/extra-utils/server/contact-form-command.ts | 2 +- shared/extra-utils/server/debug-command.ts | 2 +- shared/extra-utils/server/follows-command.ts | 2 +- shared/extra-utils/server/jobs-command.ts | 2 +- shared/extra-utils/server/plugins-command.ts | 2 +- shared/extra-utils/server/redundancy-command.ts | 2 +- shared/extra-utils/server/server.ts | 2 +- shared/extra-utils/server/servers-command.ts | 2 +- shared/extra-utils/server/stats-command.ts | 2 +- shared/extra-utils/shared/abstract-command.ts | 66 +++--- shared/extra-utils/users/accounts-command.ts | 2 +- shared/extra-utils/users/blocklist-command.ts | 2 +- shared/extra-utils/users/index.ts | 1 - shared/extra-utils/users/login-command.ts | 10 +- shared/extra-utils/users/notifications-command.ts | 2 +- shared/extra-utils/users/subscriptions-command.ts | 2 +- shared/extra-utils/users/users-command.ts | 2 +- shared/extra-utils/users/users.ts | 20 -- shared/extra-utils/videos/blacklist-command.ts | 2 +- shared/extra-utils/videos/captions-command.ts | 2 +- shared/extra-utils/videos/captions.ts | 2 +- .../extra-utils/videos/change-ownership-command.ts | 2 +- shared/extra-utils/videos/channels-command.ts | 2 +- shared/extra-utils/videos/comments-command.ts | 2 +- shared/extra-utils/videos/history-command.ts | 2 +- shared/extra-utils/videos/imports-command.ts | 2 +- shared/extra-utils/videos/live-command.ts | 2 +- shared/extra-utils/videos/playlists-command.ts | 2 +- shared/extra-utils/videos/services-command.ts | 2 +- .../videos/streaming-playlists-command.ts | 3 +- shared/extra-utils/videos/streaming-playlists.ts | 2 +- shared/extra-utils/videos/videos-command.ts | 36 +-- shared/extra-utils/videos/videos.ts | 2 +- 44 files changed, 200 insertions(+), 280 deletions(-) delete mode 100644 shared/extra-utils/users/users.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/bulk/bulk-command.ts b/shared/extra-utils/bulk/bulk-command.ts index 6dac6034f..b5c5673ce 100644 --- a/shared/extra-utils/bulk/bulk-command.ts +++ b/shared/extra-utils/bulk/bulk-command.ts @@ -1,6 +1,4 @@ - -import { BulkRemoveCommentsOfBody } from '@shared/models/bulk/bulk-remove-comments-of-body.model' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { BulkRemoveCommentsOfBody, HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class BulkCommand extends AbstractCommand { diff --git a/shared/extra-utils/custom-pages/custom-pages-command.ts b/shared/extra-utils/custom-pages/custom-pages-command.ts index 0dd77503e..6042233d4 100644 --- a/shared/extra-utils/custom-pages/custom-pages-command.ts +++ b/shared/extra-utils/custom-pages/custom-pages-command.ts @@ -1,5 +1,5 @@ import { CustomPage } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CustomPagesCommand extends AbstractCommand { diff --git a/shared/extra-utils/feeds/feeds-command.ts b/shared/extra-utils/feeds/feeds-command.ts index 2da4110a7..3c95f9536 100644 --- a/shared/extra-utils/feeds/feeds-command.ts +++ b/shared/extra-utils/feeds/feeds-command.ts @@ -1,5 +1,5 @@ -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' type FeedType = 'videos' | 'video-comments' | 'subscriptions' diff --git a/shared/extra-utils/logs/logs-command.ts b/shared/extra-utils/logs/logs-command.ts index f34c58c47..5912e814f 100644 --- a/shared/extra-utils/logs/logs-command.ts +++ b/shared/extra-utils/logs/logs-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { LogLevel } from '../../models/server/log-level.type' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/miscs/checks.ts b/shared/extra-utils/miscs/checks.ts index c81460330..7fc92f804 100644 --- a/shared/extra-utils/miscs/checks.ts +++ b/shared/extra-utils/miscs/checks.ts @@ -4,7 +4,7 @@ import { expect } from 'chai' import { pathExists, readFile } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { makeGetRequest } from '../requests' import { PeerTubeServer } from '../server' @@ -20,7 +20,7 @@ async function testImage (url: string, imageName: string, imagePath: string, ext const res = await makeGetRequest({ url, path: imagePath, - statusCodeExpected: HttpStatusCode.OK_200 + expectedStatus: HttpStatusCode.OK_200 }) const body = res.body diff --git a/shared/extra-utils/moderation/abuses-command.ts b/shared/extra-utils/moderation/abuses-command.ts index 03da0c85a..72f2c9951 100644 --- a/shared/extra-utils/moderation/abuses-command.ts +++ b/shared/extra-utils/moderation/abuses-command.ts @@ -10,7 +10,7 @@ import { ResultList, UserAbuse } from '@shared/models' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { unwrapBody } from '../requests/requests' diff --git a/shared/extra-utils/overviews/overviews-command.ts b/shared/extra-utils/overviews/overviews-command.ts index e15644d94..d4a2ac254 100644 --- a/shared/extra-utils/overviews/overviews-command.ts +++ b/shared/extra-utils/overviews/overviews-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { VideosOverview } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/requests/check-api-params.ts b/shared/extra-utils/requests/check-api-params.ts index 7df63b004..26ba1e913 100644 --- a/shared/extra-utils/requests/check-api-params.ts +++ b/shared/extra-utils/requests/check-api-params.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { makeGetRequest } from './requests' function checkBadStartPagination (url: string, path: string, token?: string, query = {}) { @@ -7,7 +7,7 @@ function checkBadStartPagination (url: string, path: string, token?: string, que path, token, query: { ...query, start: 'hello' }, - statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 + expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) } @@ -17,7 +17,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin path, token, query: { ...query, count: 'hello' }, - statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 + expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) await makeGetRequest({ @@ -25,7 +25,7 @@ async function checkBadCountPagination (url: string, path: string, token?: strin path, token, query: { ...query, count: 2000 }, - statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 + expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) } @@ -35,7 +35,7 @@ function checkBadSortPagination (url: string, path: string, token?: string, quer path, token, query: { ...query, sort: 'hello' }, - statusCodeExpected: HttpStatusCode.BAD_REQUEST_400 + expectedStatus: HttpStatusCode.BAD_REQUEST_400 }) } diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts index 60c9b938b..70f790222 100644 --- a/shared/extra-utils/requests/requests.ts +++ b/shared/extra-utils/requests/requests.ts @@ -1,111 +1,82 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ +/* eslint-disable @typescript-eslint/no-floating-promises */ -import { isAbsolute, join } from 'path' import { decode } from 'querystring' import * as request from 'supertest' import { URL } from 'url' -import { HttpStatusCode } from '@shared/core-utils' -import { buildAbsoluteFixturePath, root } from '../miscs/tests' +import { HttpStatusCode } from '@shared/models' +import { buildAbsoluteFixturePath } from '../miscs/tests' -function makeRawRequest (url: string, statusCodeExpected?: HttpStatusCode, range?: string) { - const { host, protocol, pathname } = new URL(url) - - return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range }) -} - -function makeGetRequest (options: { +export type CommonRequestParams = { url: string path?: string - query?: any - token?: string - statusCodeExpected?: HttpStatusCode contentType?: string range?: string redirects?: number accept?: string host?: string -}) { - if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 - if (options.contentType === undefined) options.contentType = 'application/json' - - const req = request(options.url).get(options.path) + token?: string + headers?: { [ name: string ]: string } + type?: string + xForwardedFor?: string + expectedStatus?: HttpStatusCode +} - if (options.contentType) req.set('Accept', options.contentType) - if (options.token) req.set('Authorization', 'Bearer ' + options.token) - if (options.query) req.query(options.query) - if (options.range) req.set('Range', options.range) - if (options.accept) req.set('Accept', options.accept) - if (options.host) req.set('Host', options.host) - if (options.redirects) req.redirects(options.redirects) +function makeRawRequest (url: string, expectedStatus?: HttpStatusCode, range?: string) { + const { host, protocol, pathname } = new URL(url) - return req.expect(options.statusCodeExpected) + return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, expectedStatus, range }) } -function makeDeleteRequest (options: { - url: string - path: string - token?: string - statusCodeExpected?: HttpStatusCode +function makeGetRequest (options: CommonRequestParams & { + query?: any }) { - if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 + const req = request(options.url).get(options.path) + .query(options.query) - const req = request(options.url) - .delete(options.path) - .set('Accept', 'application/json') + return buildRequest(req, { contentType: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options }) +} - if (options.token) req.set('Authorization', 'Bearer ' + options.token) +function makeHTMLRequest (url: string, path: string) { + return makeGetRequest({ + url, + path, + accept: 'text/html', + expectedStatus: HttpStatusCode.OK_200 + }) +} - return req.expect(options.statusCodeExpected) +function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) { + return makeGetRequest({ + url, + path, + expectedStatus: expectedStatus, + accept: 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8' + }) } -function makeUploadRequest (options: { - url: string +function makeDeleteRequest (options: CommonRequestParams) { + const req = request(options.url).delete(options.path) + + return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options }) +} + +function makeUploadRequest (options: CommonRequestParams & { method?: 'POST' | 'PUT' - path: string - token?: string fields: { [ fieldName: string ]: any } attaches?: { [ attachName: string ]: any | any[] } - - headers?: { [ name: string ]: string } - - statusCodeExpected?: HttpStatusCode }) { - if (options.statusCodeExpected === undefined) { - options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 - } + let req = options.method === 'PUT' + ? request(options.url).put(options.path) + : request(options.url).post(options.path) - let req: request.Test - if (options.method === 'PUT') { - req = request(options.url).put(options.path) - } else { - req = request(options.url).post(options.path) - } + req = buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options }) - req.set('Accept', 'application/json') - - if (options.token) req.set('Authorization', 'Bearer ' + options.token) - - Object.keys(options.headers || {}).forEach(name => { - req.set(name, options.headers[name]) - }) - - Object.keys(options.fields).forEach(field => { - const value = options.fields[field] - - if (value === undefined) return - - if (Array.isArray(value)) { - for (let i = 0; i < value.length; i++) { - req.field(field + '[' + i + ']', value[i]) - } - } else { - req.field(field, value) - } - }) + buildFields(req, options.fields) Object.keys(options.attaches || {}).forEach(attach => { const value = options.attaches[attach] + if (Array.isArray(value)) { req.attach(attach, buildAbsoluteFixturePath(value[0]), value[1]) } else { @@ -113,40 +84,16 @@ function makeUploadRequest (options: { } }) - if (options.statusCodeExpected) { - req.expect(options.statusCodeExpected) - } - return req } -function makePostBodyRequest (options: { - url: string - path: string - token?: string +function makePostBodyRequest (options: CommonRequestParams & { fields?: { [ fieldName: string ]: any } - headers?: { [ name: string ]: string } - type?: string - xForwardedFor?: string - statusCodeExpected?: HttpStatusCode }) { - if (!options.fields) options.fields = {} - if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 - - const req = request(options.url) - .post(options.path) - .set('Accept', 'application/json') + const req = request(options.url).post(options.path) + .send(options.fields) - if (options.token) req.set('Authorization', 'Bearer ' + options.token) - if (options.xForwardedFor) req.set('X-Forwarded-For', options.xForwardedFor) - if (options.type) req.type(options.type) - - Object.keys(options.headers || {}).forEach(name => { - req.set(name, options.headers[name]) - }) - - return req.send(options.fields) - .expect(options.statusCodeExpected) + return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options }) } function makePutBodyRequest (options: { @@ -154,58 +101,12 @@ function makePutBodyRequest (options: { path: string token?: string fields: { [ fieldName: string ]: any } - statusCodeExpected?: HttpStatusCode -}) { - if (!options.statusCodeExpected) options.statusCodeExpected = HttpStatusCode.BAD_REQUEST_400 - - const req = request(options.url) - .put(options.path) - .set('Accept', 'application/json') - - if (options.token) req.set('Authorization', 'Bearer ' + options.token) - - return req.send(options.fields) - .expect(options.statusCodeExpected) -} - -function makeHTMLRequest (url: string, path: string) { - return request(url) - .get(path) - .set('Accept', 'text/html') - .expect(HttpStatusCode.OK_200) -} - -function makeActivityPubGetRequest (url: string, path: string, expectedStatus = HttpStatusCode.OK_200) { - return makeGetRequest({ - url, - path, - statusCodeExpected: expectedStatus, - accept: 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8' - }) -} - -function updateImageRequest (options: { - url: string - path: string - accessToken: string - fixture: string - fieldname: string + expectedStatus?: HttpStatusCode }) { - let filePath = '' - if (isAbsolute(options.fixture)) { - filePath = options.fixture - } else { - filePath = join(root(), 'server', 'tests', 'fixtures', options.fixture) - } + const req = request(options.url).put(options.path) + .send(options.fields) - return makeUploadRequest({ - url: options.url, - path: options.path, - token: options.accessToken, - fields: {}, - attaches: { [options.fieldname]: filePath }, - statusCodeExpected: HttpStatusCode.OK_200 - }) + return buildRequest(req, { accept: 'application/json', expectedStatus: HttpStatusCode.BAD_REQUEST_400, ...options }) } function decodeQueryString (path: string) { @@ -233,6 +134,49 @@ export { makeRawRequest, makeActivityPubGetRequest, unwrapBody, - unwrapText, - updateImageRequest + unwrapText +} + +// --------------------------------------------------------------------------- + +function buildRequest (req: request.Test, options: CommonRequestParams) { + if (options.contentType) req.set('Accept', options.contentType) + if (options.token) req.set('Authorization', 'Bearer ' + options.token) + if (options.range) req.set('Range', options.range) + if (options.accept) req.set('Accept', options.accept) + if (options.host) req.set('Host', options.host) + if (options.redirects) req.redirects(options.redirects) + if (options.expectedStatus) req.expect(options.expectedStatus) + if (options.xForwardedFor) req.set('X-Forwarded-For', options.xForwardedFor) + if (options.type) req.type(options.type) + + Object.keys(options.headers || {}).forEach(name => { + req.set(name, options.headers[name]) + }) + + return req +} + +function buildFields (req: request.Test, fields: { [ fieldName: string ]: any }, namespace?: string) { + if (!fields) return + + let formKey: string + + for (const key of Object.keys(fields)) { + if (namespace) formKey = `${namespace}[${key}]` + else formKey = key + + if (fields[key] === undefined) continue + + if (Array.isArray(fields[key]) && fields[key].length === 0) { + req.field(key, null) + continue + } + + if (fields[key] !== null && typeof fields[key] === 'object') { + buildFields(req, fields[key], formKey) + } else { + req.field(formKey, fields[key]) + } + } } diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts index 7539a21ec..09f5d3f1d 100644 --- a/shared/extra-utils/search/search-command.ts +++ b/shared/extra-utils/search/search-command.ts @@ -7,7 +7,7 @@ import { VideoPlaylistsSearchQuery, VideosSearchQuery } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class SearchCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/config-command.ts b/shared/extra-utils/server/config-command.ts index f5d7fc5e3..6e875fdf6 100644 --- a/shared/extra-utils/server/config-command.ts +++ b/shared/extra-utils/server/config-command.ts @@ -1,6 +1,6 @@ import { merge } from 'lodash' -import { DeepPartial, HttpStatusCode } from '@shared/core-utils' -import { About, ServerConfig } from '@shared/models' +import { DeepPartial } from '@shared/core-utils' +import { About, ServerConfig, HttpStatusCode } from '@shared/models' import { CustomConfig } from '../../models/server/custom-config.model' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/server/contact-form-command.ts b/shared/extra-utils/server/contact-form-command.ts index 8d034552b..0e8fd6d84 100644 --- a/shared/extra-utils/server/contact-form-command.ts +++ b/shared/extra-utils/server/contact-form-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { ContactForm } from '../../models/server' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/server/debug-command.ts b/shared/extra-utils/server/debug-command.ts index 8b24b3067..36704836d 100644 --- a/shared/extra-utils/server/debug-command.ts +++ b/shared/extra-utils/server/debug-command.ts @@ -1,5 +1,5 @@ import { Debug, SendDebugCommand } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class DebugCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts index 4e9ed9494..694f5ea24 100644 --- a/shared/extra-utils/server/follows-command.ts +++ b/shared/extra-utils/server/follows-command.ts @@ -1,6 +1,6 @@ import { pick } from 'lodash' import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { PeerTubeServer } from './server' diff --git a/shared/extra-utils/server/jobs-command.ts b/shared/extra-utils/server/jobs-command.ts index 392b868c1..09a299e5b 100644 --- a/shared/extra-utils/server/jobs-command.ts +++ b/shared/extra-utils/server/jobs-command.ts @@ -1,5 +1,5 @@ import { pick } from 'lodash' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { Job, JobState, JobType, ResultList } from '../../models' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index 98049ce19..59bc79b3d 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -3,7 +3,7 @@ import { readJSON, writeJSON } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { PeerTubePlugin, PeerTubePluginIndex, diff --git a/shared/extra-utils/server/redundancy-command.ts b/shared/extra-utils/server/redundancy-command.ts index 728332fdd..137d7f01c 100644 --- a/shared/extra-utils/server/redundancy-command.ts +++ b/shared/extra-utils/server/redundancy-command.ts @@ -1,5 +1,5 @@ import { ResultList, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class RedundancyCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/server.ts b/shared/extra-utils/server/server.ts index cc6df2efe..b33bb9d1e 100644 --- a/shared/extra-utils/server/server.ts +++ b/shared/extra-utils/server/server.ts @@ -254,7 +254,7 @@ export class PeerTubeServer { process.on('exit', () => { try { - process.kill(self.server.app.pid) + process.kill(self.app.pid) } catch { /* empty */ } }) diff --git a/shared/extra-utils/server/servers-command.ts b/shared/extra-utils/server/servers-command.ts index 1a7b2aade..107e2b4ad 100644 --- a/shared/extra-utils/server/servers-command.ts +++ b/shared/extra-utils/server/servers-command.ts @@ -2,7 +2,7 @@ import { exec } from 'child_process' import { copy, ensureDir, readFile, remove } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { getFileSize } from '@uploadx/core' import { isGithubCI, wait } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/server/stats-command.ts b/shared/extra-utils/server/stats-command.ts index f0f02ca08..6db473588 100644 --- a/shared/extra-utils/server/stats-command.ts +++ b/shared/extra-utils/server/stats-command.ts @@ -1,5 +1,5 @@ import { ServerStats } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class StatsCommand extends AbstractCommand { diff --git a/shared/extra-utils/shared/abstract-command.ts b/shared/extra-utils/shared/abstract-command.ts index 967f8f2ac..021045e49 100644 --- a/shared/extra-utils/shared/abstract-command.ts +++ b/shared/extra-utils/shared/abstract-command.ts @@ -24,15 +24,20 @@ interface InternalCommonCommandOptions extends OverrideCommandOptions { // If we automatically send the server token if the token is not provided implicitToken: boolean defaultExpectedStatus: number -} -interface InternalGetCommandOptions extends InternalCommonCommandOptions { - query?: { [ id: string ]: any } + // Common optional request parameters contentType?: string accept?: string redirects?: number range?: string host?: string + headers?: { [ name: string ]: string } + requestType?: string + xForwardedFor?: string +} + +interface InternalGetCommandOptions extends InternalCommonCommandOptions { + query?: { [ id: string ]: any } } abstract class AbstractCommand { @@ -59,7 +64,7 @@ abstract class AbstractCommand { ...options, token: this.buildCommonRequestToken(options), - defaultExpectedStatus: this.buildStatusCodeExpected(options), + defaultExpectedStatus: this.buildExpectedStatus(options), url: `${protocol}//${host}`, path: pathname, @@ -68,17 +73,12 @@ abstract class AbstractCommand { } protected getRequest (options: InternalGetCommandOptions) { - const { redirects, query, contentType, accept, range, host } = options + const { query } = options return makeGetRequest({ ...this.buildCommonRequestOptions(options), - redirects, - query, - contentType, - range, - host, - accept + query }) } @@ -100,51 +100,41 @@ abstract class AbstractCommand { protected postBodyRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } - headers?: { [ name: string ]: string } - type?: string - xForwardedFor?: string }) { - const { type, fields, xForwardedFor, headers } = options + const { fields } = options return makePostBodyRequest({ ...this.buildCommonRequestOptions(options), - fields, - xForwardedFor, - type, - headers + fields }) } protected postUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } attaches?: { [ fieldName: string ]: any } - headers?: { [ name: string ]: string } }) { - const { fields, attaches, headers } = options + const { fields, attaches } = options return makeUploadRequest({ ...this.buildCommonRequestOptions(options), method: 'POST', fields, - attaches, - headers + attaches }) } protected putUploadRequest (options: InternalCommonCommandOptions & { fields?: { [ fieldName: string ]: any } attaches?: { [ fieldName: string ]: any } - headers?: { [ name: string ]: string } }) { - const { fields, attaches, headers } = options + const { fields, attaches } = options return makeUploadRequest({ ...this.buildCommonRequestOptions(options), method: 'PUT', - headers, fields, attaches }) @@ -154,12 +144,9 @@ abstract class AbstractCommand { fixture: string fieldname: string }) { - let filePath = '' - if (isAbsolute(options.fixture)) { - filePath = options.fixture - } else { - filePath = join(root(), 'server', 'tests', 'fixtures', options.fixture) - } + const filePath = isAbsolute(options.fixture) + ? options.fixture + : join(root(), 'server', 'tests', 'fixtures', options.fixture) return this.postUploadRequest({ ...options, @@ -170,14 +157,23 @@ abstract class AbstractCommand { } protected buildCommonRequestOptions (options: InternalCommonCommandOptions) { - const { url, path } = options + const { url, path, redirects, contentType, accept, range, host, headers, requestType, xForwardedFor } = options return { url: url ?? this.server.url, path, token: this.buildCommonRequestToken(options), - statusCodeExpected: this.buildStatusCodeExpected(options) + expectedStatus: this.buildExpectedStatus(options), + + redirects, + contentType, + range, + host, + accept, + headers, + type: requestType, + xForwardedFor } } @@ -191,7 +187,7 @@ abstract class AbstractCommand { return token !== undefined ? token : fallbackToken } - protected buildStatusCodeExpected (options: Pick) { + protected buildExpectedStatus (options: Pick) { const { expectedStatus, defaultExpectedStatus } = options return expectedStatus !== undefined ? expectedStatus : defaultExpectedStatus diff --git a/shared/extra-utils/users/accounts-command.ts b/shared/extra-utils/users/accounts-command.ts index 4cd1d2158..08977e58b 100644 --- a/shared/extra-utils/users/accounts-command.ts +++ b/shared/extra-utils/users/accounts-command.ts @@ -1,5 +1,5 @@ import { ResultList } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { Account } from '../../models/actors' import { AccountVideoRate, VideoRateType } from '../../models/videos' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/blocklist-command.ts b/shared/extra-utils/users/blocklist-command.ts index 089b5a579..a9431acf3 100644 --- a/shared/extra-utils/users/blocklist-command.ts +++ b/shared/extra-utils/users/blocklist-command.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { AccountBlock, ResultList, ServerBlock } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index e6107afa5..fbb454e8f 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -7,4 +7,3 @@ export * from './notifications' export * from './notifications-command' export * from './subscriptions-command' export * from './users-command' -export * from './users' diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts index 10c3db851..b39577260 100644 --- a/shared/extra-utils/users/login-command.ts +++ b/shared/extra-utils/users/login-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { PeerTubeProblemDocument } from '@shared/models' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' @@ -26,7 +26,7 @@ export class LoginCommand extends AbstractCommand { ...options, path, - type: 'form', + requestType: 'form', fields: body, implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 @@ -72,7 +72,7 @@ export class LoginCommand extends AbstractCommand { ...options, path, - type: 'form', + requestType: 'form', fields: body, implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 @@ -88,7 +88,7 @@ export class LoginCommand extends AbstractCommand { ...options, path, - type: 'form', + requestType: 'form', implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 })) @@ -111,7 +111,7 @@ export class LoginCommand extends AbstractCommand { ...options, path, - type: 'form', + requestType: 'form', fields: body, implicitToken: false, defaultExpectedStatus: HttpStatusCode.OK_200 diff --git a/shared/extra-utils/users/notifications-command.ts b/shared/extra-utils/users/notifications-command.ts index dfe574ca1..a51fcc3af 100644 --- a/shared/extra-utils/users/notifications-command.ts +++ b/shared/extra-utils/users/notifications-command.ts @@ -1,5 +1,5 @@ import { ResultList } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { UserNotification, UserNotificationSetting } from '../../models/users' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/subscriptions-command.ts b/shared/extra-utils/users/subscriptions-command.ts index e998eb426..a69d2a194 100644 --- a/shared/extra-utils/users/subscriptions-command.ts +++ b/shared/extra-utils/users/subscriptions-command.ts @@ -1,5 +1,5 @@ import { ResultList, Video, VideoChannel } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class SubscriptionsCommand extends AbstractCommand { diff --git a/shared/extra-utils/users/users-command.ts b/shared/extra-utils/users/users-command.ts index 59dc6d018..f3a251e65 100644 --- a/shared/extra-utils/users/users-command.ts +++ b/shared/extra-utils/users/users-command.ts @@ -1,5 +1,5 @@ import { omit, pick } from 'lodash' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { MyUser, ResultList, diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts deleted file mode 100644 index 6cf61d60e..000000000 --- a/shared/extra-utils/users/users.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as request from 'supertest' -import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' - -// FIXME: delete once videos does not use it anymore -function xxxgetMyUserInformation (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { - const path = '/api/v1/users/me' - - return request(url) - .get(path) - .set('Accept', 'application/json') - .set('Authorization', 'Bearer ' + accessToken) - .expect(specialStatus) - .expect('Content-Type', /json/) -} - -// --------------------------------------------------------------------------- - -export { - xxxgetMyUserInformation -} diff --git a/shared/extra-utils/videos/blacklist-command.ts b/shared/extra-utils/videos/blacklist-command.ts index fdae6b469..9404d4c08 100644 --- a/shared/extra-utils/videos/blacklist-command.ts +++ b/shared/extra-utils/videos/blacklist-command.ts @@ -1,6 +1,6 @@ import { ResultList } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { VideoBlacklist, VideoBlacklistType } from '../../models/videos' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts index ac3bde7a9..04dd32f84 100644 --- a/shared/extra-utils/videos/captions-command.ts +++ b/shared/extra-utils/videos/captions-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { ResultList, VideoCaption } from '@shared/models' import { buildAbsoluteFixturePath } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/captions.ts b/shared/extra-utils/videos/captions.ts index 2246bd133..ff8a43366 100644 --- a/shared/extra-utils/videos/captions.ts +++ b/shared/extra-utils/videos/captions.ts @@ -1,6 +1,6 @@ import { expect } from 'chai' import * as request from 'supertest' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' async function testCaptionFile (url: string, captionPath: string, containsString: string) { const res = await request(url) diff --git a/shared/extra-utils/videos/change-ownership-command.ts b/shared/extra-utils/videos/change-ownership-command.ts index 03f77a95f..ef6f07536 100644 --- a/shared/extra-utils/videos/change-ownership-command.ts +++ b/shared/extra-utils/videos/change-ownership-command.ts @@ -1,6 +1,6 @@ import { ResultList, VideoChangeOwnership } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class ChangeOwnershipCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/channels-command.ts b/shared/extra-utils/videos/channels-command.ts index a98c5cc93..e5393ff56 100644 --- a/shared/extra-utils/videos/channels-command.ts +++ b/shared/extra-utils/videos/channels-command.ts @@ -1,6 +1,6 @@ import { pick } from 'lodash' import { ResultList, VideoChannel, VideoChannelCreateResult } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' import { unwrapBody } from '../requests' diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts index b31f3e2dd..7368f3ea2 100644 --- a/shared/extra-utils/videos/comments-command.ts +++ b/shared/extra-utils/videos/comments-command.ts @@ -1,6 +1,6 @@ import { pick } from 'lodash' +import { HttpStatusCode } from '@shared/models' import { ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/history-command.ts b/shared/extra-utils/videos/history-command.ts index 8a144a312..41afc6bc6 100644 --- a/shared/extra-utils/videos/history-command.ts +++ b/shared/extra-utils/videos/history-command.ts @@ -1,5 +1,5 @@ +import { HttpStatusCode } from '@shared/models' import { ResultList, Video } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class HistoryCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/imports-command.ts b/shared/extra-utils/videos/imports-command.ts index de8b65829..d30f9745b 100644 --- a/shared/extra-utils/videos/imports-command.ts +++ b/shared/extra-utils/videos/imports-command.ts @@ -1,6 +1,6 @@ +import { HttpStatusCode } from '@shared/models' import { ResultList } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' import { VideoImport, VideoImportCreate } from '../../models/videos' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index fd66c9924..9dfe3087e 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -3,8 +3,8 @@ import { readdir } from 'fs-extra' import { omit } from 'lodash' import { join } from 'path' +import { HttpStatusCode } from '@shared/models' import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' import { wait } from '../miscs' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts index cbfc7e10f..40162c30d 100644 --- a/shared/extra-utils/videos/playlists-command.ts +++ b/shared/extra-utils/videos/playlists-command.ts @@ -1,5 +1,5 @@ import { omit, pick } from 'lodash' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { BooleanBothQuery, ResultList, diff --git a/shared/extra-utils/videos/services-command.ts b/shared/extra-utils/videos/services-command.ts index 313b7878c..06760df42 100644 --- a/shared/extra-utils/videos/services-command.ts +++ b/shared/extra-utils/videos/services-command.ts @@ -1,4 +1,4 @@ -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class ServicesCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/streaming-playlists-command.ts b/shared/extra-utils/videos/streaming-playlists-command.ts index fab3eb556..9662685da 100644 --- a/shared/extra-utils/videos/streaming-playlists-command.ts +++ b/shared/extra-utils/videos/streaming-playlists-command.ts @@ -1,5 +1,4 @@ - -import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes' +import { HttpStatusCode } from '@shared/models' import { unwrapBody, unwrapText } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts index 002ae08b2..007d3d98d 100644 --- a/shared/extra-utils/videos/streaming-playlists.ts +++ b/shared/extra-utils/videos/streaming-playlists.ts @@ -1,6 +1,6 @@ import { expect } from 'chai' import { sha256 } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { VideoStreamingPlaylist } from '@shared/models' import { PeerTubeServer } from '../server' diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts index feef5a771..f46d386f4 100644 --- a/shared/extra-utils/videos/videos-command.ts +++ b/shared/extra-utils/videos/videos-command.ts @@ -7,7 +7,7 @@ import { omit, pick } from 'lodash' import validator from 'validator' import { buildUUID } from '@server/helpers/uuid' import { loadLanguages } from '@server/initializers/constants' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { ResultList, UserVideoRateType, @@ -234,10 +234,10 @@ export class VideosCommand extends AbstractCommand { } listByAccount (options: OverrideCommandOptions & VideosWithSearchCommonQuery & { - accountName: string + handle: string }) { - const { accountName, search } = options - const path = '/api/v1/accounts/' + accountName + '/videos' + const { handle, search } = options + const path = '/api/v1/accounts/' + handle + '/videos' return this.getRequestBody>({ ...options, @@ -250,10 +250,10 @@ export class VideosCommand extends AbstractCommand { } listByChannel (options: OverrideCommandOptions & VideosWithSearchCommonQuery & { - videoChannelName: string + handle: string }) { - const { videoChannelName } = options - const path = '/api/v1/video-channels/' + videoChannelName + '/videos' + const { handle } = options + const path = '/api/v1/video-channels/' + handle + '/videos' return this.getRequestBody>({ ...options, @@ -309,13 +309,13 @@ export class VideosCommand extends AbstractCommand { }) { const path = '/api/v1/videos/' + options.id - return this.deleteRequest({ + return unwrapBody(this.deleteRequest({ ...options, path, implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) + })) } async removeAll () { @@ -396,7 +396,7 @@ export class VideosCommand extends AbstractCommand { async buildResumeUpload (options: OverrideCommandOptions & { attributes: VideoEdit - }) { + }): Promise { const { attributes, expectedStatus } = options let size = 0 @@ -414,7 +414,8 @@ export class VideosCommand extends AbstractCommand { } } - const initializeSessionRes = await this.prepareResumableUpload({ ...options, attributes, size, mimetype }) + // Do not check status automatically, we'll check it manually + const initializeSessionRes = await this.prepareResumableUpload({ ...options, expectedStatus: null, attributes, size, mimetype }) const initStatus = initializeSessionRes.status if (videoFilePath && initStatus === HttpStatusCode.CREATED_201) { @@ -425,7 +426,7 @@ export class VideosCommand extends AbstractCommand { const result = await this.sendResumableChunks({ ...options, pathUploadId, videoFilePath, size }) - return result.body.video + return result.body?.video || result.body as any } const expectedInitStatus = expectedStatus === HttpStatusCode.OK_200 @@ -434,7 +435,7 @@ export class VideosCommand extends AbstractCommand { expect(initStatus).to.equal(expectedInitStatus) - return initializeSessionRes.body.video as VideoCreateResult + return initializeSessionRes.body.video || initializeSessionRes.body } async prepareResumableUpload (options: OverrideCommandOptions & { @@ -455,7 +456,10 @@ export class VideosCommand extends AbstractCommand { 'X-Upload-Content-Length': size.toString() }, fields: { filename: attributes.fixture, ...this.buildUploadFields(options.attributes) }, + // Fixture will be sent later + attaches: this.buildUploadAttaches(omit(options.attributes, 'fixture')), implicitToken: true, + defaultExpectedStatus: null }) } @@ -539,10 +543,10 @@ export class VideosCommand extends AbstractCommand { const attributes = { name, additionalParams } - if (wait) await waitJobs([ this.server ]) - const result = await this.upload({ ...options, attributes }) + if (wait) await waitJobs([ this.server ]) + return { ...result, name } } @@ -566,7 +570,7 @@ export class VideosCommand extends AbstractCommand { } private buildUploadFields (attributes: VideoEdit) { - return omit(attributes, [ 'thumbnailfile', 'previewfile' ]) + return omit(attributes, [ 'fixture', 'thumbnailfile', 'previewfile' ]) } private buildUploadAttaches (attributes: VideoEdit) { diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index b41533808..a96073c56 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -4,7 +4,7 @@ import { expect } from 'chai' import { pathExists, readdir } from 'fs-extra' import { join } from 'path' import { getLowercaseExtension } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/core-utils' +import { HttpStatusCode } from '@shared/models' import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants' import { dateIsValid, testImage, webtorrentAdd } from '../miscs' import { makeRawRequest } from '../requests/requests' -- cgit v1.2.3 From 4c7e60bc17ee5830399bac4aa273356903421b4c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 16 Jul 2021 14:27:30 +0200 Subject: Reorganize imports --- shared/extra-utils/custom-pages/custom-pages-command.ts | 3 +-- shared/extra-utils/miscs/generate.ts | 2 +- shared/extra-utils/moderation/abuses-command.ts | 4 ++-- shared/extra-utils/overviews/overviews-command.ts | 3 +-- shared/extra-utils/requests/activitypub.ts | 2 +- shared/extra-utils/search/search-command.ts | 2 +- shared/extra-utils/server/config-command.ts | 2 +- shared/extra-utils/server/debug-command.ts | 3 +-- shared/extra-utils/server/follows-command.ts | 3 +-- shared/extra-utils/server/plugins-command.ts | 2 +- shared/extra-utils/server/redundancy-command.ts | 3 +-- shared/extra-utils/server/stats-command.ts | 3 +-- shared/extra-utils/users/accounts-command.ts | 3 +-- shared/extra-utils/users/blocklist-command.ts | 3 +-- shared/extra-utils/users/login-command.ts | 3 +-- shared/extra-utils/users/notifications-command.ts | 3 +-- shared/extra-utils/users/subscriptions-command.ts | 3 +-- shared/extra-utils/users/users-command.ts | 2 +- shared/extra-utils/videos/blacklist-command.ts | 3 +-- shared/extra-utils/videos/captions-command.ts | 3 +-- shared/extra-utils/videos/change-ownership-command.ts | 3 +-- shared/extra-utils/videos/channels-command.ts | 3 +-- shared/extra-utils/videos/comments-command.ts | 3 +-- shared/extra-utils/videos/history-command.ts | 3 +-- shared/extra-utils/videos/imports-command.ts | 3 +-- shared/extra-utils/videos/live-command.ts | 3 +-- shared/extra-utils/videos/playlists-command.ts | 2 +- shared/extra-utils/videos/streaming-playlists.ts | 3 +-- shared/extra-utils/videos/videos-command.ts | 15 ++++++++------- shared/extra-utils/videos/videos.ts | 2 +- 30 files changed, 38 insertions(+), 57 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/custom-pages/custom-pages-command.ts b/shared/extra-utils/custom-pages/custom-pages-command.ts index 6042233d4..cd869a8de 100644 --- a/shared/extra-utils/custom-pages/custom-pages-command.ts +++ b/shared/extra-utils/custom-pages/custom-pages-command.ts @@ -1,5 +1,4 @@ -import { CustomPage } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { CustomPage, HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CustomPagesCommand extends AbstractCommand { diff --git a/shared/extra-utils/miscs/generate.ts b/shared/extra-utils/miscs/generate.ts index 4e70ab853..8d6435481 100644 --- a/shared/extra-utils/miscs/generate.ts +++ b/shared/extra-utils/miscs/generate.ts @@ -1,7 +1,7 @@ +import * as ffmpeg from 'fluent-ffmpeg' import { ensureDir, pathExists } from 'fs-extra' import { dirname } from 'path' import { buildAbsoluteFixturePath } from './tests' -import * as ffmpeg from 'fluent-ffmpeg' async function generateHighBitrateVideo () { const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) diff --git a/shared/extra-utils/moderation/abuses-command.ts b/shared/extra-utils/moderation/abuses-command.ts index 72f2c9951..7b3abb056 100644 --- a/shared/extra-utils/moderation/abuses-command.ts +++ b/shared/extra-utils/moderation/abuses-command.ts @@ -7,12 +7,12 @@ import { AbuseUpdate, AbuseVideoIs, AdminAbuse, + HttpStatusCode, ResultList, UserAbuse } from '@shared/models' -import { HttpStatusCode } from '@shared/models' -import { AbstractCommand, OverrideCommandOptions } from '../shared' import { unwrapBody } from '../requests/requests' +import { AbstractCommand, OverrideCommandOptions } from '../shared' export class AbusesCommand extends AbstractCommand { diff --git a/shared/extra-utils/overviews/overviews-command.ts b/shared/extra-utils/overviews/overviews-command.ts index d4a2ac254..06b4892d2 100644 --- a/shared/extra-utils/overviews/overviews-command.ts +++ b/shared/extra-utils/overviews/overviews-command.ts @@ -1,5 +1,4 @@ -import { HttpStatusCode } from '@shared/models' -import { VideosOverview } from '@shared/models' +import { HttpStatusCode, VideosOverview } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class OverviewsCommand extends AbstractCommand { diff --git a/shared/extra-utils/requests/activitypub.ts b/shared/extra-utils/requests/activitypub.ts index ecd8ce823..4ae878384 100644 --- a/shared/extra-utils/requests/activitypub.ts +++ b/shared/extra-utils/requests/activitypub.ts @@ -1,7 +1,7 @@ +import { activityPubContextify } from '../../../server/helpers/activitypub' import { doRequest } from '../../../server/helpers/requests' import { HTTP_SIGNATURE } from '../../../server/initializers/constants' import { buildGlobalHeaders } from '../../../server/lib/job-queue/handlers/utils/activitypub-http-utils' -import { activityPubContextify } from '../../../server/helpers/activitypub' function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) { const options = { diff --git a/shared/extra-utils/search/search-command.ts b/shared/extra-utils/search/search-command.ts index 09f5d3f1d..0fbbcd6ef 100644 --- a/shared/extra-utils/search/search-command.ts +++ b/shared/extra-utils/search/search-command.ts @@ -1,4 +1,5 @@ import { + HttpStatusCode, ResultList, Video, VideoChannel, @@ -7,7 +8,6 @@ import { VideoPlaylistsSearchQuery, VideosSearchQuery } from '@shared/models' -import { HttpStatusCode } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class SearchCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/config-command.ts b/shared/extra-utils/server/config-command.ts index 6e875fdf6..11148aa46 100644 --- a/shared/extra-utils/server/config-command.ts +++ b/shared/extra-utils/server/config-command.ts @@ -1,6 +1,6 @@ import { merge } from 'lodash' import { DeepPartial } from '@shared/core-utils' -import { About, ServerConfig, HttpStatusCode } from '@shared/models' +import { About, HttpStatusCode, ServerConfig } from '@shared/models' import { CustomConfig } from '../../models/server/custom-config.model' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/server/debug-command.ts b/shared/extra-utils/server/debug-command.ts index 36704836d..3c5a785bb 100644 --- a/shared/extra-utils/server/debug-command.ts +++ b/shared/extra-utils/server/debug-command.ts @@ -1,5 +1,4 @@ -import { Debug, SendDebugCommand } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { Debug, HttpStatusCode, SendDebugCommand } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class DebugCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts index 694f5ea24..dce674ac5 100644 --- a/shared/extra-utils/server/follows-command.ts +++ b/shared/extra-utils/server/follows-command.ts @@ -1,6 +1,5 @@ import { pick } from 'lodash' -import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { ActivityPubActorType, ActorFollow, FollowState, HttpStatusCode, ResultList } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { PeerTubeServer } from './server' diff --git a/shared/extra-utils/server/plugins-command.ts b/shared/extra-utils/server/plugins-command.ts index 59bc79b3d..b944475a2 100644 --- a/shared/extra-utils/server/plugins-command.ts +++ b/shared/extra-utils/server/plugins-command.ts @@ -3,8 +3,8 @@ import { readJSON, writeJSON } from 'fs-extra' import { join } from 'path' import { root } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/models' import { + HttpStatusCode, PeerTubePlugin, PeerTubePluginIndex, PeertubePluginIndexList, diff --git a/shared/extra-utils/server/redundancy-command.ts b/shared/extra-utils/server/redundancy-command.ts index 137d7f01c..e7a8b3c29 100644 --- a/shared/extra-utils/server/redundancy-command.ts +++ b/shared/extra-utils/server/redundancy-command.ts @@ -1,5 +1,4 @@ -import { ResultList, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class RedundancyCommand extends AbstractCommand { diff --git a/shared/extra-utils/server/stats-command.ts b/shared/extra-utils/server/stats-command.ts index 6db473588..64a452306 100644 --- a/shared/extra-utils/server/stats-command.ts +++ b/shared/extra-utils/server/stats-command.ts @@ -1,5 +1,4 @@ -import { ServerStats } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ServerStats } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class StatsCommand extends AbstractCommand { diff --git a/shared/extra-utils/users/accounts-command.ts b/shared/extra-utils/users/accounts-command.ts index 08977e58b..2f586104e 100644 --- a/shared/extra-utils/users/accounts-command.ts +++ b/shared/extra-utils/users/accounts-command.ts @@ -1,5 +1,4 @@ -import { ResultList } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList } from '@shared/models' import { Account } from '../../models/actors' import { AccountVideoRate, VideoRateType } from '../../models/videos' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/blocklist-command.ts b/shared/extra-utils/users/blocklist-command.ts index a9431acf3..14491a1ae 100644 --- a/shared/extra-utils/users/blocklist-command.ts +++ b/shared/extra-utils/users/blocklist-command.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { HttpStatusCode } from '@shared/models' -import { AccountBlock, ResultList, ServerBlock } from '@shared/models' +import { AccountBlock, HttpStatusCode, ResultList, ServerBlock } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' type ListBlocklistOptions = OverrideCommandOptions & { diff --git a/shared/extra-utils/users/login-command.ts b/shared/extra-utils/users/login-command.ts index b39577260..143f72a59 100644 --- a/shared/extra-utils/users/login-command.ts +++ b/shared/extra-utils/users/login-command.ts @@ -1,5 +1,4 @@ -import { HttpStatusCode } from '@shared/models' -import { PeerTubeProblemDocument } from '@shared/models' +import { HttpStatusCode, PeerTubeProblemDocument } from '@shared/models' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/notifications-command.ts b/shared/extra-utils/users/notifications-command.ts index a51fcc3af..2d79a3747 100644 --- a/shared/extra-utils/users/notifications-command.ts +++ b/shared/extra-utils/users/notifications-command.ts @@ -1,5 +1,4 @@ -import { ResultList } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList } from '@shared/models' import { UserNotification, UserNotificationSetting } from '../../models/users' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/users/subscriptions-command.ts b/shared/extra-utils/users/subscriptions-command.ts index a69d2a194..edc60e612 100644 --- a/shared/extra-utils/users/subscriptions-command.ts +++ b/shared/extra-utils/users/subscriptions-command.ts @@ -1,5 +1,4 @@ -import { ResultList, Video, VideoChannel } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList, Video, VideoChannel } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class SubscriptionsCommand extends AbstractCommand { diff --git a/shared/extra-utils/users/users-command.ts b/shared/extra-utils/users/users-command.ts index f3a251e65..d66ad15f2 100644 --- a/shared/extra-utils/users/users-command.ts +++ b/shared/extra-utils/users/users-command.ts @@ -1,6 +1,6 @@ import { omit, pick } from 'lodash' -import { HttpStatusCode } from '@shared/models' import { + HttpStatusCode, MyUser, ResultList, User, diff --git a/shared/extra-utils/videos/blacklist-command.ts b/shared/extra-utils/videos/blacklist-command.ts index 9404d4c08..3a2ef89ba 100644 --- a/shared/extra-utils/videos/blacklist-command.ts +++ b/shared/extra-utils/videos/blacklist-command.ts @@ -1,6 +1,5 @@ -import { ResultList } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList } from '@shared/models' import { VideoBlacklist, VideoBlacklistType } from '../../models/videos' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts index 04dd32f84..a0608e1a6 100644 --- a/shared/extra-utils/videos/captions-command.ts +++ b/shared/extra-utils/videos/captions-command.ts @@ -1,5 +1,4 @@ -import { HttpStatusCode } from '@shared/models' -import { ResultList, VideoCaption } from '@shared/models' +import { HttpStatusCode, ResultList, VideoCaption } from '@shared/models' import { buildAbsoluteFixturePath } from '../miscs' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/change-ownership-command.ts b/shared/extra-utils/videos/change-ownership-command.ts index ef6f07536..ad4c726ef 100644 --- a/shared/extra-utils/videos/change-ownership-command.ts +++ b/shared/extra-utils/videos/change-ownership-command.ts @@ -1,6 +1,5 @@ -import { ResultList, VideoChangeOwnership } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList, VideoChangeOwnership } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class ChangeOwnershipCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/channels-command.ts b/shared/extra-utils/videos/channels-command.ts index e5393ff56..f8eb3f885 100644 --- a/shared/extra-utils/videos/channels-command.ts +++ b/shared/extra-utils/videos/channels-command.ts @@ -1,6 +1,5 @@ import { pick } from 'lodash' -import { ResultList, VideoChannel, VideoChannelCreateResult } from '@shared/models' -import { HttpStatusCode } from '@shared/models' +import { HttpStatusCode, ResultList, VideoChannel, VideoChannelCreateResult } from '@shared/models' import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' import { unwrapBody } from '../requests' diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts index 7368f3ea2..dd14e4b64 100644 --- a/shared/extra-utils/videos/comments-command.ts +++ b/shared/extra-utils/videos/comments-command.ts @@ -1,6 +1,5 @@ import { pick } from 'lodash' -import { HttpStatusCode } from '@shared/models' -import { ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@shared/models' +import { HttpStatusCode, ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@shared/models' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/history-command.ts b/shared/extra-utils/videos/history-command.ts index 41afc6bc6..13b7150c1 100644 --- a/shared/extra-utils/videos/history-command.ts +++ b/shared/extra-utils/videos/history-command.ts @@ -1,5 +1,4 @@ -import { HttpStatusCode } from '@shared/models' -import { ResultList, Video } from '@shared/models' +import { HttpStatusCode, ResultList, Video } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' export class HistoryCommand extends AbstractCommand { diff --git a/shared/extra-utils/videos/imports-command.ts b/shared/extra-utils/videos/imports-command.ts index d30f9745b..e4944694d 100644 --- a/shared/extra-utils/videos/imports-command.ts +++ b/shared/extra-utils/videos/imports-command.ts @@ -1,6 +1,5 @@ -import { HttpStatusCode } from '@shared/models' -import { ResultList } from '@shared/models' +import { HttpStatusCode, ResultList } from '@shared/models' import { VideoImport, VideoImportCreate } from '../../models/videos' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts index 9dfe3087e..bf9486a05 100644 --- a/shared/extra-utils/videos/live-command.ts +++ b/shared/extra-utils/videos/live-command.ts @@ -3,8 +3,7 @@ import { readdir } from 'fs-extra' import { omit } from 'lodash' import { join } from 'path' -import { HttpStatusCode } from '@shared/models' -import { LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' +import { HttpStatusCode, LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' import { wait } from '../miscs' import { unwrapBody } from '../requests' import { AbstractCommand, OverrideCommandOptions } from '../shared' diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts index 40162c30d..6f329800e 100644 --- a/shared/extra-utils/videos/playlists-command.ts +++ b/shared/extra-utils/videos/playlists-command.ts @@ -1,7 +1,7 @@ import { omit, pick } from 'lodash' -import { HttpStatusCode } from '@shared/models' import { BooleanBothQuery, + HttpStatusCode, ResultList, VideoExistInPlaylist, VideoPlaylist, diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts index 007d3d98d..1ae3fefc1 100644 --- a/shared/extra-utils/videos/streaming-playlists.ts +++ b/shared/extra-utils/videos/streaming-playlists.ts @@ -1,7 +1,6 @@ import { expect } from 'chai' import { sha256 } from '@server/helpers/core-utils' -import { HttpStatusCode } from '@shared/models' -import { VideoStreamingPlaylist } from '@shared/models' +import { HttpStatusCode, VideoStreamingPlaylist } from '@shared/models' import { PeerTubeServer } from '../server' async function checkSegmentHash (options: { diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts index f46d386f4..40cc4dc28 100644 --- a/shared/extra-utils/videos/videos-command.ts +++ b/shared/extra-utils/videos/videos-command.ts @@ -7,8 +7,8 @@ import { omit, pick } from 'lodash' import validator from 'validator' import { buildUUID } from '@server/helpers/uuid' import { loadLanguages } from '@server/initializers/constants' -import { HttpStatusCode } from '@shared/models' import { + HttpStatusCode, ResultList, UserVideoRateType, Video, @@ -332,7 +332,7 @@ export class VideosCommand extends AbstractCommand { attributes?: VideoEdit mode?: 'legacy' | 'resumable' // default legacy } = {}) { - const { mode = 'legacy', expectedStatus } = options + const { mode = 'legacy' } = options let defaultChannelId = 1 try { @@ -360,22 +360,23 @@ export class VideosCommand extends AbstractCommand { ...options.attributes } - const res = mode === 'legacy' + const created = mode === 'legacy' ? await this.buildLegacyUpload({ ...options, attributes }) : await this.buildResumeUpload({ ...options, attributes }) // Wait torrent generation + const expectedStatus = this.buildExpectedStatus({ ...options, defaultExpectedStatus: HttpStatusCode.OK_200 }) if (expectedStatus === HttpStatusCode.OK_200) { let video: VideoDetails do { - video = await this.getWithToken({ ...options, id: video.uuid }) + video = await this.getWithToken({ ...options, id: created.uuid }) await wait(50) } while (!video.files[0].torrentUrl) } - return res + return created } async buildLegacyUpload (options: OverrideCommandOptions & { @@ -535,13 +536,13 @@ export class VideosCommand extends AbstractCommand { async randomUpload (options: OverrideCommandOptions & { wait?: boolean // default true - additionalParams?: VideoEdit & { prefixName: string } + additionalParams?: VideoEdit & { prefixName?: string } } = {}) { const { wait = true, additionalParams } = options const prefixName = additionalParams?.prefixName || '' const name = prefixName + buildUUID() - const attributes = { name, additionalParams } + const attributes = { name, ...additionalParams } const result = await this.upload({ ...options, attributes }) diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts index a96073c56..9a9bfb3cf 100644 --- a/shared/extra-utils/videos/videos.ts +++ b/shared/extra-utils/videos/videos.ts @@ -202,7 +202,7 @@ async function uploadRandomVideoOnServers ( additionalParams?: VideoEdit & { prefixName?: string } ) { const server = servers.find(s => s.serverNumber === serverNumber) - const res = await server.videos.randomUpload({ wait: false, ...additionalParams }) + const res = await server.videos.randomUpload({ wait: false, additionalParams }) await waitJobs(servers) -- cgit v1.2.3 From 4d029ef8ec3d5274eeaa3ee6d808eb7035e7faef Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 20 Jul 2021 14:15:15 +0200 Subject: Add ability for instances to follow any actor --- shared/extra-utils/server/follows-command.ts | 35 +++++++++---- shared/extra-utils/server/follows.ts | 4 +- shared/extra-utils/users/accounts.ts | 44 ---------------- shared/extra-utils/users/actors.ts | 73 +++++++++++++++++++++++++++ shared/extra-utils/users/index.ts | 2 +- shared/extra-utils/videos/comments-command.ts | 21 ++++++++ shared/extra-utils/videos/videos-command.ts | 10 ++++ 7 files changed, 132 insertions(+), 57 deletions(-) delete mode 100644 shared/extra-utils/users/accounts.ts create mode 100644 shared/extra-utils/users/actors.ts (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/server/follows-command.ts b/shared/extra-utils/server/follows-command.ts index dce674ac5..2b889cf66 100644 --- a/shared/extra-utils/server/follows-command.ts +++ b/shared/extra-utils/server/follows-command.ts @@ -1,5 +1,5 @@ import { pick } from 'lodash' -import { ActivityPubActorType, ActorFollow, FollowState, HttpStatusCode, ResultList } from '@shared/models' +import { ActivityPubActorType, ActorFollow, FollowState, HttpStatusCode, ResultList, ServerFollowCreate } from '@shared/models' import { AbstractCommand, OverrideCommandOptions } from '../shared' import { PeerTubeServer } from './server' @@ -29,13 +29,13 @@ export class FollowsCommand extends AbstractCommand { } getFollowings (options: OverrideCommandOptions & { - start: number - count: number - sort: string + start?: number + count?: number + sort?: string search?: string actorType?: ActivityPubActorType state?: FollowState - }) { + } = {}) { const path = '/api/v1/server/following' const toPick = [ 'start', 'count', 'sort', 'search', 'state', 'actorType' ] @@ -52,26 +52,41 @@ export class FollowsCommand extends AbstractCommand { } follow (options: OverrideCommandOptions & { - targets: string[] + hosts?: string[] + handles?: string[] }) { const path = '/api/v1/server/following' - const hosts = options.targets.map(f => f.replace(/^http:\/\//, '')) + const fields: ServerFollowCreate = {} + + if (options.hosts) { + fields.hosts = options.hosts.map(f => f.replace(/^http:\/\//, '')) + } + + if (options.handles) { + fields.handles = options.handles + } return this.postBodyRequest({ ...options, path, - fields: { hosts }, + fields, implicitToken: true, defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 }) } async unfollow (options: OverrideCommandOptions & { - target: PeerTubeServer + target: PeerTubeServer | string }) { - const path = '/api/v1/server/following/' + options.target.host + const { target } = options + + const handle = typeof target === 'string' + ? target + : target.host + + const path = '/api/v1/server/following/' + handle return this.deleteRequest({ ...options, diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts index 0188be1aa..698238f29 100644 --- a/shared/extra-utils/server/follows.ts +++ b/shared/extra-utils/server/follows.ts @@ -3,8 +3,8 @@ import { PeerTubeServer } from './server' async function doubleFollow (server1: PeerTubeServer, server2: PeerTubeServer) { await Promise.all([ - server1.follows.follow({ targets: [ server2.url ] }), - server2.follows.follow({ targets: [ server1.url ] }) + server1.follows.follow({ hosts: [ server2.url ] }), + server2.follows.follow({ hosts: [ server1.url ] }) ]) // Wait request propagation diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts deleted file mode 100644 index 9fc1bcfc4..000000000 --- a/shared/extra-utils/users/accounts.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { join } from 'path' -import { root } from '@server/helpers/core-utils' -import { PeerTubeServer } from '../server' - -async function expectAccountFollows (options: { - server: PeerTubeServer - handle: string - followers: number - following: number -}) { - const { server, handle, followers, following } = options - - const body = await server.accounts.list() - const account = body.data.find(a => a.name + '@' + a.host === handle) - - const message = `${handle} on ${server.url}` - expect(account.followersCount).to.equal(followers, message) - expect(account.followingCount).to.equal(following, message) -} - -async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { - const testDirectory = 'test' + serverNumber - - for (const directory of [ 'avatars' ]) { - const directoryPath = join(root(), testDirectory, directory) - - const directoryExists = await pathExists(directoryPath) - expect(directoryExists).to.be.true - - const files = await readdir(directoryPath) - for (const file of files) { - expect(file).to.not.contain(filename) - } - } -} - -export { - expectAccountFollows, - checkActorFilesWereRemoved -} diff --git a/shared/extra-utils/users/actors.ts b/shared/extra-utils/users/actors.ts new file mode 100644 index 000000000..cfcc7d0a7 --- /dev/null +++ b/shared/extra-utils/users/actors.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import { expect } from 'chai' +import { pathExists, readdir } from 'fs-extra' +import { join } from 'path' +import { root } from '@server/helpers/core-utils' +import { Account, VideoChannel } from '@shared/models' +import { PeerTubeServer } from '../server' + +async function expectChannelsFollows (options: { + server: PeerTubeServer + handle: string + followers: number + following: number +}) { + const { server } = options + const { data } = await server.channels.list() + + return expectActorFollow({ ...options, data }) +} + +async function expectAccountFollows (options: { + server: PeerTubeServer + handle: string + followers: number + following: number +}) { + const { server } = options + const { data } = await server.accounts.list() + + return expectActorFollow({ ...options, data }) +} + +async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { + const testDirectory = 'test' + serverNumber + + for (const directory of [ 'avatars' ]) { + const directoryPath = join(root(), testDirectory, directory) + + const directoryExists = await pathExists(directoryPath) + expect(directoryExists).to.be.true + + const files = await readdir(directoryPath) + for (const file of files) { + expect(file).to.not.contain(filename) + } + } +} + +export { + expectAccountFollows, + expectChannelsFollows, + checkActorFilesWereRemoved +} + +// --------------------------------------------------------------------------- + +function expectActorFollow (options: { + server: PeerTubeServer + data: (Account | VideoChannel)[] + handle: string + followers: number + following: number +}) { + const { server, data, handle, followers, following } = options + + const actor = data.find(a => a.name + '@' + a.host === handle) + const message = `${handle} on ${server.url}` + + expect(actor, message).to.exist + expect(actor.followersCount).to.equal(followers, message) + expect(actor.followingCount).to.equal(following, message) +} diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts index fbb454e8f..460a06f70 100644 --- a/shared/extra-utils/users/index.ts +++ b/shared/extra-utils/users/index.ts @@ -1,5 +1,5 @@ export * from './accounts-command' -export * from './accounts' +export * from './actors' export * from './blocklist-command' export * from './login' export * from './login-command' diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts index dd14e4b64..5034c57ad 100644 --- a/shared/extra-utils/videos/comments-command.ts +++ b/shared/extra-utils/videos/comments-command.ts @@ -5,6 +5,10 @@ import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CommentsCommand extends AbstractCommand { + private lastVideoId: number | string + private lastThreadId: number + private lastReplyId: number + listForAdmin (options: OverrideCommandOptions & { start?: number count?: number @@ -80,6 +84,9 @@ export class CommentsCommand extends AbstractCommand { defaultExpectedStatus: HttpStatusCode.OK_200 })) + this.lastThreadId = body.comment.id + this.lastVideoId = videoId + return body.comment } @@ -100,9 +107,23 @@ export class CommentsCommand extends AbstractCommand { defaultExpectedStatus: HttpStatusCode.OK_200 })) + this.lastReplyId = body.comment.id + return body.comment } + async addReplyToLastReply (options: OverrideCommandOptions & { + text: string + }) { + return this.addReply({ ...options, videoId: this.lastVideoId, toCommentId: this.lastReplyId }) + } + + async addReplyToLastThread (options: OverrideCommandOptions & { + text: string + }) { + return this.addReply({ ...options, videoId: this.lastVideoId, toCommentId: this.lastThreadId }) + } + async findCommentId (options: OverrideCommandOptions & { videoId: number | string text: string diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts index 40cc4dc28..98465e8f6 100644 --- a/shared/extra-utils/videos/videos-command.ts +++ b/shared/extra-utils/videos/videos-command.ts @@ -267,6 +267,16 @@ export class VideosCommand extends AbstractCommand { // --------------------------------------------------------------------------- + async find (options: OverrideCommandOptions & { + name: string + }) { + const { data } = await this.list(options) + + return data.find(v => v.name === options.name) + } + + // --------------------------------------------------------------------------- + update (options: OverrideCommandOptions & { id: number | string attributes?: VideoEdit -- cgit v1.2.3 From c63830f15403ac4e750829f27d8bbbdc9a59282c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 21 Jul 2021 13:58:35 +0200 Subject: Rename captions commands --- shared/extra-utils/videos/captions-command.ts | 6 +++--- shared/extra-utils/videos/comments-command.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'shared/extra-utils') diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts index a0608e1a6..a65ea99e3 100644 --- a/shared/extra-utils/videos/captions-command.ts +++ b/shared/extra-utils/videos/captions-command.ts @@ -4,7 +4,7 @@ import { AbstractCommand, OverrideCommandOptions } from '../shared' export class CaptionsCommand extends AbstractCommand { - createVideoCaption (options: OverrideCommandOptions & { + add (options: OverrideCommandOptions & { videoId: string | number language: string fixture: string @@ -32,7 +32,7 @@ export class CaptionsCommand extends AbstractCommand { }) } - listVideoCaptions (options: OverrideCommandOptions & { + list (options: OverrideCommandOptions & { videoId: string | number }) { const { videoId } = options @@ -47,7 +47,7 @@ export class CaptionsCommand extends AbstractCommand { }) } - deleteVideoCaption (options: OverrideCommandOptions & { + delete (options: OverrideCommandOptions & { videoId: string | number language: string }) { diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts index 5034c57ad..f0d163a07 100644 --- a/shared/extra-utils/videos/comments-command.ts +++ b/shared/extra-utils/videos/comments-command.ts @@ -84,7 +84,7 @@ export class CommentsCommand extends AbstractCommand { defaultExpectedStatus: HttpStatusCode.OK_200 })) - this.lastThreadId = body.comment.id + this.lastThreadId = body.comment?.id this.lastVideoId = videoId return body.comment @@ -107,7 +107,7 @@ export class CommentsCommand extends AbstractCommand { defaultExpectedStatus: HttpStatusCode.OK_200 })) - this.lastReplyId = body.comment.id + this.lastReplyId = body.comment?.id return body.comment } -- cgit v1.2.3