aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/extra-utils/users
diff options
context:
space:
mode:
Diffstat (limited to 'shared/extra-utils/users')
-rw-r--r--shared/extra-utils/users/accounts.ts80
-rw-r--r--shared/extra-utils/users/blocklist.ts197
-rw-r--r--shared/extra-utils/users/login.ts62
-rw-r--r--shared/extra-utils/users/user-notifications.ts496
-rw-r--r--shared/extra-utils/users/user-subscriptions.ts82
-rw-r--r--shared/extra-utils/users/users.ts330
6 files changed, 1247 insertions, 0 deletions
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
new file mode 100644
index 000000000..f64a2dbad
--- /dev/null
+++ b/shared/extra-utils/users/accounts.ts
@@ -0,0 +1,80 @@
1/* tslint:disable:no-unused-expression */
2
3import * as request from 'supertest'
4import { expect } from 'chai'
5import { existsSync, readdir } from 'fs-extra'
6import { join } from 'path'
7import { Account } from '../../models/actors'
8import { root } from '../miscs/miscs'
9import { makeGetRequest } from '../requests/requests'
10import { VideoRateType } from '../../models/videos'
11
12function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = 200) {
13 const path = '/api/v1/accounts'
14
15 return makeGetRequest({
16 url,
17 query: { sort },
18 path,
19 statusCodeExpected
20 })
21}
22
23function getAccount (url: string, accountName: string, statusCodeExpected = 200) {
24 const path = '/api/v1/accounts/' + accountName
25
26 return makeGetRequest({
27 url,
28 path,
29 statusCodeExpected
30 })
31}
32
33async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) {
34 const res = await getAccountsList(url)
35 const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain)
36
37 const message = `${nameWithDomain} on ${url}`
38 expect(account.followersCount).to.equal(followersCount, message)
39 expect(account.followingCount).to.equal(followingCount, message)
40}
41
42async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) {
43 const testDirectory = 'test' + serverNumber
44
45 for (const directory of [ 'avatars' ]) {
46 const directoryPath = join(root(), testDirectory, directory)
47
48 const directoryExists = existsSync(directoryPath)
49 expect(directoryExists).to.be.true
50
51 const files = await readdir(directoryPath)
52 for (const file of files) {
53 expect(file).to.not.contain(actorUUID)
54 }
55 }
56}
57
58function getAccountRatings (url: string, accountName: string, accessToken: string, rating?: VideoRateType, statusCodeExpected = 200) {
59 const path = '/api/v1/accounts/' + accountName + '/ratings'
60
61 const query = rating ? { rating } : {}
62
63 return request(url)
64 .get(path)
65 .query(query)
66 .set('Accept', 'application/json')
67 .set('Authorization', 'Bearer ' + accessToken)
68 .expect(statusCodeExpected)
69 .expect('Content-Type', /json/)
70}
71
72// ---------------------------------------------------------------------------
73
74export {
75 getAccount,
76 expectAccountFollows,
77 getAccountsList,
78 checkActorFilesWereRemoved,
79 getAccountRatings
80}
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts
new file mode 100644
index 000000000..5feb84179
--- /dev/null
+++ b/shared/extra-utils/users/blocklist.ts
@@ -0,0 +1,197 @@
1/* tslint:disable:no-unused-expression */
2
3import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests'
4
5function getAccountBlocklistByAccount (
6 url: string,
7 token: string,
8 start: number,
9 count: number,
10 sort = '-createdAt',
11 statusCodeExpected = 200
12) {
13 const path = '/api/v1/users/me/blocklist/accounts'
14
15 return makeGetRequest({
16 url,
17 token,
18 query: { start, count, sort },
19 path,
20 statusCodeExpected
21 })
22}
23
24function addAccountToAccountBlocklist (url: string, token: string, accountToBlock: string, statusCodeExpected = 204) {
25 const path = '/api/v1/users/me/blocklist/accounts'
26
27 return makePostBodyRequest({
28 url,
29 path,
30 token,
31 fields: {
32 accountName: accountToBlock
33 },
34 statusCodeExpected
35 })
36}
37
38function removeAccountFromAccountBlocklist (url: string, token: string, accountToUnblock: string, statusCodeExpected = 204) {
39 const path = '/api/v1/users/me/blocklist/accounts/' + accountToUnblock
40
41 return makeDeleteRequest({
42 url,
43 path,
44 token,
45 statusCodeExpected
46 })
47}
48
49function getServerBlocklistByAccount (
50 url: string,
51 token: string,
52 start: number,
53 count: number,
54 sort = '-createdAt',
55 statusCodeExpected = 200
56) {
57 const path = '/api/v1/users/me/blocklist/servers'
58
59 return makeGetRequest({
60 url,
61 token,
62 query: { start, count, sort },
63 path,
64 statusCodeExpected
65 })
66}
67
68function addServerToAccountBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
69 const path = '/api/v1/users/me/blocklist/servers'
70
71 return makePostBodyRequest({
72 url,
73 path,
74 token,
75 fields: {
76 host: serverToBlock
77 },
78 statusCodeExpected
79 })
80}
81
82function removeServerFromAccountBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
83 const path = '/api/v1/users/me/blocklist/servers/' + serverToBlock
84
85 return makeDeleteRequest({
86 url,
87 path,
88 token,
89 statusCodeExpected
90 })
91}
92
93function getAccountBlocklistByServer (
94 url: string,
95 token: string,
96 start: number,
97 count: number,
98 sort = '-createdAt',
99 statusCodeExpected = 200
100) {
101 const path = '/api/v1/server/blocklist/accounts'
102
103 return makeGetRequest({
104 url,
105 token,
106 query: { start, count, sort },
107 path,
108 statusCodeExpected
109 })
110}
111
112function addAccountToServerBlocklist (url: string, token: string, accountToBlock: string, statusCodeExpected = 204) {
113 const path = '/api/v1/server/blocklist/accounts'
114
115 return makePostBodyRequest({
116 url,
117 path,
118 token,
119 fields: {
120 accountName: accountToBlock
121 },
122 statusCodeExpected
123 })
124}
125
126function removeAccountFromServerBlocklist (url: string, token: string, accountToUnblock: string, statusCodeExpected = 204) {
127 const path = '/api/v1/server/blocklist/accounts/' + accountToUnblock
128
129 return makeDeleteRequest({
130 url,
131 path,
132 token,
133 statusCodeExpected
134 })
135}
136
137function getServerBlocklistByServer (
138 url: string,
139 token: string,
140 start: number,
141 count: number,
142 sort = '-createdAt',
143 statusCodeExpected = 200
144) {
145 const path = '/api/v1/server/blocklist/servers'
146
147 return makeGetRequest({
148 url,
149 token,
150 query: { start, count, sort },
151 path,
152 statusCodeExpected
153 })
154}
155
156function addServerToServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
157 const path = '/api/v1/server/blocklist/servers'
158
159 return makePostBodyRequest({
160 url,
161 path,
162 token,
163 fields: {
164 host: serverToBlock
165 },
166 statusCodeExpected
167 })
168}
169
170function removeServerFromServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
171 const path = '/api/v1/server/blocklist/servers/' + serverToBlock
172
173 return makeDeleteRequest({
174 url,
175 path,
176 token,
177 statusCodeExpected
178 })
179}
180
181// ---------------------------------------------------------------------------
182
183export {
184 getAccountBlocklistByAccount,
185 addAccountToAccountBlocklist,
186 removeAccountFromAccountBlocklist,
187 getServerBlocklistByAccount,
188 addServerToAccountBlocklist,
189 removeServerFromAccountBlocklist,
190
191 getAccountBlocklistByServer,
192 addAccountToServerBlocklist,
193 removeAccountFromServerBlocklist,
194 getServerBlocklistByServer,
195 addServerToServerBlocklist,
196 removeServerFromServerBlocklist
197}
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts
new file mode 100644
index 000000000..ddeb9df2a
--- /dev/null
+++ b/shared/extra-utils/users/login.ts
@@ -0,0 +1,62 @@
1import * as request from 'supertest'
2
3import { ServerInfo } from '../server/servers'
4
5type Client = { id: string, secret: string }
6type User = { username: string, password: string }
7type Server = { url: string, client: Client, user: User }
8
9function login (url: string, client: Client, user: User, expectedStatus = 200) {
10 const path = '/api/v1/users/token'
11
12 const body = {
13 client_id: client.id,
14 client_secret: client.secret,
15 username: user.username,
16 password: user.password,
17 response_type: 'code',
18 grant_type: 'password',
19 scope: 'upload'
20 }
21
22 return request(url)
23 .post(path)
24 .type('form')
25 .send(body)
26 .expect(expectedStatus)
27}
28
29async function serverLogin (server: Server) {
30 const res = await login(server.url, server.client, server.user, 200)
31
32 return res.body.access_token as string
33}
34
35async function userLogin (server: Server, user: User, expectedStatus = 200) {
36 const res = await login(server.url, server.client, user, expectedStatus)
37
38 return res.body.access_token as string
39}
40
41function setAccessTokensToServers (servers: ServerInfo[]) {
42 const tasks: Promise<any>[] = []
43
44 for (const server of servers) {
45 const p = serverLogin(server).then(t => server.accessToken = t)
46 tasks.push(p)
47 }
48
49 return Promise.all(tasks)
50}
51
52// ---------------------------------------------------------------------------
53
54export {
55 login,
56 serverLogin,
57 userLogin,
58 setAccessTokensToServers,
59 Server,
60 Client,
61 User
62}
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
new file mode 100644
index 000000000..495ff80d9
--- /dev/null
+++ b/shared/extra-utils/users/user-notifications.ts
@@ -0,0 +1,496 @@
1/* tslint:disable:no-unused-expression */
2
3import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
4import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
5import { ServerInfo } from '..'
6import { expect } from 'chai'
7import { inspect } from 'util'
8
9function updateMyNotificationSettings (url: string, token: string, settings: UserNotificationSetting, statusCodeExpected = 204) {
10 const path = '/api/v1/users/me/notification-settings'
11
12 return makePutBodyRequest({
13 url,
14 path,
15 token,
16 fields: settings,
17 statusCodeExpected
18 })
19}
20
21async function getUserNotifications (
22 url: string,
23 token: string,
24 start: number,
25 count: number,
26 unread?: boolean,
27 sort = '-createdAt',
28 statusCodeExpected = 200
29) {
30 const path = '/api/v1/users/me/notifications'
31
32 return makeGetRequest({
33 url,
34 path,
35 token,
36 query: {
37 start,
38 count,
39 sort,
40 unread
41 },
42 statusCodeExpected
43 })
44}
45
46function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = 204) {
47 const path = '/api/v1/users/me/notifications/read'
48
49 return makePostBodyRequest({
50 url,
51 path,
52 token,
53 fields: { ids },
54 statusCodeExpected
55 })
56}
57function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
58 const path = '/api/v1/users/me/notifications/read-all'
59
60 return makePostBodyRequest({
61 url,
62 path,
63 token,
64 statusCodeExpected
65 })
66}
67
68async function getLastNotification (serverUrl: string, accessToken: string) {
69 const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt')
70
71 if (res.body.total === 0) return undefined
72
73 return res.body.data[0] as UserNotification
74}
75
76type CheckerBaseParams = {
77 server: ServerInfo
78 emails: object[]
79 socketNotifications: UserNotification[]
80 token: string,
81 check?: { web: boolean, mail: boolean }
82}
83
84type CheckerType = 'presence' | 'absence'
85
86async function checkNotification (
87 base: CheckerBaseParams,
88 notificationChecker: (notification: UserNotification, type: CheckerType) => void,
89 emailNotificationFinder: (email: object) => boolean,
90 checkType: CheckerType
91) {
92 const check = base.check || { web: true, mail: true }
93
94 if (check.web) {
95 const notification = await getLastNotification(base.server.url, base.token)
96
97 if (notification || checkType !== 'absence') {
98 notificationChecker(notification, checkType)
99 }
100
101 const socketNotification = base.socketNotifications.find(n => {
102 try {
103 notificationChecker(n, 'presence')
104 return true
105 } catch {
106 return false
107 }
108 })
109
110 if (checkType === 'presence') {
111 const obj = inspect(base.socketNotifications, { depth: 5 })
112 expect(socketNotification, 'The socket notification is absent. ' + obj).to.not.be.undefined
113 } else {
114 const obj = inspect(socketNotification, { depth: 5 })
115 expect(socketNotification, 'The socket notification is present. ' + obj).to.be.undefined
116 }
117 }
118
119 if (check.mail) {
120 // Last email
121 const email = base.emails
122 .slice()
123 .reverse()
124 .find(e => emailNotificationFinder(e))
125
126 if (checkType === 'presence') {
127 expect(email, 'The email is absent. ' + inspect(base.emails)).to.not.be.undefined
128 } else {
129 expect(email, 'The email is present. ' + inspect(email)).to.be.undefined
130 }
131 }
132}
133
134function checkVideo (video: any, videoName?: string, videoUUID?: string) {
135 expect(video.name).to.be.a('string')
136 expect(video.name).to.not.be.empty
137 if (videoName) expect(video.name).to.equal(videoName)
138
139 expect(video.uuid).to.be.a('string')
140 expect(video.uuid).to.not.be.empty
141 if (videoUUID) expect(video.uuid).to.equal(videoUUID)
142
143 expect(video.id).to.be.a('number')
144}
145
146function checkActor (actor: any) {
147 expect(actor.displayName).to.be.a('string')
148 expect(actor.displayName).to.not.be.empty
149 expect(actor.host).to.not.be.undefined
150}
151
152function checkComment (comment: any, commentId: number, threadId: number) {
153 expect(comment.id).to.equal(commentId)
154 expect(comment.threadId).to.equal(threadId)
155}
156
157async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
158 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
159
160 function notificationChecker (notification: UserNotification, type: CheckerType) {
161 if (type === 'presence') {
162 expect(notification).to.not.be.undefined
163 expect(notification.type).to.equal(notificationType)
164
165 checkVideo(notification.video, videoName, videoUUID)
166 checkActor(notification.video.channel)
167 } else {
168 expect(notification).to.satisfy((n: UserNotification) => {
169 return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
170 })
171 }
172 }
173
174 function emailFinder (email: object) {
175 const text = email[ 'text' ]
176 return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
177 }
178
179 await checkNotification(base, notificationChecker, emailFinder, type)
180}
181
182async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
183 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
184
185 function notificationChecker (notification: UserNotification, type: CheckerType) {
186 if (type === 'presence') {
187 expect(notification).to.not.be.undefined
188 expect(notification.type).to.equal(notificationType)
189
190 checkVideo(notification.video, videoName, videoUUID)
191 checkActor(notification.video.channel)
192 } else {
193 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
194 }
195 }
196
197 function emailFinder (email: object) {
198 const text: string = email[ 'text' ]
199 return text.includes(videoUUID) && text.includes('Your video')
200 }
201
202 await checkNotification(base, notificationChecker, emailFinder, type)
203}
204
205async function checkMyVideoImportIsFinished (
206 base: CheckerBaseParams,
207 videoName: string,
208 videoUUID: string,
209 url: string,
210 success: boolean,
211 type: CheckerType
212) {
213 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
214
215 function notificationChecker (notification: UserNotification, type: CheckerType) {
216 if (type === 'presence') {
217 expect(notification).to.not.be.undefined
218 expect(notification.type).to.equal(notificationType)
219
220 expect(notification.videoImport.targetUrl).to.equal(url)
221
222 if (success) checkVideo(notification.videoImport.video, videoName, videoUUID)
223 } else {
224 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
225 }
226 }
227
228 function emailFinder (email: object) {
229 const text: string = email[ 'text' ]
230 const toFind = success ? ' finished' : ' error'
231
232 return text.includes(url) && text.includes(toFind)
233 }
234
235 await checkNotification(base, notificationChecker, emailFinder, type)
236}
237
238async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
239 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
240
241 function notificationChecker (notification: UserNotification, type: CheckerType) {
242 if (type === 'presence') {
243 expect(notification).to.not.be.undefined
244 expect(notification.type).to.equal(notificationType)
245
246 checkActor(notification.account)
247 expect(notification.account.name).to.equal(username)
248 } else {
249 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
250 }
251 }
252
253 function emailFinder (email: object) {
254 const text: string = email[ 'text' ]
255
256 return text.includes(' registered ') && text.includes(username)
257 }
258
259 await checkNotification(base, notificationChecker, emailFinder, type)
260}
261
262async function checkNewActorFollow (
263 base: CheckerBaseParams,
264 followType: 'channel' | 'account',
265 followerName: string,
266 followerDisplayName: string,
267 followingDisplayName: string,
268 type: CheckerType
269) {
270 const notificationType = UserNotificationType.NEW_FOLLOW
271
272 function notificationChecker (notification: UserNotification, type: CheckerType) {
273 if (type === 'presence') {
274 expect(notification).to.not.be.undefined
275 expect(notification.type).to.equal(notificationType)
276
277 checkActor(notification.actorFollow.follower)
278 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
279 expect(notification.actorFollow.follower.name).to.equal(followerName)
280 expect(notification.actorFollow.follower.host).to.not.be.undefined
281
282 expect(notification.actorFollow.following.displayName).to.equal(followingDisplayName)
283 expect(notification.actorFollow.following.type).to.equal(followType)
284 } else {
285 expect(notification).to.satisfy(n => {
286 return n.type !== notificationType ||
287 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
288 })
289 }
290 }
291
292 function emailFinder (email: object) {
293 const text: string = email[ 'text' ]
294
295 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
296 }
297
298 await checkNotification(base, notificationChecker, emailFinder, type)
299}
300
301async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) {
302 const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
303
304 function notificationChecker (notification: UserNotification, type: CheckerType) {
305 if (type === 'presence') {
306 expect(notification).to.not.be.undefined
307 expect(notification.type).to.equal(notificationType)
308
309 checkActor(notification.actorFollow.follower)
310 expect(notification.actorFollow.follower.name).to.equal('peertube')
311 expect(notification.actorFollow.follower.host).to.equal(followerHost)
312
313 expect(notification.actorFollow.following.name).to.equal('peertube')
314 } else {
315 expect(notification).to.satisfy(n => {
316 return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
317 })
318 }
319 }
320
321 function emailFinder (email: object) {
322 const text: string = email[ 'text' ]
323
324 return text.includes('instance has a new follower') && text.includes(followerHost)
325 }
326
327 await checkNotification(base, notificationChecker, emailFinder, type)
328}
329
330async function checkCommentMention (
331 base: CheckerBaseParams,
332 uuid: string,
333 commentId: number,
334 threadId: number,
335 byAccountDisplayName: string,
336 type: CheckerType
337) {
338 const notificationType = UserNotificationType.COMMENT_MENTION
339
340 function notificationChecker (notification: UserNotification, type: CheckerType) {
341 if (type === 'presence') {
342 expect(notification).to.not.be.undefined
343 expect(notification.type).to.equal(notificationType)
344
345 checkComment(notification.comment, commentId, threadId)
346 checkActor(notification.comment.account)
347 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
348
349 checkVideo(notification.comment.video, undefined, uuid)
350 } else {
351 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
352 }
353 }
354
355 function emailFinder (email: object) {
356 const text: string = email[ 'text' ]
357
358 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
359 }
360
361 await checkNotification(base, notificationChecker, emailFinder, type)
362}
363
364let lastEmailCount = 0
365async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
366 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
367
368 function notificationChecker (notification: UserNotification, type: CheckerType) {
369 if (type === 'presence') {
370 expect(notification).to.not.be.undefined
371 expect(notification.type).to.equal(notificationType)
372
373 checkComment(notification.comment, commentId, threadId)
374 checkActor(notification.comment.account)
375 checkVideo(notification.comment.video, undefined, uuid)
376 } else {
377 expect(notification).to.satisfy((n: UserNotification) => {
378 return n === undefined || n.comment === undefined || n.comment.id !== commentId
379 })
380 }
381 }
382
383 const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
384 function emailFinder (email: object) {
385 return email[ 'text' ].indexOf(commentUrl) !== -1
386 }
387
388 await checkNotification(base, notificationChecker, emailFinder, type)
389
390 if (type === 'presence') {
391 // We cannot detect email duplicates, so check we received another email
392 expect(base.emails).to.have.length.above(lastEmailCount)
393 lastEmailCount = base.emails.length
394 }
395}
396
397async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
398 const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
399
400 function notificationChecker (notification: UserNotification, type: CheckerType) {
401 if (type === 'presence') {
402 expect(notification).to.not.be.undefined
403 expect(notification.type).to.equal(notificationType)
404
405 expect(notification.videoAbuse.id).to.be.a('number')
406 checkVideo(notification.videoAbuse.video, videoName, videoUUID)
407 } else {
408 expect(notification).to.satisfy((n: UserNotification) => {
409 return n === undefined || n.videoAbuse === undefined || n.videoAbuse.video.uuid !== videoUUID
410 })
411 }
412 }
413
414 function emailFinder (email: object) {
415 const text = email[ 'text' ]
416 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
417 }
418
419 await checkNotification(base, notificationChecker, emailFinder, type)
420}
421
422async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
423 const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
424
425 function notificationChecker (notification: UserNotification, type: CheckerType) {
426 if (type === 'presence') {
427 expect(notification).to.not.be.undefined
428 expect(notification.type).to.equal(notificationType)
429
430 expect(notification.video.id).to.be.a('number')
431 checkVideo(notification.video, videoName, videoUUID)
432 } else {
433 expect(notification).to.satisfy((n: UserNotification) => {
434 return n === undefined || n.video === undefined || n.video.uuid !== videoUUID
435 })
436 }
437 }
438
439 function emailFinder (email: object) {
440 const text = email[ 'text' ]
441 return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1
442 }
443
444 await checkNotification(base, notificationChecker, emailFinder, type)
445}
446
447async function checkNewBlacklistOnMyVideo (
448 base: CheckerBaseParams,
449 videoUUID: string,
450 videoName: string,
451 blacklistType: 'blacklist' | 'unblacklist'
452) {
453 const notificationType = blacklistType === 'blacklist'
454 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
455 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
456
457 function notificationChecker (notification: UserNotification) {
458 expect(notification).to.not.be.undefined
459 expect(notification.type).to.equal(notificationType)
460
461 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
462
463 checkVideo(video, videoName, videoUUID)
464 }
465
466 function emailFinder (email: object) {
467 const text = email[ 'text' ]
468 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
469 }
470
471 await checkNotification(base, notificationChecker, emailFinder, 'presence')
472}
473
474// ---------------------------------------------------------------------------
475
476export {
477 CheckerBaseParams,
478 CheckerType,
479 checkNotification,
480 markAsReadAllNotifications,
481 checkMyVideoImportIsFinished,
482 checkUserRegistered,
483 checkVideoIsPublished,
484 checkNewVideoFromSubscription,
485 checkNewActorFollow,
486 checkNewCommentOnMyVideo,
487 checkNewBlacklistOnMyVideo,
488 checkCommentMention,
489 updateMyNotificationSettings,
490 checkNewVideoAbuseForModerators,
491 checkVideoAutoBlacklistForModerators,
492 getUserNotifications,
493 markAsReadNotifications,
494 getLastNotification,
495 checkNewInstanceFollower
496}
diff --git a/shared/extra-utils/users/user-subscriptions.ts b/shared/extra-utils/users/user-subscriptions.ts
new file mode 100644
index 000000000..7148fbfca
--- /dev/null
+++ b/shared/extra-utils/users/user-subscriptions.ts
@@ -0,0 +1,82 @@
1import { makeDeleteRequest, makeGetRequest, makePostBodyRequest } from '../requests/requests'
2
3function addUserSubscription (url: string, token: string, targetUri: string, statusCodeExpected = 204) {
4 const path = '/api/v1/users/me/subscriptions'
5
6 return makePostBodyRequest({
7 url,
8 path,
9 token,
10 statusCodeExpected,
11 fields: { uri: targetUri }
12 })
13}
14
15function listUserSubscriptions (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
16 const path = '/api/v1/users/me/subscriptions'
17
18 return makeGetRequest({
19 url,
20 path,
21 token,
22 statusCodeExpected,
23 query: { sort }
24 })
25}
26
27function listUserSubscriptionVideos (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
28 const path = '/api/v1/users/me/subscriptions/videos'
29
30 return makeGetRequest({
31 url,
32 path,
33 token,
34 statusCodeExpected,
35 query: { sort }
36 })
37}
38
39function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 200) {
40 const path = '/api/v1/users/me/subscriptions/' + uri
41
42 return makeGetRequest({
43 url,
44 path,
45 token,
46 statusCodeExpected
47 })
48}
49
50function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) {
51 const path = '/api/v1/users/me/subscriptions/' + uri
52
53 return makeDeleteRequest({
54 url,
55 path,
56 token,
57 statusCodeExpected
58 })
59}
60
61function areSubscriptionsExist (url: string, token: string, uris: string[], statusCodeExpected = 200) {
62 const path = '/api/v1/users/me/subscriptions/exist'
63
64 return makeGetRequest({
65 url,
66 path,
67 query: { 'uris[]': uris },
68 token,
69 statusCodeExpected
70 })
71}
72
73// ---------------------------------------------------------------------------
74
75export {
76 areSubscriptionsExist,
77 addUserSubscription,
78 listUserSubscriptions,
79 getUserSubscription,
80 listUserSubscriptionVideos,
81 removeUserSubscription
82}
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
new file mode 100644
index 000000000..2bd37b8be
--- /dev/null
+++ b/shared/extra-utils/users/users.ts
@@ -0,0 +1,330 @@
1import * as request from 'supertest'
2import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
3
4import { UserRole } from '../../index'
5import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
6import { ServerInfo, userLogin } from '..'
7import { UserAdminFlag } from '../../models/users/user-flag.model'
8
9type CreateUserArgs = { url: string,
10 accessToken: string,
11 username: string,
12 password: string,
13 videoQuota?: number,
14 videoQuotaDaily?: number,
15 role?: UserRole,
16 adminFlags?: UserAdminFlag,
17 specialStatus?: number
18}
19function createUser (parameters: CreateUserArgs) {
20 const {
21 url,
22 accessToken,
23 username,
24 adminFlags,
25 password = 'password',
26 videoQuota = 1000000,
27 videoQuotaDaily = -1,
28 role = UserRole.USER,
29 specialStatus = 200
30 } = parameters
31
32 const path = '/api/v1/users'
33 const body = {
34 username,
35 password,
36 role,
37 adminFlags,
38 email: username + '@example.com',
39 videoQuota,
40 videoQuotaDaily
41 }
42
43 return request(url)
44 .post(path)
45 .set('Accept', 'application/json')
46 .set('Authorization', 'Bearer ' + accessToken)
47 .send(body)
48 .expect(specialStatus)
49}
50
51async function generateUserAccessToken (server: ServerInfo, username: string) {
52 const password = 'my super password'
53 await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
54
55 return userLogin(server, { username, password })
56}
57
58function registerUser (url: string, username: string, password: string, specialStatus = 204) {
59 const path = '/api/v1/users/register'
60 const body = {
61 username,
62 password,
63 email: username + '@example.com'
64 }
65
66 return request(url)
67 .post(path)
68 .set('Accept', 'application/json')
69 .send(body)
70 .expect(specialStatus)
71}
72
73function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) {
74 const path = '/api/v1/users/me'
75
76 return request(url)
77 .get(path)
78 .set('Accept', 'application/json')
79 .set('Authorization', 'Bearer ' + accessToken)
80 .expect(specialStatus)
81 .expect('Content-Type', /json/)
82}
83
84function deleteMe (url: string, accessToken: string, specialStatus = 204) {
85 const path = '/api/v1/users/me'
86
87 return request(url)
88 .delete(path)
89 .set('Accept', 'application/json')
90 .set('Authorization', 'Bearer ' + accessToken)
91 .expect(specialStatus)
92}
93
94function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = 200) {
95 const path = '/api/v1/users/me/video-quota-used'
96
97 return request(url)
98 .get(path)
99 .set('Accept', 'application/json')
100 .set('Authorization', 'Bearer ' + accessToken)
101 .expect(specialStatus)
102 .expect('Content-Type', /json/)
103}
104
105function getUserInformation (url: string, accessToken: string, userId: number) {
106 const path = '/api/v1/users/' + userId
107
108 return request(url)
109 .get(path)
110 .set('Accept', 'application/json')
111 .set('Authorization', 'Bearer ' + accessToken)
112 .expect(200)
113 .expect('Content-Type', /json/)
114}
115
116function getMyUserVideoRating (url: string, accessToken: string, videoId: number | string, specialStatus = 200) {
117 const path = '/api/v1/users/me/videos/' + videoId + '/rating'
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
127function getUsersList (url: string, accessToken: string) {
128 const path = '/api/v1/users'
129
130 return request(url)
131 .get(path)
132 .set('Accept', 'application/json')
133 .set('Authorization', 'Bearer ' + accessToken)
134 .expect(200)
135 .expect('Content-Type', /json/)
136}
137
138function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) {
139 const path = '/api/v1/users'
140
141 return request(url)
142 .get(path)
143 .query({ start })
144 .query({ count })
145 .query({ sort })
146 .query({ search })
147 .set('Accept', 'application/json')
148 .set('Authorization', 'Bearer ' + accessToken)
149 .expect(200)
150 .expect('Content-Type', /json/)
151}
152
153function removeUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
154 const path = '/api/v1/users'
155
156 return request(url)
157 .delete(path + '/' + userId)
158 .set('Accept', 'application/json')
159 .set('Authorization', 'Bearer ' + accessToken)
160 .expect(expectedStatus)
161}
162
163function blockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204, reason?: string) {
164 const path = '/api/v1/users'
165 let body: any
166 if (reason) body = { reason }
167
168 return request(url)
169 .post(path + '/' + userId + '/block')
170 .send(body)
171 .set('Accept', 'application/json')
172 .set('Authorization', 'Bearer ' + accessToken)
173 .expect(expectedStatus)
174}
175
176function unblockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
177 const path = '/api/v1/users'
178
179 return request(url)
180 .post(path + '/' + userId + '/unblock')
181 .set('Accept', 'application/json')
182 .set('Authorization', 'Bearer ' + accessToken)
183 .expect(expectedStatus)
184}
185
186function updateMyUser (options: {
187 url: string
188 accessToken: string
189 currentPassword?: string
190 newPassword?: string
191 nsfwPolicy?: NSFWPolicyType
192 email?: string
193 autoPlayVideo?: boolean
194 displayName?: string
195 description?: string
196 videosHistoryEnabled?: boolean
197}) {
198 const path = '/api/v1/users/me'
199
200 const toSend = {}
201 if (options.currentPassword !== undefined && options.currentPassword !== null) toSend['currentPassword'] = options.currentPassword
202 if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword
203 if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend['nsfwPolicy'] = options.nsfwPolicy
204 if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
205 if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
206 if (options.description !== undefined && options.description !== null) toSend['description'] = options.description
207 if (options.displayName !== undefined && options.displayName !== null) toSend['displayName'] = options.displayName
208 if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) {
209 toSend['videosHistoryEnabled'] = options.videosHistoryEnabled
210 }
211
212 return makePutBodyRequest({
213 url: options.url,
214 path,
215 token: options.accessToken,
216 fields: toSend,
217 statusCodeExpected: 204
218 })
219}
220
221function updateMyAvatar (options: {
222 url: string,
223 accessToken: string,
224 fixture: string
225}) {
226 const path = '/api/v1/users/me/avatar/pick'
227
228 return updateAvatarRequest(Object.assign(options, { path }))
229}
230
231function updateUser (options: {
232 url: string
233 userId: number,
234 accessToken: string,
235 email?: string,
236 emailVerified?: boolean,
237 videoQuota?: number,
238 videoQuotaDaily?: number,
239 password?: string,
240 adminFlags?: UserAdminFlag,
241 role?: UserRole
242}) {
243 const path = '/api/v1/users/' + options.userId
244
245 const toSend = {}
246 if (options.password !== undefined && options.password !== null) toSend['password'] = options.password
247 if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
248 if (options.emailVerified !== undefined && options.emailVerified !== null) toSend['emailVerified'] = options.emailVerified
249 if (options.videoQuota !== undefined && options.videoQuota !== null) toSend['videoQuota'] = options.videoQuota
250 if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend['videoQuotaDaily'] = options.videoQuotaDaily
251 if (options.role !== undefined && options.role !== null) toSend['role'] = options.role
252 if (options.adminFlags !== undefined && options.adminFlags !== null) toSend['adminFlags'] = options.adminFlags
253
254 return makePutBodyRequest({
255 url: options.url,
256 path,
257 token: options.accessToken,
258 fields: toSend,
259 statusCodeExpected: 204
260 })
261}
262
263function askResetPassword (url: string, email: string) {
264 const path = '/api/v1/users/ask-reset-password'
265
266 return makePostBodyRequest({
267 url,
268 path,
269 fields: { email },
270 statusCodeExpected: 204
271 })
272}
273
274function resetPassword (url: string, userId: number, verificationString: string, password: string, statusCodeExpected = 204) {
275 const path = '/api/v1/users/' + userId + '/reset-password'
276
277 return makePostBodyRequest({
278 url,
279 path,
280 fields: { password, verificationString },
281 statusCodeExpected
282 })
283}
284
285function askSendVerifyEmail (url: string, email: string) {
286 const path = '/api/v1/users/ask-send-verify-email'
287
288 return makePostBodyRequest({
289 url,
290 path,
291 fields: { email },
292 statusCodeExpected: 204
293 })
294}
295
296function verifyEmail (url: string, userId: number, verificationString: string, statusCodeExpected = 204) {
297 const path = '/api/v1/users/' + userId + '/verify-email'
298
299 return makePostBodyRequest({
300 url,
301 path,
302 fields: { verificationString },
303 statusCodeExpected
304 })
305}
306
307// ---------------------------------------------------------------------------
308
309export {
310 createUser,
311 registerUser,
312 getMyUserInformation,
313 getMyUserVideoRating,
314 deleteMe,
315 getMyUserVideoQuotaUsed,
316 getUsersList,
317 getUsersListPaginationAndSort,
318 removeUser,
319 updateUser,
320 updateMyUser,
321 getUserInformation,
322 blockUser,
323 unblockUser,
324 askResetPassword,
325 resetPassword,
326 updateMyAvatar,
327 askSendVerifyEmail,
328 generateUserAccessToken,
329 verifyEmail
330}