diff options
Diffstat (limited to 'shared/extra-utils/users')
-rw-r--r-- | shared/extra-utils/users/accounts-command.ts | 56 | ||||
-rw-r--r-- | shared/extra-utils/users/accounts.ts | 87 | ||||
-rw-r--r-- | shared/extra-utils/users/actors.ts | 73 | ||||
-rw-r--r-- | shared/extra-utils/users/blocklist-command.ts | 139 | ||||
-rw-r--r-- | shared/extra-utils/users/blocklist.ts | 238 | ||||
-rw-r--r-- | shared/extra-utils/users/index.ts | 9 | ||||
-rw-r--r-- | shared/extra-utils/users/login-command.ts | 132 | ||||
-rw-r--r-- | shared/extra-utils/users/login.ts | 124 | ||||
-rw-r--r-- | shared/extra-utils/users/notifications-command.ts | 86 | ||||
-rw-r--r-- | shared/extra-utils/users/notifications.ts (renamed from shared/extra-utils/users/user-notifications.ts) | 628 | ||||
-rw-r--r-- | shared/extra-utils/users/subscriptions-command.ts | 99 | ||||
-rw-r--r-- | shared/extra-utils/users/user-subscriptions.ts | 93 | ||||
-rw-r--r-- | shared/extra-utils/users/users-command.ts | 415 | ||||
-rw-r--r-- | shared/extra-utils/users/users.ts | 415 |
14 files changed, 1321 insertions, 1273 deletions
diff --git a/shared/extra-utils/users/accounts-command.ts b/shared/extra-utils/users/accounts-command.ts new file mode 100644 index 000000000..2f586104e --- /dev/null +++ b/shared/extra-utils/users/accounts-command.ts | |||
@@ -0,0 +1,56 @@ | |||
1 | import { HttpStatusCode, ResultList } from '@shared/models' | ||
2 | import { Account } from '../../models/actors' | ||
3 | import { AccountVideoRate, VideoRateType } from '../../models/videos' | ||
4 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
5 | |||
6 | export class AccountsCommand extends AbstractCommand { | ||
7 | |||
8 | list (options: OverrideCommandOptions & { | ||
9 | sort?: string // default -createdAt | ||
10 | } = {}) { | ||
11 | const { sort = '-createdAt' } = options | ||
12 | const path = '/api/v1/accounts' | ||
13 | |||
14 | return this.getRequestBody<ResultList<Account>>({ | ||
15 | ...options, | ||
16 | |||
17 | path, | ||
18 | query: { sort }, | ||
19 | implicitToken: false, | ||
20 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
21 | }) | ||
22 | } | ||
23 | |||
24 | get (options: OverrideCommandOptions & { | ||
25 | accountName: string | ||
26 | }) { | ||
27 | const path = '/api/v1/accounts/' + options.accountName | ||
28 | |||
29 | return this.getRequestBody<Account>({ | ||
30 | ...options, | ||
31 | |||
32 | path, | ||
33 | implicitToken: false, | ||
34 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
35 | }) | ||
36 | } | ||
37 | |||
38 | listRatings (options: OverrideCommandOptions & { | ||
39 | accountName: string | ||
40 | rating?: VideoRateType | ||
41 | }) { | ||
42 | const { rating, accountName } = options | ||
43 | const path = '/api/v1/accounts/' + accountName + '/ratings' | ||
44 | |||
45 | const query = { rating } | ||
46 | |||
47 | return this.getRequestBody<ResultList<AccountVideoRate>>({ | ||
48 | ...options, | ||
49 | |||
50 | path, | ||
51 | query, | ||
52 | implicitToken: true, | ||
53 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
54 | }) | ||
55 | } | ||
56 | } | ||
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts deleted file mode 100644 index 4ea7f1402..000000000 --- a/shared/extra-utils/users/accounts.ts +++ /dev/null | |||
@@ -1,87 +0,0 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import * as request from 'supertest' | ||
4 | import { expect } from 'chai' | ||
5 | import { existsSync, readdir } from 'fs-extra' | ||
6 | import { join } from 'path' | ||
7 | import { Account } from '../../models/actors' | ||
8 | import { root } from '../miscs/miscs' | ||
9 | import { makeGetRequest } from '../requests/requests' | ||
10 | import { VideoRateType } from '../../models/videos' | ||
11 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
12 | |||
13 | function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = HttpStatusCode.OK_200) { | ||
14 | const path = '/api/v1/accounts' | ||
15 | |||
16 | return makeGetRequest({ | ||
17 | url, | ||
18 | query: { sort }, | ||
19 | path, | ||
20 | statusCodeExpected | ||
21 | }) | ||
22 | } | ||
23 | |||
24 | function getAccount (url: string, accountName: string, statusCodeExpected = HttpStatusCode.OK_200) { | ||
25 | const path = '/api/v1/accounts/' + accountName | ||
26 | |||
27 | return makeGetRequest({ | ||
28 | url, | ||
29 | path, | ||
30 | statusCodeExpected | ||
31 | }) | ||
32 | } | ||
33 | |||
34 | async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) { | ||
35 | const res = await getAccountsList(url) | ||
36 | const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain) | ||
37 | |||
38 | const message = `${nameWithDomain} on ${url}` | ||
39 | expect(account.followersCount).to.equal(followersCount, message) | ||
40 | expect(account.followingCount).to.equal(followingCount, message) | ||
41 | } | ||
42 | |||
43 | async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { | ||
44 | const testDirectory = 'test' + serverNumber | ||
45 | |||
46 | for (const directory of [ 'avatars' ]) { | ||
47 | const directoryPath = join(root(), testDirectory, directory) | ||
48 | |||
49 | const directoryExists = existsSync(directoryPath) | ||
50 | expect(directoryExists).to.be.true | ||
51 | |||
52 | const files = await readdir(directoryPath) | ||
53 | for (const file of files) { | ||
54 | expect(file).to.not.contain(filename) | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
59 | function getAccountRatings ( | ||
60 | url: string, | ||
61 | accountName: string, | ||
62 | accessToken: string, | ||
63 | rating?: VideoRateType, | ||
64 | statusCodeExpected = HttpStatusCode.OK_200 | ||
65 | ) { | ||
66 | const path = '/api/v1/accounts/' + accountName + '/ratings' | ||
67 | |||
68 | const query = rating ? { rating } : {} | ||
69 | |||
70 | return request(url) | ||
71 | .get(path) | ||
72 | .query(query) | ||
73 | .set('Accept', 'application/json') | ||
74 | .set('Authorization', 'Bearer ' + accessToken) | ||
75 | .expect(statusCodeExpected) | ||
76 | .expect('Content-Type', /json/) | ||
77 | } | ||
78 | |||
79 | // --------------------------------------------------------------------------- | ||
80 | |||
81 | export { | ||
82 | getAccount, | ||
83 | expectAccountFollows, | ||
84 | getAccountsList, | ||
85 | checkActorFilesWereRemoved, | ||
86 | getAccountRatings | ||
87 | } | ||
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 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readdir } from 'fs-extra' | ||
5 | import { join } from 'path' | ||
6 | import { root } from '@server/helpers/core-utils' | ||
7 | import { Account, VideoChannel } from '@shared/models' | ||
8 | import { PeerTubeServer } from '../server' | ||
9 | |||
10 | async function expectChannelsFollows (options: { | ||
11 | server: PeerTubeServer | ||
12 | handle: string | ||
13 | followers: number | ||
14 | following: number | ||
15 | }) { | ||
16 | const { server } = options | ||
17 | const { data } = await server.channels.list() | ||
18 | |||
19 | return expectActorFollow({ ...options, data }) | ||
20 | } | ||
21 | |||
22 | async function expectAccountFollows (options: { | ||
23 | server: PeerTubeServer | ||
24 | handle: string | ||
25 | followers: number | ||
26 | following: number | ||
27 | }) { | ||
28 | const { server } = options | ||
29 | const { data } = await server.accounts.list() | ||
30 | |||
31 | return expectActorFollow({ ...options, data }) | ||
32 | } | ||
33 | |||
34 | async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { | ||
35 | const testDirectory = 'test' + serverNumber | ||
36 | |||
37 | for (const directory of [ 'avatars' ]) { | ||
38 | const directoryPath = join(root(), testDirectory, directory) | ||
39 | |||
40 | const directoryExists = await pathExists(directoryPath) | ||
41 | expect(directoryExists).to.be.true | ||
42 | |||
43 | const files = await readdir(directoryPath) | ||
44 | for (const file of files) { | ||
45 | expect(file).to.not.contain(filename) | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | export { | ||
51 | expectAccountFollows, | ||
52 | expectChannelsFollows, | ||
53 | checkActorFilesWereRemoved | ||
54 | } | ||
55 | |||
56 | // --------------------------------------------------------------------------- | ||
57 | |||
58 | function expectActorFollow (options: { | ||
59 | server: PeerTubeServer | ||
60 | data: (Account | VideoChannel)[] | ||
61 | handle: string | ||
62 | followers: number | ||
63 | following: number | ||
64 | }) { | ||
65 | const { server, data, handle, followers, following } = options | ||
66 | |||
67 | const actor = data.find(a => a.name + '@' + a.host === handle) | ||
68 | const message = `${handle} on ${server.url}` | ||
69 | |||
70 | expect(actor, message).to.exist | ||
71 | expect(actor.followersCount).to.equal(followers, message) | ||
72 | expect(actor.followingCount).to.equal(following, message) | ||
73 | } | ||
diff --git a/shared/extra-utils/users/blocklist-command.ts b/shared/extra-utils/users/blocklist-command.ts new file mode 100644 index 000000000..14491a1ae --- /dev/null +++ b/shared/extra-utils/users/blocklist-command.ts | |||
@@ -0,0 +1,139 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { AccountBlock, HttpStatusCode, ResultList, ServerBlock } from '@shared/models' | ||
4 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
5 | |||
6 | type ListBlocklistOptions = OverrideCommandOptions & { | ||
7 | start: number | ||
8 | count: number | ||
9 | sort: string // default -createdAt | ||
10 | } | ||
11 | |||
12 | export class BlocklistCommand extends AbstractCommand { | ||
13 | |||
14 | listMyAccountBlocklist (options: ListBlocklistOptions) { | ||
15 | const path = '/api/v1/users/me/blocklist/accounts' | ||
16 | |||
17 | return this.listBlocklist<AccountBlock>(options, path) | ||
18 | } | ||
19 | |||
20 | listMyServerBlocklist (options: ListBlocklistOptions) { | ||
21 | const path = '/api/v1/users/me/blocklist/servers' | ||
22 | |||
23 | return this.listBlocklist<ServerBlock>(options, path) | ||
24 | } | ||
25 | |||
26 | listServerAccountBlocklist (options: ListBlocklistOptions) { | ||
27 | const path = '/api/v1/server/blocklist/accounts' | ||
28 | |||
29 | return this.listBlocklist<AccountBlock>(options, path) | ||
30 | } | ||
31 | |||
32 | listServerServerBlocklist (options: ListBlocklistOptions) { | ||
33 | const path = '/api/v1/server/blocklist/servers' | ||
34 | |||
35 | return this.listBlocklist<ServerBlock>(options, path) | ||
36 | } | ||
37 | |||
38 | // --------------------------------------------------------------------------- | ||
39 | |||
40 | addToMyBlocklist (options: OverrideCommandOptions & { | ||
41 | account?: string | ||
42 | server?: string | ||
43 | }) { | ||
44 | const { account, server } = options | ||
45 | |||
46 | const path = account | ||
47 | ? '/api/v1/users/me/blocklist/accounts' | ||
48 | : '/api/v1/users/me/blocklist/servers' | ||
49 | |||
50 | return this.postBodyRequest({ | ||
51 | ...options, | ||
52 | |||
53 | path, | ||
54 | fields: { | ||
55 | accountName: account, | ||
56 | host: server | ||
57 | }, | ||
58 | implicitToken: true, | ||
59 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
60 | }) | ||
61 | } | ||
62 | |||
63 | addToServerBlocklist (options: OverrideCommandOptions & { | ||
64 | account?: string | ||
65 | server?: string | ||
66 | }) { | ||
67 | const { account, server } = options | ||
68 | |||
69 | const path = account | ||
70 | ? '/api/v1/server/blocklist/accounts' | ||
71 | : '/api/v1/server/blocklist/servers' | ||
72 | |||
73 | return this.postBodyRequest({ | ||
74 | ...options, | ||
75 | |||
76 | path, | ||
77 | fields: { | ||
78 | accountName: account, | ||
79 | host: server | ||
80 | }, | ||
81 | implicitToken: true, | ||
82 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
83 | }) | ||
84 | } | ||
85 | |||
86 | // --------------------------------------------------------------------------- | ||
87 | |||
88 | removeFromMyBlocklist (options: OverrideCommandOptions & { | ||
89 | account?: string | ||
90 | server?: string | ||
91 | }) { | ||
92 | const { account, server } = options | ||
93 | |||
94 | const path = account | ||
95 | ? '/api/v1/users/me/blocklist/accounts/' + account | ||
96 | : '/api/v1/users/me/blocklist/servers/' + server | ||
97 | |||
98 | return this.deleteRequest({ | ||
99 | ...options, | ||
100 | |||
101 | path, | ||
102 | implicitToken: true, | ||
103 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
104 | }) | ||
105 | } | ||
106 | |||
107 | removeFromServerBlocklist (options: OverrideCommandOptions & { | ||
108 | account?: string | ||
109 | server?: string | ||
110 | }) { | ||
111 | const { account, server } = options | ||
112 | |||
113 | const path = account | ||
114 | ? '/api/v1/server/blocklist/accounts/' + account | ||
115 | : '/api/v1/server/blocklist/servers/' + server | ||
116 | |||
117 | return this.deleteRequest({ | ||
118 | ...options, | ||
119 | |||
120 | path, | ||
121 | implicitToken: true, | ||
122 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
123 | }) | ||
124 | } | ||
125 | |||
126 | private listBlocklist <T> (options: ListBlocklistOptions, path: string) { | ||
127 | const { start, count, sort = '-createdAt' } = options | ||
128 | |||
129 | return this.getRequestBody<ResultList<T>>({ | ||
130 | ...options, | ||
131 | |||
132 | path, | ||
133 | query: { start, count, sort }, | ||
134 | implicitToken: true, | ||
135 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
136 | }) | ||
137 | } | ||
138 | |||
139 | } | ||
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 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests' | ||
4 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
5 | |||
6 | function getAccountBlocklistByAccount ( | ||
7 | url: string, | ||
8 | token: string, | ||
9 | start: number, | ||
10 | count: number, | ||
11 | sort = '-createdAt', | ||
12 | statusCodeExpected = HttpStatusCode.OK_200 | ||
13 | ) { | ||
14 | const path = '/api/v1/users/me/blocklist/accounts' | ||
15 | |||
16 | return makeGetRequest({ | ||
17 | url, | ||
18 | token, | ||
19 | query: { start, count, sort }, | ||
20 | path, | ||
21 | statusCodeExpected | ||
22 | }) | ||
23 | } | ||
24 | |||
25 | function addAccountToAccountBlocklist ( | ||
26 | url: string, | ||
27 | token: string, | ||
28 | accountToBlock: string, | ||
29 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
30 | ) { | ||
31 | const path = '/api/v1/users/me/blocklist/accounts' | ||
32 | |||
33 | return makePostBodyRequest({ | ||
34 | url, | ||
35 | path, | ||
36 | token, | ||
37 | fields: { | ||
38 | accountName: accountToBlock | ||
39 | }, | ||
40 | statusCodeExpected | ||
41 | }) | ||
42 | } | ||
43 | |||
44 | function removeAccountFromAccountBlocklist ( | ||
45 | url: string, | ||
46 | token: string, | ||
47 | accountToUnblock: string, | ||
48 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
49 | ) { | ||
50 | const path = '/api/v1/users/me/blocklist/accounts/' + accountToUnblock | ||
51 | |||
52 | return makeDeleteRequest({ | ||
53 | url, | ||
54 | path, | ||
55 | token, | ||
56 | statusCodeExpected | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | function getServerBlocklistByAccount ( | ||
61 | url: string, | ||
62 | token: string, | ||
63 | start: number, | ||
64 | count: number, | ||
65 | sort = '-createdAt', | ||
66 | statusCodeExpected = HttpStatusCode.OK_200 | ||
67 | ) { | ||
68 | const path = '/api/v1/users/me/blocklist/servers' | ||
69 | |||
70 | return makeGetRequest({ | ||
71 | url, | ||
72 | token, | ||
73 | query: { start, count, sort }, | ||
74 | path, | ||
75 | statusCodeExpected | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | function addServerToAccountBlocklist ( | ||
80 | url: string, | ||
81 | token: string, | ||
82 | serverToBlock: string, | ||
83 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
84 | ) { | ||
85 | const path = '/api/v1/users/me/blocklist/servers' | ||
86 | |||
87 | return makePostBodyRequest({ | ||
88 | url, | ||
89 | path, | ||
90 | token, | ||
91 | fields: { | ||
92 | host: serverToBlock | ||
93 | }, | ||
94 | statusCodeExpected | ||
95 | }) | ||
96 | } | ||
97 | |||
98 | function removeServerFromAccountBlocklist ( | ||
99 | url: string, | ||
100 | token: string, | ||
101 | serverToBlock: string, | ||
102 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
103 | ) { | ||
104 | const path = '/api/v1/users/me/blocklist/servers/' + serverToBlock | ||
105 | |||
106 | return makeDeleteRequest({ | ||
107 | url, | ||
108 | path, | ||
109 | token, | ||
110 | statusCodeExpected | ||
111 | }) | ||
112 | } | ||
113 | |||
114 | function getAccountBlocklistByServer ( | ||
115 | url: string, | ||
116 | token: string, | ||
117 | start: number, | ||
118 | count: number, | ||
119 | sort = '-createdAt', | ||
120 | statusCodeExpected = HttpStatusCode.OK_200 | ||
121 | ) { | ||
122 | const path = '/api/v1/server/blocklist/accounts' | ||
123 | |||
124 | return makeGetRequest({ | ||
125 | url, | ||
126 | token, | ||
127 | query: { start, count, sort }, | ||
128 | path, | ||
129 | statusCodeExpected | ||
130 | }) | ||
131 | } | ||
132 | |||
133 | function addAccountToServerBlocklist ( | ||
134 | url: string, | ||
135 | token: string, | ||
136 | accountToBlock: string, | ||
137 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
138 | ) { | ||
139 | const path = '/api/v1/server/blocklist/accounts' | ||
140 | |||
141 | return makePostBodyRequest({ | ||
142 | url, | ||
143 | path, | ||
144 | token, | ||
145 | fields: { | ||
146 | accountName: accountToBlock | ||
147 | }, | ||
148 | statusCodeExpected | ||
149 | }) | ||
150 | } | ||
151 | |||
152 | function removeAccountFromServerBlocklist ( | ||
153 | url: string, | ||
154 | token: string, | ||
155 | accountToUnblock: string, | ||
156 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
157 | ) { | ||
158 | const path = '/api/v1/server/blocklist/accounts/' + accountToUnblock | ||
159 | |||
160 | return makeDeleteRequest({ | ||
161 | url, | ||
162 | path, | ||
163 | token, | ||
164 | statusCodeExpected | ||
165 | }) | ||
166 | } | ||
167 | |||
168 | function getServerBlocklistByServer ( | ||
169 | url: string, | ||
170 | token: string, | ||
171 | start: number, | ||
172 | count: number, | ||
173 | sort = '-createdAt', | ||
174 | statusCodeExpected = HttpStatusCode.OK_200 | ||
175 | ) { | ||
176 | const path = '/api/v1/server/blocklist/servers' | ||
177 | |||
178 | return makeGetRequest({ | ||
179 | url, | ||
180 | token, | ||
181 | query: { start, count, sort }, | ||
182 | path, | ||
183 | statusCodeExpected | ||
184 | }) | ||
185 | } | ||
186 | |||
187 | function addServerToServerBlocklist ( | ||
188 | url: string, | ||
189 | token: string, | ||
190 | serverToBlock: string, | ||
191 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
192 | ) { | ||
193 | const path = '/api/v1/server/blocklist/servers' | ||
194 | |||
195 | return makePostBodyRequest({ | ||
196 | url, | ||
197 | path, | ||
198 | token, | ||
199 | fields: { | ||
200 | host: serverToBlock | ||
201 | }, | ||
202 | statusCodeExpected | ||
203 | }) | ||
204 | } | ||
205 | |||
206 | function removeServerFromServerBlocklist ( | ||
207 | url: string, | ||
208 | token: string, | ||
209 | serverToBlock: string, | ||
210 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
211 | ) { | ||
212 | const path = '/api/v1/server/blocklist/servers/' + serverToBlock | ||
213 | |||
214 | return makeDeleteRequest({ | ||
215 | url, | ||
216 | path, | ||
217 | token, | ||
218 | statusCodeExpected | ||
219 | }) | ||
220 | } | ||
221 | |||
222 | // --------------------------------------------------------------------------- | ||
223 | |||
224 | export { | ||
225 | getAccountBlocklistByAccount, | ||
226 | addAccountToAccountBlocklist, | ||
227 | removeAccountFromAccountBlocklist, | ||
228 | getServerBlocklistByAccount, | ||
229 | addServerToAccountBlocklist, | ||
230 | removeServerFromAccountBlocklist, | ||
231 | |||
232 | getAccountBlocklistByServer, | ||
233 | addAccountToServerBlocklist, | ||
234 | removeAccountFromServerBlocklist, | ||
235 | getServerBlocklistByServer, | ||
236 | addServerToServerBlocklist, | ||
237 | removeServerFromServerBlocklist | ||
238 | } | ||
diff --git a/shared/extra-utils/users/index.ts b/shared/extra-utils/users/index.ts new file mode 100644 index 000000000..460a06f70 --- /dev/null +++ b/shared/extra-utils/users/index.ts | |||
@@ -0,0 +1,9 @@ | |||
1 | export * from './accounts-command' | ||
2 | export * from './actors' | ||
3 | export * from './blocklist-command' | ||
4 | export * from './login' | ||
5 | export * from './login-command' | ||
6 | export * from './notifications' | ||
7 | export * from './notifications-command' | ||
8 | export * from './subscriptions-command' | ||
9 | export * from './users-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..143f72a59 --- /dev/null +++ b/shared/extra-utils/users/login-command.ts | |||
@@ -0,0 +1,132 @@ | |||
1 | import { HttpStatusCode, PeerTubeProblemDocument } from '@shared/models' | ||
2 | import { unwrapBody } from '../requests' | ||
3 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
4 | |||
5 | export class LoginCommand extends AbstractCommand { | ||
6 | |||
7 | login (options: OverrideCommandOptions & { | ||
8 | client?: { id?: string, secret?: string } | ||
9 | user?: { username: string, password?: string } | ||
10 | } = {}) { | ||
11 | const { client = this.server.store.client, user = this.server.store.user } = options | ||
12 | const path = '/api/v1/users/token' | ||
13 | |||
14 | const body = { | ||
15 | client_id: client.id, | ||
16 | client_secret: client.secret, | ||
17 | username: user.username, | ||
18 | password: user.password ?? 'password', | ||
19 | response_type: 'code', | ||
20 | grant_type: 'password', | ||
21 | scope: 'upload' | ||
22 | } | ||
23 | |||
24 | return unwrapBody<{ access_token: string, refresh_token: string } & PeerTubeProblemDocument>(this.postBodyRequest({ | ||
25 | ...options, | ||
26 | |||
27 | path, | ||
28 | requestType: 'form', | ||
29 | fields: body, | ||
30 | implicitToken: false, | ||
31 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
32 | })) | ||
33 | } | ||
34 | |||
35 | getAccessToken (arg1?: { username: string, password?: string }): Promise<string> | ||
36 | getAccessToken (arg1: string, password?: string): Promise<string> | ||
37 | async getAccessToken (arg1?: { username: string, password?: string } | string, password?: string) { | ||
38 | let user: { username: string, password?: string } | ||
39 | |||
40 | if (!arg1) user = this.server.store.user | ||
41 | else if (typeof arg1 === 'object') user = arg1 | ||
42 | else user = { username: arg1, password } | ||
43 | |||
44 | try { | ||
45 | const body = await this.login({ user }) | ||
46 | |||
47 | return body.access_token | ||
48 | } catch (err) { | ||
49 | throw new Error(`Cannot authenticate. Please check your username/password. (${err})`) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | loginUsingExternalToken (options: OverrideCommandOptions & { | ||
54 | username: string | ||
55 | externalAuthToken: string | ||
56 | }) { | ||
57 | const { username, externalAuthToken } = options | ||
58 | const path = '/api/v1/users/token' | ||
59 | |||
60 | const body = { | ||
61 | client_id: this.server.store.client.id, | ||
62 | client_secret: this.server.store.client.secret, | ||
63 | username: username, | ||
64 | response_type: 'code', | ||
65 | grant_type: 'password', | ||
66 | scope: 'upload', | ||
67 | externalAuthToken | ||
68 | } | ||
69 | |||
70 | return this.postBodyRequest({ | ||
71 | ...options, | ||
72 | |||
73 | path, | ||
74 | requestType: 'form', | ||
75 | fields: body, | ||
76 | implicitToken: false, | ||
77 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
78 | }) | ||
79 | } | ||
80 | |||
81 | logout (options: OverrideCommandOptions & { | ||
82 | token: string | ||
83 | }) { | ||
84 | const path = '/api/v1/users/revoke-token' | ||
85 | |||
86 | return unwrapBody<{ redirectUrl: string }>(this.postBodyRequest({ | ||
87 | ...options, | ||
88 | |||
89 | path, | ||
90 | requestType: 'form', | ||
91 | implicitToken: false, | ||
92 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
93 | })) | ||
94 | } | ||
95 | |||
96 | refreshToken (options: OverrideCommandOptions & { | ||
97 | refreshToken: string | ||
98 | }) { | ||
99 | const path = '/api/v1/users/token' | ||
100 | |||
101 | const body = { | ||
102 | client_id: this.server.store.client.id, | ||
103 | client_secret: this.server.store.client.secret, | ||
104 | refresh_token: options.refreshToken, | ||
105 | response_type: 'code', | ||
106 | grant_type: 'refresh_token' | ||
107 | } | ||
108 | |||
109 | return this.postBodyRequest({ | ||
110 | ...options, | ||
111 | |||
112 | path, | ||
113 | requestType: 'form', | ||
114 | fields: body, | ||
115 | implicitToken: false, | ||
116 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
117 | }) | ||
118 | } | ||
119 | |||
120 | getClient (options: OverrideCommandOptions = {}) { | ||
121 | const path = '/api/v1/oauth-clients/local' | ||
122 | |||
123 | return this.getRequestBody<{ client_id: string, client_secret: string }>({ | ||
124 | ...options, | ||
125 | |||
126 | path, | ||
127 | host: this.server.host, | ||
128 | implicitToken: false, | ||
129 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
130 | }) | ||
131 | } | ||
132 | } | ||
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts index 39e1a2747..f1df027d3 100644 --- a/shared/extra-utils/users/login.ts +++ b/shared/extra-utils/users/login.ts | |||
@@ -1,133 +1,19 @@ | |||
1 | import * as request from 'supertest' | 1 | import { PeerTubeServer } from '../server/server' |
2 | 2 | ||
3 | import { ServerInfo } from '../server/servers' | 3 | function setAccessTokensToServers (servers: PeerTubeServer[]) { |
4 | import { getClient } from '../server/clients' | ||
5 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
6 | |||
7 | type Client = { id: string, secret: string } | ||
8 | type User = { username: string, password: string } | ||
9 | type Server = { url: string, client: Client, user: User } | ||
10 | |||
11 | function login (url: string, client: Client, user: User, expectedStatus = HttpStatusCode.OK_200) { | ||
12 | const path = '/api/v1/users/token' | ||
13 | |||
14 | const body = { | ||
15 | client_id: client.id, | ||
16 | client_secret: client.secret, | ||
17 | username: user.username, | ||
18 | password: user.password, | ||
19 | response_type: 'code', | ||
20 | grant_type: 'password', | ||
21 | scope: 'upload' | ||
22 | } | ||
23 | |||
24 | return request(url) | ||
25 | .post(path) | ||
26 | .type('form') | ||
27 | .send(body) | ||
28 | .expect(expectedStatus) | ||
29 | } | ||
30 | |||
31 | function logout (url: string, token: string, expectedStatus = HttpStatusCode.OK_200) { | ||
32 | const path = '/api/v1/users/revoke-token' | ||
33 | |||
34 | return request(url) | ||
35 | .post(path) | ||
36 | .set('Authorization', 'Bearer ' + token) | ||
37 | .type('form') | ||
38 | .expect(expectedStatus) | ||
39 | } | ||
40 | |||
41 | async function serverLogin (server: Server) { | ||
42 | const res = await login(server.url, server.client, server.user, HttpStatusCode.OK_200) | ||
43 | |||
44 | return res.body.access_token as string | ||
45 | } | ||
46 | |||
47 | function refreshToken (server: ServerInfo, refreshToken: string, expectedStatus = HttpStatusCode.OK_200) { | ||
48 | const path = '/api/v1/users/token' | ||
49 | |||
50 | const body = { | ||
51 | client_id: server.client.id, | ||
52 | client_secret: server.client.secret, | ||
53 | refresh_token: refreshToken, | ||
54 | response_type: 'code', | ||
55 | grant_type: 'refresh_token' | ||
56 | } | ||
57 | |||
58 | return request(server.url) | ||
59 | .post(path) | ||
60 | .type('form') | ||
61 | .send(body) | ||
62 | .expect(expectedStatus) | ||
63 | } | ||
64 | |||
65 | async function userLogin (server: Server, user: User, expectedStatus = HttpStatusCode.OK_200) { | ||
66 | const res = await login(server.url, server.client, user, expectedStatus) | ||
67 | |||
68 | return res.body.access_token as string | ||
69 | } | ||
70 | |||
71 | async function getAccessToken (url: string, username: string, password: string) { | ||
72 | const resClient = await getClient(url) | ||
73 | const client = { | ||
74 | id: resClient.body.client_id, | ||
75 | secret: resClient.body.client_secret | ||
76 | } | ||
77 | |||
78 | const user = { username, password } | ||
79 | |||
80 | try { | ||
81 | const res = await login(url, client, user) | ||
82 | return res.body.access_token | ||
83 | } catch (err) { | ||
84 | throw new Error('Cannot authenticate. Please check your username/password.') | ||
85 | } | ||
86 | } | ||
87 | |||
88 | function setAccessTokensToServers (servers: ServerInfo[]) { | ||
89 | const tasks: Promise<any>[] = [] | 4 | const tasks: Promise<any>[] = [] |
90 | 5 | ||
91 | for (const server of servers) { | 6 | for (const server of servers) { |
92 | const p = serverLogin(server).then(t => { server.accessToken = t }) | 7 | const p = server.login.getAccessToken() |
8 | .then(t => { server.accessToken = t }) | ||
93 | tasks.push(p) | 9 | tasks.push(p) |
94 | } | 10 | } |
95 | 11 | ||
96 | return Promise.all(tasks) | 12 | return Promise.all(tasks) |
97 | } | 13 | } |
98 | 14 | ||
99 | function loginUsingExternalToken (server: Server, username: string, externalAuthToken: string, expectedStatus = HttpStatusCode.OK_200) { | ||
100 | const path = '/api/v1/users/token' | ||
101 | |||
102 | const body = { | ||
103 | client_id: server.client.id, | ||
104 | client_secret: server.client.secret, | ||
105 | username: username, | ||
106 | response_type: 'code', | ||
107 | grant_type: 'password', | ||
108 | scope: 'upload', | ||
109 | externalAuthToken | ||
110 | } | ||
111 | |||
112 | return request(server.url) | ||
113 | .post(path) | ||
114 | .type('form') | ||
115 | .send(body) | ||
116 | .expect(expectedStatus) | ||
117 | } | ||
118 | |||
119 | // --------------------------------------------------------------------------- | 15 | // --------------------------------------------------------------------------- |
120 | 16 | ||
121 | export { | 17 | export { |
122 | login, | 18 | setAccessTokensToServers |
123 | logout, | ||
124 | serverLogin, | ||
125 | refreshToken, | ||
126 | userLogin, | ||
127 | getAccessToken, | ||
128 | setAccessTokensToServers, | ||
129 | Server, | ||
130 | Client, | ||
131 | User, | ||
132 | loginUsingExternalToken | ||
133 | } | 19 | } |
diff --git a/shared/extra-utils/users/notifications-command.ts b/shared/extra-utils/users/notifications-command.ts new file mode 100644 index 000000000..2d79a3747 --- /dev/null +++ b/shared/extra-utils/users/notifications-command.ts | |||
@@ -0,0 +1,86 @@ | |||
1 | import { HttpStatusCode, ResultList } from '@shared/models' | ||
2 | import { UserNotification, UserNotificationSetting } from '../../models/users' | ||
3 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
4 | |||
5 | export class NotificationsCommand extends AbstractCommand { | ||
6 | |||
7 | updateMySettings (options: OverrideCommandOptions & { | ||
8 | settings: UserNotificationSetting | ||
9 | }) { | ||
10 | const path = '/api/v1/users/me/notification-settings' | ||
11 | |||
12 | return this.putBodyRequest({ | ||
13 | ...options, | ||
14 | |||
15 | path, | ||
16 | fields: options.settings, | ||
17 | implicitToken: true, | ||
18 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
19 | }) | ||
20 | } | ||
21 | |||
22 | list (options: OverrideCommandOptions & { | ||
23 | start?: number | ||
24 | count?: number | ||
25 | unread?: boolean | ||
26 | sort?: string | ||
27 | }) { | ||
28 | const { start, count, unread, sort = '-createdAt' } = options | ||
29 | const path = '/api/v1/users/me/notifications' | ||
30 | |||
31 | return this.getRequestBody<ResultList<UserNotification>>({ | ||
32 | ...options, | ||
33 | |||
34 | path, | ||
35 | query: { | ||
36 | start, | ||
37 | count, | ||
38 | sort, | ||
39 | unread | ||
40 | }, | ||
41 | implicitToken: true, | ||
42 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
43 | }) | ||
44 | } | ||
45 | |||
46 | markAsRead (options: OverrideCommandOptions & { | ||
47 | ids: number[] | ||
48 | }) { | ||
49 | const { ids } = options | ||
50 | const path = '/api/v1/users/me/notifications/read' | ||
51 | |||
52 | return this.postBodyRequest({ | ||
53 | ...options, | ||
54 | |||
55 | path, | ||
56 | fields: { ids }, | ||
57 | implicitToken: true, | ||
58 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
59 | }) | ||
60 | } | ||
61 | |||
62 | markAsReadAll (options: OverrideCommandOptions) { | ||
63 | const path = '/api/v1/users/me/notifications/read-all' | ||
64 | |||
65 | return this.postBodyRequest({ | ||
66 | ...options, | ||
67 | |||
68 | path, | ||
69 | implicitToken: true, | ||
70 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
71 | }) | ||
72 | } | ||
73 | |||
74 | async getLastest (options: OverrideCommandOptions = {}) { | ||
75 | const { total, data } = await this.list({ | ||
76 | ...options, | ||
77 | start: 0, | ||
78 | count: 1, | ||
79 | sort: '-createdAt' | ||
80 | }) | ||
81 | |||
82 | if (total === 0) return undefined | ||
83 | |||
84 | return data[0] | ||
85 | } | ||
86 | } | ||
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/notifications.ts index 844f4442d..7db4bfd3f 100644 --- a/shared/extra-utils/users/user-notifications.ts +++ b/shared/extra-utils/users/notifications.ts | |||
@@ -3,91 +3,15 @@ | |||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { inspect } from 'util' | 4 | import { inspect } from 'util' |
5 | import { AbuseState, PluginType } from '@shared/models' | 5 | import { AbuseState, PluginType } from '@shared/models' |
6 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
7 | import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' | 6 | import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users' |
8 | import { MockSmtpServer } from '../miscs/email' | 7 | import { MockSmtpServer } from '../mock-servers/mock-email' |
9 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests' | 8 | import { PeerTubeServer } from '../server' |
10 | import { doubleFollow } from '../server/follows' | 9 | import { doubleFollow } from '../server/follows' |
11 | import { flushAndRunMultipleServers, ServerInfo } from '../server/servers' | 10 | import { createMultipleServers } from '../server/servers' |
12 | import { getUserNotificationSocket } from '../socket/socket-io' | 11 | import { setAccessTokensToServers } from './login' |
13 | import { setAccessTokensToServers, userLogin } from './login' | ||
14 | import { createUser, getMyUserInformation } from './users' | ||
15 | |||
16 | function updateMyNotificationSettings ( | ||
17 | url: string, | ||
18 | token: string, | ||
19 | settings: UserNotificationSetting, | ||
20 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
21 | ) { | ||
22 | const path = '/api/v1/users/me/notification-settings' | ||
23 | |||
24 | return makePutBodyRequest({ | ||
25 | url, | ||
26 | path, | ||
27 | token, | ||
28 | fields: settings, | ||
29 | statusCodeExpected | ||
30 | }) | ||
31 | } | ||
32 | |||
33 | async function getUserNotifications ( | ||
34 | url: string, | ||
35 | token: string, | ||
36 | start: number, | ||
37 | count: number, | ||
38 | unread?: boolean, | ||
39 | sort = '-createdAt', | ||
40 | statusCodeExpected = HttpStatusCode.OK_200 | ||
41 | ) { | ||
42 | const path = '/api/v1/users/me/notifications' | ||
43 | |||
44 | return makeGetRequest({ | ||
45 | url, | ||
46 | path, | ||
47 | token, | ||
48 | query: { | ||
49 | start, | ||
50 | count, | ||
51 | sort, | ||
52 | unread | ||
53 | }, | ||
54 | statusCodeExpected | ||
55 | }) | ||
56 | } | ||
57 | |||
58 | function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { | ||
59 | const path = '/api/v1/users/me/notifications/read' | ||
60 | |||
61 | return makePostBodyRequest({ | ||
62 | url, | ||
63 | path, | ||
64 | token, | ||
65 | fields: { ids }, | ||
66 | statusCodeExpected | ||
67 | }) | ||
68 | } | ||
69 | |||
70 | function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { | ||
71 | const path = '/api/v1/users/me/notifications/read-all' | ||
72 | |||
73 | return makePostBodyRequest({ | ||
74 | url, | ||
75 | path, | ||
76 | token, | ||
77 | statusCodeExpected | ||
78 | }) | ||
79 | } | ||
80 | |||
81 | async function getLastNotification (serverUrl: string, accessToken: string) { | ||
82 | const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt') | ||
83 | |||
84 | if (res.body.total === 0) return undefined | ||
85 | |||
86 | return res.body.data[0] as UserNotification | ||
87 | } | ||
88 | 12 | ||
89 | type CheckerBaseParams = { | 13 | type CheckerBaseParams = { |
90 | server: ServerInfo | 14 | server: PeerTubeServer |
91 | emails: any[] | 15 | emails: any[] |
92 | socketNotifications: UserNotification[] | 16 | socketNotifications: UserNotification[] |
93 | token: string | 17 | token: string |
@@ -96,91 +20,41 @@ type CheckerBaseParams = { | |||
96 | 20 | ||
97 | type CheckerType = 'presence' | 'absence' | 21 | type CheckerType = 'presence' | 'absence' |
98 | 22 | ||
99 | async function checkNotification ( | 23 | function getAllNotificationsSettings (): UserNotificationSetting { |
100 | base: CheckerBaseParams, | 24 | return { |
101 | notificationChecker: (notification: UserNotification, type: CheckerType) => void, | 25 | newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
102 | emailNotificationFinder: (email: object) => boolean, | 26 | newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
103 | checkType: CheckerType | 27 | abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
104 | ) { | 28 | videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
105 | const check = base.check || { web: true, mail: true } | 29 | blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
106 | 30 | myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | |
107 | if (check.web) { | 31 | myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
108 | const notification = await getLastNotification(base.server.url, base.token) | 32 | commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
109 | 33 | newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | |
110 | if (notification || checkType !== 'absence') { | 34 | newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
111 | notificationChecker(notification, checkType) | 35 | newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
112 | } | 36 | abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
113 | 37 | abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | |
114 | const socketNotification = base.socketNotifications.find(n => { | 38 | autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
115 | try { | 39 | newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, |
116 | notificationChecker(n, 'presence') | 40 | newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL |
117 | return true | ||
118 | } catch { | ||
119 | return false | ||
120 | } | ||
121 | }) | ||
122 | |||
123 | if (checkType === 'presence') { | ||
124 | const obj = inspect(base.socketNotifications, { depth: 5 }) | ||
125 | expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined | ||
126 | } else { | ||
127 | const obj = inspect(socketNotification, { depth: 5 }) | ||
128 | expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (check.mail) { | ||
133 | // Last email | ||
134 | const email = base.emails | ||
135 | .slice() | ||
136 | .reverse() | ||
137 | .find(e => emailNotificationFinder(e)) | ||
138 | |||
139 | if (checkType === 'presence') { | ||
140 | const emails = base.emails.map(e => e.text) | ||
141 | expect(email, 'The email is absent when is should be present. ' + inspect(emails)).to.not.be.undefined | ||
142 | } else { | ||
143 | expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined | ||
144 | } | ||
145 | } | ||
146 | } | ||
147 | |||
148 | function checkVideo (video: any, videoName?: string, videoUUID?: string) { | ||
149 | if (videoName) { | ||
150 | expect(video.name).to.be.a('string') | ||
151 | expect(video.name).to.not.be.empty | ||
152 | expect(video.name).to.equal(videoName) | ||
153 | } | ||
154 | |||
155 | if (videoUUID) { | ||
156 | expect(video.uuid).to.be.a('string') | ||
157 | expect(video.uuid).to.not.be.empty | ||
158 | expect(video.uuid).to.equal(videoUUID) | ||
159 | } | 41 | } |
160 | |||
161 | expect(video.id).to.be.a('number') | ||
162 | } | 42 | } |
163 | 43 | ||
164 | function checkActor (actor: any) { | 44 | async function checkNewVideoFromSubscription (options: CheckerBaseParams & { |
165 | expect(actor.displayName).to.be.a('string') | 45 | videoName: string |
166 | expect(actor.displayName).to.not.be.empty | 46 | shortUUID: string |
167 | expect(actor.host).to.not.be.undefined | 47 | checkType: CheckerType |
168 | } | 48 | }) { |
169 | 49 | const { videoName, shortUUID } = options | |
170 | function checkComment (comment: any, commentId: number, threadId: number) { | ||
171 | expect(comment.id).to.equal(commentId) | ||
172 | expect(comment.threadId).to.equal(threadId) | ||
173 | } | ||
174 | |||
175 | async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { | ||
176 | const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION | 50 | const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION |
177 | 51 | ||
178 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 52 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
179 | if (type === 'presence') { | 53 | if (checkType === 'presence') { |
180 | expect(notification).to.not.be.undefined | 54 | expect(notification).to.not.be.undefined |
181 | expect(notification.type).to.equal(notificationType) | 55 | expect(notification.type).to.equal(notificationType) |
182 | 56 | ||
183 | checkVideo(notification.video, videoName, videoUUID) | 57 | checkVideo(notification.video, videoName, shortUUID) |
184 | checkActor(notification.video.channel) | 58 | checkActor(notification.video.channel) |
185 | } else { | 59 | } else { |
186 | expect(notification).to.satisfy((n: UserNotification) => { | 60 | expect(notification).to.satisfy((n: UserNotification) => { |
@@ -191,21 +65,26 @@ async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName | |||
191 | 65 | ||
192 | function emailNotificationFinder (email: object) { | 66 | function emailNotificationFinder (email: object) { |
193 | const text = email['text'] | 67 | const text = email['text'] |
194 | return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1 | 68 | return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1 |
195 | } | 69 | } |
196 | 70 | ||
197 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 71 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
198 | } | 72 | } |
199 | 73 | ||
200 | async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) { | 74 | async function checkVideoIsPublished (options: CheckerBaseParams & { |
75 | videoName: string | ||
76 | shortUUID: string | ||
77 | checkType: CheckerType | ||
78 | }) { | ||
79 | const { videoName, shortUUID } = options | ||
201 | const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED | 80 | const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED |
202 | 81 | ||
203 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 82 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
204 | if (type === 'presence') { | 83 | if (checkType === 'presence') { |
205 | expect(notification).to.not.be.undefined | 84 | expect(notification).to.not.be.undefined |
206 | expect(notification.type).to.equal(notificationType) | 85 | expect(notification.type).to.equal(notificationType) |
207 | 86 | ||
208 | checkVideo(notification.video, videoName, videoUUID) | 87 | checkVideo(notification.video, videoName, shortUUID) |
209 | checkActor(notification.video.channel) | 88 | checkActor(notification.video.channel) |
210 | } else { | 89 | } else { |
211 | expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) | 90 | expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) |
@@ -214,30 +93,31 @@ async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string | |||
214 | 93 | ||
215 | function emailNotificationFinder (email: object) { | 94 | function emailNotificationFinder (email: object) { |
216 | const text: string = email['text'] | 95 | const text: string = email['text'] |
217 | return text.includes(videoUUID) && text.includes('Your video') | 96 | return text.includes(shortUUID) && text.includes('Your video') |
218 | } | 97 | } |
219 | 98 | ||
220 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 99 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
221 | } | 100 | } |
222 | 101 | ||
223 | async function checkMyVideoImportIsFinished ( | 102 | async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { |
224 | base: CheckerBaseParams, | 103 | videoName: string |
225 | videoName: string, | 104 | shortUUID: string |
226 | videoUUID: string, | 105 | url: string |
227 | url: string, | 106 | success: boolean |
228 | success: boolean, | 107 | checkType: CheckerType |
229 | type: CheckerType | 108 | }) { |
230 | ) { | 109 | const { videoName, shortUUID, url, success } = options |
110 | |||
231 | const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR | 111 | const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR |
232 | 112 | ||
233 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 113 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
234 | if (type === 'presence') { | 114 | if (checkType === 'presence') { |
235 | expect(notification).to.not.be.undefined | 115 | expect(notification).to.not.be.undefined |
236 | expect(notification.type).to.equal(notificationType) | 116 | expect(notification.type).to.equal(notificationType) |
237 | 117 | ||
238 | expect(notification.videoImport.targetUrl).to.equal(url) | 118 | expect(notification.videoImport.targetUrl).to.equal(url) |
239 | 119 | ||
240 | if (success) checkVideo(notification.videoImport.video, videoName, videoUUID) | 120 | if (success) checkVideo(notification.videoImport.video, videoName, shortUUID) |
241 | } else { | 121 | } else { |
242 | expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) | 122 | expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) |
243 | } | 123 | } |
@@ -250,14 +130,18 @@ async function checkMyVideoImportIsFinished ( | |||
250 | return text.includes(url) && text.includes(toFind) | 130 | return text.includes(url) && text.includes(toFind) |
251 | } | 131 | } |
252 | 132 | ||
253 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 133 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
254 | } | 134 | } |
255 | 135 | ||
256 | async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) { | 136 | async function checkUserRegistered (options: CheckerBaseParams & { |
137 | username: string | ||
138 | checkType: CheckerType | ||
139 | }) { | ||
140 | const { username } = options | ||
257 | const notificationType = UserNotificationType.NEW_USER_REGISTRATION | 141 | const notificationType = UserNotificationType.NEW_USER_REGISTRATION |
258 | 142 | ||
259 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 143 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
260 | if (type === 'presence') { | 144 | if (checkType === 'presence') { |
261 | expect(notification).to.not.be.undefined | 145 | expect(notification).to.not.be.undefined |
262 | expect(notification.type).to.equal(notificationType) | 146 | expect(notification.type).to.equal(notificationType) |
263 | 147 | ||
@@ -274,21 +158,21 @@ async function checkUserRegistered (base: CheckerBaseParams, username: string, t | |||
274 | return text.includes(' registered.') && text.includes(username) | 158 | return text.includes(' registered.') && text.includes(username) |
275 | } | 159 | } |
276 | 160 | ||
277 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 161 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
278 | } | 162 | } |
279 | 163 | ||
280 | async function checkNewActorFollow ( | 164 | async function checkNewActorFollow (options: CheckerBaseParams & { |
281 | base: CheckerBaseParams, | 165 | followType: 'channel' | 'account' |
282 | followType: 'channel' | 'account', | 166 | followerName: string |
283 | followerName: string, | 167 | followerDisplayName: string |
284 | followerDisplayName: string, | 168 | followingDisplayName: string |
285 | followingDisplayName: string, | 169 | checkType: CheckerType |
286 | type: CheckerType | 170 | }) { |
287 | ) { | 171 | const { followType, followerName, followerDisplayName, followingDisplayName } = options |
288 | const notificationType = UserNotificationType.NEW_FOLLOW | 172 | const notificationType = UserNotificationType.NEW_FOLLOW |
289 | 173 | ||
290 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 174 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
291 | if (type === 'presence') { | 175 | if (checkType === 'presence') { |
292 | expect(notification).to.not.be.undefined | 176 | expect(notification).to.not.be.undefined |
293 | expect(notification.type).to.equal(notificationType) | 177 | expect(notification.type).to.equal(notificationType) |
294 | 178 | ||
@@ -314,14 +198,18 @@ async function checkNewActorFollow ( | |||
314 | return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) | 198 | return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) |
315 | } | 199 | } |
316 | 200 | ||
317 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 201 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
318 | } | 202 | } |
319 | 203 | ||
320 | async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) { | 204 | async function checkNewInstanceFollower (options: CheckerBaseParams & { |
205 | followerHost: string | ||
206 | checkType: CheckerType | ||
207 | }) { | ||
208 | const { followerHost } = options | ||
321 | const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER | 209 | const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER |
322 | 210 | ||
323 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 211 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
324 | if (type === 'presence') { | 212 | if (checkType === 'presence') { |
325 | expect(notification).to.not.be.undefined | 213 | expect(notification).to.not.be.undefined |
326 | expect(notification.type).to.equal(notificationType) | 214 | expect(notification.type).to.equal(notificationType) |
327 | 215 | ||
@@ -343,14 +231,19 @@ async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: | |||
343 | return text.includes('instance has a new follower') && text.includes(followerHost) | 231 | return text.includes('instance has a new follower') && text.includes(followerHost) |
344 | } | 232 | } |
345 | 233 | ||
346 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 234 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
347 | } | 235 | } |
348 | 236 | ||
349 | async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost: string, followingHost: string, type: CheckerType) { | 237 | async function checkAutoInstanceFollowing (options: CheckerBaseParams & { |
238 | followerHost: string | ||
239 | followingHost: string | ||
240 | checkType: CheckerType | ||
241 | }) { | ||
242 | const { followerHost, followingHost } = options | ||
350 | const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING | 243 | const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING |
351 | 244 | ||
352 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 245 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
353 | if (type === 'presence') { | 246 | if (checkType === 'presence') { |
354 | expect(notification).to.not.be.undefined | 247 | expect(notification).to.not.be.undefined |
355 | expect(notification.type).to.equal(notificationType) | 248 | expect(notification.type).to.equal(notificationType) |
356 | 249 | ||
@@ -374,21 +267,21 @@ async function checkAutoInstanceFollowing (base: CheckerBaseParams, followerHost | |||
374 | return text.includes(' automatically followed a new instance') && text.includes(followingHost) | 267 | return text.includes(' automatically followed a new instance') && text.includes(followingHost) |
375 | } | 268 | } |
376 | 269 | ||
377 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 270 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
378 | } | 271 | } |
379 | 272 | ||
380 | async function checkCommentMention ( | 273 | async function checkCommentMention (options: CheckerBaseParams & { |
381 | base: CheckerBaseParams, | 274 | shortUUID: string |
382 | uuid: string, | 275 | commentId: number |
383 | commentId: number, | 276 | threadId: number |
384 | threadId: number, | 277 | byAccountDisplayName: string |
385 | byAccountDisplayName: string, | 278 | checkType: CheckerType |
386 | type: CheckerType | 279 | }) { |
387 | ) { | 280 | const { shortUUID, commentId, threadId, byAccountDisplayName } = options |
388 | const notificationType = UserNotificationType.COMMENT_MENTION | 281 | const notificationType = UserNotificationType.COMMENT_MENTION |
389 | 282 | ||
390 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 283 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
391 | if (type === 'presence') { | 284 | if (checkType === 'presence') { |
392 | expect(notification).to.not.be.undefined | 285 | expect(notification).to.not.be.undefined |
393 | expect(notification.type).to.equal(notificationType) | 286 | expect(notification.type).to.equal(notificationType) |
394 | 287 | ||
@@ -396,7 +289,7 @@ async function checkCommentMention ( | |||
396 | checkActor(notification.comment.account) | 289 | checkActor(notification.comment.account) |
397 | expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) | 290 | expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) |
398 | 291 | ||
399 | checkVideo(notification.comment.video, undefined, uuid) | 292 | checkVideo(notification.comment.video, undefined, shortUUID) |
400 | } else { | 293 | } else { |
401 | expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) | 294 | expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) |
402 | } | 295 | } |
@@ -405,25 +298,31 @@ async function checkCommentMention ( | |||
405 | function emailNotificationFinder (email: object) { | 298 | function emailNotificationFinder (email: object) { |
406 | const text: string = email['text'] | 299 | const text: string = email['text'] |
407 | 300 | ||
408 | return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName) | 301 | return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName) |
409 | } | 302 | } |
410 | 303 | ||
411 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 304 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
412 | } | 305 | } |
413 | 306 | ||
414 | let lastEmailCount = 0 | 307 | let lastEmailCount = 0 |
415 | 308 | ||
416 | async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) { | 309 | async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { |
310 | shortUUID: string | ||
311 | commentId: number | ||
312 | threadId: number | ||
313 | checkType: CheckerType | ||
314 | }) { | ||
315 | const { server, shortUUID, commentId, threadId, checkType, emails } = options | ||
417 | const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO | 316 | const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO |
418 | 317 | ||
419 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 318 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
420 | if (type === 'presence') { | 319 | if (checkType === 'presence') { |
421 | expect(notification).to.not.be.undefined | 320 | expect(notification).to.not.be.undefined |
422 | expect(notification.type).to.equal(notificationType) | 321 | expect(notification.type).to.equal(notificationType) |
423 | 322 | ||
424 | checkComment(notification.comment, commentId, threadId) | 323 | checkComment(notification.comment, commentId, threadId) |
425 | checkActor(notification.comment.account) | 324 | checkActor(notification.comment.account) |
426 | checkVideo(notification.comment.video, undefined, uuid) | 325 | checkVideo(notification.comment.video, undefined, shortUUID) |
427 | } else { | 326 | } else { |
428 | expect(notification).to.satisfy((n: UserNotification) => { | 327 | expect(notification).to.satisfy((n: UserNotification) => { |
429 | return n === undefined || n.comment === undefined || n.comment.id !== commentId | 328 | return n === undefined || n.comment === undefined || n.comment.id !== commentId |
@@ -431,51 +330,62 @@ async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, | |||
431 | } | 330 | } |
432 | } | 331 | } |
433 | 332 | ||
434 | const commentUrl = `http://localhost:${base.server.port}/w/${uuid};threadId=${threadId}` | 333 | const commentUrl = `http://localhost:${server.port}/w/${shortUUID};threadId=${threadId}` |
435 | 334 | ||
436 | function emailNotificationFinder (email: object) { | 335 | function emailNotificationFinder (email: object) { |
437 | return email['text'].indexOf(commentUrl) !== -1 | 336 | return email['text'].indexOf(commentUrl) !== -1 |
438 | } | 337 | } |
439 | 338 | ||
440 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 339 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
441 | 340 | ||
442 | if (type === 'presence') { | 341 | if (checkType === 'presence') { |
443 | // We cannot detect email duplicates, so check we received another email | 342 | // We cannot detect email duplicates, so check we received another email |
444 | expect(base.emails).to.have.length.above(lastEmailCount) | 343 | expect(emails).to.have.length.above(lastEmailCount) |
445 | lastEmailCount = base.emails.length | 344 | lastEmailCount = emails.length |
446 | } | 345 | } |
447 | } | 346 | } |
448 | 347 | ||
449 | async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 348 | async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & { |
349 | shortUUID: string | ||
350 | videoName: string | ||
351 | checkType: CheckerType | ||
352 | }) { | ||
353 | const { shortUUID, videoName } = options | ||
450 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | 354 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS |
451 | 355 | ||
452 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 356 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
453 | if (type === 'presence') { | 357 | if (checkType === 'presence') { |
454 | expect(notification).to.not.be.undefined | 358 | expect(notification).to.not.be.undefined |
455 | expect(notification.type).to.equal(notificationType) | 359 | expect(notification.type).to.equal(notificationType) |
456 | 360 | ||
457 | expect(notification.abuse.id).to.be.a('number') | 361 | expect(notification.abuse.id).to.be.a('number') |
458 | checkVideo(notification.abuse.video, videoName, videoUUID) | 362 | checkVideo(notification.abuse.video, videoName, shortUUID) |
459 | } else { | 363 | } else { |
460 | expect(notification).to.satisfy((n: UserNotification) => { | 364 | expect(notification).to.satisfy((n: UserNotification) => { |
461 | return n === undefined || n.abuse === undefined || n.abuse.video.uuid !== videoUUID | 365 | return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID |
462 | }) | 366 | }) |
463 | } | 367 | } |
464 | } | 368 | } |
465 | 369 | ||
466 | function emailNotificationFinder (email: object) { | 370 | function emailNotificationFinder (email: object) { |
467 | const text = email['text'] | 371 | const text = email['text'] |
468 | return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 | 372 | return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 |
469 | } | 373 | } |
470 | 374 | ||
471 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 375 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
472 | } | 376 | } |
473 | 377 | ||
474 | async function checkNewAbuseMessage (base: CheckerBaseParams, abuseId: number, message: string, toEmail: string, type: CheckerType) { | 378 | async function checkNewAbuseMessage (options: CheckerBaseParams & { |
379 | abuseId: number | ||
380 | message: string | ||
381 | toEmail: string | ||
382 | checkType: CheckerType | ||
383 | }) { | ||
384 | const { abuseId, message, toEmail } = options | ||
475 | const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE | 385 | const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE |
476 | 386 | ||
477 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 387 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
478 | if (type === 'presence') { | 388 | if (checkType === 'presence') { |
479 | expect(notification).to.not.be.undefined | 389 | expect(notification).to.not.be.undefined |
480 | expect(notification.type).to.equal(notificationType) | 390 | expect(notification.type).to.equal(notificationType) |
481 | 391 | ||
@@ -494,14 +404,19 @@ async function checkNewAbuseMessage (base: CheckerBaseParams, abuseId: number, m | |||
494 | return text.indexOf(message) !== -1 && to.length !== 0 | 404 | return text.indexOf(message) !== -1 && to.length !== 0 |
495 | } | 405 | } |
496 | 406 | ||
497 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 407 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
498 | } | 408 | } |
499 | 409 | ||
500 | async function checkAbuseStateChange (base: CheckerBaseParams, abuseId: number, state: AbuseState, type: CheckerType) { | 410 | async function checkAbuseStateChange (options: CheckerBaseParams & { |
411 | abuseId: number | ||
412 | state: AbuseState | ||
413 | checkType: CheckerType | ||
414 | }) { | ||
415 | const { abuseId, state } = options | ||
501 | const notificationType = UserNotificationType.ABUSE_STATE_CHANGE | 416 | const notificationType = UserNotificationType.ABUSE_STATE_CHANGE |
502 | 417 | ||
503 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 418 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
504 | if (type === 'presence') { | 419 | if (checkType === 'presence') { |
505 | expect(notification).to.not.be.undefined | 420 | expect(notification).to.not.be.undefined |
506 | expect(notification.type).to.equal(notificationType) | 421 | expect(notification.type).to.equal(notificationType) |
507 | 422 | ||
@@ -524,39 +439,48 @@ async function checkAbuseStateChange (base: CheckerBaseParams, abuseId: number, | |||
524 | return text.indexOf(contains) !== -1 | 439 | return text.indexOf(contains) !== -1 |
525 | } | 440 | } |
526 | 441 | ||
527 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 442 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
528 | } | 443 | } |
529 | 444 | ||
530 | async function checkNewCommentAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 445 | async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & { |
446 | shortUUID: string | ||
447 | videoName: string | ||
448 | checkType: CheckerType | ||
449 | }) { | ||
450 | const { shortUUID, videoName } = options | ||
531 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | 451 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS |
532 | 452 | ||
533 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 453 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
534 | if (type === 'presence') { | 454 | if (checkType === 'presence') { |
535 | expect(notification).to.not.be.undefined | 455 | expect(notification).to.not.be.undefined |
536 | expect(notification.type).to.equal(notificationType) | 456 | expect(notification.type).to.equal(notificationType) |
537 | 457 | ||
538 | expect(notification.abuse.id).to.be.a('number') | 458 | expect(notification.abuse.id).to.be.a('number') |
539 | checkVideo(notification.abuse.comment.video, videoName, videoUUID) | 459 | checkVideo(notification.abuse.comment.video, videoName, shortUUID) |
540 | } else { | 460 | } else { |
541 | expect(notification).to.satisfy((n: UserNotification) => { | 461 | expect(notification).to.satisfy((n: UserNotification) => { |
542 | return n === undefined || n.abuse === undefined || n.abuse.comment.video.uuid !== videoUUID | 462 | return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID |
543 | }) | 463 | }) |
544 | } | 464 | } |
545 | } | 465 | } |
546 | 466 | ||
547 | function emailNotificationFinder (email: object) { | 467 | function emailNotificationFinder (email: object) { |
548 | const text = email['text'] | 468 | const text = email['text'] |
549 | return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1 | 469 | return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 |
550 | } | 470 | } |
551 | 471 | ||
552 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 472 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
553 | } | 473 | } |
554 | 474 | ||
555 | async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displayName: string, type: CheckerType) { | 475 | async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & { |
476 | displayName: string | ||
477 | checkType: CheckerType | ||
478 | }) { | ||
479 | const { displayName } = options | ||
556 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | 480 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS |
557 | 481 | ||
558 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 482 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
559 | if (type === 'presence') { | 483 | if (checkType === 'presence') { |
560 | expect(notification).to.not.be.undefined | 484 | expect(notification).to.not.be.undefined |
561 | expect(notification.type).to.equal(notificationType) | 485 | expect(notification.type).to.equal(notificationType) |
562 | 486 | ||
@@ -574,40 +498,45 @@ async function checkNewAccountAbuseForModerators (base: CheckerBaseParams, displ | |||
574 | return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 | 498 | return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 |
575 | } | 499 | } |
576 | 500 | ||
577 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 501 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
578 | } | 502 | } |
579 | 503 | ||
580 | async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) { | 504 | async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & { |
505 | shortUUID: string | ||
506 | videoName: string | ||
507 | checkType: CheckerType | ||
508 | }) { | ||
509 | const { shortUUID, videoName } = options | ||
581 | const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS | 510 | const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS |
582 | 511 | ||
583 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 512 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
584 | if (type === 'presence') { | 513 | if (checkType === 'presence') { |
585 | expect(notification).to.not.be.undefined | 514 | expect(notification).to.not.be.undefined |
586 | expect(notification.type).to.equal(notificationType) | 515 | expect(notification.type).to.equal(notificationType) |
587 | 516 | ||
588 | expect(notification.videoBlacklist.video.id).to.be.a('number') | 517 | expect(notification.videoBlacklist.video.id).to.be.a('number') |
589 | checkVideo(notification.videoBlacklist.video, videoName, videoUUID) | 518 | checkVideo(notification.videoBlacklist.video, videoName, shortUUID) |
590 | } else { | 519 | } else { |
591 | expect(notification).to.satisfy((n: UserNotification) => { | 520 | expect(notification).to.satisfy((n: UserNotification) => { |
592 | return n === undefined || n.video === undefined || n.video.uuid !== videoUUID | 521 | return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID |
593 | }) | 522 | }) |
594 | } | 523 | } |
595 | } | 524 | } |
596 | 525 | ||
597 | function emailNotificationFinder (email: object) { | 526 | function emailNotificationFinder (email: object) { |
598 | const text = email['text'] | 527 | const text = email['text'] |
599 | return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 | 528 | return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 |
600 | } | 529 | } |
601 | 530 | ||
602 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 531 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
603 | } | 532 | } |
604 | 533 | ||
605 | async function checkNewBlacklistOnMyVideo ( | 534 | async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & { |
606 | base: CheckerBaseParams, | 535 | shortUUID: string |
607 | videoUUID: string, | 536 | videoName: string |
608 | videoName: string, | ||
609 | blacklistType: 'blacklist' | 'unblacklist' | 537 | blacklistType: 'blacklist' | 'unblacklist' |
610 | ) { | 538 | }) { |
539 | const { videoName, shortUUID, blacklistType } = options | ||
611 | const notificationType = blacklistType === 'blacklist' | 540 | const notificationType = blacklistType === 'blacklist' |
612 | ? UserNotificationType.BLACKLIST_ON_MY_VIDEO | 541 | ? UserNotificationType.BLACKLIST_ON_MY_VIDEO |
613 | : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO | 542 | : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO |
@@ -618,22 +547,30 @@ async function checkNewBlacklistOnMyVideo ( | |||
618 | 547 | ||
619 | const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video | 548 | const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video |
620 | 549 | ||
621 | checkVideo(video, videoName, videoUUID) | 550 | checkVideo(video, videoName, shortUUID) |
622 | } | 551 | } |
623 | 552 | ||
624 | function emailNotificationFinder (email: object) { | 553 | function emailNotificationFinder (email: object) { |
625 | const text = email['text'] | 554 | const text = email['text'] |
626 | return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1 | 555 | const blacklistText = blacklistType === 'blacklist' |
556 | ? 'blacklisted' | ||
557 | : 'unblacklisted' | ||
558 | |||
559 | return text.includes(shortUUID) && text.includes(blacklistText) | ||
627 | } | 560 | } |
628 | 561 | ||
629 | await checkNotification(base, notificationChecker, emailNotificationFinder, 'presence') | 562 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' }) |
630 | } | 563 | } |
631 | 564 | ||
632 | async function checkNewPeerTubeVersion (base: CheckerBaseParams, latestVersion: string, type: CheckerType) { | 565 | async function checkNewPeerTubeVersion (options: CheckerBaseParams & { |
566 | latestVersion: string | ||
567 | checkType: CheckerType | ||
568 | }) { | ||
569 | const { latestVersion } = options | ||
633 | const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION | 570 | const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION |
634 | 571 | ||
635 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 572 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
636 | if (type === 'presence') { | 573 | if (checkType === 'presence') { |
637 | expect(notification).to.not.be.undefined | 574 | expect(notification).to.not.be.undefined |
638 | expect(notification.type).to.equal(notificationType) | 575 | expect(notification.type).to.equal(notificationType) |
639 | 576 | ||
@@ -652,14 +589,19 @@ async function checkNewPeerTubeVersion (base: CheckerBaseParams, latestVersion: | |||
652 | return text.includes(latestVersion) | 589 | return text.includes(latestVersion) |
653 | } | 590 | } |
654 | 591 | ||
655 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 592 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
656 | } | 593 | } |
657 | 594 | ||
658 | async function checkNewPluginVersion (base: CheckerBaseParams, pluginType: PluginType, pluginName: string, type: CheckerType) { | 595 | async function checkNewPluginVersion (options: CheckerBaseParams & { |
596 | pluginType: PluginType | ||
597 | pluginName: string | ||
598 | checkType: CheckerType | ||
599 | }) { | ||
600 | const { pluginName, pluginType } = options | ||
659 | const notificationType = UserNotificationType.NEW_PLUGIN_VERSION | 601 | const notificationType = UserNotificationType.NEW_PLUGIN_VERSION |
660 | 602 | ||
661 | function notificationChecker (notification: UserNotification, type: CheckerType) { | 603 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { |
662 | if (type === 'presence') { | 604 | if (checkType === 'presence') { |
663 | expect(notification).to.not.be.undefined | 605 | expect(notification).to.not.be.undefined |
664 | expect(notification.type).to.equal(notificationType) | 606 | expect(notification.type).to.equal(notificationType) |
665 | 607 | ||
@@ -678,28 +620,7 @@ async function checkNewPluginVersion (base: CheckerBaseParams, pluginType: Plugi | |||
678 | return text.includes(pluginName) | 620 | return text.includes(pluginName) |
679 | } | 621 | } |
680 | 622 | ||
681 | await checkNotification(base, notificationChecker, emailNotificationFinder, type) | 623 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) |
682 | } | ||
683 | |||
684 | function getAllNotificationsSettings (): UserNotificationSetting { | ||
685 | return { | ||
686 | newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
687 | newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
688 | abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
689 | videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
690 | blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
691 | myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
692 | myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
693 | commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
694 | newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
695 | newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
696 | newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
697 | abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
698 | abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
699 | autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
700 | newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
701 | newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL | ||
702 | } | ||
703 | } | 624 | } |
704 | 625 | ||
705 | async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { | 626 | async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { |
@@ -719,7 +640,7 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an | |||
719 | limit: 20 | 640 | limit: 20 |
720 | } | 641 | } |
721 | } | 642 | } |
722 | const servers = await flushAndRunMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) | 643 | const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) |
723 | 644 | ||
724 | await setAccessTokensToServers(servers) | 645 | await setAccessTokensToServers(servers) |
725 | 646 | ||
@@ -727,42 +648,33 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an | |||
727 | await doubleFollow(servers[0], servers[1]) | 648 | await doubleFollow(servers[0], servers[1]) |
728 | } | 649 | } |
729 | 650 | ||
730 | const user = { | 651 | const user = { username: 'user_1', password: 'super password' } |
731 | username: 'user_1', | 652 | await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 }) |
732 | password: 'super password' | 653 | const userAccessToken = await servers[0].login.getAccessToken(user) |
733 | } | ||
734 | await createUser({ | ||
735 | url: servers[0].url, | ||
736 | accessToken: servers[0].accessToken, | ||
737 | username: user.username, | ||
738 | password: user.password, | ||
739 | videoQuota: 10 * 1000 * 1000 | ||
740 | }) | ||
741 | const userAccessToken = await userLogin(servers[0], user) | ||
742 | 654 | ||
743 | await updateMyNotificationSettings(servers[0].url, userAccessToken, getAllNotificationsSettings()) | 655 | await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) |
744 | await updateMyNotificationSettings(servers[0].url, servers[0].accessToken, getAllNotificationsSettings()) | 656 | await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) |
745 | 657 | ||
746 | if (serversCount > 1) { | 658 | if (serversCount > 1) { |
747 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, getAllNotificationsSettings()) | 659 | await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) |
748 | } | 660 | } |
749 | 661 | ||
750 | { | 662 | { |
751 | const socket = getUserNotificationSocket(servers[0].url, userAccessToken) | 663 | const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken }) |
752 | socket.on('new-notification', n => userNotifications.push(n)) | 664 | socket.on('new-notification', n => userNotifications.push(n)) |
753 | } | 665 | } |
754 | { | 666 | { |
755 | const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken) | 667 | const socket = servers[0].socketIO.getUserNotificationSocket() |
756 | socket.on('new-notification', n => adminNotifications.push(n)) | 668 | socket.on('new-notification', n => adminNotifications.push(n)) |
757 | } | 669 | } |
758 | 670 | ||
759 | if (serversCount > 1) { | 671 | if (serversCount > 1) { |
760 | const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken) | 672 | const socket = servers[1].socketIO.getUserNotificationSocket() |
761 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) | 673 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) |
762 | } | 674 | } |
763 | 675 | ||
764 | const resChannel = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 676 | const { videoChannels } = await servers[0].users.getMyInfo() |
765 | const channelId = resChannel.body.videoChannels[0].id | 677 | const channelId = videoChannels[0].id |
766 | 678 | ||
767 | return { | 679 | return { |
768 | userNotifications, | 680 | userNotifications, |
@@ -778,11 +690,10 @@ async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: an | |||
778 | // --------------------------------------------------------------------------- | 690 | // --------------------------------------------------------------------------- |
779 | 691 | ||
780 | export { | 692 | export { |
693 | getAllNotificationsSettings, | ||
694 | |||
781 | CheckerBaseParams, | 695 | CheckerBaseParams, |
782 | CheckerType, | 696 | CheckerType, |
783 | getAllNotificationsSettings, | ||
784 | checkNotification, | ||
785 | markAsReadAllNotifications, | ||
786 | checkMyVideoImportIsFinished, | 697 | checkMyVideoImportIsFinished, |
787 | checkUserRegistered, | 698 | checkUserRegistered, |
788 | checkAutoInstanceFollowing, | 699 | checkAutoInstanceFollowing, |
@@ -792,14 +703,10 @@ export { | |||
792 | checkNewCommentOnMyVideo, | 703 | checkNewCommentOnMyVideo, |
793 | checkNewBlacklistOnMyVideo, | 704 | checkNewBlacklistOnMyVideo, |
794 | checkCommentMention, | 705 | checkCommentMention, |
795 | updateMyNotificationSettings, | ||
796 | checkNewVideoAbuseForModerators, | 706 | checkNewVideoAbuseForModerators, |
797 | checkVideoAutoBlacklistForModerators, | 707 | checkVideoAutoBlacklistForModerators, |
798 | checkNewAbuseMessage, | 708 | checkNewAbuseMessage, |
799 | checkAbuseStateChange, | 709 | checkAbuseStateChange, |
800 | getUserNotifications, | ||
801 | markAsReadNotifications, | ||
802 | getLastNotification, | ||
803 | checkNewInstanceFollower, | 710 | checkNewInstanceFollower, |
804 | prepareNotificationsTest, | 711 | prepareNotificationsTest, |
805 | checkNewCommentAbuseForModerators, | 712 | checkNewCommentAbuseForModerators, |
@@ -807,3 +714,82 @@ export { | |||
807 | checkNewPeerTubeVersion, | 714 | checkNewPeerTubeVersion, |
808 | checkNewPluginVersion | 715 | checkNewPluginVersion |
809 | } | 716 | } |
717 | |||
718 | // --------------------------------------------------------------------------- | ||
719 | |||
720 | async function checkNotification (options: CheckerBaseParams & { | ||
721 | notificationChecker: (notification: UserNotification, checkType: CheckerType) => void | ||
722 | emailNotificationFinder: (email: object) => boolean | ||
723 | checkType: CheckerType | ||
724 | }) { | ||
725 | const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options | ||
726 | |||
727 | const check = options.check || { web: true, mail: true } | ||
728 | |||
729 | if (check.web) { | ||
730 | const notification = await server.notifications.getLastest({ token: token }) | ||
731 | |||
732 | if (notification || checkType !== 'absence') { | ||
733 | notificationChecker(notification, checkType) | ||
734 | } | ||
735 | |||
736 | const socketNotification = socketNotifications.find(n => { | ||
737 | try { | ||
738 | notificationChecker(n, 'presence') | ||
739 | return true | ||
740 | } catch { | ||
741 | return false | ||
742 | } | ||
743 | }) | ||
744 | |||
745 | if (checkType === 'presence') { | ||
746 | const obj = inspect(socketNotifications, { depth: 5 }) | ||
747 | expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined | ||
748 | } else { | ||
749 | const obj = inspect(socketNotification, { depth: 5 }) | ||
750 | expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined | ||
751 | } | ||
752 | } | ||
753 | |||
754 | if (check.mail) { | ||
755 | // Last email | ||
756 | const email = emails | ||
757 | .slice() | ||
758 | .reverse() | ||
759 | .find(e => emailNotificationFinder(e)) | ||
760 | |||
761 | if (checkType === 'presence') { | ||
762 | const texts = emails.map(e => e.text) | ||
763 | expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined | ||
764 | } else { | ||
765 | expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined | ||
766 | } | ||
767 | } | ||
768 | } | ||
769 | |||
770 | function checkVideo (video: any, videoName?: string, shortUUID?: string) { | ||
771 | if (videoName) { | ||
772 | expect(video.name).to.be.a('string') | ||
773 | expect(video.name).to.not.be.empty | ||
774 | expect(video.name).to.equal(videoName) | ||
775 | } | ||
776 | |||
777 | if (shortUUID) { | ||
778 | expect(video.shortUUID).to.be.a('string') | ||
779 | expect(video.shortUUID).to.not.be.empty | ||
780 | expect(video.shortUUID).to.equal(shortUUID) | ||
781 | } | ||
782 | |||
783 | expect(video.id).to.be.a('number') | ||
784 | } | ||
785 | |||
786 | function checkActor (actor: any) { | ||
787 | expect(actor.displayName).to.be.a('string') | ||
788 | expect(actor.displayName).to.not.be.empty | ||
789 | expect(actor.host).to.not.be.undefined | ||
790 | } | ||
791 | |||
792 | function checkComment (comment: any, commentId: number, threadId: number) { | ||
793 | expect(comment.id).to.equal(commentId) | ||
794 | expect(comment.threadId).to.equal(threadId) | ||
795 | } | ||
diff --git a/shared/extra-utils/users/subscriptions-command.ts b/shared/extra-utils/users/subscriptions-command.ts new file mode 100644 index 000000000..edc60e612 --- /dev/null +++ b/shared/extra-utils/users/subscriptions-command.ts | |||
@@ -0,0 +1,99 @@ | |||
1 | import { HttpStatusCode, ResultList, Video, VideoChannel } from '@shared/models' | ||
2 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
3 | |||
4 | export class SubscriptionsCommand extends AbstractCommand { | ||
5 | |||
6 | add (options: OverrideCommandOptions & { | ||
7 | targetUri: string | ||
8 | }) { | ||
9 | const path = '/api/v1/users/me/subscriptions' | ||
10 | |||
11 | return this.postBodyRequest({ | ||
12 | ...options, | ||
13 | |||
14 | path, | ||
15 | fields: { uri: options.targetUri }, | ||
16 | implicitToken: true, | ||
17 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
18 | }) | ||
19 | } | ||
20 | |||
21 | list (options: OverrideCommandOptions & { | ||
22 | sort?: string // default -createdAt | ||
23 | search?: string | ||
24 | } = {}) { | ||
25 | const { sort = '-createdAt', search } = options | ||
26 | const path = '/api/v1/users/me/subscriptions' | ||
27 | |||
28 | return this.getRequestBody<ResultList<VideoChannel>>({ | ||
29 | ...options, | ||
30 | |||
31 | path, | ||
32 | query: { | ||
33 | sort, | ||
34 | search | ||
35 | }, | ||
36 | implicitToken: true, | ||
37 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
38 | }) | ||
39 | } | ||
40 | |||
41 | listVideos (options: OverrideCommandOptions & { | ||
42 | sort?: string // default -createdAt | ||
43 | } = {}) { | ||
44 | const { sort = '-createdAt' } = options | ||
45 | const path = '/api/v1/users/me/subscriptions/videos' | ||
46 | |||
47 | return this.getRequestBody<ResultList<Video>>({ | ||
48 | ...options, | ||
49 | |||
50 | path, | ||
51 | query: { sort }, | ||
52 | implicitToken: true, | ||
53 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
54 | }) | ||
55 | } | ||
56 | |||
57 | get (options: OverrideCommandOptions & { | ||
58 | uri: string | ||
59 | }) { | ||
60 | const path = '/api/v1/users/me/subscriptions/' + options.uri | ||
61 | |||
62 | return this.getRequestBody<VideoChannel>({ | ||
63 | ...options, | ||
64 | |||
65 | path, | ||
66 | implicitToken: true, | ||
67 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
68 | }) | ||
69 | } | ||
70 | |||
71 | remove (options: OverrideCommandOptions & { | ||
72 | uri: string | ||
73 | }) { | ||
74 | const path = '/api/v1/users/me/subscriptions/' + options.uri | ||
75 | |||
76 | return this.deleteRequest({ | ||
77 | ...options, | ||
78 | |||
79 | path, | ||
80 | implicitToken: true, | ||
81 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
82 | }) | ||
83 | } | ||
84 | |||
85 | exist (options: OverrideCommandOptions & { | ||
86 | uris: string[] | ||
87 | }) { | ||
88 | const path = '/api/v1/users/me/subscriptions/exist' | ||
89 | |||
90 | return this.getRequestBody<{ [id: string ]: boolean }>({ | ||
91 | ...options, | ||
92 | |||
93 | path, | ||
94 | query: { 'uris[]': options.uris }, | ||
95 | implicitToken: true, | ||
96 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
97 | }) | ||
98 | } | ||
99 | } | ||
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 @@ | |||
1 | import { makeDeleteRequest, makeGetRequest, makePostBodyRequest } from '../requests/requests' | ||
2 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
3 | |||
4 | function addUserSubscription (url: string, token: string, targetUri: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { | ||
5 | const path = '/api/v1/users/me/subscriptions' | ||
6 | |||
7 | return makePostBodyRequest({ | ||
8 | url, | ||
9 | path, | ||
10 | token, | ||
11 | statusCodeExpected, | ||
12 | fields: { uri: targetUri } | ||
13 | }) | ||
14 | } | ||
15 | |||
16 | function listUserSubscriptions (parameters: { | ||
17 | url: string | ||
18 | token: string | ||
19 | sort?: string | ||
20 | search?: string | ||
21 | statusCodeExpected?: number | ||
22 | }) { | ||
23 | const { url, token, sort = '-createdAt', search, statusCodeExpected = HttpStatusCode.OK_200 } = parameters | ||
24 | const path = '/api/v1/users/me/subscriptions' | ||
25 | |||
26 | return makeGetRequest({ | ||
27 | url, | ||
28 | path, | ||
29 | token, | ||
30 | statusCodeExpected, | ||
31 | query: { | ||
32 | sort, | ||
33 | search | ||
34 | } | ||
35 | }) | ||
36 | } | ||
37 | |||
38 | function listUserSubscriptionVideos (url: string, token: string, sort = '-createdAt', statusCodeExpected = HttpStatusCode.OK_200) { | ||
39 | const path = '/api/v1/users/me/subscriptions/videos' | ||
40 | |||
41 | return makeGetRequest({ | ||
42 | url, | ||
43 | path, | ||
44 | token, | ||
45 | statusCodeExpected, | ||
46 | query: { sort } | ||
47 | }) | ||
48 | } | ||
49 | |||
50 | function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = HttpStatusCode.OK_200) { | ||
51 | const path = '/api/v1/users/me/subscriptions/' + uri | ||
52 | |||
53 | return makeGetRequest({ | ||
54 | url, | ||
55 | path, | ||
56 | token, | ||
57 | statusCodeExpected | ||
58 | }) | ||
59 | } | ||
60 | |||
61 | function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = HttpStatusCode.NO_CONTENT_204) { | ||
62 | const path = '/api/v1/users/me/subscriptions/' + uri | ||
63 | |||
64 | return makeDeleteRequest({ | ||
65 | url, | ||
66 | path, | ||
67 | token, | ||
68 | statusCodeExpected | ||
69 | }) | ||
70 | } | ||
71 | |||
72 | function areSubscriptionsExist (url: string, token: string, uris: string[], statusCodeExpected = HttpStatusCode.OK_200) { | ||
73 | const path = '/api/v1/users/me/subscriptions/exist' | ||
74 | |||
75 | return makeGetRequest({ | ||
76 | url, | ||
77 | path, | ||
78 | query: { 'uris[]': uris }, | ||
79 | token, | ||
80 | statusCodeExpected | ||
81 | }) | ||
82 | } | ||
83 | |||
84 | // --------------------------------------------------------------------------- | ||
85 | |||
86 | export { | ||
87 | areSubscriptionsExist, | ||
88 | addUserSubscription, | ||
89 | listUserSubscriptions, | ||
90 | getUserSubscription, | ||
91 | listUserSubscriptionVideos, | ||
92 | removeUserSubscription | ||
93 | } | ||
diff --git a/shared/extra-utils/users/users-command.ts b/shared/extra-utils/users/users-command.ts new file mode 100644 index 000000000..ddd20d041 --- /dev/null +++ b/shared/extra-utils/users/users-command.ts | |||
@@ -0,0 +1,415 @@ | |||
1 | import { omit } from 'lodash' | ||
2 | import { pick } from '@shared/core-utils' | ||
3 | import { | ||
4 | HttpStatusCode, | ||
5 | MyUser, | ||
6 | ResultList, | ||
7 | User, | ||
8 | UserAdminFlag, | ||
9 | UserCreateResult, | ||
10 | UserRole, | ||
11 | UserUpdate, | ||
12 | UserUpdateMe, | ||
13 | UserVideoQuota, | ||
14 | UserVideoRate | ||
15 | } from '@shared/models' | ||
16 | import { ScopedToken } from '@shared/models/users/user-scoped-token' | ||
17 | import { unwrapBody } from '../requests' | ||
18 | import { AbstractCommand, OverrideCommandOptions } from '../shared' | ||
19 | |||
20 | export class UsersCommand extends AbstractCommand { | ||
21 | |||
22 | askResetPassword (options: OverrideCommandOptions & { | ||
23 | email: string | ||
24 | }) { | ||
25 | const { email } = options | ||
26 | const path = '/api/v1/users/ask-reset-password' | ||
27 | |||
28 | return this.postBodyRequest({ | ||
29 | ...options, | ||
30 | |||
31 | path, | ||
32 | fields: { email }, | ||
33 | implicitToken: false, | ||
34 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
35 | }) | ||
36 | } | ||
37 | |||
38 | resetPassword (options: OverrideCommandOptions & { | ||
39 | userId: number | ||
40 | verificationString: string | ||
41 | password: string | ||
42 | }) { | ||
43 | const { userId, verificationString, password } = options | ||
44 | const path = '/api/v1/users/' + userId + '/reset-password' | ||
45 | |||
46 | return this.postBodyRequest({ | ||
47 | ...options, | ||
48 | |||
49 | path, | ||
50 | fields: { password, verificationString }, | ||
51 | implicitToken: false, | ||
52 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
53 | }) | ||
54 | } | ||
55 | |||
56 | // --------------------------------------------------------------------------- | ||
57 | |||
58 | askSendVerifyEmail (options: OverrideCommandOptions & { | ||
59 | email: string | ||
60 | }) { | ||
61 | const { email } = options | ||
62 | const path = '/api/v1/users/ask-send-verify-email' | ||
63 | |||
64 | return this.postBodyRequest({ | ||
65 | ...options, | ||
66 | |||
67 | path, | ||
68 | fields: { email }, | ||
69 | implicitToken: false, | ||
70 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
71 | }) | ||
72 | } | ||
73 | |||
74 | verifyEmail (options: OverrideCommandOptions & { | ||
75 | userId: number | ||
76 | verificationString: string | ||
77 | isPendingEmail?: boolean // default false | ||
78 | }) { | ||
79 | const { userId, verificationString, isPendingEmail = false } = options | ||
80 | const path = '/api/v1/users/' + userId + '/verify-email' | ||
81 | |||
82 | return this.postBodyRequest({ | ||
83 | ...options, | ||
84 | |||
85 | path, | ||
86 | fields: { | ||
87 | verificationString, | ||
88 | isPendingEmail | ||
89 | }, | ||
90 | implicitToken: false, | ||
91 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
92 | }) | ||
93 | } | ||
94 | |||
95 | // --------------------------------------------------------------------------- | ||
96 | |||
97 | banUser (options: OverrideCommandOptions & { | ||
98 | userId: number | ||
99 | reason?: string | ||
100 | }) { | ||
101 | const { userId, reason } = options | ||
102 | const path = '/api/v1/users' + '/' + userId + '/block' | ||
103 | |||
104 | return this.postBodyRequest({ | ||
105 | ...options, | ||
106 | |||
107 | path, | ||
108 | fields: { reason }, | ||
109 | implicitToken: true, | ||
110 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
111 | }) | ||
112 | } | ||
113 | |||
114 | unbanUser (options: OverrideCommandOptions & { | ||
115 | userId: number | ||
116 | }) { | ||
117 | const { userId } = options | ||
118 | const path = '/api/v1/users' + '/' + userId + '/unblock' | ||
119 | |||
120 | return this.postBodyRequest({ | ||
121 | ...options, | ||
122 | |||
123 | path, | ||
124 | implicitToken: true, | ||
125 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
126 | }) | ||
127 | } | ||
128 | |||
129 | // --------------------------------------------------------------------------- | ||
130 | |||
131 | getMyScopedTokens (options: OverrideCommandOptions = {}) { | ||
132 | const path = '/api/v1/users/scoped-tokens' | ||
133 | |||
134 | return this.getRequestBody<ScopedToken>({ | ||
135 | ...options, | ||
136 | |||
137 | path, | ||
138 | implicitToken: true, | ||
139 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
140 | }) | ||
141 | } | ||
142 | |||
143 | renewMyScopedTokens (options: OverrideCommandOptions = {}) { | ||
144 | const path = '/api/v1/users/scoped-tokens' | ||
145 | |||
146 | return this.postBodyRequest({ | ||
147 | ...options, | ||
148 | |||
149 | path, | ||
150 | implicitToken: true, | ||
151 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
152 | }) | ||
153 | } | ||
154 | |||
155 | // --------------------------------------------------------------------------- | ||
156 | |||
157 | create (options: OverrideCommandOptions & { | ||
158 | username: string | ||
159 | password?: string | ||
160 | videoQuota?: number | ||
161 | videoQuotaDaily?: number | ||
162 | role?: UserRole | ||
163 | adminFlags?: UserAdminFlag | ||
164 | }) { | ||
165 | const { | ||
166 | username, | ||
167 | adminFlags, | ||
168 | password = 'password', | ||
169 | videoQuota = 42000000, | ||
170 | videoQuotaDaily = -1, | ||
171 | role = UserRole.USER | ||
172 | } = options | ||
173 | |||
174 | const path = '/api/v1/users' | ||
175 | |||
176 | return unwrapBody<{ user: UserCreateResult }>(this.postBodyRequest({ | ||
177 | ...options, | ||
178 | |||
179 | path, | ||
180 | fields: { | ||
181 | username, | ||
182 | password, | ||
183 | role, | ||
184 | adminFlags, | ||
185 | email: username + '@example.com', | ||
186 | videoQuota, | ||
187 | videoQuotaDaily | ||
188 | }, | ||
189 | implicitToken: true, | ||
190 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
191 | })).then(res => res.user) | ||
192 | } | ||
193 | |||
194 | async generate (username: string) { | ||
195 | const password = 'password' | ||
196 | const user = await this.create({ username, password }) | ||
197 | |||
198 | const token = await this.server.login.getAccessToken({ username, password }) | ||
199 | |||
200 | const me = await this.getMyInfo({ token }) | ||
201 | |||
202 | return { | ||
203 | token, | ||
204 | userId: user.id, | ||
205 | userChannelId: me.videoChannels[0].id | ||
206 | } | ||
207 | } | ||
208 | |||
209 | async generateUserAndToken (username: string) { | ||
210 | const password = 'password' | ||
211 | await this.create({ username, password }) | ||
212 | |||
213 | return this.server.login.getAccessToken({ username, password }) | ||
214 | } | ||
215 | |||
216 | register (options: OverrideCommandOptions & { | ||
217 | username: string | ||
218 | password?: string | ||
219 | displayName?: string | ||
220 | channel?: { | ||
221 | name: string | ||
222 | displayName: string | ||
223 | } | ||
224 | }) { | ||
225 | const { username, password = 'password', displayName, channel } = options | ||
226 | const path = '/api/v1/users/register' | ||
227 | |||
228 | return this.postBodyRequest({ | ||
229 | ...options, | ||
230 | |||
231 | path, | ||
232 | fields: { | ||
233 | username, | ||
234 | password, | ||
235 | email: username + '@example.com', | ||
236 | displayName, | ||
237 | channel | ||
238 | }, | ||
239 | implicitToken: false, | ||
240 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
241 | }) | ||
242 | } | ||
243 | |||
244 | // --------------------------------------------------------------------------- | ||
245 | |||
246 | getMyInfo (options: OverrideCommandOptions = {}) { | ||
247 | const path = '/api/v1/users/me' | ||
248 | |||
249 | return this.getRequestBody<MyUser>({ | ||
250 | ...options, | ||
251 | |||
252 | path, | ||
253 | implicitToken: true, | ||
254 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
255 | }) | ||
256 | } | ||
257 | |||
258 | getMyQuotaUsed (options: OverrideCommandOptions = {}) { | ||
259 | const path = '/api/v1/users/me/video-quota-used' | ||
260 | |||
261 | return this.getRequestBody<UserVideoQuota>({ | ||
262 | ...options, | ||
263 | |||
264 | path, | ||
265 | implicitToken: true, | ||
266 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
267 | }) | ||
268 | } | ||
269 | |||
270 | getMyRating (options: OverrideCommandOptions & { | ||
271 | videoId: number | string | ||
272 | }) { | ||
273 | const { videoId } = options | ||
274 | const path = '/api/v1/users/me/videos/' + videoId + '/rating' | ||
275 | |||
276 | return this.getRequestBody<UserVideoRate>({ | ||
277 | ...options, | ||
278 | |||
279 | path, | ||
280 | implicitToken: true, | ||
281 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
282 | }) | ||
283 | } | ||
284 | |||
285 | deleteMe (options: OverrideCommandOptions = {}) { | ||
286 | const path = '/api/v1/users/me' | ||
287 | |||
288 | return this.deleteRequest({ | ||
289 | ...options, | ||
290 | |||
291 | path, | ||
292 | implicitToken: true, | ||
293 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
294 | }) | ||
295 | } | ||
296 | |||
297 | updateMe (options: OverrideCommandOptions & UserUpdateMe) { | ||
298 | const path = '/api/v1/users/me' | ||
299 | |||
300 | const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') | ||
301 | |||
302 | return this.putBodyRequest({ | ||
303 | ...options, | ||
304 | |||
305 | path, | ||
306 | fields: toSend, | ||
307 | implicitToken: true, | ||
308 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
309 | }) | ||
310 | } | ||
311 | |||
312 | updateMyAvatar (options: OverrideCommandOptions & { | ||
313 | fixture: string | ||
314 | }) { | ||
315 | const { fixture } = options | ||
316 | const path = '/api/v1/users/me/avatar/pick' | ||
317 | |||
318 | return this.updateImageRequest({ | ||
319 | ...options, | ||
320 | |||
321 | path, | ||
322 | fixture, | ||
323 | fieldname: 'avatarfile', | ||
324 | |||
325 | implicitToken: true, | ||
326 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
327 | }) | ||
328 | } | ||
329 | |||
330 | // --------------------------------------------------------------------------- | ||
331 | |||
332 | get (options: OverrideCommandOptions & { | ||
333 | userId: number | ||
334 | withStats?: boolean // default false | ||
335 | }) { | ||
336 | const { userId, withStats } = options | ||
337 | const path = '/api/v1/users/' + userId | ||
338 | |||
339 | return this.getRequestBody<User>({ | ||
340 | ...options, | ||
341 | |||
342 | path, | ||
343 | query: { withStats }, | ||
344 | implicitToken: true, | ||
345 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
346 | }) | ||
347 | } | ||
348 | |||
349 | list (options: OverrideCommandOptions & { | ||
350 | start?: number | ||
351 | count?: number | ||
352 | sort?: string | ||
353 | search?: string | ||
354 | blocked?: boolean | ||
355 | } = {}) { | ||
356 | const path = '/api/v1/users' | ||
357 | |||
358 | return this.getRequestBody<ResultList<User>>({ | ||
359 | ...options, | ||
360 | |||
361 | path, | ||
362 | query: pick(options, [ 'start', 'count', 'sort', 'search', 'blocked' ]), | ||
363 | implicitToken: true, | ||
364 | defaultExpectedStatus: HttpStatusCode.OK_200 | ||
365 | }) | ||
366 | } | ||
367 | |||
368 | remove (options: OverrideCommandOptions & { | ||
369 | userId: number | ||
370 | }) { | ||
371 | const { userId } = options | ||
372 | const path = '/api/v1/users/' + userId | ||
373 | |||
374 | return this.deleteRequest({ | ||
375 | ...options, | ||
376 | |||
377 | path, | ||
378 | implicitToken: true, | ||
379 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
380 | }) | ||
381 | } | ||
382 | |||
383 | update (options: OverrideCommandOptions & { | ||
384 | userId: number | ||
385 | email?: string | ||
386 | emailVerified?: boolean | ||
387 | videoQuota?: number | ||
388 | videoQuotaDaily?: number | ||
389 | password?: string | ||
390 | adminFlags?: UserAdminFlag | ||
391 | pluginAuth?: string | ||
392 | role?: UserRole | ||
393 | }) { | ||
394 | const path = '/api/v1/users/' + options.userId | ||
395 | |||
396 | const toSend: UserUpdate = {} | ||
397 | if (options.password !== undefined && options.password !== null) toSend.password = options.password | ||
398 | if (options.email !== undefined && options.email !== null) toSend.email = options.email | ||
399 | if (options.emailVerified !== undefined && options.emailVerified !== null) toSend.emailVerified = options.emailVerified | ||
400 | if (options.videoQuota !== undefined && options.videoQuota !== null) toSend.videoQuota = options.videoQuota | ||
401 | if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend.videoQuotaDaily = options.videoQuotaDaily | ||
402 | if (options.role !== undefined && options.role !== null) toSend.role = options.role | ||
403 | if (options.adminFlags !== undefined && options.adminFlags !== null) toSend.adminFlags = options.adminFlags | ||
404 | if (options.pluginAuth !== undefined) toSend.pluginAuth = options.pluginAuth | ||
405 | |||
406 | return this.putBodyRequest({ | ||
407 | ...options, | ||
408 | |||
409 | path, | ||
410 | fields: toSend, | ||
411 | implicitToken: true, | ||
412 | defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 | ||
413 | }) | ||
414 | } | ||
415 | } | ||
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts deleted file mode 100644 index 0f15962ad..000000000 --- a/shared/extra-utils/users/users.ts +++ /dev/null | |||
@@ -1,415 +0,0 @@ | |||
1 | import { omit } from 'lodash' | ||
2 | import * as request from 'supertest' | ||
3 | import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' | ||
4 | import { UserUpdateMe } from '../../models/users' | ||
5 | import { UserAdminFlag } from '../../models/users/user-flag.model' | ||
6 | import { UserRegister } from '../../models/users/user-register.model' | ||
7 | import { UserRole } from '../../models/users/user-role' | ||
8 | import { makeGetRequest, makePostBodyRequest, makePutBodyRequest, updateImageRequest } from '../requests/requests' | ||
9 | import { ServerInfo } from '../server/servers' | ||
10 | import { userLogin } from './login' | ||
11 | |||
12 | function createUser (parameters: { | ||
13 | url: string | ||
14 | accessToken: string | ||
15 | username: string | ||
16 | password: string | ||
17 | videoQuota?: number | ||
18 | videoQuotaDaily?: number | ||
19 | role?: UserRole | ||
20 | adminFlags?: UserAdminFlag | ||
21 | specialStatus?: number | ||
22 | }) { | ||
23 | const { | ||
24 | url, | ||
25 | accessToken, | ||
26 | username, | ||
27 | adminFlags, | ||
28 | password = 'password', | ||
29 | videoQuota = 1000000, | ||
30 | videoQuotaDaily = -1, | ||
31 | role = UserRole.USER, | ||
32 | specialStatus = HttpStatusCode.OK_200 | ||
33 | } = parameters | ||
34 | |||
35 | const path = '/api/v1/users' | ||
36 | const body = { | ||
37 | username, | ||
38 | password, | ||
39 | role, | ||
40 | adminFlags, | ||
41 | email: username + '@example.com', | ||
42 | videoQuota, | ||
43 | videoQuotaDaily | ||
44 | } | ||
45 | |||
46 | return request(url) | ||
47 | .post(path) | ||
48 | .set('Accept', 'application/json') | ||
49 | .set('Authorization', 'Bearer ' + accessToken) | ||
50 | .send(body) | ||
51 | .expect(specialStatus) | ||
52 | } | ||
53 | |||
54 | async function generateUser (server: ServerInfo, username: string) { | ||
55 | const password = 'my super password' | ||
56 | const resCreate = await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) | ||
57 | |||
58 | const token = await userLogin(server, { username, password }) | ||
59 | |||
60 | const resMe = await getMyUserInformation(server.url, token) | ||
61 | |||
62 | return { | ||
63 | token, | ||
64 | userId: resCreate.body.user.id, | ||
65 | userChannelId: resMe.body.videoChannels[0].id | ||
66 | } | ||
67 | } | ||
68 | |||
69 | async function generateUserAccessToken (server: ServerInfo, username: string) { | ||
70 | const password = 'my super password' | ||
71 | await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password }) | ||
72 | |||
73 | return userLogin(server, { username, password }) | ||
74 | } | ||
75 | |||
76 | function registerUser (url: string, username: string, password: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { | ||
77 | const path = '/api/v1/users/register' | ||
78 | const body = { | ||
79 | username, | ||
80 | password, | ||
81 | email: username + '@example.com' | ||
82 | } | ||
83 | |||
84 | return request(url) | ||
85 | .post(path) | ||
86 | .set('Accept', 'application/json') | ||
87 | .send(body) | ||
88 | .expect(specialStatus) | ||
89 | } | ||
90 | |||
91 | function registerUserWithChannel (options: { | ||
92 | url: string | ||
93 | user: { username: string, password: string, displayName?: string } | ||
94 | channel: { name: string, displayName: string } | ||
95 | }) { | ||
96 | const path = '/api/v1/users/register' | ||
97 | const body: UserRegister = { | ||
98 | username: options.user.username, | ||
99 | password: options.user.password, | ||
100 | email: options.user.username + '@example.com', | ||
101 | channel: options.channel | ||
102 | } | ||
103 | |||
104 | if (options.user.displayName) { | ||
105 | Object.assign(body, { displayName: options.user.displayName }) | ||
106 | } | ||
107 | |||
108 | return makePostBodyRequest({ | ||
109 | url: options.url, | ||
110 | path, | ||
111 | fields: body, | ||
112 | statusCodeExpected: HttpStatusCode.NO_CONTENT_204 | ||
113 | }) | ||
114 | } | ||
115 | |||
116 | function getMyUserInformation (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { | ||
117 | const path = '/api/v1/users/me' | ||
118 | |||
119 | return request(url) | ||
120 | .get(path) | ||
121 | .set('Accept', 'application/json') | ||
122 | .set('Authorization', 'Bearer ' + accessToken) | ||
123 | .expect(specialStatus) | ||
124 | .expect('Content-Type', /json/) | ||
125 | } | ||
126 | |||
127 | function getUserScopedTokens (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { | ||
128 | const path = '/api/v1/users/scoped-tokens' | ||
129 | |||
130 | return makeGetRequest({ | ||
131 | url, | ||
132 | path, | ||
133 | token, | ||
134 | statusCodeExpected | ||
135 | }) | ||
136 | } | ||
137 | |||
138 | function renewUserScopedTokens (url: string, token: string, statusCodeExpected = HttpStatusCode.OK_200) { | ||
139 | const path = '/api/v1/users/scoped-tokens' | ||
140 | |||
141 | return makePostBodyRequest({ | ||
142 | url, | ||
143 | path, | ||
144 | token, | ||
145 | statusCodeExpected | ||
146 | }) | ||
147 | } | ||
148 | |||
149 | function deleteMe (url: string, accessToken: string, specialStatus = HttpStatusCode.NO_CONTENT_204) { | ||
150 | const path = '/api/v1/users/me' | ||
151 | |||
152 | return request(url) | ||
153 | .delete(path) | ||
154 | .set('Accept', 'application/json') | ||
155 | .set('Authorization', 'Bearer ' + accessToken) | ||
156 | .expect(specialStatus) | ||
157 | } | ||
158 | |||
159 | function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = HttpStatusCode.OK_200) { | ||
160 | const path = '/api/v1/users/me/video-quota-used' | ||
161 | |||
162 | return request(url) | ||
163 | .get(path) | ||
164 | .set('Accept', 'application/json') | ||
165 | .set('Authorization', 'Bearer ' + accessToken) | ||
166 | .expect(specialStatus) | ||
167 | .expect('Content-Type', /json/) | ||
168 | } | ||
169 | |||
170 | function getUserInformation (url: string, accessToken: string, userId: number, withStats = false) { | ||
171 | const path = '/api/v1/users/' + userId | ||
172 | |||
173 | return request(url) | ||
174 | .get(path) | ||
175 | .query({ withStats }) | ||
176 | .set('Accept', 'application/json') | ||
177 | .set('Authorization', 'Bearer ' + accessToken) | ||
178 | .expect(HttpStatusCode.OK_200) | ||
179 | .expect('Content-Type', /json/) | ||
180 | } | ||
181 | |||
182 | function getMyUserVideoRating (url: string, accessToken: string, videoId: number | string, specialStatus = HttpStatusCode.OK_200) { | ||
183 | const path = '/api/v1/users/me/videos/' + videoId + '/rating' | ||
184 | |||
185 | return request(url) | ||
186 | .get(path) | ||
187 | .set('Accept', 'application/json') | ||
188 | .set('Authorization', 'Bearer ' + accessToken) | ||
189 | .expect(specialStatus) | ||
190 | .expect('Content-Type', /json/) | ||
191 | } | ||
192 | |||
193 | function getUsersList (url: string, accessToken: string) { | ||
194 | const path = '/api/v1/users' | ||
195 | |||
196 | return request(url) | ||
197 | .get(path) | ||
198 | .set('Accept', 'application/json') | ||
199 | .set('Authorization', 'Bearer ' + accessToken) | ||
200 | .expect(HttpStatusCode.OK_200) | ||
201 | .expect('Content-Type', /json/) | ||
202 | } | ||
203 | |||
204 | function getUsersListPaginationAndSort ( | ||
205 | url: string, | ||
206 | accessToken: string, | ||
207 | start: number, | ||
208 | count: number, | ||
209 | sort: string, | ||
210 | search?: string, | ||
211 | blocked?: boolean | ||
212 | ) { | ||
213 | const path = '/api/v1/users' | ||
214 | |||
215 | const query = { | ||
216 | start, | ||
217 | count, | ||
218 | sort, | ||
219 | search, | ||
220 | blocked | ||
221 | } | ||
222 | |||
223 | return request(url) | ||
224 | .get(path) | ||
225 | .query(query) | ||
226 | .set('Accept', 'application/json') | ||
227 | .set('Authorization', 'Bearer ' + accessToken) | ||
228 | .expect(HttpStatusCode.OK_200) | ||
229 | .expect('Content-Type', /json/) | ||
230 | } | ||
231 | |||
232 | function removeUser (url: string, userId: number | string, accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { | ||
233 | const path = '/api/v1/users' | ||
234 | |||
235 | return request(url) | ||
236 | .delete(path + '/' + userId) | ||
237 | .set('Accept', 'application/json') | ||
238 | .set('Authorization', 'Bearer ' + accessToken) | ||
239 | .expect(expectedStatus) | ||
240 | } | ||
241 | |||
242 | function blockUser ( | ||
243 | url: string, | ||
244 | userId: number | string, | ||
245 | accessToken: string, | ||
246 | expectedStatus = HttpStatusCode.NO_CONTENT_204, | ||
247 | reason?: string | ||
248 | ) { | ||
249 | const path = '/api/v1/users' | ||
250 | let body: any | ||
251 | if (reason) body = { reason } | ||
252 | |||
253 | return request(url) | ||
254 | .post(path + '/' + userId + '/block') | ||
255 | .send(body) | ||
256 | .set('Accept', 'application/json') | ||
257 | .set('Authorization', 'Bearer ' + accessToken) | ||
258 | .expect(expectedStatus) | ||
259 | } | ||
260 | |||
261 | function unblockUser (url: string, userId: number | string, accessToken: string, expectedStatus = HttpStatusCode.NO_CONTENT_204) { | ||
262 | const path = '/api/v1/users' | ||
263 | |||
264 | return request(url) | ||
265 | .post(path + '/' + userId + '/unblock') | ||
266 | .set('Accept', 'application/json') | ||
267 | .set('Authorization', 'Bearer ' + accessToken) | ||
268 | .expect(expectedStatus) | ||
269 | } | ||
270 | |||
271 | function updateMyUser (options: { url: string, accessToken: string, statusCodeExpected?: HttpStatusCode } & UserUpdateMe) { | ||
272 | const path = '/api/v1/users/me' | ||
273 | |||
274 | const toSend: UserUpdateMe = omit(options, 'url', 'accessToken') | ||
275 | |||
276 | return makePutBodyRequest({ | ||
277 | url: options.url, | ||
278 | path, | ||
279 | token: options.accessToken, | ||
280 | fields: toSend, | ||
281 | statusCodeExpected: options.statusCodeExpected || HttpStatusCode.NO_CONTENT_204 | ||
282 | }) | ||
283 | } | ||
284 | |||
285 | function updateMyAvatar (options: { | ||
286 | url: string | ||
287 | accessToken: string | ||
288 | fixture: string | ||
289 | }) { | ||
290 | const path = '/api/v1/users/me/avatar/pick' | ||
291 | |||
292 | return updateImageRequest({ ...options, path, fieldname: 'avatarfile' }) | ||
293 | } | ||
294 | |||
295 | function updateUser (options: { | ||
296 | url: string | ||
297 | userId: number | ||
298 | accessToken: string | ||
299 | email?: string | ||
300 | emailVerified?: boolean | ||
301 | videoQuota?: number | ||
302 | videoQuotaDaily?: number | ||
303 | password?: string | ||
304 | adminFlags?: UserAdminFlag | ||
305 | pluginAuth?: string | ||
306 | role?: UserRole | ||
307 | }) { | ||
308 | const path = '/api/v1/users/' + options.userId | ||
309 | |||
310 | const toSend = {} | ||
311 | if (options.password !== undefined && options.password !== null) toSend['password'] = options.password | ||
312 | if (options.email !== undefined && options.email !== null) toSend['email'] = options.email | ||
313 | if (options.emailVerified !== undefined && options.emailVerified !== null) toSend['emailVerified'] = options.emailVerified | ||
314 | if (options.videoQuota !== undefined && options.videoQuota !== null) toSend['videoQuota'] = options.videoQuota | ||
315 | if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend['videoQuotaDaily'] = options.videoQuotaDaily | ||
316 | if (options.role !== undefined && options.role !== null) toSend['role'] = options.role | ||
317 | if (options.adminFlags !== undefined && options.adminFlags !== null) toSend['adminFlags'] = options.adminFlags | ||
318 | if (options.pluginAuth !== undefined) toSend['pluginAuth'] = options.pluginAuth | ||
319 | |||
320 | return makePutBodyRequest({ | ||
321 | url: options.url, | ||
322 | path, | ||
323 | token: options.accessToken, | ||
324 | fields: toSend, | ||
325 | statusCodeExpected: HttpStatusCode.NO_CONTENT_204 | ||
326 | }) | ||
327 | } | ||
328 | |||
329 | function askResetPassword (url: string, email: string) { | ||
330 | const path = '/api/v1/users/ask-reset-password' | ||
331 | |||
332 | return makePostBodyRequest({ | ||
333 | url, | ||
334 | path, | ||
335 | fields: { email }, | ||
336 | statusCodeExpected: HttpStatusCode.NO_CONTENT_204 | ||
337 | }) | ||
338 | } | ||
339 | |||
340 | function resetPassword ( | ||
341 | url: string, | ||
342 | userId: number, | ||
343 | verificationString: string, | ||
344 | password: string, | ||
345 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
346 | ) { | ||
347 | const path = '/api/v1/users/' + userId + '/reset-password' | ||
348 | |||
349 | return makePostBodyRequest({ | ||
350 | url, | ||
351 | path, | ||
352 | fields: { password, verificationString }, | ||
353 | statusCodeExpected | ||
354 | }) | ||
355 | } | ||
356 | |||
357 | function askSendVerifyEmail (url: string, email: string) { | ||
358 | const path = '/api/v1/users/ask-send-verify-email' | ||
359 | |||
360 | return makePostBodyRequest({ | ||
361 | url, | ||
362 | path, | ||
363 | fields: { email }, | ||
364 | statusCodeExpected: HttpStatusCode.NO_CONTENT_204 | ||
365 | }) | ||
366 | } | ||
367 | |||
368 | function verifyEmail ( | ||
369 | url: string, | ||
370 | userId: number, | ||
371 | verificationString: string, | ||
372 | isPendingEmail = false, | ||
373 | statusCodeExpected = HttpStatusCode.NO_CONTENT_204 | ||
374 | ) { | ||
375 | const path = '/api/v1/users/' + userId + '/verify-email' | ||
376 | |||
377 | return makePostBodyRequest({ | ||
378 | url, | ||
379 | path, | ||
380 | fields: { | ||
381 | verificationString, | ||
382 | isPendingEmail | ||
383 | }, | ||
384 | statusCodeExpected | ||
385 | }) | ||
386 | } | ||
387 | |||
388 | // --------------------------------------------------------------------------- | ||
389 | |||
390 | export { | ||
391 | createUser, | ||
392 | registerUser, | ||
393 | getMyUserInformation, | ||
394 | getMyUserVideoRating, | ||
395 | deleteMe, | ||
396 | registerUserWithChannel, | ||
397 | getMyUserVideoQuotaUsed, | ||
398 | getUsersList, | ||
399 | getUsersListPaginationAndSort, | ||
400 | removeUser, | ||
401 | updateUser, | ||
402 | updateMyUser, | ||
403 | getUserInformation, | ||
404 | blockUser, | ||
405 | unblockUser, | ||
406 | askResetPassword, | ||
407 | resetPassword, | ||
408 | renewUserScopedTokens, | ||
409 | updateMyAvatar, | ||
410 | generateUser, | ||
411 | askSendVerifyEmail, | ||
412 | generateUserAccessToken, | ||
413 | verifyEmail, | ||
414 | getUserScopedTokens | ||
415 | } | ||