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/users/user-notifications.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared/extra-utils/users') 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 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/users/user-notifications.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'shared/extra-utils/users') 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/users/accounts-command.ts | 54 ++++++++++++++++++ shared/extra-utils/users/accounts.ts | 83 +++++++--------------------- shared/extra-utils/users/index.ts | 8 +++ 3 files changed, 82 insertions(+), 63 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/users') 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/users/blocklist-command.ts | 135 +++++++++++++++ shared/extra-utils/users/blocklist.ts | 238 -------------------------- shared/extra-utils/users/index.ts | 4 +- 3 files changed, 137 insertions(+), 240 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/users') 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/users/index.ts | 2 +- shared/extra-utils/users/subscriptions-command.ts | 94 +++++++++++++++++++++++ shared/extra-utils/users/user-subscriptions.ts | 93 ---------------------- 3 files changed, 95 insertions(+), 94 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/users') 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/users/index.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'shared/extra-utils/users') 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' -- 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/users/accounts-command.ts | 3 +++ shared/extra-utils/users/blocklist-command.ts | 5 +++++ shared/extra-utils/users/subscriptions-command.ts | 6 ++++++ 3 files changed, 14 insertions(+) (limited to 'shared/extra-utils/users') 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 }) } -- 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/users/login.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared/extra-utils/users') 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 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/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 ---------------------- 4 files changed, 818 insertions(+), 809 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/users') 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 -} -- 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/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 +- 5 files changed, 142 insertions(+), 122 deletions(-) create mode 100644 shared/extra-utils/users/login-command.ts (limited to 'shared/extra-utils/users') 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/users') 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/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 +---------------------------- 5 files changed, 428 insertions(+), 417 deletions(-) create mode 100644 shared/extra-utils/users/users-command.ts (limited to 'shared/extra-utils/users') 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 } -- 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/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 ++-- 5 files changed, 20 insertions(+), 20 deletions(-) (limited to 'shared/extra-utils/users') 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 & { -- 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/users/accounts.ts | 4 ++-- shared/extra-utils/users/login.ts | 4 ++-- shared/extra-utils/users/notifications.ts | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'shared/extra-utils/users') 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) -- 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/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 -------------------- 8 files changed, 10 insertions(+), 31 deletions(-) delete mode 100644 shared/extra-utils/users/users.ts (limited to 'shared/extra-utils/users') 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 -} -- 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/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 +- 6 files changed, 6 insertions(+), 11 deletions(-) (limited to 'shared/extra-utils/users') 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, -- 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/users/accounts.ts | 44 ---------------------- shared/extra-utils/users/actors.ts | 73 ++++++++++++++++++++++++++++++++++++ shared/extra-utils/users/index.ts | 2 +- 3 files changed, 74 insertions(+), 45 deletions(-) delete mode 100644 shared/extra-utils/users/accounts.ts create mode 100644 shared/extra-utils/users/actors.ts (limited to 'shared/extra-utils/users') 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' -- cgit v1.2.3