From 7ad9b9846c44d198a736183fb186c2039f5236b5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 12 Oct 2018 15:26:04 +0200 Subject: Add ability for users to block an account/instance on server side --- server/tests/api/check-params/blocklist.ts | 222 +++++++++++++++++++++ server/tests/api/check-params/index.ts | 1 + server/tests/api/users/account-blocklist.ts | 294 ++++++++++++++++++++++++++++ server/tests/utils/requests/requests.ts | 4 +- server/tests/utils/users/blocklist.ts | 103 ++++++++++ server/tests/utils/videos/video-comments.ts | 14 +- 6 files changed, 630 insertions(+), 8 deletions(-) create mode 100644 server/tests/api/check-params/blocklist.ts create mode 100644 server/tests/api/users/account-blocklist.ts create mode 100644 server/tests/utils/users/blocklist.ts (limited to 'server/tests') diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts new file mode 100644 index 000000000..8117c46a6 --- /dev/null +++ b/server/tests/api/check-params/blocklist.ts @@ -0,0 +1,222 @@ +/* tslint:disable:no-unused-expression */ + +import 'mocha' + +import { + createUser, + doubleFollow, + flushAndRunMultipleServers, + flushTests, + killallServers, + makeDeleteRequest, + makeGetRequest, + makePostBodyRequest, + ServerInfo, + setAccessTokensToServers +} from '../../utils' +import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params' + +describe('Test blocklist API validators', function () { + let servers: ServerInfo[] + let server: ServerInfo + + before(async function () { + this.timeout(60000) + + await flushTests() + + servers = await flushAndRunMultipleServers(2) + await setAccessTokensToServers(servers) + + server = servers[0] + + const user = { username: 'user1', password: 'password' } + await createUser(server.url, server.accessToken, user.username, user.password) + + await doubleFollow(servers[0], servers[1]) + }) + + // --------------------------------------------------------------- + + describe('When managing user blocklist', function () { + const path = '/api/v1/users/me/blocklist/accounts' + + describe('When managing user accounts blocklist', function () { + + describe('When listing blocked accounts', function () { + it('Should fail with an unauthenticated user', async function () { + await makeGetRequest({ + url: server.url, + path, + statusCodeExpected: 401 + }) + }) + + it('Should fail with a bad start pagination', async function () { + await checkBadStartPagination(server.url, path, server.accessToken) + }) + + it('Should fail with a bad count pagination', async function () { + await checkBadCountPagination(server.url, path, server.accessToken) + }) + + it('Should fail with an incorrect sort', async function () { + await checkBadSortPagination(server.url, path, server.accessToken) + }) + }) + + describe('When blocking an account', function () { + it('Should fail with an unauthenticated user', async function () { + await makePostBodyRequest({ + url: server.url, + path, + fields: { accountName: 'user1' }, + statusCodeExpected: 401 + }) + }) + + it('Should fail with an unknown account', async function () { + await makePostBodyRequest({ + url: server.url, + token: server.accessToken, + path, + fields: { accountName: 'user2' }, + statusCodeExpected: 404 + }) + }) + + it('Should succeed with the correct params', async function () { + await makePostBodyRequest({ + url: server.url, + token: server.accessToken, + path, + fields: { accountName: 'user1' }, + statusCodeExpected: 204 + }) + }) + }) + + describe('When unblocking an account', function () { + it('Should fail with an unauthenticated user', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/user1', + statusCodeExpected: 401 + }) + }) + + it('Should fail with an unknown account block', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/user2', + token: server.accessToken, + statusCodeExpected: 404 + }) + }) + + it('Should succeed with the correct params', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/user1', + token: server.accessToken, + statusCodeExpected: 204 + }) + }) + }) + }) + + describe('When managing user servers blocklist', function () { + const path = '/api/v1/users/me/blocklist/servers' + + describe('When listing blocked servers', function () { + it('Should fail with an unauthenticated user', async function () { + await makeGetRequest({ + url: server.url, + path, + statusCodeExpected: 401 + }) + }) + + it('Should fail with a bad start pagination', async function () { + await checkBadStartPagination(server.url, path, server.accessToken) + }) + + it('Should fail with a bad count pagination', async function () { + await checkBadCountPagination(server.url, path, server.accessToken) + }) + + it('Should fail with an incorrect sort', async function () { + await checkBadSortPagination(server.url, path, server.accessToken) + }) + }) + + describe('When blocking a server', function () { + it('Should fail with an unauthenticated user', async function () { + await makePostBodyRequest({ + url: server.url, + path, + fields: { host: 'localhost:9002' }, + statusCodeExpected: 401 + }) + }) + + it('Should fail with an unknown server', async function () { + await makePostBodyRequest({ + url: server.url, + token: server.accessToken, + path, + fields: { host: 'localhost:9003' }, + statusCodeExpected: 404 + }) + }) + + it('Should succeed with the correct params', async function () { + await makePostBodyRequest({ + url: server.url, + token: server.accessToken, + path, + fields: { host: 'localhost:9002' }, + statusCodeExpected: 204 + }) + }) + }) + + describe('When unblocking a server', function () { + it('Should fail with an unauthenticated user', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/localhost:9002', + statusCodeExpected: 401 + }) + }) + + it('Should fail with an unknown server block', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/localhost:9003', + token: server.accessToken, + statusCodeExpected: 404 + }) + }) + + it('Should succeed with the correct params', async function () { + await makeDeleteRequest({ + url: server.url, + path: path + '/localhost:9002', + token: server.accessToken, + statusCodeExpected: 204 + }) + }) + }) + }) + }) + + after(async function () { + killallServers(servers) + + // Keep the logs if the test failed + if (this['ok']) { + await flushTests() + } + }) +}) diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index bfc550ae5..877ceb0a7 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts @@ -1,5 +1,6 @@ // Order of the tests we want to execute import './accounts' +import './blocklist' import './config' import './follows' import './jobs' diff --git a/server/tests/api/users/account-blocklist.ts b/server/tests/api/users/account-blocklist.ts new file mode 100644 index 000000000..00ad51461 --- /dev/null +++ b/server/tests/api/users/account-blocklist.ts @@ -0,0 +1,294 @@ +/* tslint:disable:no-unused-expression */ + +import * as chai from 'chai' +import 'mocha' +import { AccountBlock, ServerBlock, Video } from '../../../../shared/index' +import { + createUser, + doubleFollow, + flushAndRunMultipleServers, + flushTests, + killallServers, + ServerInfo, + uploadVideo, + userLogin +} from '../../utils/index' +import { setAccessTokensToServers } from '../../utils/users/login' +import { getVideosListWithToken } from '../../utils/videos/videos' +import { + addVideoCommentReply, + addVideoCommentThread, + getVideoCommentThreads, + getVideoThreadComments +} from '../../utils/videos/video-comments' +import { waitJobs } from '../../utils/server/jobs' +import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' +import { + addAccountToAccountBlocklist, + addServerToAccountBlocklist, + getAccountBlocklistByAccount, getServerBlocklistByAccount, + removeAccountFromAccountBlocklist, + removeServerFromAccountBlocklist +} from '../../utils/users/blocklist' + +const expect = chai.expect + +async function checkAllVideos (url: string, token: string) { + const res = await getVideosListWithToken(url, token) + + expect(res.body.data).to.have.lengthOf(4) +} + +async function checkAllComments (url: string, token: string, videoUUID: string) { + const resThreads = await getVideoCommentThreads(url, videoUUID, 0, 5, '-createdAt', token) + + const threads: VideoComment[] = resThreads.body.data + expect(threads).to.have.lengthOf(2) + + for (const thread of threads) { + const res = await getVideoThreadComments(url, videoUUID, thread.id, token) + + const tree: VideoCommentThreadTree = res.body + expect(tree.children).to.have.lengthOf(1) + } +} + +describe('Test accounts blocklist', function () { + let servers: ServerInfo[] + let videoUUID1: string + let videoUUID2: string + let userToken1: string + let userToken2: string + + before(async function () { + this.timeout(60000) + + await flushTests() + + servers = await flushAndRunMultipleServers(2) + await setAccessTokensToServers(servers) + + { + const user = { username: 'user1', password: 'password' } + await createUser(servers[0].url, servers[0].accessToken, user.username, user.password) + + userToken1 = await userLogin(servers[0], user) + await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) + } + + { + const user = { username: 'user2', password: 'password' } + await createUser(servers[1].url, servers[1].accessToken, user.username, user.password) + + userToken2 = await userLogin(servers[1], user) + await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) + } + + { + const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video server 1' }) + videoUUID1 = res.body.video.uuid + } + + { + const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video server 2' }) + videoUUID2 = res.body.video.uuid + } + + await doubleFollow(servers[0], servers[1]) + + { + const resComment = await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, 'comment root 1') + const resReply = await addVideoCommentReply(servers[ 0 ].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') + await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') + } + + { + const resComment = await addVideoCommentThread(servers[ 0 ].url, userToken1, videoUUID1, 'comment user 1') + await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') + } + + await waitJobs(servers) + }) + + describe('When managing account blocklist', function () { + it('Should list all videos', function () { + return checkAllVideos(servers[0].url, servers[0].accessToken) + }) + + it('Should list the comments', function () { + return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) + }) + + it('Should block a remote account', async function () { + await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:9002') + }) + + it('Should hide its videos', async function () { + const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) + + const videos: Video[] = res.body.data + expect(videos).to.have.lengthOf(3) + + const v = videos.find(v => v.name === 'video user 2') + expect(v).to.be.undefined + }) + + it('Should block a local account', async function () { + await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') + }) + + it('Should hide its videos', async function () { + const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) + + const videos: Video[] = res.body.data + expect(videos).to.have.lengthOf(2) + + const v = videos.find(v => v.name === 'video user 1') + expect(v).to.be.undefined + }) + + it('Should hide its comments', async function () { + const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken) + + const threads: VideoComment[] = resThreads.body.data + expect(threads).to.have.lengthOf(1) + expect(threads[0].totalReplies).to.equal(0) + + const t = threads.find(t => t.text === 'comment user 1') + expect(t).to.be.undefined + + for (const thread of threads) { + const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, servers[0].accessToken) + + const tree: VideoCommentThreadTree = res.body + expect(tree.children).to.have.lengthOf(0) + } + }) + + it('Should list all the videos with another user', async function () { + return checkAllVideos(servers[0].url, userToken1) + }) + + it('Should list all the comments with another user', async function () { + return checkAllComments(servers[0].url, userToken1, videoUUID1) + }) + + it('Should list blocked accounts', async function () { + { + const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') + const blocks: AccountBlock[] = res.body.data + + expect(res.body.total).to.equal(2) + + const block = blocks[0] + expect(block.byAccount.displayName).to.equal('root') + expect(block.byAccount.name).to.equal('root') + expect(block.accountBlocked.displayName).to.equal('user2') + expect(block.accountBlocked.name).to.equal('user2') + expect(block.accountBlocked.host).to.equal('localhost:9002') + } + + { + const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') + const blocks: AccountBlock[] = res.body.data + + expect(res.body.total).to.equal(2) + + const block = blocks[0] + expect(block.byAccount.displayName).to.equal('root') + expect(block.byAccount.name).to.equal('root') + expect(block.accountBlocked.displayName).to.equal('user1') + expect(block.accountBlocked.name).to.equal('user1') + expect(block.accountBlocked.host).to.equal('localhost:9001') + } + }) + + it('Should unblock the remote account', async function () { + await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:9002') + }) + + it('Should display its videos', async function () { + const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) + + const videos: Video[] = res.body.data + expect(videos).to.have.lengthOf(3) + + const v = videos.find(v => v.name === 'video user 2') + expect(v).not.to.be.undefined + }) + + it('Should unblock the local account', async function () { + await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') + }) + + it('Should display its comments', function () { + return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) + }) + }) + + describe('When managing server blocklist', function () { + it('Should list all videos', function () { + return checkAllVideos(servers[0].url, servers[0].accessToken) + }) + + it('Should list the comments', function () { + return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) + }) + + it('Should block a remote server', async function () { + await addServerToAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:9002') + }) + + it('Should hide its videos', async function () { + const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) + + const videos: Video[] = res.body.data + expect(videos).to.have.lengthOf(2) + + const v1 = videos.find(v => v.name === 'video user 2') + const v2 = videos.find(v => v.name === 'video server 2') + + expect(v1).to.be.undefined + expect(v2).to.be.undefined + }) + + it('Should list all the videos with another user', async function () { + return checkAllVideos(servers[0].url, userToken1) + }) + + it('Should hide its comments') + + it('Should list blocked servers', async function () { + const res = await getServerBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') + const blocks: ServerBlock[] = res.body.data + + expect(res.body.total).to.equal(1) + + const block = blocks[0] + expect(block.byAccount.displayName).to.equal('root') + expect(block.byAccount.name).to.equal('root') + expect(block.serverBlocked.host).to.equal('localhost:9002') + }) + + it('Should unblock the remote server', async function () { + await removeServerFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:9002') + }) + + it('Should display its videos', function () { + return checkAllVideos(servers[0].url, servers[0].accessToken) + }) + + it('Should display its comments', function () { + return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) + }) + }) + + after(async function () { + killallServers(servers) + + // Keep the logs if the test failed + if (this[ 'ok' ]) { + await flushTests() + } + }) +}) diff --git a/server/tests/utils/requests/requests.ts b/server/tests/utils/requests/requests.ts index 27a529eda..5796540f7 100644 --- a/server/tests/utils/requests/requests.ts +++ b/server/tests/utils/requests/requests.ts @@ -37,9 +37,7 @@ function makeDeleteRequest (options: { if (options.token) req.set('Authorization', 'Bearer ' + options.token) - return req - .expect('Content-Type', /json/) - .expect(options.statusCodeExpected) + return req.expect(options.statusCodeExpected) } function makeUploadRequest (options: { diff --git a/server/tests/utils/users/blocklist.ts b/server/tests/utils/users/blocklist.ts new file mode 100644 index 000000000..47b315480 --- /dev/null +++ b/server/tests/utils/users/blocklist.ts @@ -0,0 +1,103 @@ +/* tslint:disable:no-unused-expression */ + +import { makeDeleteRequest, makePostBodyRequest } from '../index' +import { makeGetRequest } from '../requests/requests' + +function getAccountBlocklistByAccount ( + url: string, + token: string, + start: number, + count: number, + sort = '-createdAt', + statusCodeExpected = 200 +) { + const path = '/api/v1/users/me/blocklist/accounts' + + return makeGetRequest({ + url, + token, + query: { start, count, sort }, + path, + statusCodeExpected + }) +} + +function addAccountToAccountBlocklist (url: string, token: string, accountToBlock: string, statusCodeExpected = 204) { + const path = '/api/v1/users/me/blocklist/accounts' + + return makePostBodyRequest({ + url, + path, + token, + fields: { + accountName: accountToBlock + }, + statusCodeExpected + }) +} + +function removeAccountFromAccountBlocklist (url: string, token: string, accountToUnblock: string, statusCodeExpected = 204) { + const path = '/api/v1/users/me/blocklist/accounts/' + accountToUnblock + + return makeDeleteRequest({ + url, + path, + token, + statusCodeExpected + }) +} + +function getServerBlocklistByAccount ( + url: string, + token: string, + start: number, + count: number, + sort = '-createdAt', + statusCodeExpected = 200 +) { + const path = '/api/v1/users/me/blocklist/servers' + + return makeGetRequest({ + url, + token, + query: { start, count, sort }, + path, + statusCodeExpected + }) +} + +function addServerToAccountBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) { + const path = '/api/v1/users/me/blocklist/servers' + + return makePostBodyRequest({ + url, + path, + token, + fields: { + host: serverToBlock + }, + statusCodeExpected + }) +} + +function removeServerFromAccountBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) { + const path = '/api/v1/users/me/blocklist/servers/' + serverToBlock + + return makeDeleteRequest({ + url, + path, + token, + statusCodeExpected + }) +} + +// --------------------------------------------------------------------------- + +export { + getAccountBlocklistByAccount, + addAccountToAccountBlocklist, + removeAccountFromAccountBlocklist, + getServerBlocklistByAccount, + addServerToAccountBlocklist, + removeServerFromAccountBlocklist +} diff --git a/server/tests/utils/videos/video-comments.ts b/server/tests/utils/videos/video-comments.ts index 1b9ee452e..7d4cae364 100644 --- a/server/tests/utils/videos/video-comments.ts +++ b/server/tests/utils/videos/video-comments.ts @@ -1,7 +1,7 @@ import * as request from 'supertest' import { makeDeleteRequest } from '../' -function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string) { +function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string, token?: string) { const path = '/api/v1/videos/' + videoId + '/comment-threads' const req = request(url) @@ -10,20 +10,24 @@ function getVideoCommentThreads (url: string, videoId: number | string, start: n .query({ count: count }) if (sort) req.query({ sort }) + if (token) req.set('Authorization', 'Bearer ' + token) return req.set('Accept', 'application/json') .expect(200) .expect('Content-Type', /json/) } -function getVideoThreadComments (url: string, videoId: number | string, threadId: number) { +function getVideoThreadComments (url: string, videoId: number | string, threadId: number, token?: string) { const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId - return request(url) + const req = request(url) .get(path) .set('Accept', 'application/json') - .expect(200) - .expect('Content-Type', /json/) + + if (token) req.set('Authorization', 'Bearer ' + token) + + return req.expect(200) + .expect('Content-Type', /json/) } function addVideoCommentThread (url: string, token: string, videoId: number | string, text: string, expectedStatus = 200) { -- cgit v1.2.3