Shared utils -> extra-utils
authorChocobozzz <me@florianbigard.com>
Mon, 15 Apr 2019 13:26:15 +0000 (15:26 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 24 Apr 2019 14:25:52 +0000 (16:25 +0200)
Because they need dev dependencies

174 files changed:
server/tests/api/activitypub/client.ts
server/tests/api/activitypub/fetch.ts
server/tests/api/activitypub/helpers.ts
server/tests/api/activitypub/refresher.ts
server/tests/api/activitypub/security.ts
server/tests/api/check-params/accounts.ts
server/tests/api/check-params/blocklist.ts
server/tests/api/check-params/config.ts
server/tests/api/check-params/contact-form.ts
server/tests/api/check-params/debug.ts
server/tests/api/check-params/follows.ts
server/tests/api/check-params/jobs.ts
server/tests/api/check-params/logs.ts
server/tests/api/check-params/redundancy.ts
server/tests/api/check-params/search.ts
server/tests/api/check-params/services.ts
server/tests/api/check-params/user-notifications.ts
server/tests/api/check-params/user-subscriptions.ts
server/tests/api/check-params/users.ts
server/tests/api/check-params/video-abuses.ts
server/tests/api/check-params/video-blacklist.ts
server/tests/api/check-params/video-captions.ts
server/tests/api/check-params/video-channels.ts
server/tests/api/check-params/video-comments.ts
server/tests/api/check-params/video-imports.ts
server/tests/api/check-params/video-playlists.ts
server/tests/api/check-params/videos-filter.ts
server/tests/api/check-params/videos-history.ts
server/tests/api/check-params/videos.ts
server/tests/api/notifications/user-notifications.ts
server/tests/api/redundancy/redundancy.ts
server/tests/api/search/search-activitypub-video-channels.ts
server/tests/api/search/search-activitypub-videos.ts
server/tests/api/search/search-videos.ts
server/tests/api/server/config.ts
server/tests/api/server/contact-form.ts
server/tests/api/server/email.ts
server/tests/api/server/follow-constraints.ts
server/tests/api/server/follows-moderation.ts
server/tests/api/server/follows.ts
server/tests/api/server/handle-down.ts
server/tests/api/server/jobs.ts
server/tests/api/server/logs.ts
server/tests/api/server/no-client.ts
server/tests/api/server/reverse-proxy.ts
server/tests/api/server/stats.ts
server/tests/api/server/tracker.ts
server/tests/api/users/blocklist.ts
server/tests/api/users/user-subscriptions.ts
server/tests/api/users/users-multiple-servers.ts
server/tests/api/users/users-verification.ts
server/tests/api/users/users.ts
server/tests/api/videos/multiple-servers.ts
server/tests/api/videos/services.ts
server/tests/api/videos/single-server.ts
server/tests/api/videos/video-abuse.ts
server/tests/api/videos/video-blacklist.ts
server/tests/api/videos/video-captions.ts
server/tests/api/videos/video-change-ownership.ts
server/tests/api/videos/video-channels.ts
server/tests/api/videos/video-comments.ts
server/tests/api/videos/video-description.ts
server/tests/api/videos/video-hls.ts
server/tests/api/videos/video-imports.ts
server/tests/api/videos/video-nsfw.ts
server/tests/api/videos/video-playlists.ts
server/tests/api/videos/video-privacy.ts
server/tests/api/videos/video-schedule-update.ts
server/tests/api/videos/video-transcoder.ts
server/tests/api/videos/videos-filter.ts
server/tests/api/videos/videos-history.ts
server/tests/api/videos/videos-overview.ts
server/tests/api/videos/videos-views-cleaner.ts
server/tests/cli/create-import-video-file-job.ts
server/tests/cli/create-transcoding-job.ts
server/tests/cli/optimize-old-videos.ts
server/tests/cli/peertube.ts
server/tests/cli/reset-password.ts
server/tests/cli/update-host.ts
server/tests/client.ts
server/tests/feeds/feeds.ts
server/tests/helpers/request.ts
server/tests/misc-endpoints.ts
server/tests/real-world/populate-database.ts
server/tests/real-world/real-world.ts
server/tools/peertube-get-access-token.ts
server/tools/peertube-import-videos.ts
server/tools/peertube-upload.ts
shared/extra-utils/cli/cli.ts [new file with mode: 0644]
shared/extra-utils/feeds/feeds.ts [new file with mode: 0644]
shared/extra-utils/index.ts [new file with mode: 0644]
shared/extra-utils/logs/logs.ts [new file with mode: 0644]
shared/extra-utils/miscs/email-child-process.js [new file with mode: 0644]
shared/extra-utils/miscs/email.ts [new file with mode: 0644]
shared/extra-utils/miscs/miscs.ts [new file with mode: 0644]
shared/extra-utils/miscs/sql.ts [new file with mode: 0644]
shared/extra-utils/miscs/stubs.ts [new file with mode: 0644]
shared/extra-utils/overviews/overviews.ts [new file with mode: 0644]
shared/extra-utils/requests/activitypub.ts [new file with mode: 0644]
shared/extra-utils/requests/check-api-params.ts [new file with mode: 0644]
shared/extra-utils/requests/requests.ts [new file with mode: 0644]
shared/extra-utils/search/video-channels.ts [new file with mode: 0644]
shared/extra-utils/search/videos.ts [new file with mode: 0644]
shared/extra-utils/server/activitypub.ts [new file with mode: 0644]
shared/extra-utils/server/clients.ts [new file with mode: 0644]
shared/extra-utils/server/config.ts [new file with mode: 0644]
shared/extra-utils/server/contact-form.ts [new file with mode: 0644]
shared/extra-utils/server/follows.ts [new file with mode: 0644]
shared/extra-utils/server/jobs.ts [new file with mode: 0644]
shared/extra-utils/server/redundancy.ts [new file with mode: 0644]
shared/extra-utils/server/servers.ts [new file with mode: 0644]
shared/extra-utils/server/stats.ts [new file with mode: 0644]
shared/extra-utils/socket/socket-io.ts [new file with mode: 0644]
shared/extra-utils/users/accounts.ts [new file with mode: 0644]
shared/extra-utils/users/blocklist.ts [new file with mode: 0644]
shared/extra-utils/users/login.ts [new file with mode: 0644]
shared/extra-utils/users/user-notifications.ts [new file with mode: 0644]
shared/extra-utils/users/user-subscriptions.ts [new file with mode: 0644]
shared/extra-utils/users/users.ts [new file with mode: 0644]
shared/extra-utils/videos/services.ts [new file with mode: 0644]
shared/extra-utils/videos/video-abuses.ts [new file with mode: 0644]
shared/extra-utils/videos/video-blacklist.ts [new file with mode: 0644]
shared/extra-utils/videos/video-captions.ts [new file with mode: 0644]
shared/extra-utils/videos/video-change-ownership.ts [new file with mode: 0644]
shared/extra-utils/videos/video-channels.ts [new file with mode: 0644]
shared/extra-utils/videos/video-comments.ts [new file with mode: 0644]
shared/extra-utils/videos/video-history.ts [new file with mode: 0644]
shared/extra-utils/videos/video-imports.ts [new file with mode: 0644]
shared/extra-utils/videos/video-playlists.ts [new file with mode: 0644]
shared/extra-utils/videos/video-streaming-playlists.ts [new file with mode: 0644]
shared/extra-utils/videos/videos.ts [new file with mode: 0644]
shared/utils/cli/cli.ts [deleted file]
shared/utils/feeds/feeds.ts [deleted file]
shared/utils/index.ts [deleted file]
shared/utils/logs/logs.ts [deleted file]
shared/utils/miscs/email-child-process.js [deleted file]
shared/utils/miscs/email.ts [deleted file]
shared/utils/miscs/miscs.ts [deleted file]
shared/utils/miscs/sql.ts [deleted file]
shared/utils/miscs/stubs.ts [deleted file]
shared/utils/overviews/overviews.ts [deleted file]
shared/utils/requests/activitypub.ts [deleted file]
shared/utils/requests/check-api-params.ts [deleted file]
shared/utils/requests/requests.ts [deleted file]
shared/utils/search/video-channels.ts [deleted file]
shared/utils/search/videos.ts [deleted file]
shared/utils/server/activitypub.ts [deleted file]
shared/utils/server/clients.ts [deleted file]
shared/utils/server/config.ts [deleted file]
shared/utils/server/contact-form.ts [deleted file]
shared/utils/server/follows.ts [deleted file]
shared/utils/server/jobs.ts [deleted file]
shared/utils/server/redundancy.ts [deleted file]
shared/utils/server/servers.ts [deleted file]
shared/utils/server/stats.ts [deleted file]
shared/utils/socket/socket-io.ts [deleted file]
shared/utils/users/accounts.ts [deleted file]
shared/utils/users/blocklist.ts [deleted file]
shared/utils/users/login.ts [deleted file]
shared/utils/users/user-notifications.ts [deleted file]
shared/utils/users/user-subscriptions.ts [deleted file]
shared/utils/users/users.ts [deleted file]
shared/utils/videos/services.ts [deleted file]
shared/utils/videos/video-abuses.ts [deleted file]
shared/utils/videos/video-blacklist.ts [deleted file]
shared/utils/videos/video-captions.ts [deleted file]
shared/utils/videos/video-change-ownership.ts [deleted file]
shared/utils/videos/video-channels.ts [deleted file]
shared/utils/videos/video-comments.ts [deleted file]
shared/utils/videos/video-history.ts [deleted file]
shared/utils/videos/video-imports.ts [deleted file]
shared/utils/videos/video-playlists.ts [deleted file]
shared/utils/videos/video-streaming-playlists.ts [deleted file]
shared/utils/videos/videos.ts [deleted file]

index 6d90d8643783d9e7718b7bf59d958b4e8fd1dbe9..52e7e27f8bb6cce5f9cce61b9f999af22402fa5f 100644 (file)
@@ -11,7 +11,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 const expect = chai.expect
 
index 9cbc7dd848864fc3256d0c32e566f53ba98f28b6..f9dba3418d537e1f6ed5e1a03bbf5514d83ed2be 100644 (file)
@@ -17,7 +17,7 @@ import {
   uploadVideo,
   userLogin,
   waitJobs
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import * as chai from 'chai'
 import { Video } from '../../../../shared/models/videos'
 
index ac6e755c3678a298c553239d08b77d44622d4cfc..365d0e1aefeba3422484148cc3d413b26cf325c2 100644 (file)
@@ -2,7 +2,7 @@
 
 import 'mocha'
 import { expect } from 'chai'
-import { buildRequestStub } from '../../../../shared/utils/miscs/stubs'
+import { buildRequestStub } from '../../../../shared/extra-utils/miscs/stubs'
 import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto'
 import { cloneDeep } from 'lodash'
 import { buildSignedActivity } from '../../../helpers/activitypub'
index 665a9f9f0fb0f5e01c6ec60c6fb4303507515648..7b08b1dabc234b0aa269eae93ae0ed3303d7f366 100644 (file)
@@ -20,8 +20,8 @@ import {
   uploadVideoAndGetId,
   wait,
   waitJobs
-} from '../../../../shared/utils'
-import { getAccount } from '../../../../shared/utils/users/accounts'
+} from '../../../../shared/extra-utils'
+import { getAccount } from '../../../../shared/extra-utils/users/accounts'
 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos'
 
 describe('Test AP refresher', function () {
index 2c55876bad01464f91d9f77a4679d09206a0eadd..2346e9c8ebb367fb5adc1f5f90e48cfced2a8c43 100644 (file)
@@ -9,12 +9,12 @@ import {
   killallServers,
   ServerInfo,
   setActorField
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { HTTP_SIGNATURE } from '../../../initializers/constants'
 import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils'
 import * as chai from 'chai'
 import { activityPubContextify, buildSignedActivity } from '../../../helpers/activitypub'
-import { makeFollowRequest, makePOSTAPRequest } from '../../../../shared/utils/requests/activitypub'
+import { makeFollowRequest, makePOSTAPRequest } from '../../../../shared/extra-utils/requests/activitypub'
 
 const expect = chai.expect
 
index 68f9519c6b328e89b6b898bef290b2966bd7992b..4c145c41d49250293bc9a9faba3ac0bb4e10809a 100644 (file)
@@ -2,13 +2,13 @@
 
 import 'mocha'
 
-import { flushTests, killallServers, runServer, ServerInfo } from '../../../../shared/utils'
+import { flushTests, killallServers, runServer, ServerInfo } from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { getAccount } from '../../../../shared/utils/users/accounts'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { getAccount } from '../../../../shared/extra-utils/users/accounts'
 
 describe('Test accounts API validators', function () {
   const path = '/api/v1/accounts/'
index 62a2c2a5202a440fd96ac91dbf89e8d0fc87fca8..6c7351d3886fcb2942ac8ba6252624afef46ff5f 100644 (file)
@@ -13,12 +13,12 @@ import {
   makePostBodyRequest,
   ServerInfo,
   setAccessTokensToServers, userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 
 describe('Test blocklist API validators', function () {
   let servers: ServerInfo[]
index 3bcb015d9105b12db5a90a976ff975f34dd3a729..ba07552cfa4e3bbc280bc4cf62326b82535e518a 100644 (file)
@@ -7,7 +7,7 @@ import { CustomConfig } from '../../../../shared/models/server/custom-config.mod
 import {
   createUser, flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePutBodyRequest, runServer, ServerInfo,
   setAccessTokensToServers, userLogin, immutableAssign
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 describe('Test config API validators', function () {
   const path = '/api/v1/config/custom'
index c7e014b1ff04a90fc296e719522764656c928fd7..9ba6136aaea71982465fd101c3af8c6ed75a8bd6 100644 (file)
@@ -10,15 +10,15 @@ import {
   runServer,
   ServerInfo,
   setAccessTokensToServers
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { getAccount } from '../../../../shared/utils/users/accounts'
-import { sendContactForm } from '../../../../shared/utils/server/contact-form'
-import { MockSmtpServer } from '../../../../shared/utils/miscs/email'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { getAccount } from '../../../../shared/extra-utils/users/accounts'
+import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
+import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
 
 describe('Test contact form API validators', function () {
   let server: ServerInfo
index da94beffeb70f7befdbe3679f9d20149081e7466..8ba7e04305317bc2cd607f28f5a897d923ed0492 100644 (file)
@@ -10,8 +10,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
-import { makeGetRequest } from '../../../../shared/utils/requests/requests'
+} from '../../../../shared/extra-utils'
+import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
 
 describe('Test debug API validators', function () {
   const path = '/api/v1/server/debug'
index 5bb337682f46d296e4052904a5c95292c820330e..e75631312018be728c20c9c79b00ed6627191b65 100644 (file)
@@ -5,12 +5,12 @@ import 'mocha'
 import {
   createUser, flushTests, killallServers, makeDeleteRequest, makePostBodyRequest, runServer, ServerInfo, setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 
 describe('Test server follows API validators', function () {
   let server: ServerInfo
index 5fb2b96060dd9fff66e0272729ad849517d06da2..682406e87282a98d55043866931b436b084019e0 100644 (file)
@@ -10,13 +10,13 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { makeGetRequest } from '../../../../shared/utils/requests/requests'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
 
 describe('Test jobs API validators', function () {
   const path = '/api/v1/jobs/failed'
index 9bc6ac2440d1475a22a8195d34baf775c3298c1b..0948f7c5e6325fa0d3b6c0ec6f62bf060193b8ee 100644 (file)
@@ -10,8 +10,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
-import { makeGetRequest } from '../../../../shared/utils/requests/requests'
+} from '../../../../shared/extra-utils'
+import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
 
 describe('Test logs API validators', function () {
   const path = '/api/v1/server/logs'
index d14e35cf218c06246bd69dcf56a165d408a710d0..93b905feabdc9a69f3a53fe9e8a489ee1a23d37c 100644 (file)
@@ -12,7 +12,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 describe('Test server redundancy API validators', function () {
   let servers: ServerInfo[]
index 7b7e07784f96d965f075faa834b86fbb0146c48a..1fcdedd90ae25f2e918931324c29ce6cafeaa502 100644 (file)
@@ -2,12 +2,12 @@
 
 import 'mocha'
 
-import { flushTests, immutableAssign, killallServers, makeGetRequest, runServer, ServerInfo } from '../../../../shared/utils'
+import { flushTests, immutableAssign, killallServers, makeGetRequest, runServer, ServerInfo } from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 
 describe('Test videos API validator', function () {
   let server: ServerInfo
index 28591af9ddb36a849928484a6ddf7c7cc169e64b..813bc7e364f32d6c2fcd49a291644275113b398e 100644 (file)
@@ -10,7 +10,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 describe('Test services API validators', function () {
   let server: ServerInfo
index 4b75f6920bdac59de312643589cd9f7454e3f0f1..c5632840695c027d19504f5c8bf71cd71c3f4c0e 100644 (file)
@@ -14,12 +14,12 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   wait
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 import { UserNotificationSetting, UserNotificationSettingValue } from '../../../../shared/models/users'
 
 describe('Test user notifications API validators', function () {
index a18e1a43b9fada9e141541e5e43ad9c273651619..d33b3bca6374a8a414aed35f3d6b2c3a085ab34a 100644 (file)
@@ -13,14 +13,14 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 describe('Test user subscriptions API validators', function () {
   const path = '/api/v1/users/me/subscriptions'
index b5c812e8f16c6a746a5fe0005c1bb2afd1b6fcf9..b62806554b4077f0305306c5bea41ecf29170be7 100644 (file)
@@ -9,15 +9,15 @@ import {
   createUser, flushTests, getMyUserInformation, getMyUserVideoRating, getUsersList, immutableAssign, killallServers, makeGetRequest,
   makePostBodyRequest, makeUploadRequest, makePutBodyRequest, registerUser, removeUser, runServer, ServerInfo, setAccessTokensToServers,
   updateUser, uploadVideo, userLogin, deleteMe, unblockUser, blockUser
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/utils/videos/video-imports'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
 import { VideoPrivacy } from '../../../../shared/models/videos'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { expect } from 'chai'
 import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
 
index 7edc8e39d42e3220aebe04ec6482db93cfa81d50..78e4acf2feb24cd3c39960913fb5f149104053c0 100644 (file)
@@ -15,12 +15,12 @@ import {
   updateVideoAbuse,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 import { VideoAbuseState } from '../../../../shared/models/videos'
 
 describe('Test video abuses API validators', function () {
index 81423aee9044c0307d43d23c1e9f8d99ca7d2327..c2e9622cc41caefdaf0341d66643332fd3063915 100644 (file)
@@ -18,12 +18,12 @@ import {
   setAccessTokensToServers,
   uploadVideo,
   userLogin, waitJobs
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 import { VideoDetails, VideoBlacklistType } from '../../../../shared/models/videos'
 import { expect } from 'chai'
 
index de2ca8cd12d53a7f91dbb89385ea02051a2740bd..4ef5e03ede87f999ce34613782cbc7a5031cb11d 100644 (file)
@@ -13,9 +13,9 @@ import {
   setAccessTokensToServers,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { join } from 'path'
-import { createVideoCaption } from '../../../../shared/utils/videos/video-captions'
+import { createVideoCaption } from '../../../../shared/extra-utils/videos/video-captions'
 
 describe('Test video captions API validator', function () {
   const path = '/api/v1/videos/'
index b72fc42206bae1d7040526095a45360ea5a1b129..b6aa745ab5da6b02575305cda8628baaf64c3350 100644 (file)
@@ -20,12 +20,12 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 import { User } from '../../../../shared/models/users'
 import { join } from 'path'
 
index 5f70998efe2cca8dba0615c859c4df631ab3ddef..b80d91279992256756a9367acfa8b6c0950d42ec 100644 (file)
@@ -6,13 +6,13 @@ import {
   createUser,
   flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePostBodyRequest, runServer, ServerInfo, setAccessTokensToServers,
   uploadVideo, userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { addVideoCommentThread } from '../../../../shared/utils/videos/video-comments'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
 
 const expect = chai.expect
 
index 4d2bf2e8d8952024418aec1318ed17e1187eb5ee..ad4c4def03e5fc5db829cc57a03fc180714a97e2 100644 (file)
@@ -18,13 +18,13 @@ import {
   setAccessTokensToServers,
   updateCustomSubConfig,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { getMagnetURI, getYoutubeVideoUrl } from '../../../../shared/utils/videos/video-imports'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { getMagnetURI, getYoutubeVideoUrl } from '../../../../shared/extra-utils/videos/video-imports'
 
 describe('Test video imports API validator', function () {
   const path = '/api/v1/videos/imports'
index 229c231180eb2a9efb0b79cd0e4aa7eef1f4a187..0f34847633bd778853e1812b8ffff54acee2119c 100644 (file)
@@ -20,12 +20,12 @@ import {
   updateVideoPlaylist,
   updateVideoPlaylistElement,
   uploadVideoAndGetId
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
+} from '../../../../shared/extra-utils/requests/check-api-params'
 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
 import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
 
index 7c487ae814ef25a0ea8b3b475aca8dc0541fbf06..971867b27d30a58d104560dfcb873b31cca7e4d0 100644 (file)
@@ -11,7 +11,7 @@ import {
   ServerInfo,
   setAccessTokensToServers, setDefaultVideoChannel,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { UserRole } from '../../../../shared/models/users'
 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
 
index 8c079a956c455aec6964fbcced561726bae6bafb..11e277644043de7fc5f32c5709d7ae8bd596e6a6 100644 (file)
@@ -14,7 +14,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 const expect = chai.expect
 
index 3f0e0d646e0e4cb67c88d74bbc8c62d347460006..e96f324cc27e0dd326b33fc9492aab9b2a343caf 100644 (file)
@@ -9,13 +9,13 @@ import {
   createUser, flushTests, getMyUserInformation, getVideo, getVideosList, immutableAssign, killallServers, makeDeleteRequest,
   makeGetRequest, makeUploadRequest, makePutBodyRequest, removeVideo, uploadVideo,
   runServer, ServerInfo, setAccessTokensToServers, userLogin, updateCustomSubConfig
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   checkBadCountPagination,
   checkBadSortPagination,
   checkBadStartPagination
-} from '../../../../shared/utils/requests/check-api-params'
-import { getAccountsList } from '../../../../shared/utils/users/accounts'
+} from '../../../../shared/extra-utils/requests/check-api-params'
+import { getAccountsList } from '../../../../shared/extra-utils/users/accounts'
 
 const expect = chai.expect
 
index d1d6f3c35866a361205c78755e353c465d35efb5..8f7ce82a48b06397f630aa57dd29e44187c00380 100644 (file)
@@ -20,11 +20,11 @@ import {
   wait,
   getCustomConfig,
   updateCustomConfig, getVideoThreadComments, getVideoCommentThreads, follow
-} from '../../../../shared/utils'
-import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/utils/index'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { getUserNotificationSocket } from '../../../../shared/utils/socket/socket-io'
+} from '../../../../shared/extra-utils'
+import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { getUserNotificationSocket } from '../../../../shared/extra-utils/socket/socket-io'
 import {
   checkCommentMention,
   CheckerBaseParams,
@@ -42,7 +42,7 @@ import {
   markAsReadNotifications,
   updateMyNotificationSettings,
   markAsReadAllNotifications, checkNewInstanceFollower
-} from '../../../../shared/utils/users/user-notifications'
+} from '../../../../shared/extra-utils/users/user-notifications'
 import {
   User,
   UserNotification,
@@ -50,13 +50,13 @@ import {
   UserNotificationSettingValue,
   UserNotificationType
 } from '../../../../shared/models/users'
-import { MockSmtpServer } from '../../../../shared/utils/miscs/email'
-import { addUserSubscription, removeUserSubscription } from '../../../../shared/utils/users/user-subscriptions'
+import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
+import { addUserSubscription, removeUserSubscription } from '../../../../shared/extra-utils/users/user-subscriptions'
 import { VideoPrivacy } from '../../../../shared/models/videos'
-import { getBadVideoUrl, getYoutubeVideoUrl, importVideo } from '../../../../shared/utils/videos/video-imports'
-import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/utils/videos/video-comments'
+import { getBadVideoUrl, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
+import { addVideoCommentReply, addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
 import * as uuidv4 from 'uuid/v4'
-import { addAccountToAccountBlocklist, removeAccountFromAccountBlocklist } from '../../../../shared/utils/users/blocklist'
+import { addAccountToAccountBlocklist, removeAccountFromAccountBlocklist } from '../../../../shared/extra-utils/users/blocklist'
 import { CustomConfig } from '../../../../shared/models/server'
 import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
 
index 33921763da2433927f8a1d8eb924ce83729bea34..280a4c64b5b0df431075a3ae3d65a1f67fb011ab 100644 (file)
@@ -24,16 +24,16 @@ import {
   viewVideo,
   wait,
   waitUntilLog
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 import * as magnetUtil from 'magnet-uri'
-import { updateRedundancy } from '../../../../shared/utils/server/redundancy'
+import { updateRedundancy } from '../../../../shared/extra-utils/server/redundancy'
 import { ActorFollow } from '../../../../shared/models/actors'
 import { readdir } from 'fs-extra'
 import { join } from 'path'
 import { VideoRedundancyStrategy } from '../../../../shared/models/redundancy'
-import { getStats } from '../../../../shared/utils/server/stats'
+import { getStats } from '../../../../shared/extra-utils/server/stats'
 import { ServerStats } from '../../../../shared/models/server/server-stats.model'
 
 const expect = chai.expect
index 682bd262a8c16b929bc0aca9caa68b40889c36db..1f59a951be35655aa604da5fa8b6ad9cf138bd17 100644 (file)
@@ -17,10 +17,10 @@ import {
   uploadVideo,
   userLogin,
   wait
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { VideoChannel } from '../../../../shared/models/videos'
-import { searchVideoChannel } from '../../../../shared/utils/search/video-channels'
+import { searchVideoChannel } from '../../../../shared/extra-utils/search/video-channels'
 
 const expect = chai.expect
 
index f881917e75403f49db9b538e49be43824b4cdb4d..d984c696c27eb0f6970dec208e608560d6707975 100644 (file)
@@ -16,8 +16,8 @@ import {
   uploadVideo,
   wait,
   searchVideo
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { Video, VideoPrivacy } from '../../../../shared/models/videos'
 
 const expect = chai.expect
index fa4078b99ff6ac41c9a95b3cb8eb9dd9eaac2aa3..65f3c9186221f064fd73642d9cc78ff2408c72c3 100644 (file)
@@ -13,7 +13,7 @@ import {
   uploadVideo,
   wait,
   immutableAssign
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 const expect = chai.expect
 
index 5373d02f228c62c29b60b97a3a8f5438c44de020..a999166278c70a29b071809b888f8be4f222a6b7 100644 (file)
@@ -16,7 +16,7 @@ import {
   runServer,
   setAccessTokensToServers,
   updateCustomConfig
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { ServerConfig } from '../../../../shared/models'
 
 const expect = chai.expect
index 06a2f89b0b97154f68ebd1d1a1171ee7554dc2b1..fdd5e97302de55c3676e0fca015ce3aa4815c7d0 100644 (file)
@@ -2,10 +2,10 @@
 
 import * as chai from 'chai'
 import 'mocha'
-import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/utils'
-import { MockSmtpServer } from '../../../../shared/utils/miscs/email'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { sendContactForm } from '../../../../shared/utils/server/contact-form'
+import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/extra-utils'
+import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
 
 const expect = chai.expect
 
index bc45102d280418e14928013fb849d14246d0b22a..a40a281f82fc6219615de67b460d81cde1e0c36c 100644 (file)
@@ -19,9 +19,9 @@ import {
   killallServers,
   ServerInfo,
   setAccessTokensToServers
-} from '../../../../shared/utils'
-import { MockSmtpServer } from '../../../../shared/utils/miscs/email'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 28862a1c641e174e4780563ff4f5f7b73c25b51b..bdd8b1c700eca1b8e8bf4d771e02adeb9a2ee221 100644 (file)
@@ -13,10 +13,10 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils'
-import { unfollow } from '../../../../shared/utils/server/follows'
-import { userLogin } from '../../../../shared/utils/users/login'
-import { createUser } from '../../../../shared/utils/users/users'
+} from '../../../../shared/extra-utils'
+import { unfollow } from '../../../../shared/extra-utils/server/follows'
+import { userLogin } from '../../../../shared/extra-utils/users/login'
+import { createUser } from '../../../../shared/extra-utils/users/users'
 
 const expect = chai.expect
 
index 0bb3aa866d285855097ba5232c1bcc9232ffbc73..f4a826ea8eb945999268a94526245428167e4093 100644 (file)
@@ -9,15 +9,15 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   updateCustomSubConfig
-} from '../../../../shared/utils/index'
+} from '../../../../shared/extra-utils/index'
 import {
   follow,
   getFollowersListPaginationAndSort,
   getFollowingListPaginationAndSort,
   removeFollower,
   rejectFollower
-} from '../../../../shared/utils/server/follows'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/server/follows'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { ActorFollow } from '../../../../shared/models/actors'
 
 const expect = chai.expect
index a5e6c3c1e01d251d289f65d21e39955c628034d8..527b54e1ed0a9b86e5724c2524746ae3321e45b1 100644 (file)
@@ -4,7 +4,7 @@ import * as chai from 'chai'
 import 'mocha'
 import { Video, VideoPrivacy } from '../../../../shared/models/videos'
 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
-import { completeVideoCheck } from '../../../../shared/utils'
+import { completeVideoCheck } from '../../../../shared/extra-utils'
 import {
   flushAndRunMultipleServers,
   getVideosList,
@@ -12,26 +12,26 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { dateIsValid } from '../../../../shared/utils/miscs/miscs'
+} from '../../../../shared/extra-utils/index'
+import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
 import {
   follow,
   getFollowersListPaginationAndSort,
   getFollowingListPaginationAndSort,
   unfollow
-} from '../../../../shared/utils/server/follows'
-import { expectAccountFollows } from '../../../../shared/utils/users/accounts'
-import { userLogin } from '../../../../shared/utils/users/login'
-import { createUser } from '../../../../shared/utils/users/users'
+} from '../../../../shared/extra-utils/server/follows'
+import { expectAccountFollows } from '../../../../shared/extra-utils/users/accounts'
+import { userLogin } from '../../../../shared/extra-utils/users/login'
+import { createUser } from '../../../../shared/extra-utils/users/users'
 import {
   addVideoCommentReply,
   addVideoCommentThread,
   getVideoCommentThreads,
   getVideoThreadComments
-} from '../../../../shared/utils/videos/video-comments'
-import { rateVideo } from '../../../../shared/utils/videos/videos'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { createVideoCaption, listVideoCaptions, testCaptionFile } from '../../../../shared/utils/videos/video-captions'
+} from '../../../../shared/extra-utils/videos/video-comments'
+import { rateVideo } from '../../../../shared/extra-utils/videos/videos'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { createVideoCaption, listVideoCaptions, testCaptionFile } from '../../../../shared/extra-utils/videos/video-captions'
 import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
 
 const expect = chai.expect
index cd5acbe168925b8532425c4227ad55f6940669dc..8c49541ee17a38152315fbad214887727e3b1b36 100644 (file)
@@ -20,15 +20,15 @@ import {
   updateVideo,
   uploadVideo,
   wait
-} from '../../../../shared/utils'
-import { follow, getFollowersListPaginationAndSort } from '../../../../shared/utils/server/follows'
-import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows'
+import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import {
   addVideoCommentReply,
   addVideoCommentThread,
   getVideoCommentThreads,
   getVideoThreadComments
-} from '../../../../shared/utils/videos/video-comments'
+} from '../../../../shared/extra-utils/videos/video-comments'
 
 const expect = chai.expect
 
index 52948b1d64164dfef47f84c2e5204bc35276724f..1d74298733d6b361b75e9ddc79f563f9a9e7011e 100644 (file)
@@ -2,12 +2,12 @@
 
 import * as chai from 'chai'
 import 'mocha'
-import { killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/utils/index'
-import { doubleFollow } from '../../../../shared/utils/server/follows'
-import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/utils/server/jobs'
-import { flushAndRunMultipleServers } from '../../../../shared/utils/server/servers'
-import { uploadVideo } from '../../../../shared/utils/videos/videos'
-import { dateIsValid } from '../../../../shared/utils/miscs/miscs'
+import { killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
+import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers'
+import { uploadVideo } from '../../../../shared/extra-utils/videos/videos'
+import { dateIsValid } from '../../../../shared/extra-utils/miscs/miscs'
 
 const expect = chai.expect
 
index 05b0308deba1c82cc110b37eba8362863f74716f..f55e1240760daf8ce98267b88454e94624f12a2f 100644 (file)
@@ -2,10 +2,10 @@
 
 import * as chai from 'chai'
 import 'mocha'
-import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers } from '../../../../shared/utils/index'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { uploadVideo } from '../../../../shared/utils/videos/videos'
-import { getLogs } from '../../../../shared/utils/logs/logs'
+import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { uploadVideo } from '../../../../shared/extra-utils/videos/videos'
+import { getLogs } from '../../../../shared/extra-utils/logs/logs'
 
 const expect = chai.expect
 
index 3b95ce945bab0dd456df09f458cf911b3bafa662..88d34063cbf51268c0832e0a10ee6fee2b37f160 100644 (file)
@@ -4,8 +4,8 @@ import {
   flushTests,
   killallServers,
   ServerInfo
-} from '../../../../shared/utils'
-import { runServer } from '../../../../shared/utils/server/servers'
+} from '../../../../shared/extra-utils'
+import { runServer } from '../../../../shared/extra-utils/server/servers'
 
 describe('Start and stop server without web client routes', function () {
   let server: ServerInfo
index ee0fffd5ae3f6e7d1373b8c150043408d290bad6..e7dc1653158c8715c9df165b8bddd414fbe40e04 100644 (file)
@@ -15,7 +15,7 @@ import {
   userLogin,
   viewVideo,
   wait
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 const expect = chai.expect
 
 import {
@@ -23,7 +23,7 @@ import {
   flushTests,
   runServer,
   registerUser, getCustomConfig, setAccessTokensToServers, updateCustomConfig
-} from '../../../../shared/utils/index'
+} from '../../../../shared/extra-utils/index'
 
 describe('Test application behind a reverse proxy', function () {
   let server = null
index eadbcaf834844ede0f97be2270770d85fb036443..48addad227905cfe69a9653c26524e23c8df3a0e 100644 (file)
@@ -13,11 +13,11 @@ import {
   uploadVideo,
   viewVideo,
   wait
-} from '../../../../shared/utils'
-import { flushTests, setAccessTokensToServers } from '../../../../shared/utils/index'
-import { getStats } from '../../../../shared/utils/server/stats'
-import { addVideoCommentThread } from '../../../../shared/utils/videos/video-comments'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { getStats } from '../../../../shared/extra-utils/server/stats'
+import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 41803aef133d61893458bdbcbdd6823ad80aa685..4f7cc05a7a64e4b62ecb5b3683f830ea97e9853a 100644 (file)
@@ -2,8 +2,8 @@
 
 import * as magnetUtil from 'magnet-uri'
 import 'mocha'
-import { getVideo, killallServers, reRunServer, runServer, ServerInfo, uploadVideo } from '../../../../shared/utils'
-import { flushTests, setAccessTokensToServers } from '../../../../shared/utils/index'
+import { getVideo, killallServers, reRunServer, runServer, ServerInfo, uploadVideo } from '../../../../shared/extra-utils'
+import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
 import { VideoDetails } from '../../../../shared/models/videos'
 import * as WebTorrent from 'webtorrent'
 
index 638a443bad6194ebda9bb616f7ef092e7d8d746b..cd96ffe2accd3cc1eee9ad3f43ede95e0c1c1c1e 100644 (file)
@@ -12,16 +12,16 @@ import {
   ServerInfo,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils/index'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
-import { getVideosListWithToken, getVideosList } from '../../../../shared/utils/videos/videos'
+} from '../../../../shared/extra-utils/index'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
+import { getVideosListWithToken, getVideosList } from '../../../../shared/extra-utils/videos/videos'
 import {
   addVideoCommentReply,
   addVideoCommentThread,
   getVideoCommentThreads,
   getVideoThreadComments
-} from '../../../../shared/utils/videos/video-comments'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/videos/video-comments'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
 import {
   addAccountToAccountBlocklist,
@@ -36,7 +36,7 @@ import {
   removeAccountFromServerBlocklist,
   removeServerFromAccountBlocklist,
   removeServerFromServerBlocklist
-} from '../../../../shared/utils/users/blocklist'
+} from '../../../../shared/extra-utils/users/blocklist'
 
 const expect = chai.expect
 
index 037a79a76d57576f354466d72785769efe0726f9..5be185678a880c374e5a7a88e8be5e7b58743ea8 100644 (file)
@@ -11,18 +11,18 @@ import {
   unfollow,
   updateVideo,
   userLogin
-} from '../../../../shared/utils'
-import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/utils/index'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
+} from '../../../../shared/extra-utils'
+import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
 import { Video, VideoChannel } from '../../../../shared/models/videos'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import {
   addUserSubscription,
   listUserSubscriptions,
   listUserSubscriptionVideos,
   removeUserSubscription,
   getUserSubscription, areSubscriptionsExist
-} from '../../../../shared/utils/users/user-subscriptions'
+} from '../../../../shared/extra-utils/users/user-subscriptions'
 
 const expect = chai.expect
 
index 0510b2de9f16da21be9ad4fb481f20dc26c7b85c..9b8db00725a6db032820f460d2ac63f56d771f6b 100644 (file)
@@ -14,13 +14,20 @@ import {
   removeUser,
   updateMyUser,
   userLogin
-} from '../../../../shared/utils'
-import { getMyUserInformation, killallServers, ServerInfo, testImage, updateMyAvatar, uploadVideo } from '../../../../shared/utils/index'
-import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/utils/users/accounts'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
+} from '../../../../shared/extra-utils'
+import {
+  getMyUserInformation,
+  killallServers,
+  ServerInfo,
+  testImage,
+  updateMyAvatar,
+  uploadVideo
+} from '../../../../shared/extra-utils/index'
+import { checkActorFilesWereRemoved, getAccount, getAccountsList } from '../../../../shared/extra-utils/users/accounts'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
 import { User } from '../../../../shared/models/users'
 import { VideoChannel } from '../../../../shared/models/videos'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index babeda2b892327a66f251d24ed5d990d60f8ae80..7fcd3e50b5c0876e6ee9ea33456d2b3370595aed 100644 (file)
@@ -5,10 +5,10 @@ import 'mocha'
 import {
   registerUser, flushTests, getUserInformation, getMyUserInformation, killallServers,
   userLogin, login, runServer, ServerInfo, verifyEmail, updateCustomSubConfig, wait
-} from '../../../../shared/utils'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
-import { MockSmtpServer } from '../../../../shared/utils/miscs/email'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
+import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 13511e070d7f9f28387e8dce0c54988197c7fbfa..472ff511ccecf0fd66a5e00e434587f342de33da 100644 (file)
@@ -33,10 +33,10 @@ import {
   updateUser,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils'
-import { follow } from '../../../../shared/utils/server/follows'
-import { setAccessTokensToServers } from '../../../../shared/utils/users/login'
-import { getMyVideos } from '../../../../shared/utils/videos/videos'
+} from '../../../../shared/extra-utils'
+import { follow } from '../../../../shared/extra-utils/server/follows'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
+import { getMyVideos } from '../../../../shared/extra-utils/videos/videos'
 import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
 
 const expect = chai.expect
index 46486b7773dbb374cd872821452a9e2a9143afd7..dd50f905d2bca98ba36b78c393c662e63e8d7127 100644 (file)
@@ -32,15 +32,15 @@ import {
   viewVideo,
   wait,
   webtorrentAdd
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   addVideoCommentReply,
   addVideoCommentThread,
   deleteVideoComment,
   getVideoCommentThreads,
   getVideoThreadComments
-} from '../../../../shared/utils/videos/video-comments'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/videos/video-comments'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 2da86964ff6273a859444096b556ba9a87197663..e79ce59a6a6766ae7dd0cddc33bdd7219c354ce9 100644 (file)
@@ -10,8 +10,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { runServer } from '../../../../shared/utils/server/servers'
+} from '../../../../shared/extra-utils/index'
+import { runServer } from '../../../../shared/extra-utils/server/servers'
 
 const expect = chai.expect
 
index cfdcbaf3f1ac8cc8ae6fb7bd214728b9958e8fdf..ea3e7c42143b447b90bb57f5ae5b12e43cddb75c 100644 (file)
@@ -28,7 +28,7 @@ import {
   uploadVideo,
   viewVideo,
   wait
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 
 const expect = chai.expect
 
index 3a7b623daa2ba3d46ede1aa5ef8ad308cace0e80..2ae1bf34d08e4ddbd44441a8f5644297df7cb59f 100644 (file)
@@ -14,9 +14,9 @@ import {
   setAccessTokensToServers,
   updateVideoAbuse,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { doubleFollow } from '../../../../shared/utils/server/follows'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/index'
+import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 1feae19e93d9aae0324cf2fe3de710125b4d010d..582c82e05bf5ff9f4d5fa21576b611cef02f2901 100644 (file)
@@ -20,9 +20,9 @@ import {
   updateVideoBlacklist,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils/index'
-import { doubleFollow } from '../../../../shared/utils/server/follows'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/index'
+import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos'
 import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
 import { UserRole } from '../../../../shared/models/users'
index 57bee713f9c1ce182e02b1ce728c03803189c749..da920e00c5af9862ffa7a1667a20c53542c49165 100644 (file)
@@ -9,10 +9,15 @@ import {
   removeVideo,
   uploadVideo,
   wait
-} from '../../../../shared/utils'
-import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/utils/index'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { createVideoCaption, deleteVideoCaption, listVideoCaptions, testCaptionFile } from '../../../../shared/utils/videos/video-captions'
+} from '../../../../shared/extra-utils'
+import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import {
+  createVideoCaption,
+  deleteVideoCaption,
+  listVideoCaptions,
+  testCaptionFile
+} from '../../../../shared/extra-utils/videos/video-captions'
 import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
 
 const expect = chai.expect
index a23e30dc0dc60564aa50cd3e0977e9eba6d8c10f..9040ac3084cb63be1db8d61a4efb164241524691 100644 (file)
@@ -18,8 +18,8 @@ import {
   uploadVideo,
   userLogin,
   getVideo
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { User } from '../../../../shared/models/users'
 import { VideoDetails } from '../../../../shared/models/videos'
 
index bd672cf41c84ff8d4972e5f537b970bcd0a8527a..e30e6bb4fca79ba20df071b3c48a46f091ccb9b3 100644 (file)
@@ -13,7 +13,7 @@ import {
   updateVideoChannelAvatar,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import {
   addVideoChannel,
   deleteVideoChannel,
@@ -26,8 +26,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   updateVideoChannel
-} from '../../../../shared/utils/index'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/index'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index ce1b17e35f881dfb4cc569d36cea642d68ed47dc..abf4d0c44955a9b72a651fe03970eb14e4bf67e2 100644 (file)
@@ -3,7 +3,7 @@
 import * as chai from 'chai'
 import 'mocha'
 import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
-import { testImage } from '../../../../shared/utils'
+import { testImage } from '../../../../shared/extra-utils'
 import {
   dateIsValid,
   flushTests,
@@ -13,14 +13,14 @@ import {
   setAccessTokensToServers,
   updateMyAvatar,
   uploadVideo
-} from '../../../../shared/utils/index'
+} from '../../../../shared/extra-utils/index'
 import {
   addVideoCommentReply,
   addVideoCommentThread,
   deleteVideoComment,
   getVideoCommentThreads,
   getVideoThreadComments
-} from '../../../../shared/utils/videos/video-comments'
+} from '../../../../shared/extra-utils/videos/video-comments'
 
 const expect = chai.expect
 
index cbda0b9a6cfc72c9c1be1fd55699143681926828..0c03d17d85233757fd930e0df509a35c1bba879c 100644 (file)
@@ -12,9 +12,9 @@ import {
   setAccessTokensToServers,
   updateVideo,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { doubleFollow } from '../../../../shared/utils/server/follows'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/index'
+import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 3d04758b16101ded78ba10048c72961ba8a454bd..a9251406abe6a5493d96a97863a745cd3fc399e8 100644 (file)
@@ -18,7 +18,7 @@ import {
   updateVideo,
   uploadVideo,
   waitJobs
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { VideoDetails } from '../../../../shared/models/videos'
 import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
 import { join } from 'path'
index c5ffb793baa96ae2ff52f83a5a6a051ef2376425..f8b2c0407e092b44595718ae8ad90c4be81d5306 100644 (file)
@@ -14,9 +14,9 @@ import {
   killallServers,
   ServerInfo,
   setAccessTokensToServers
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
-import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/utils/videos/video-imports'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
+import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/extra-utils/videos/video-imports'
 
 const expect = chai.expect
 
index cb972d92100ea8ec6298235b6881498b35712763..9f2d99ffec5d5e62353010337ceefaf0e1657114 100644 (file)
@@ -9,10 +9,10 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { userLogin } from '../../../../shared/utils/users/login'
-import { createUser } from '../../../../shared/utils/users/users'
-import { getMyVideos } from '../../../../shared/utils/videos/videos'
+} from '../../../../shared/extra-utils/index'
+import { userLogin } from '../../../../shared/extra-utils/users/login'
+import { createUser } from '../../../../shared/extra-utils/users/users'
+import { getMyVideos } from '../../../../shared/extra-utils/videos/videos'
 import {
   getAccountVideos,
   getConfig,
@@ -25,7 +25,7 @@ import {
   searchVideoWithToken,
   updateCustomConfig,
   updateMyUser
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { ServerConfig } from '../../../../shared/models'
 import { CustomConfig } from '../../../../shared/models/server/custom-config.model'
 import { User } from '../../../../shared/models/users'
index d9cb71992822dc4d8406a26648ad20b2eb188bb4..8c3542906da2a1e7585db483ecebfaa1938fa0ac 100644 (file)
@@ -36,7 +36,7 @@ import {
   uploadVideoAndGetId,
   userLogin,
   waitJobs
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
 import { VideoPlaylist } from '../../../../shared/models/videos/playlist/video-playlist.model'
 import { Video } from '../../../../shared/models/videos'
index e1b5fb1939b1f4cc1ccb5df9785e623e5cd4f9dc..ba5e0f044d5b457fcc7157793c799ee2d6407461 100644 (file)
@@ -10,12 +10,12 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../../shared/utils/index'
-import { doubleFollow } from '../../../../shared/utils/server/follows'
-import { userLogin } from '../../../../shared/utils/users/login'
-import { createUser } from '../../../../shared/utils/users/users'
-import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/utils/videos/videos'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils/index'
+import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
+import { userLogin } from '../../../../shared/extra-utils/users/login'
+import { createUser } from '../../../../shared/extra-utils/users/users'
+import { getMyVideos, getVideo, getVideoWithToken, updateVideo } from '../../../../shared/extra-utils/videos/videos'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 632c4244ce22caa7fe8a953a3c9302fc5c0da918..b19a9116aafcb84697c2f94696b4acd4a48c43e2 100644 (file)
@@ -15,8 +15,8 @@ import {
   updateVideo,
   uploadVideo,
   wait
-} from '../../../../shared/utils'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+} from '../../../../shared/extra-utils'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index eefd32ef81a34e0785a1b2709962542b3bacd1a6..3d4739ca96f373d4e1a17ac42c4cce33c99e85b0 100644 (file)
@@ -19,9 +19,9 @@ import {
   setAccessTokensToServers,
   uploadVideo,
   webtorrentAdd
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { extname, join } from 'path'
-import { waitJobs } from '../../../../shared/utils/server/jobs'
+import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
 import { VIDEO_TRANSCODING_FPS } from '../../../../server/initializers/constants'
 
 const expect = chai.expect
index 920ca0023050862db3ca60f475f83665e1556280..36664b17fc25475e69b8e99a655d4f5fde08efec 100644 (file)
@@ -13,7 +13,7 @@ import {
   setAccessTokensToServers,
   uploadVideo,
   userLogin
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { Video, VideoPrivacy } from '../../../../shared/models/videos'
 import { UserRole } from '../../../../shared/models/users'
 
index ab40bb64cb76c1455b445a22c5b05dc661e8f1aa..6f75ce42c62bda0176e5cb291f2318910823610f 100644 (file)
@@ -16,9 +16,9 @@ import {
   uploadVideo,
   userLogin,
   wait
-} from '../../../../shared/utils'
+} from '../../../../shared/extra-utils'
 import { Video, VideoDetails } from '../../../../shared/models/videos'
-import { listMyVideosHistory, removeMyVideosHistory, userWatchVideo } from '../../../../shared/utils/videos/video-history'
+import { listMyVideosHistory, removeMyVideosHistory, userWatchVideo } from '../../../../shared/extra-utils/videos/video-history'
 
 const expect = chai.expect
 
index 7221bcae653c678bd3103adb4055a252a1c1c180..233ca8a5dd6f41f43782b76c7c707610f2446e01 100644 (file)
@@ -2,8 +2,8 @@
 
 import * as chai from 'chai'
 import 'mocha'
-import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../../../../shared/utils'
-import { getVideosOverview } from '../../../../shared/utils/overviews/overviews'
+import { flushTests, killallServers, runServer, ServerInfo, setAccessTokensToServers, uploadVideo } from '../../../../shared/extra-utils'
+import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
 import { VideosOverview } from '../../../../shared/models/overviews'
 
 const expect = chai.expect
index 9f268c8e6b7f44f6f99fdc6f4e8eb467491326af..4001969c3cc01bb777eebd5c2768d9f47cb69979 100644 (file)
@@ -11,10 +11,10 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs
-} from '../../../../shared/utils'
-import { getVideosOverview } from '../../../../shared/utils/overviews/overviews'
+} from '../../../../shared/extra-utils'
+import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
 import { VideosOverview } from '../../../../shared/models/overviews'
-import { listMyVideosHistory } from '../../../../shared/utils/videos/video-history'
+import { listMyVideosHistory } from '../../../../shared/extra-utils/videos/video-history'
 
 const expect = chai.expect
 
index 4acda47b1c2f89dc16d6dc7d53f3ddc43ffc593b..4dc12a1c61e496c0295e9b18b134d22e8f353836 100644 (file)
@@ -15,8 +15,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../shared/utils'
-import { waitJobs } from '../../../shared/utils/server/jobs'
+} from '../../../shared/extra-utils'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index 50be5fa19f09b989f4b36206811bed2c889191f9..bd1de207948ece805091f34966d4ed9db55cec4f 100644 (file)
@@ -15,8 +15,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo, wait
-} from '../../../shared/utils'
-import { waitJobs } from '../../../shared/utils/server/jobs'
+} from '../../../shared/extra-utils'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
 
 const expect = chai.expect
 
index f84ba1ecefa9761e6c3d5589dc5a4215c546d5d5..b3724476b1a9ba66514eb7447a9c8cffa184d95c 100644 (file)
@@ -15,8 +15,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo, viewVideo, wait
-} from '../../../shared/utils'
-import { waitJobs } from '../../../shared/utils/server/jobs'
+} from '../../../shared/extra-utils'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
 import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '../../helpers/ffmpeg-utils'
 import { VIDEO_TRANSCODING_FPS } from '../../initializers/constants'
 import { join } from 'path'
index b0ae876d35589dd7facfc474930165afcc8b4048..45411bdbc609b636c00d386a946dafea91356478 100644 (file)
@@ -11,7 +11,7 @@ import {
   runServer,
   ServerInfo,
   setAccessTokensToServers
-} from '../../../shared/utils'
+} from '../../../shared/extra-utils'
 
 describe('Test CLI wrapper', function () {
   let server: ServerInfo
index 4c9f0c5f800ef65297f73abdc280aeed3055c432..3c56bf45b7b4745ba7dace70dd16be6c7aea86da 100644 (file)
@@ -10,7 +10,7 @@ import {
   runServer,
   ServerInfo,
   setAccessTokensToServers
-} from '../../../shared/utils'
+} from '../../../shared/extra-utils'
 
 describe('Test reset password scripts', function () {
   let server: ServerInfo
index 39533edea66b88611f7038a28e6b155b26d4ec5b..2270ff4945d53acd91fe85cb2a26ad7e98f8eab5 100644 (file)
@@ -3,8 +3,8 @@
 import 'mocha'
 import * as chai from 'chai'
 import { VideoDetails } from '../../../shared/models/videos'
-import { waitJobs } from '../../../shared/utils/server/jobs'
-import { addVideoCommentThread } from '../../../shared/utils/videos/video-comments'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
+import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments'
 import {
   addVideoChannel,
   createUser,
@@ -21,8 +21,8 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../shared/utils'
-import { getAccountsList } from '../../../shared/utils/users/accounts'
+} from '../../../shared/extra-utils'
+import { getAccountsList } from '../../../shared/extra-utils/users/accounts'
 
 const expect = chai.expect
 
index 06b4a9c5a1c404599e3398b333e42d4125cf21a9..1161895100183ab0616856644dc79399ad268f70 100644 (file)
@@ -15,7 +15,7 @@ import {
   updateCustomConfig,
   updateCustomSubConfig,
   uploadVideo
-} from '../../shared/utils'
+} from '../../shared/extra-utils'
 
 const expect = chai.expect
 
index d632be42756017c77c2f93323bd36614742979bb..0e9ea1a18eaa70f8aef3b6d0dc95503519ea5b82 100644 (file)
@@ -13,10 +13,10 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo, userLogin
-} from '../../../shared/utils'
+} from '../../../shared/extra-utils'
 import * as libxmljs from 'libxmljs'
-import { addVideoCommentThread } from '../../../shared/utils/videos/video-comments'
-import { waitJobs } from '../../../shared/utils/server/jobs'
+import { addVideoCommentThread } from '../../../shared/extra-utils/videos/video-comments'
+import { waitJobs } from '../../../shared/extra-utils/server/jobs'
 import { User } from '../../../shared/models/users'
 
 chai.use(require('chai-xml'))
index 95a74fdfaa0e28e77ed667e72e4578833474051f..a754bc6e27ab39c5560c6ebc66a7d744f2def7f0 100644 (file)
@@ -2,7 +2,7 @@
 
 import 'mocha'
 import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
-import { get4KFileUrl, root, wait } from '../../../shared/utils'
+import { get4KFileUrl, root, wait } from '../../../shared/extra-utils'
 import { join } from 'path'
 import { pathExists, remove } from 'fs-extra'
 import { expect } from 'chai'
index 104876f2f2465c6ea28ff3e950aa88272c849160..d78b62d60c35186fb4e8f86b03a5fc8b030075a6 100644 (file)
@@ -12,7 +12,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../shared/utils'
+} from '../../shared/extra-utils'
 import { VideoPrivacy } from '../../shared/models/videos'
 
 const expect = chai.expect
index 3616127ad038d1f6adf258b0bd227d85aae74d65..459c9cbd83fc8f97d9c94ff69b9c318f612ad185 100644 (file)
@@ -10,7 +10,7 @@ import {
   ServerInfo,
   setAccessTokensToServers,
   uploadVideo
-} from '../../../shared/utils'
+} from '../../../shared/extra-utils'
 import * as Bluebird from 'bluebird'
 
 start()
index ac3baaf9a1a697067aa2394f8d5fa8577085f352..8b070004d7ac06fedcd880c4c224ea253f4c9679 100644 (file)
@@ -16,8 +16,8 @@ import {
   updateVideo,
   uploadVideo, viewVideo,
   wait
-} from '../../../shared/utils'
-import { getJobsListPaginationAndSort } from '../../../shared/utils/server/jobs'
+} from '../../../shared/extra-utils'
+import { getJobsListPaginationAndSort } from '../../../shared/extra-utils/server/jobs'
 
 interface ServerInfo extends DefaultServerInfo {
   requestsNumber: number
index a68665f5bb7ff6bcfe6888a60201869a1495fc60..85660de2c9c0716b268f570c28f146a872d1ab09 100644 (file)
@@ -6,7 +6,7 @@ import {
   Server,
   Client,
   User
-} from '../../shared/utils'
+} from '../../shared/extra-utils'
 
 program
   .option('-u, --url <url>', 'Server url')
index 03f13b5e2681a49d4a2cdb6140bf5b7d3e482dd2..8c4c711f78daf0d4d34624c3ba25b8baf0f008a1 100644 (file)
@@ -6,7 +6,7 @@ import { join } from 'path'
 import { VideoPrivacy } from '../../shared/models/videos'
 import { doRequestAndSaveToFile } from '../helpers/requests'
 import { CONSTRAINTS_FIELDS } from '../initializers/constants'
-import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/utils/index'
+import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/extra-utils/index'
 import { truncate } from 'lodash'
 import * as prompt from 'prompt'
 import { remove } from 'fs-extra'
index ebc62c96512ce6a6c2b7aaa65fe41130c3f9f980..13ca94e516a8fd5da343ad4b5161301b4a1e88bc 100644 (file)
@@ -1,8 +1,8 @@
 import * as program from 'commander'
 import { access, constants } from 'fs-extra'
 import { isAbsolute } from 'path'
-import { getClient, login } from '../../shared/utils'
-import { uploadVideo } from '../../shared/utils/'
+import { getClient, login } from '../../shared/extra-utils'
+import { uploadVideo } from '../../shared/extra-utils/'
 import { VideoPrivacy } from '../../shared/models/videos'
 import { netrc, getSettings } from './cli'
 
diff --git a/shared/extra-utils/cli/cli.ts b/shared/extra-utils/cli/cli.ts
new file mode 100644 (file)
index 0000000..54d05e9
--- /dev/null
@@ -0,0 +1,24 @@
+import { exec } from 'child_process'
+
+import { ServerInfo } from '../server/servers'
+
+function getEnvCli (server?: ServerInfo) {
+  return `NODE_ENV=test NODE_APP_INSTANCE=${server.serverNumber}`
+}
+
+async function execCLI (command: string) {
+  return new Promise<string>((res, rej) => {
+    exec(command, (err, stdout, stderr) => {
+      if (err) return rej(err)
+
+      return res(stdout)
+    })
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  execCLI,
+  getEnvCli
+}
diff --git a/shared/extra-utils/feeds/feeds.ts b/shared/extra-utils/feeds/feeds.ts
new file mode 100644 (file)
index 0000000..af6df2b
--- /dev/null
@@ -0,0 +1,32 @@
+import * as request from 'supertest'
+
+type FeedType = 'videos' | 'video-comments'
+
+function getXMLfeed (url: string, feed: FeedType, format?: string) {
+  const path = '/feeds/' + feed + '.xml'
+
+  return request(url)
+          .get(path)
+          .query((format) ? { format: format } : {})
+          .set('Accept', 'application/xml')
+          .expect(200)
+          .expect('Content-Type', /xml/)
+}
+
+function getJSONfeed (url: string, feed: FeedType, query: any = {}) {
+  const path = '/feeds/' + feed + '.json'
+
+  return request(url)
+          .get(path)
+          .query(query)
+          .set('Accept', 'application/json')
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getXMLfeed,
+  getJSONfeed
+}
diff --git a/shared/extra-utils/index.ts b/shared/extra-utils/index.ts
new file mode 100644 (file)
index 0000000..9d0bbaa
--- /dev/null
@@ -0,0 +1,26 @@
+export * from './server/activitypub'
+export * from './cli/cli'
+export * from './server/clients'
+export * from './server/config'
+export * from './server/jobs'
+export * from './users/login'
+export * from './miscs/miscs'
+export * from './miscs/stubs'
+export * from './miscs/sql'
+export * from './server/follows'
+export * from './requests/requests'
+export * from './requests/check-api-params'
+export * from './server/servers'
+export * from './videos/services'
+export * from './videos/video-playlists'
+export * from './users/users'
+export * from './users/accounts'
+export * from './videos/video-abuses'
+export * from './videos/video-blacklist'
+export * from './videos/video-channels'
+export * from './videos/video-comments'
+export * from './videos/video-streaming-playlists'
+export * from './videos/videos'
+export * from './videos/video-change-ownership'
+export * from './feeds/feeds'
+export * from './search/videos'
diff --git a/shared/extra-utils/logs/logs.ts b/shared/extra-utils/logs/logs.ts
new file mode 100644 (file)
index 0000000..cbb1afb
--- /dev/null
@@ -0,0 +1,18 @@
+import { makeGetRequest } from '../requests/requests'
+import { LogLevel } from '../../models/server/log-level.type'
+
+function getLogs (url: string, accessToken: string, startDate: Date, endDate?: Date, level?: LogLevel) {
+  const path = '/api/v1/server/logs'
+
+  return makeGetRequest({
+    url,
+    path,
+    token: accessToken,
+    query: { startDate, endDate, level },
+    statusCodeExpected: 200
+  })
+}
+
+export {
+  getLogs
+}
diff --git a/shared/extra-utils/miscs/email-child-process.js b/shared/extra-utils/miscs/email-child-process.js
new file mode 100644 (file)
index 0000000..40ae37d
--- /dev/null
@@ -0,0 +1,27 @@
+const MailDev = require('maildev')
+
+// must run maildev as forked ChildProcess
+// failed instantiation stops main process with exit code 0
+process.on('message', (msg) => {
+  if (msg.start) {
+    const maildev = new MailDev({
+      ip: '127.0.0.1',
+      smtp: 1025,
+      disableWeb: true,
+      silent: true
+    })
+
+    maildev.on('new', email => {
+      process.send({ email })
+    })
+
+    maildev.listen(err => {
+      if (err) {
+        // cannot send as Error object
+        return process.send({ err: err.message })
+      }
+
+      return process.send({ err: null })
+    })
+  }
+})
diff --git a/shared/extra-utils/miscs/email.ts b/shared/extra-utils/miscs/email.ts
new file mode 100644 (file)
index 0000000..f9f1bd9
--- /dev/null
@@ -0,0 +1,64 @@
+import { fork, ChildProcess } from 'child_process'
+
+class MockSmtpServer {
+
+  private static instance: MockSmtpServer
+  private started = false
+  private emailChildProcess: ChildProcess
+  private emails: object[]
+
+  private constructor () {
+    this.emailChildProcess = fork(`${__dirname}/email-child-process`, [])
+
+    this.emailChildProcess.on('message', (msg) => {
+      if (msg.email) {
+        return this.emails.push(msg.email)
+      }
+    })
+
+    process.on('exit', () => this.kill())
+  }
+
+  collectEmails (emailsCollection: object[]) {
+    return new Promise((res, rej) => {
+      if (this.started) {
+        this.emails = emailsCollection
+        return res()
+      }
+
+      // ensure maildev isn't started until
+      // unexpected exit can be reported to test runner
+      this.emailChildProcess.send({ start: true })
+      this.emailChildProcess.on('exit', () => {
+        return rej(new Error('maildev exited unexpectedly, confirm port not in use'))
+      })
+      this.emailChildProcess.on('message', (msg) => {
+        if (msg.err) {
+          return rej(new Error(msg.err))
+        }
+        this.started = true
+        this.emails = emailsCollection
+        return res()
+      })
+    })
+  }
+
+  kill () {
+    if (!this.emailChildProcess) return
+
+    process.kill(this.emailChildProcess.pid)
+
+    this.emailChildProcess = null
+    MockSmtpServer.instance = null
+  }
+
+  static get Instance () {
+    return this.instance || (this.instance = new this())
+  }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  MockSmtpServer
+}
diff --git a/shared/extra-utils/miscs/miscs.ts b/shared/extra-utils/miscs/miscs.ts
new file mode 100644 (file)
index 0000000..d1ffb7b
--- /dev/null
@@ -0,0 +1,101 @@
+/* tslint:disable:no-unused-expression */
+
+import * as chai from 'chai'
+import { isAbsolute, join } from 'path'
+import * as request from 'supertest'
+import * as WebTorrent from 'webtorrent'
+import { pathExists, readFile } from 'fs-extra'
+import * as ffmpeg from 'fluent-ffmpeg'
+
+const expect = chai.expect
+let webtorrent = new WebTorrent()
+
+function immutableAssign <T, U> (target: T, source: U) {
+  return Object.assign<{}, T, U>({}, target, source)
+}
+
+  // Default interval -> 5 minutes
+function dateIsValid (dateString: string, interval = 300000) {
+  const dateToCheck = new Date(dateString)
+  const now = new Date()
+
+  return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval
+}
+
+function wait (milliseconds: number) {
+  return new Promise(resolve => setTimeout(resolve, milliseconds))
+}
+
+function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
+  if (refreshWebTorrent === true) webtorrent = new WebTorrent()
+
+  return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
+}
+
+function root () {
+  // We are in /miscs
+  return join(__dirname, '..', '..', '..')
+}
+
+async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {
+  const res = await request(url)
+    .get(imagePath)
+    .expect(200)
+
+  const body = res.body
+
+  const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension))
+  const minLength = body.length - ((20 * body.length) / 100)
+  const maxLength = body.length + ((20 * body.length) / 100)
+
+  expect(data.length).to.be.above(minLength)
+  expect(data.length).to.be.below(maxLength)
+}
+
+function buildAbsoluteFixturePath (path: string, customTravisPath = false) {
+  if (isAbsolute(path)) {
+    return path
+  }
+
+  if (customTravisPath && process.env.TRAVIS) return join(process.env.HOME, 'fixtures', path)
+
+  return join(root(), 'server', 'tests', 'fixtures', path)
+}
+
+async function generateHighBitrateVideo () {
+  const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true)
+
+  const exists = await pathExists(tempFixturePath)
+  if (!exists) {
+
+    // Generate a random, high bitrate video on the fly, so we don't have to include
+    // a large file in the repo. The video needs to have a certain minimum length so
+    // that FFmpeg properly applies bitrate limits.
+    // https://stackoverflow.com/a/15795112
+    return new Promise<string>(async (res, rej) => {
+      ffmpeg()
+        .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
+        .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
+        .outputOptions([ '-maxrate 10M', '-bufsize 10M' ])
+        .output(tempFixturePath)
+        .on('error', rej)
+        .on('end', () => res(tempFixturePath))
+        .run()
+    })
+  }
+
+  return tempFixturePath
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  dateIsValid,
+  wait,
+  webtorrentAdd,
+  immutableAssign,
+  testImage,
+  buildAbsoluteFixturePath,
+  root,
+  generateHighBitrateVideo
+}
diff --git a/shared/extra-utils/miscs/sql.ts b/shared/extra-utils/miscs/sql.ts
new file mode 100644 (file)
index 0000000..b281471
--- /dev/null
@@ -0,0 +1,80 @@
+import * as Sequelize from 'sequelize'
+
+let sequelizes: { [ id: number ]: Sequelize.Sequelize } = {}
+
+function getSequelize (serverNumber: number) {
+  if (sequelizes[serverNumber]) return sequelizes[serverNumber]
+
+  const dbname = 'peertube_test' + serverNumber
+  const username = 'peertube'
+  const password = 'peertube'
+  const host = 'localhost'
+  const port = 5432
+
+  const seq = new Sequelize(dbname, username, password, {
+    dialect: 'postgres',
+    host,
+    port,
+    operatorsAliases: false,
+    logging: false
+  })
+
+  sequelizes[serverNumber] = seq
+
+  return seq
+}
+
+function setActorField (serverNumber: number, to: string, field: string, value: string) {
+  const seq = getSequelize(serverNumber)
+
+  const options = { type: Sequelize.QueryTypes.UPDATE }
+
+  return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
+}
+
+function setVideoField (serverNumber: number, uuid: string, field: string, value: string) {
+  const seq = getSequelize(serverNumber)
+
+  const options = { type: Sequelize.QueryTypes.UPDATE }
+
+  return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
+}
+
+function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) {
+  const seq = getSequelize(serverNumber)
+
+  const options = { type: Sequelize.QueryTypes.UPDATE }
+
+  return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
+}
+
+async function countVideoViewsOf (serverNumber: number, uuid: string) {
+  const seq = getSequelize(serverNumber)
+
+  // tslint:disable
+  const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
+
+  const options = { type: Sequelize.QueryTypes.SELECT }
+  const [ { total } ] = await seq.query(query, options)
+
+  if (!total) return 0
+
+  return parseInt(total, 10)
+}
+
+async function closeAllSequelize (servers: any[]) {
+  for (let i = 1; i <= servers.length; i++) {
+    if (sequelizes[ i ]) {
+      await sequelizes[ i ].close()
+      delete sequelizes[ i ]
+    }
+  }
+}
+
+export {
+  setVideoField,
+  setPlaylistField,
+  setActorField,
+  countVideoViewsOf,
+  closeAllSequelize
+}
diff --git a/shared/extra-utils/miscs/stubs.ts b/shared/extra-utils/miscs/stubs.ts
new file mode 100644 (file)
index 0000000..d1eb0e3
--- /dev/null
@@ -0,0 +1,14 @@
+function buildRequestStub (): any {
+  return { }
+}
+
+function buildResponseStub (): any {
+  return {
+    locals: {}
+  }
+}
+
+export {
+  buildResponseStub,
+  buildRequestStub
+}
diff --git a/shared/extra-utils/overviews/overviews.ts b/shared/extra-utils/overviews/overviews.ts
new file mode 100644 (file)
index 0000000..23e3ceb
--- /dev/null
@@ -0,0 +1,18 @@
+import { makeGetRequest } from '../requests/requests'
+
+function getVideosOverview (url: string, useCache = false) {
+  const path = '/api/v1/overviews/videos'
+
+  const query = {
+    t: useCache ? undefined : new Date().getTime()
+  }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+export { getVideosOverview }
diff --git a/shared/extra-utils/requests/activitypub.ts b/shared/extra-utils/requests/activitypub.ts
new file mode 100644 (file)
index 0000000..4762a86
--- /dev/null
@@ -0,0 +1,43 @@
+import { doRequest } from '../../../server/helpers/requests'
+import { HTTP_SIGNATURE } from '../../../server/initializers/constants'
+import { buildGlobalHeaders } from '../../../server/lib/job-queue/handlers/utils/activitypub-http-utils'
+import { activityPubContextify } from '../../../server/helpers/activitypub'
+
+function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) {
+  const options = {
+    method: 'POST',
+    uri: url,
+    json: body,
+    httpSignature,
+    headers
+  }
+
+  return doRequest(options)
+}
+
+async function makeFollowRequest (to: { url: string }, by: { url: string, privateKey }) {
+  const follow = {
+    type: 'Follow',
+    id: by.url + '/toto',
+    actor: by.url,
+    object: to.url
+  }
+
+  const body = activityPubContextify(follow)
+
+  const httpSignature = {
+    algorithm: HTTP_SIGNATURE.ALGORITHM,
+    authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
+    keyId: by.url,
+    key: by.privateKey,
+    headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
+  }
+  const headers = buildGlobalHeaders(body)
+
+  return makePOSTAPRequest(to.url, body, httpSignature, headers)
+}
+
+export {
+  makePOSTAPRequest,
+  makeFollowRequest
+}
diff --git a/shared/extra-utils/requests/check-api-params.ts b/shared/extra-utils/requests/check-api-params.ts
new file mode 100644 (file)
index 0000000..a2a5496
--- /dev/null
@@ -0,0 +1,40 @@
+import { makeGetRequest } from './requests'
+import { immutableAssign } from '../miscs/miscs'
+
+function checkBadStartPagination (url: string, path: string, token?: string, query = {}) {
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    query: immutableAssign(query, { start: 'hello' }),
+    statusCodeExpected: 400
+  })
+}
+
+function checkBadCountPagination (url: string, path: string, token?: string, query = {}) {
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    query: immutableAssign(query, { count: 'hello' }),
+    statusCodeExpected: 400
+  })
+}
+
+function checkBadSortPagination (url: string, path: string, token?: string, query = {}) {
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    query: immutableAssign(query, { sort: 'hello' }),
+    statusCodeExpected: 400
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  checkBadStartPagination,
+  checkBadCountPagination,
+  checkBadSortPagination
+}
diff --git a/shared/extra-utils/requests/requests.ts b/shared/extra-utils/requests/requests.ts
new file mode 100644 (file)
index 0000000..3532fb4
--- /dev/null
@@ -0,0 +1,184 @@
+import * as request from 'supertest'
+import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
+import { isAbsolute, join } from 'path'
+import { parse } from 'url'
+
+function get4KFileUrl () {
+  return 'https://download.cpy.re/peertube/4k_file.txt'
+}
+
+function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
+  const { host, protocol, pathname } = parse(url)
+
+  return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
+}
+
+function makeGetRequest (options: {
+  url: string,
+  path?: string,
+  query?: any,
+  token?: string,
+  statusCodeExpected?: number,
+  contentType?: string,
+  range?: string
+}) {
+  if (!options.statusCodeExpected) options.statusCodeExpected = 400
+  if (options.contentType === undefined) options.contentType = 'application/json'
+
+  const req = request(options.url).get(options.path)
+
+  if (options.contentType) req.set('Accept', options.contentType)
+  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
+  if (options.query) req.query(options.query)
+  if (options.range) req.set('Range', options.range)
+
+  return req.expect(options.statusCodeExpected)
+}
+
+function makeDeleteRequest (options: {
+  url: string,
+  path: string,
+  token?: string,
+  statusCodeExpected?: number
+}) {
+  if (!options.statusCodeExpected) options.statusCodeExpected = 400
+
+  const req = request(options.url)
+    .delete(options.path)
+    .set('Accept', 'application/json')
+
+  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
+
+  return req.expect(options.statusCodeExpected)
+}
+
+function makeUploadRequest (options: {
+  url: string,
+  method?: 'POST' | 'PUT',
+  path: string,
+  token?: string,
+  fields: { [ fieldName: string ]: any },
+  attaches: { [ attachName: string ]: any | any[] },
+  statusCodeExpected?: number
+}) {
+  if (!options.statusCodeExpected) options.statusCodeExpected = 400
+
+  let req: request.Test
+  if (options.method === 'PUT') {
+    req = request(options.url).put(options.path)
+  } else {
+    req = request(options.url).post(options.path)
+  }
+
+  req.set('Accept', 'application/json')
+
+  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
+
+  Object.keys(options.fields).forEach(field => {
+    const value = options.fields[field]
+
+    if (value === undefined) return
+
+    if (Array.isArray(value)) {
+      for (let i = 0; i < value.length; i++) {
+        req.field(field + '[' + i + ']', value[i])
+      }
+    } else {
+      req.field(field, value)
+    }
+  })
+
+  Object.keys(options.attaches).forEach(attach => {
+    const value = options.attaches[attach]
+    if (Array.isArray(value)) {
+      req.attach(attach, buildAbsoluteFixturePath(value[0]), value[1])
+    } else {
+      req.attach(attach, buildAbsoluteFixturePath(value))
+    }
+  })
+
+  return req.expect(options.statusCodeExpected)
+}
+
+function makePostBodyRequest (options: {
+  url: string,
+  path: string,
+  token?: string,
+  fields?: { [ fieldName: string ]: any },
+  statusCodeExpected?: number
+}) {
+  if (!options.fields) options.fields = {}
+  if (!options.statusCodeExpected) options.statusCodeExpected = 400
+
+  const req = request(options.url)
+                .post(options.path)
+                .set('Accept', 'application/json')
+
+  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
+
+  return req.send(options.fields)
+            .expect(options.statusCodeExpected)
+}
+
+function makePutBodyRequest (options: {
+  url: string,
+  path: string,
+  token?: string,
+  fields: { [ fieldName: string ]: any },
+  statusCodeExpected?: number
+}) {
+  if (!options.statusCodeExpected) options.statusCodeExpected = 400
+
+  const req = request(options.url)
+                .put(options.path)
+                .set('Accept', 'application/json')
+
+  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
+
+  return req.send(options.fields)
+            .expect(options.statusCodeExpected)
+}
+
+function makeHTMLRequest (url: string, path: string) {
+  return request(url)
+    .get(path)
+    .set('Accept', 'text/html')
+    .expect(200)
+}
+
+function updateAvatarRequest (options: {
+  url: string,
+  path: string,
+  accessToken: string,
+  fixture: string
+}) {
+  let filePath = ''
+  if (isAbsolute(options.fixture)) {
+    filePath = options.fixture
+  } else {
+    filePath = join(root(), 'server', 'tests', 'fixtures', options.fixture)
+  }
+
+  return makeUploadRequest({
+    url: options.url,
+    path: options.path,
+    token: options.accessToken,
+    fields: {},
+    attaches: { avatarfile: filePath },
+    statusCodeExpected: 200
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  get4KFileUrl,
+  makeHTMLRequest,
+  makeGetRequest,
+  makeUploadRequest,
+  makePostBodyRequest,
+  makePutBodyRequest,
+  makeDeleteRequest,
+  makeRawRequest,
+  updateAvatarRequest
+}
diff --git a/shared/extra-utils/search/video-channels.ts b/shared/extra-utils/search/video-channels.ts
new file mode 100644 (file)
index 0000000..0532134
--- /dev/null
@@ -0,0 +1,22 @@
+import { makeGetRequest } from '../requests/requests'
+
+function searchVideoChannel (url: string, search: string, token?: string, statusCodeExpected = 200) {
+  const path = '/api/v1/search/video-channels'
+
+  return makeGetRequest({
+    url,
+    path,
+    query: {
+      sort: '-createdAt',
+      search
+    },
+    token,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  searchVideoChannel
+}
diff --git a/shared/extra-utils/search/videos.ts b/shared/extra-utils/search/videos.ts
new file mode 100644 (file)
index 0000000..ba46270
--- /dev/null
@@ -0,0 +1,77 @@
+/* tslint:disable:no-unused-expression */
+
+import * as request from 'supertest'
+import { VideosSearchQuery } from '../../models/search'
+import { immutableAssign } from '../miscs/miscs'
+
+function searchVideo (url: string, search: string) {
+  const path = '/api/v1/search/videos'
+  const req = request(url)
+    .get(path)
+    .query({ sort: '-publishedAt', search })
+    .set('Accept', 'application/json')
+
+  return req.expect(200)
+            .expect('Content-Type', /json/)
+}
+
+function searchVideoWithToken (url: string, search: string, token: string, query: { nsfw?: boolean } = {}) {
+  const path = '/api/v1/search/videos'
+  const req = request(url)
+    .get(path)
+    .set('Authorization', 'Bearer ' + token)
+    .query(immutableAssign(query, { sort: '-publishedAt', search }))
+    .set('Accept', 'application/json')
+
+  return req.expect(200)
+            .expect('Content-Type', /json/)
+}
+
+function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/search/videos'
+
+  const req = request(url)
+    .get(path)
+    .query({ start })
+    .query({ search })
+    .query({ count })
+
+  if (sort) req.query({ sort })
+
+  return req.set('Accept', 'application/json')
+            .expect(200)
+            .expect('Content-Type', /json/)
+}
+
+function searchVideoWithSort (url: string, search: string, sort: string) {
+  const path = '/api/v1/search/videos'
+
+  return request(url)
+    .get(path)
+    .query({ search })
+    .query({ sort })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function advancedVideosSearch (url: string, options: VideosSearchQuery) {
+  const path = '/api/v1/search/videos'
+
+  return request(url)
+    .get(path)
+    .query(options)
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  searchVideo,
+  advancedVideosSearch,
+  searchVideoWithToken,
+  searchVideoWithPagination,
+  searchVideoWithSort
+}
diff --git a/shared/extra-utils/server/activitypub.ts b/shared/extra-utils/server/activitypub.ts
new file mode 100644 (file)
index 0000000..eccb198
--- /dev/null
@@ -0,0 +1,14 @@
+import * as request from 'supertest'
+
+function makeActivityPubGetRequest (url: string, path: string, expectedStatus = 200) {
+  return request(url)
+    .get(path)
+    .set('Accept', 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8')
+    .expect(expectedStatus)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  makeActivityPubGetRequest
+}
diff --git a/shared/extra-utils/server/clients.ts b/shared/extra-utils/server/clients.ts
new file mode 100644 (file)
index 0000000..273aac7
--- /dev/null
@@ -0,0 +1,19 @@
+import * as request from 'supertest'
+import * as urlUtil from 'url'
+
+function getClient (url: string) {
+  const path = '/api/v1/oauth-clients/local'
+
+  return request(url)
+          .get(path)
+          .set('Host', urlUtil.parse(url).host)
+          .set('Accept', 'application/json')
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getClient
+}
diff --git a/shared/extra-utils/server/config.ts b/shared/extra-utils/server/config.ts
new file mode 100644 (file)
index 0000000..deb77e9
--- /dev/null
@@ -0,0 +1,156 @@
+import { makeDeleteRequest, makeGetRequest, makePutBodyRequest } from '../requests/requests'
+import { CustomConfig } from '../../models/server/custom-config.model'
+
+function getConfig (url: string) {
+  const path = '/api/v1/config'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getAbout (url: string) {
+  const path = '/api/v1/config/about'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getCustomConfig (url: string, token: string, statusCodeExpected = 200) {
+  const path = '/api/v1/config/custom'
+
+  return makeGetRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+function updateCustomConfig (url: string, token: string, newCustomConfig: CustomConfig, statusCodeExpected = 200) {
+  const path = '/api/v1/config/custom'
+
+  return makePutBodyRequest({
+    url,
+    token,
+    path,
+    fields: newCustomConfig,
+    statusCodeExpected
+  })
+}
+
+function updateCustomSubConfig (url: string, token: string, newConfig: any) {
+  const updateParams: CustomConfig = {
+    instance: {
+      name: 'PeerTube updated',
+      shortDescription: 'my short description',
+      description: 'my super description',
+      terms: 'my super terms',
+      defaultClientRoute: '/videos/recently-added',
+      isNSFW: true,
+      defaultNSFWPolicy: 'blur',
+      customizations: {
+        javascript: 'alert("coucou")',
+        css: 'body { background-color: red; }'
+      }
+    },
+    services: {
+      twitter: {
+        username: '@MySuperUsername',
+        whitelisted: true
+      }
+    },
+    cache: {
+      previews: {
+        size: 2
+      },
+      captions: {
+        size: 3
+      }
+    },
+    signup: {
+      enabled: false,
+      limit: 5,
+      requiresEmailVerification: false
+    },
+    admin: {
+      email: 'superadmin1@example.com'
+    },
+    contactForm: {
+      enabled: true
+    },
+    user: {
+      videoQuota: 5242881,
+      videoQuotaDaily: 318742
+    },
+    transcoding: {
+      enabled: true,
+      allowAdditionalExtensions: true,
+      threads: 1,
+      resolutions: {
+        '240p': false,
+        '360p': true,
+        '480p': true,
+        '720p': false,
+        '1080p': false
+      },
+      hls: {
+        enabled: false
+      }
+    },
+    import: {
+      videos: {
+        http: {
+          enabled: false
+        },
+        torrent: {
+          enabled: false
+        }
+      }
+    },
+    autoBlacklist: {
+      videos: {
+        ofUsers: {
+          enabled: false
+        }
+      }
+    },
+    followers: {
+      instance: {
+        enabled: true,
+        manualApproval: false
+      }
+    }
+  }
+
+  Object.assign(updateParams, newConfig)
+
+  return updateCustomConfig(url, token, updateParams)
+}
+
+function deleteCustomConfig (url: string, token: string, statusCodeExpected = 200) {
+  const path = '/api/v1/config/custom'
+
+  return makeDeleteRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getConfig,
+  getCustomConfig,
+  updateCustomConfig,
+  getAbout,
+  deleteCustomConfig,
+  updateCustomSubConfig
+}
diff --git a/shared/extra-utils/server/contact-form.ts b/shared/extra-utils/server/contact-form.ts
new file mode 100644 (file)
index 0000000..80394cf
--- /dev/null
@@ -0,0 +1,28 @@
+import * as request from 'supertest'
+import { ContactForm } from '../../models/server'
+
+function sendContactForm (options: {
+  url: string,
+  fromEmail: string,
+  fromName: string,
+  body: string,
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/server/contact'
+
+  const body: ContactForm = {
+    fromEmail: options.fromEmail,
+    fromName: options.fromName,
+    body: options.body
+  }
+  return request(options.url)
+    .post(path)
+    .send(body)
+    .expect(options.expectedStatus || 204)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  sendContactForm
+}
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
new file mode 100644 (file)
index 0000000..1505804
--- /dev/null
@@ -0,0 +1,111 @@
+import * as request from 'supertest'
+import { ServerInfo } from './servers'
+import { waitJobs } from './jobs'
+import { makeGetRequest, makePostBodyRequest } from '..'
+
+function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
+  const path = '/api/v1/server/followers'
+
+  return request(url)
+    .get(path)
+    .query({ start })
+    .query({ count })
+    .query({ sort })
+    .query({ search })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function acceptFollower (url: string, token: string, follower: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/followers/' + follower + '/accept'
+
+  return makePostBodyRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+function rejectFollower (url: string, token: string, follower: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/followers/' + follower + '/reject'
+
+  return makePostBodyRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
+  const path = '/api/v1/server/following'
+
+  return request(url)
+    .get(path)
+    .query({ start })
+    .query({ count })
+    .query({ sort })
+    .query({ search })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function follow (follower: string, following: string[], accessToken: string, expectedStatus = 204) {
+  const path = '/api/v1/server/following'
+
+  const followingHosts = following.map(f => f.replace(/^http:\/\//, ''))
+  return request(follower)
+    .post(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .send({ 'hosts': followingHosts })
+    .expect(expectedStatus)
+}
+
+async function unfollow (url: string, accessToken: string, target: ServerInfo, expectedStatus = 204) {
+  const path = '/api/v1/server/following/' + target.host
+
+  return request(url)
+    .delete(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(expectedStatus)
+}
+
+function removeFollower (url: string, accessToken: string, follower: ServerInfo, expectedStatus = 204) {
+  const path = '/api/v1/server/followers/peertube@' + follower.host
+
+  return request(url)
+    .delete(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(expectedStatus)
+}
+
+async function doubleFollow (server1: ServerInfo, server2: ServerInfo) {
+  await Promise.all([
+    follow(server1.url, [ server2.url ], server1.accessToken),
+    follow(server2.url, [ server1.url ], server2.accessToken)
+  ])
+
+  // Wait request propagation
+  await waitJobs([ server1, server2 ])
+
+  return true
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getFollowersListPaginationAndSort,
+  getFollowingListPaginationAndSort,
+  unfollow,
+  removeFollower,
+  follow,
+  doubleFollow,
+  acceptFollower,
+  rejectFollower
+}
diff --git a/shared/extra-utils/server/jobs.ts b/shared/extra-utils/server/jobs.ts
new file mode 100644 (file)
index 0000000..692b5e2
--- /dev/null
@@ -0,0 +1,82 @@
+import * as request from 'supertest'
+import { Job, JobState } from '../../models'
+import { wait } from '../miscs/miscs'
+import { ServerInfo } from './servers'
+
+function getJobsList (url: string, accessToken: string, state: JobState) {
+  const path = '/api/v1/jobs/' + state
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function getJobsListPaginationAndSort (url: string, accessToken: string, state: JobState, start: number, count: number, sort: string) {
+  const path = '/api/v1/jobs/' + state
+
+  return request(url)
+          .get(path)
+          .query({ start })
+          .query({ count })
+          .query({ sort })
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
+  const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) : 2000
+  let servers: ServerInfo[]
+
+  if (Array.isArray(serversArg) === false) servers = [ serversArg as ServerInfo ]
+  else servers = serversArg as ServerInfo[]
+
+  const states: JobState[] = [ 'waiting', 'active', 'delayed' ]
+  let pendingRequests = false
+
+  function tasksBuilder () {
+    const tasks: Promise<any>[] = []
+    pendingRequests = false
+
+    // Check if each server has pending request
+    for (const server of servers) {
+      for (const state of states) {
+        const p = getJobsListPaginationAndSort(server.url, server.accessToken, state, 0, 10, '-createdAt')
+          .then(res => res.body.data)
+          .then((jobs: Job[]) => jobs.filter(j => j.type !== 'videos-views'))
+          .then(jobs => {
+            if (jobs.length !== 0) pendingRequests = true
+          })
+        tasks.push(p)
+      }
+    }
+
+    return tasks
+  }
+
+  do {
+    await Promise.all(tasksBuilder())
+
+    // Retry, in case of new jobs were created
+    if (pendingRequests === false) {
+      await wait(pendingJobWait)
+      await Promise.all(tasksBuilder())
+    }
+
+    if (pendingRequests) {
+      await wait(1000)
+    }
+  } while (pendingRequests)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getJobsList,
+  waitJobs,
+  getJobsListPaginationAndSort
+}
diff --git a/shared/extra-utils/server/redundancy.ts b/shared/extra-utils/server/redundancy.ts
new file mode 100644 (file)
index 0000000..c39ff2c
--- /dev/null
@@ -0,0 +1,17 @@
+import { makePutBodyRequest } from '../requests/requests'
+
+async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) {
+  const path = '/api/v1/server/redundancy/' + host
+
+  return makePutBodyRequest({
+    url,
+    path,
+    token: accessToken,
+    fields: { redundancyAllowed },
+    statusCodeExpected: expectedStatus
+  })
+}
+
+export {
+  updateRedundancy
+}
diff --git a/shared/extra-utils/server/servers.ts b/shared/extra-utils/server/servers.ts
new file mode 100644 (file)
index 0000000..5288d25
--- /dev/null
@@ -0,0 +1,219 @@
+/* tslint:disable:no-unused-expression */
+
+import { ChildProcess, exec, fork } from 'child_process'
+import { join } from 'path'
+import { root, wait } from '../miscs/miscs'
+import { readdir, readFile } from 'fs-extra'
+import { existsSync } from 'fs'
+import { expect } from 'chai'
+import { VideoChannel } from '../../models/videos'
+
+interface ServerInfo {
+  app: ChildProcess,
+  url: string
+  host: string
+  serverNumber: number
+
+  client: {
+    id: string,
+    secret: string
+  }
+
+  user: {
+    username: string,
+    password: string,
+    email?: string
+  }
+
+  accessToken?: string
+  videoChannel?: VideoChannel
+
+  video?: {
+    id: number
+    uuid: string
+    name: string
+    account: {
+      name: string
+    }
+  }
+
+  remoteVideo?: {
+    id: number
+    uuid: string
+  }
+
+  videos?: { id: number, uuid: string }[]
+}
+
+function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
+  let apps = []
+  let i = 0
+
+  return new Promise<ServerInfo[]>(res => {
+    function anotherServerDone (serverNumber, app) {
+      apps[serverNumber - 1] = app
+      i++
+      if (i === totalServers) {
+        return res(apps)
+      }
+    }
+
+    flushTests()
+      .then(() => {
+        for (let j = 1; j <= totalServers; j++) {
+          runServer(j, configOverride).then(app => anotherServerDone(j, app))
+        }
+      })
+  })
+}
+
+function flushTests () {
+  return new Promise<void>((res, rej) => {
+    return exec('npm run clean:server:test', err => {
+      if (err) return rej(err)
+
+      return res()
+    })
+  })
+}
+
+function runServer (serverNumber: number, configOverride?: Object, args = []) {
+  const server: ServerInfo = {
+    app: null,
+    serverNumber: serverNumber,
+    url: `http://localhost:${9000 + serverNumber}`,
+    host: `localhost:${9000 + serverNumber}`,
+    client: {
+      id: null,
+      secret: null
+    },
+    user: {
+      username: null,
+      password: null
+    }
+  }
+
+  // These actions are async so we need to be sure that they have both been done
+  const serverRunString = {
+    'Server listening': false
+  }
+  const key = 'Database peertube_test' + serverNumber + ' is ready'
+  serverRunString[key] = false
+
+  const regexps = {
+    client_id: 'Client id: (.+)',
+    client_secret: 'Client secret: (.+)',
+    user_username: 'Username: (.+)',
+    user_password: 'User password: (.+)'
+  }
+
+  // Share the environment
+  const env = Object.create(process.env)
+  env['NODE_ENV'] = 'test'
+  env['NODE_APP_INSTANCE'] = serverNumber.toString()
+
+  if (configOverride !== undefined) {
+    env['NODE_CONFIG'] = JSON.stringify(configOverride)
+  }
+
+  const options = {
+    silent: true,
+    env: env,
+    detached: true
+  }
+
+  return new Promise<ServerInfo>(res => {
+    server.app = fork(join(root(), 'dist', 'server.js'), args, options)
+    server.app.stdout.on('data', function onStdout (data) {
+      let dontContinue = false
+
+      // Capture things if we want to
+      for (const key of Object.keys(regexps)) {
+        const regexp = regexps[key]
+        const matches = data.toString().match(regexp)
+        if (matches !== null) {
+          if (key === 'client_id') server.client.id = matches[1]
+          else if (key === 'client_secret') server.client.secret = matches[1]
+          else if (key === 'user_username') server.user.username = matches[1]
+          else if (key === 'user_password') server.user.password = matches[1]
+        }
+      }
+
+      // Check if all required sentences are here
+      for (const key of Object.keys(serverRunString)) {
+        if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
+        if (serverRunString[key] === false) dontContinue = true
+      }
+
+      // If no, there is maybe one thing not already initialized (client/user credentials generation...)
+      if (dontContinue === true) return
+
+      server.app.stdout.removeListener('data', onStdout)
+
+      process.on('exit', () => {
+        try {
+          process.kill(server.app.pid)
+        } catch { /* empty */ }
+      })
+
+      res(server)
+    })
+
+  })
+}
+
+async function reRunServer (server: ServerInfo, configOverride?: any) {
+  const newServer = await runServer(server.serverNumber, configOverride)
+  server.app = newServer.app
+
+  return server
+}
+
+async function checkTmpIsEmpty (server: ServerInfo) {
+  return checkDirectoryIsEmpty(server, 'tmp')
+}
+
+async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) {
+  const testDirectory = 'test' + server.serverNumber
+
+  const directoryPath = join(root(), testDirectory, directory)
+
+  const directoryExists = existsSync(directoryPath)
+  expect(directoryExists).to.be.true
+
+  const files = await readdir(directoryPath)
+  expect(files).to.have.lengthOf(0)
+}
+
+function killallServers (servers: ServerInfo[]) {
+  for (const server of servers) {
+    process.kill(-server.app.pid)
+  }
+}
+
+async function waitUntilLog (server: ServerInfo, str: string, count = 1) {
+  const logfile = join(root(), 'test' + server.serverNumber, 'logs/peertube.log')
+
+  while (true) {
+    const buf = await readFile(logfile)
+
+    const matches = buf.toString().match(new RegExp(str, 'g'))
+    if (matches && matches.length === count) return
+
+    await wait(1000)
+  }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  checkDirectoryIsEmpty,
+  checkTmpIsEmpty,
+  ServerInfo,
+  flushAndRunMultipleServers,
+  flushTests,
+  runServer,
+  killallServers,
+  reRunServer,
+  waitUntilLog
+}
diff --git a/shared/extra-utils/server/stats.ts b/shared/extra-utils/server/stats.ts
new file mode 100644 (file)
index 0000000..6f079ad
--- /dev/null
@@ -0,0 +1,22 @@
+import { makeGetRequest } from '../requests/requests'
+
+function getStats (url: string, useCache = false) {
+  const path = '/api/v1/server/stats'
+
+  const query = {
+    t: useCache ? undefined : new Date().getTime()
+  }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getStats
+}
diff --git a/shared/extra-utils/socket/socket-io.ts b/shared/extra-utils/socket/socket-io.ts
new file mode 100644 (file)
index 0000000..854ab71
--- /dev/null
@@ -0,0 +1,13 @@
+import * as io from 'socket.io-client'
+
+function getUserNotificationSocket (serverUrl: string, accessToken: string) {
+  return io(serverUrl + '/user-notifications', {
+    query: { accessToken }
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getUserNotificationSocket
+}
diff --git a/shared/extra-utils/users/accounts.ts b/shared/extra-utils/users/accounts.ts
new file mode 100644 (file)
index 0000000..f64a2db
--- /dev/null
@@ -0,0 +1,80 @@
+/* tslint:disable:no-unused-expression */
+
+import * as request from 'supertest'
+import { expect } from 'chai'
+import { existsSync, readdir } from 'fs-extra'
+import { join } from 'path'
+import { Account } from '../../models/actors'
+import { root } from '../miscs/miscs'
+import { makeGetRequest } from '../requests/requests'
+import { VideoRateType } from '../../models/videos'
+
+function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = 200) {
+  const path = '/api/v1/accounts'
+
+  return makeGetRequest({
+    url,
+    query: { sort },
+    path,
+    statusCodeExpected
+  })
+}
+
+function getAccount (url: string, accountName: string, statusCodeExpected = 200) {
+  const path = '/api/v1/accounts/' + accountName
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected
+  })
+}
+
+async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) {
+  const res = await getAccountsList(url)
+  const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain)
+
+  const message = `${nameWithDomain} on ${url}`
+  expect(account.followersCount).to.equal(followersCount, message)
+  expect(account.followingCount).to.equal(followingCount, message)
+}
+
+async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) {
+  const testDirectory = 'test' + serverNumber
+
+  for (const directory of [ 'avatars' ]) {
+    const directoryPath = join(root(), testDirectory, directory)
+
+    const directoryExists = existsSync(directoryPath)
+    expect(directoryExists).to.be.true
+
+    const files = await readdir(directoryPath)
+    for (const file of files) {
+      expect(file).to.not.contain(actorUUID)
+    }
+  }
+}
+
+function getAccountRatings (url: string, accountName: string, accessToken: string, rating?: VideoRateType, statusCodeExpected = 200) {
+  const path = '/api/v1/accounts/' + accountName + '/ratings'
+
+  const query = rating ? { rating } : {}
+
+  return request(url)
+          .get(path)
+          .query(query)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(statusCodeExpected)
+          .expect('Content-Type', /json/)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getAccount,
+  expectAccountFollows,
+  getAccountsList,
+  checkActorFilesWereRemoved,
+  getAccountRatings
+}
diff --git a/shared/extra-utils/users/blocklist.ts b/shared/extra-utils/users/blocklist.ts
new file mode 100644 (file)
index 0000000..5feb841
--- /dev/null
@@ -0,0 +1,197 @@
+/* tslint:disable:no-unused-expression */
+
+import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } 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
+  })
+}
+
+function getAccountBlocklistByServer (
+  url: string,
+  token: string,
+  start: number,
+  count: number,
+  sort = '-createdAt',
+  statusCodeExpected = 200
+) {
+  const path = '/api/v1/server/blocklist/accounts'
+
+  return makeGetRequest({
+    url,
+    token,
+    query: { start, count, sort },
+    path,
+    statusCodeExpected
+  })
+}
+
+function addAccountToServerBlocklist (url: string, token: string, accountToBlock: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/blocklist/accounts'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    fields: {
+      accountName: accountToBlock
+    },
+    statusCodeExpected
+  })
+}
+
+function removeAccountFromServerBlocklist (url: string, token: string, accountToUnblock: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/blocklist/accounts/' + accountToUnblock
+
+  return makeDeleteRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+function getServerBlocklistByServer (
+  url: string,
+  token: string,
+  start: number,
+  count: number,
+  sort = '-createdAt',
+  statusCodeExpected = 200
+) {
+  const path = '/api/v1/server/blocklist/servers'
+
+  return makeGetRequest({
+    url,
+    token,
+    query: { start, count, sort },
+    path,
+    statusCodeExpected
+  })
+}
+
+function addServerToServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/blocklist/servers'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    fields: {
+      host: serverToBlock
+    },
+    statusCodeExpected
+  })
+}
+
+function removeServerFromServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
+  const path = '/api/v1/server/blocklist/servers/' + serverToBlock
+
+  return makeDeleteRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getAccountBlocklistByAccount,
+  addAccountToAccountBlocklist,
+  removeAccountFromAccountBlocklist,
+  getServerBlocklistByAccount,
+  addServerToAccountBlocklist,
+  removeServerFromAccountBlocklist,
+
+  getAccountBlocklistByServer,
+  addAccountToServerBlocklist,
+  removeAccountFromServerBlocklist,
+  getServerBlocklistByServer,
+  addServerToServerBlocklist,
+  removeServerFromServerBlocklist
+}
diff --git a/shared/extra-utils/users/login.ts b/shared/extra-utils/users/login.ts
new file mode 100644 (file)
index 0000000..ddeb9df
--- /dev/null
@@ -0,0 +1,62 @@
+import * as request from 'supertest'
+
+import { ServerInfo } from '../server/servers'
+
+type Client = { id: string, secret: string }
+type User = { username: string, password: string }
+type Server = { url: string, client: Client, user: User }
+
+function login (url: string, client: Client, user: User, expectedStatus = 200) {
+  const path = '/api/v1/users/token'
+
+  const body = {
+    client_id: client.id,
+    client_secret: client.secret,
+    username: user.username,
+    password: user.password,
+    response_type: 'code',
+    grant_type: 'password',
+    scope: 'upload'
+  }
+
+  return request(url)
+          .post(path)
+          .type('form')
+          .send(body)
+          .expect(expectedStatus)
+}
+
+async function serverLogin (server: Server) {
+  const res = await login(server.url, server.client, server.user, 200)
+
+  return res.body.access_token as string
+}
+
+async function userLogin (server: Server, user: User, expectedStatus = 200) {
+  const res = await login(server.url, server.client, user, expectedStatus)
+
+  return res.body.access_token as string
+}
+
+function setAccessTokensToServers (servers: ServerInfo[]) {
+  const tasks: Promise<any>[] = []
+
+  for (const server of servers) {
+    const p = serverLogin(server).then(t => server.accessToken = t)
+    tasks.push(p)
+  }
+
+  return Promise.all(tasks)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  login,
+  serverLogin,
+  userLogin,
+  setAccessTokensToServers,
+  Server,
+  Client,
+  User
+}
diff --git a/shared/extra-utils/users/user-notifications.ts b/shared/extra-utils/users/user-notifications.ts
new file mode 100644 (file)
index 0000000..495ff80
--- /dev/null
@@ -0,0 +1,496 @@
+/* tslint:disable:no-unused-expression */
+
+import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
+import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
+import { ServerInfo } from '..'
+import { expect } from 'chai'
+import { inspect } from 'util'
+
+function updateMyNotificationSettings (url: string, token: string, settings: UserNotificationSetting, statusCodeExpected = 204) {
+  const path = '/api/v1/users/me/notification-settings'
+
+  return makePutBodyRequest({
+    url,
+    path,
+    token,
+    fields: settings,
+    statusCodeExpected
+  })
+}
+
+async function getUserNotifications (
+  url: string,
+  token: string,
+  start: number,
+  count: number,
+  unread?: boolean,
+  sort = '-createdAt',
+  statusCodeExpected = 200
+) {
+  const path = '/api/v1/users/me/notifications'
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    query: {
+      start,
+      count,
+      sort,
+      unread
+    },
+    statusCodeExpected
+  })
+}
+
+function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = 204) {
+  const path = '/api/v1/users/me/notifications/read'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    fields: { ids },
+    statusCodeExpected
+  })
+}
+function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
+  const path = '/api/v1/users/me/notifications/read-all'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+async function getLastNotification (serverUrl: string, accessToken: string) {
+  const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt')
+
+  if (res.body.total === 0) return undefined
+
+  return res.body.data[0] as UserNotification
+}
+
+type CheckerBaseParams = {
+  server: ServerInfo
+  emails: object[]
+  socketNotifications: UserNotification[]
+  token: string,
+  check?: { web: boolean, mail: boolean }
+}
+
+type CheckerType = 'presence' | 'absence'
+
+async function checkNotification (
+  base: CheckerBaseParams,
+  notificationChecker: (notification: UserNotification, type: CheckerType) => void,
+  emailNotificationFinder: (email: object) => boolean,
+  checkType: CheckerType
+) {
+  const check = base.check || { web: true, mail: true }
+
+  if (check.web) {
+    const notification = await getLastNotification(base.server.url, base.token)
+
+    if (notification || checkType !== 'absence') {
+      notificationChecker(notification, checkType)
+    }
+
+    const socketNotification = base.socketNotifications.find(n => {
+      try {
+        notificationChecker(n, 'presence')
+        return true
+      } catch {
+        return false
+      }
+    })
+
+    if (checkType === 'presence') {
+      const obj = inspect(base.socketNotifications, { depth: 5 })
+      expect(socketNotification, 'The socket notification is absent. ' + obj).to.not.be.undefined
+    } else {
+      const obj = inspect(socketNotification, { depth: 5 })
+      expect(socketNotification, 'The socket notification is present. ' + obj).to.be.undefined
+    }
+  }
+
+  if (check.mail) {
+    // Last email
+    const email = base.emails
+                      .slice()
+                      .reverse()
+                      .find(e => emailNotificationFinder(e))
+
+    if (checkType === 'presence') {
+      expect(email, 'The email is absent. ' + inspect(base.emails)).to.not.be.undefined
+    } else {
+      expect(email, 'The email is present. ' + inspect(email)).to.be.undefined
+    }
+  }
+}
+
+function checkVideo (video: any, videoName?: string, videoUUID?: string) {
+  expect(video.name).to.be.a('string')
+  expect(video.name).to.not.be.empty
+  if (videoName) expect(video.name).to.equal(videoName)
+
+  expect(video.uuid).to.be.a('string')
+  expect(video.uuid).to.not.be.empty
+  if (videoUUID) expect(video.uuid).to.equal(videoUUID)
+
+  expect(video.id).to.be.a('number')
+}
+
+function checkActor (actor: any) {
+  expect(actor.displayName).to.be.a('string')
+  expect(actor.displayName).to.not.be.empty
+  expect(actor.host).to.not.be.undefined
+}
+
+function checkComment (comment: any, commentId: number, threadId: number) {
+  expect(comment.id).to.equal(commentId)
+  expect(comment.threadId).to.equal(threadId)
+}
+
+async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
+  const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkVideo(notification.video, videoName, videoUUID)
+      checkActor(notification.video.channel)
+    } else {
+      expect(notification).to.satisfy((n: UserNotification) => {
+        return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
+      })
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text = email[ 'text' ]
+    return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
+  const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkVideo(notification.video, videoName, videoUUID)
+      checkActor(notification.video.channel)
+    } else {
+      expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+    return text.includes(videoUUID) && text.includes('Your video')
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkMyVideoImportIsFinished (
+  base: CheckerBaseParams,
+  videoName: string,
+  videoUUID: string,
+  url: string,
+  success: boolean,
+  type: CheckerType
+) {
+  const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      expect(notification.videoImport.targetUrl).to.equal(url)
+
+      if (success) checkVideo(notification.videoImport.video, videoName, videoUUID)
+    } else {
+      expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+    const toFind = success ? ' finished' : ' error'
+
+    return text.includes(url) && text.includes(toFind)
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
+  const notificationType = UserNotificationType.NEW_USER_REGISTRATION
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkActor(notification.account)
+      expect(notification.account.name).to.equal(username)
+    } else {
+      expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+
+    return text.includes(' registered ') && text.includes(username)
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkNewActorFollow (
+  base: CheckerBaseParams,
+  followType: 'channel' | 'account',
+  followerName: string,
+  followerDisplayName: string,
+  followingDisplayName: string,
+  type: CheckerType
+) {
+  const notificationType = UserNotificationType.NEW_FOLLOW
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkActor(notification.actorFollow.follower)
+      expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
+      expect(notification.actorFollow.follower.name).to.equal(followerName)
+      expect(notification.actorFollow.follower.host).to.not.be.undefined
+
+      expect(notification.actorFollow.following.displayName).to.equal(followingDisplayName)
+      expect(notification.actorFollow.following.type).to.equal(followType)
+    } else {
+      expect(notification).to.satisfy(n => {
+        return n.type !== notificationType ||
+          (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
+      })
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+
+    return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) {
+  const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkActor(notification.actorFollow.follower)
+      expect(notification.actorFollow.follower.name).to.equal('peertube')
+      expect(notification.actorFollow.follower.host).to.equal(followerHost)
+
+      expect(notification.actorFollow.following.name).to.equal('peertube')
+    } else {
+      expect(notification).to.satisfy(n => {
+        return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
+      })
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+
+    return text.includes('instance has a new follower') && text.includes(followerHost)
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkCommentMention (
+  base: CheckerBaseParams,
+  uuid: string,
+  commentId: number,
+  threadId: number,
+  byAccountDisplayName: string,
+  type: CheckerType
+) {
+  const notificationType = UserNotificationType.COMMENT_MENTION
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkComment(notification.comment, commentId, threadId)
+      checkActor(notification.comment.account)
+      expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
+
+      checkVideo(notification.comment.video, undefined, uuid)
+    } else {
+      expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text: string = email[ 'text' ]
+
+    return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+let lastEmailCount = 0
+async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
+  const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      checkComment(notification.comment, commentId, threadId)
+      checkActor(notification.comment.account)
+      checkVideo(notification.comment.video, undefined, uuid)
+    } else {
+      expect(notification).to.satisfy((n: UserNotification) => {
+        return n === undefined || n.comment === undefined || n.comment.id !== commentId
+      })
+    }
+  }
+
+  const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
+  function emailFinder (email: object) {
+    return email[ 'text' ].indexOf(commentUrl) !== -1
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+
+  if (type === 'presence') {
+    // We cannot detect email duplicates, so check we received another email
+    expect(base.emails).to.have.length.above(lastEmailCount)
+    lastEmailCount = base.emails.length
+  }
+}
+
+async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
+  const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      expect(notification.videoAbuse.id).to.be.a('number')
+      checkVideo(notification.videoAbuse.video, videoName, videoUUID)
+    } else {
+      expect(notification).to.satisfy((n: UserNotification) => {
+        return n === undefined || n.videoAbuse === undefined || n.videoAbuse.video.uuid !== videoUUID
+      })
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text = email[ 'text' ]
+    return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
+  const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
+
+  function notificationChecker (notification: UserNotification, type: CheckerType) {
+    if (type === 'presence') {
+      expect(notification).to.not.be.undefined
+      expect(notification.type).to.equal(notificationType)
+
+      expect(notification.video.id).to.be.a('number')
+      checkVideo(notification.video, videoName, videoUUID)
+    } else {
+      expect(notification).to.satisfy((n: UserNotification) => {
+        return n === undefined || n.video === undefined || n.video.uuid !== videoUUID
+      })
+    }
+  }
+
+  function emailFinder (email: object) {
+    const text = email[ 'text' ]
+    return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, type)
+}
+
+async function checkNewBlacklistOnMyVideo (
+  base: CheckerBaseParams,
+  videoUUID: string,
+  videoName: string,
+  blacklistType: 'blacklist' | 'unblacklist'
+) {
+  const notificationType = blacklistType === 'blacklist'
+    ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
+    : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
+
+  function notificationChecker (notification: UserNotification) {
+    expect(notification).to.not.be.undefined
+    expect(notification.type).to.equal(notificationType)
+
+    const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
+
+    checkVideo(video, videoName, videoUUID)
+  }
+
+  function emailFinder (email: object) {
+    const text = email[ 'text' ]
+    return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
+  }
+
+  await checkNotification(base, notificationChecker, emailFinder, 'presence')
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  CheckerBaseParams,
+  CheckerType,
+  checkNotification,
+  markAsReadAllNotifications,
+  checkMyVideoImportIsFinished,
+  checkUserRegistered,
+  checkVideoIsPublished,
+  checkNewVideoFromSubscription,
+  checkNewActorFollow,
+  checkNewCommentOnMyVideo,
+  checkNewBlacklistOnMyVideo,
+  checkCommentMention,
+  updateMyNotificationSettings,
+  checkNewVideoAbuseForModerators,
+  checkVideoAutoBlacklistForModerators,
+  getUserNotifications,
+  markAsReadNotifications,
+  getLastNotification,
+  checkNewInstanceFollower
+}
diff --git a/shared/extra-utils/users/user-subscriptions.ts b/shared/extra-utils/users/user-subscriptions.ts
new file mode 100644 (file)
index 0000000..7148fbf
--- /dev/null
@@ -0,0 +1,82 @@
+import { makeDeleteRequest, makeGetRequest, makePostBodyRequest } from '../requests/requests'
+
+function addUserSubscription (url: string, token: string, targetUri: string, statusCodeExpected = 204) {
+  const path = '/api/v1/users/me/subscriptions'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected,
+    fields: { uri: targetUri }
+  })
+}
+
+function listUserSubscriptions (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
+  const path = '/api/v1/users/me/subscriptions'
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected,
+    query: { sort }
+  })
+}
+
+function listUserSubscriptionVideos (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
+  const path = '/api/v1/users/me/subscriptions/videos'
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected,
+    query: { sort }
+  })
+}
+
+function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 200) {
+  const path = '/api/v1/users/me/subscriptions/' + uri
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) {
+  const path = '/api/v1/users/me/subscriptions/' + uri
+
+  return makeDeleteRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+function areSubscriptionsExist (url: string, token: string, uris: string[], statusCodeExpected = 200) {
+  const path = '/api/v1/users/me/subscriptions/exist'
+
+  return makeGetRequest({
+    url,
+    path,
+    query: { 'uris[]': uris },
+    token,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  areSubscriptionsExist,
+  addUserSubscription,
+  listUserSubscriptions,
+  getUserSubscription,
+  listUserSubscriptionVideos,
+  removeUserSubscription
+}
diff --git a/shared/extra-utils/users/users.ts b/shared/extra-utils/users/users.ts
new file mode 100644 (file)
index 0000000..2bd37b8
--- /dev/null
@@ -0,0 +1,330 @@
+import * as request from 'supertest'
+import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
+
+import { UserRole } from '../../index'
+import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
+import { ServerInfo, userLogin } from '..'
+import { UserAdminFlag } from '../../models/users/user-flag.model'
+
+type CreateUserArgs = { url: string,
+  accessToken: string,
+  username: string,
+  password: string,
+  videoQuota?: number,
+  videoQuotaDaily?: number,
+  role?: UserRole,
+  adminFlags?: UserAdminFlag,
+  specialStatus?: number
+}
+function createUser (parameters: CreateUserArgs) {
+  const {
+    url,
+    accessToken,
+    username,
+    adminFlags,
+    password = 'password',
+    videoQuota = 1000000,
+    videoQuotaDaily = -1,
+    role = UserRole.USER,
+    specialStatus = 200
+  } = parameters
+
+  const path = '/api/v1/users'
+  const body = {
+    username,
+    password,
+    role,
+    adminFlags,
+    email: username + '@example.com',
+    videoQuota,
+    videoQuotaDaily
+  }
+
+  return request(url)
+          .post(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .send(body)
+          .expect(specialStatus)
+}
+
+async function generateUserAccessToken (server: ServerInfo, username: string) {
+  const password = 'my super password'
+  await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
+
+  return userLogin(server, { username, password })
+}
+
+function registerUser (url: string, username: string, password: string, specialStatus = 204) {
+  const path = '/api/v1/users/register'
+  const body = {
+    username,
+    password,
+    email: username + '@example.com'
+  }
+
+  return request(url)
+          .post(path)
+          .set('Accept', 'application/json')
+          .send(body)
+          .expect(specialStatus)
+}
+
+function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) {
+  const path = '/api/v1/users/me'
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(specialStatus)
+          .expect('Content-Type', /json/)
+}
+
+function deleteMe (url: string, accessToken: string, specialStatus = 204) {
+  const path = '/api/v1/users/me'
+
+  return request(url)
+    .delete(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(specialStatus)
+}
+
+function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = 200) {
+  const path = '/api/v1/users/me/video-quota-used'
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(specialStatus)
+          .expect('Content-Type', /json/)
+}
+
+function getUserInformation (url: string, accessToken: string, userId: number) {
+  const path = '/api/v1/users/' + userId
+
+  return request(url)
+    .get(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getMyUserVideoRating (url: string, accessToken: string, videoId: number | string, specialStatus = 200) {
+  const path = '/api/v1/users/me/videos/' + videoId + '/rating'
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(specialStatus)
+          .expect('Content-Type', /json/)
+}
+
+function getUsersList (url: string, accessToken: string) {
+  const path = '/api/v1/users'
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) {
+  const path = '/api/v1/users'
+
+  return request(url)
+          .get(path)
+          .query({ start })
+          .query({ count })
+          .query({ sort })
+          .query({ search })
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function removeUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
+  const path = '/api/v1/users'
+
+  return request(url)
+          .delete(path + '/' + userId)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .expect(expectedStatus)
+}
+
+function blockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204, reason?: string) {
+  const path = '/api/v1/users'
+  let body: any
+  if (reason) body = { reason }
+
+  return request(url)
+    .post(path + '/' + userId + '/block')
+    .send(body)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(expectedStatus)
+}
+
+function unblockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
+  const path = '/api/v1/users'
+
+  return request(url)
+    .post(path + '/' + userId + '/unblock')
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(expectedStatus)
+}
+
+function updateMyUser (options: {
+  url: string
+  accessToken: string
+  currentPassword?: string
+  newPassword?: string
+  nsfwPolicy?: NSFWPolicyType
+  email?: string
+  autoPlayVideo?: boolean
+  displayName?: string
+  description?: string
+  videosHistoryEnabled?: boolean
+}) {
+  const path = '/api/v1/users/me'
+
+  const toSend = {}
+  if (options.currentPassword !== undefined && options.currentPassword !== null) toSend['currentPassword'] = options.currentPassword
+  if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword
+  if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend['nsfwPolicy'] = options.nsfwPolicy
+  if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
+  if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
+  if (options.description !== undefined && options.description !== null) toSend['description'] = options.description
+  if (options.displayName !== undefined && options.displayName !== null) toSend['displayName'] = options.displayName
+  if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) {
+    toSend['videosHistoryEnabled'] = options.videosHistoryEnabled
+  }
+
+  return makePutBodyRequest({
+    url: options.url,
+    path,
+    token: options.accessToken,
+    fields: toSend,
+    statusCodeExpected: 204
+  })
+}
+
+function updateMyAvatar (options: {
+  url: string,
+  accessToken: string,
+  fixture: string
+}) {
+  const path = '/api/v1/users/me/avatar/pick'
+
+  return updateAvatarRequest(Object.assign(options, { path }))
+}
+
+function updateUser (options: {
+  url: string
+  userId: number,
+  accessToken: string,
+  email?: string,
+  emailVerified?: boolean,
+  videoQuota?: number,
+  videoQuotaDaily?: number,
+  password?: string,
+  adminFlags?: UserAdminFlag,
+  role?: UserRole
+}) {
+  const path = '/api/v1/users/' + options.userId
+
+  const toSend = {}
+  if (options.password !== undefined && options.password !== null) toSend['password'] = options.password
+  if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
+  if (options.emailVerified !== undefined && options.emailVerified !== null) toSend['emailVerified'] = options.emailVerified
+  if (options.videoQuota !== undefined && options.videoQuota !== null) toSend['videoQuota'] = options.videoQuota
+  if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend['videoQuotaDaily'] = options.videoQuotaDaily
+  if (options.role !== undefined && options.role !== null) toSend['role'] = options.role
+  if (options.adminFlags !== undefined && options.adminFlags !== null) toSend['adminFlags'] = options.adminFlags
+
+  return makePutBodyRequest({
+    url: options.url,
+    path,
+    token: options.accessToken,
+    fields: toSend,
+    statusCodeExpected: 204
+  })
+}
+
+function askResetPassword (url: string, email: string) {
+  const path = '/api/v1/users/ask-reset-password'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    fields: { email },
+    statusCodeExpected: 204
+  })
+}
+
+function resetPassword (url: string, userId: number, verificationString: string, password: string, statusCodeExpected = 204) {
+  const path = '/api/v1/users/' + userId + '/reset-password'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    fields: { password, verificationString },
+    statusCodeExpected
+  })
+}
+
+function askSendVerifyEmail (url: string, email: string) {
+  const path = '/api/v1/users/ask-send-verify-email'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    fields: { email },
+    statusCodeExpected: 204
+  })
+}
+
+function verifyEmail (url: string, userId: number, verificationString: string, statusCodeExpected = 204) {
+  const path = '/api/v1/users/' + userId + '/verify-email'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    fields: { verificationString },
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  createUser,
+  registerUser,
+  getMyUserInformation,
+  getMyUserVideoRating,
+  deleteMe,
+  getMyUserVideoQuotaUsed,
+  getUsersList,
+  getUsersListPaginationAndSort,
+  removeUser,
+  updateUser,
+  updateMyUser,
+  getUserInformation,
+  blockUser,
+  unblockUser,
+  askResetPassword,
+  resetPassword,
+  updateMyAvatar,
+  askSendVerifyEmail,
+  generateUserAccessToken,
+  verifyEmail
+}
diff --git a/shared/extra-utils/videos/services.ts b/shared/extra-utils/videos/services.ts
new file mode 100644 (file)
index 0000000..1a53dd4
--- /dev/null
@@ -0,0 +1,23 @@
+import * as request from 'supertest'
+
+function getOEmbed (url: string, oembedUrl: string, format?: string, maxHeight?: number, maxWidth?: number) {
+  const path = '/services/oembed'
+  const query = {
+    url: oembedUrl,
+    format,
+    maxheight: maxHeight,
+    maxwidth: maxWidth
+  }
+
+  return request(url)
+          .get(path)
+          .query(query)
+          .set('Accept', 'application/json')
+          .expect(200)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getOEmbed
+}
diff --git a/shared/extra-utils/videos/video-abuses.ts b/shared/extra-utils/videos/video-abuses.ts
new file mode 100644 (file)
index 0000000..7f011ec
--- /dev/null
@@ -0,0 +1,65 @@
+import * as request from 'supertest'
+import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model'
+import { makeDeleteRequest, makePutBodyRequest } from '../requests/requests'
+
+function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) {
+  const path = '/api/v1/videos/' + videoId + '/abuse'
+
+  return request(url)
+          .post(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + token)
+          .send({ reason })
+          .expect(specialStatus)
+}
+
+function getVideoAbusesList (url: string, token: string) {
+  const path = '/api/v1/videos/abuse'
+
+  return request(url)
+          .get(path)
+          .query({ sort: 'createdAt' })
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + token)
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function updateVideoAbuse (
+  url: string,
+  token: string,
+  videoId: string | number,
+  videoAbuseId: number,
+  body: VideoAbuseUpdate,
+  statusCodeExpected = 204
+) {
+  const path = '/api/v1/videos/' + videoId + '/abuse/' + videoAbuseId
+
+  return makePutBodyRequest({
+    url,
+    token,
+    path,
+    fields: body,
+    statusCodeExpected
+  })
+}
+
+function deleteVideoAbuse (url: string, token: string, videoId: string | number, videoAbuseId: number, statusCodeExpected = 204) {
+  const path = '/api/v1/videos/' + videoId + '/abuse/' + videoAbuseId
+
+  return makeDeleteRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  reportVideoAbuse,
+  getVideoAbusesList,
+  updateVideoAbuse,
+  deleteVideoAbuse
+}
diff --git a/shared/extra-utils/videos/video-blacklist.ts b/shared/extra-utils/videos/video-blacklist.ts
new file mode 100644 (file)
index 0000000..e25a292
--- /dev/null
@@ -0,0 +1,72 @@
+import * as request from 'supertest'
+import { VideoBlacklistType } from '../../models/videos'
+import { makeGetRequest } from '..'
+
+function addVideoToBlacklist (
+  url: string,
+  token: string,
+  videoId: number | string,
+  reason?: string,
+  unfederate?: boolean,
+  specialStatus = 204
+) {
+  const path = '/api/v1/videos/' + videoId + '/blacklist'
+
+  return request(url)
+          .post(path)
+          .send({ reason, unfederate })
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + token)
+          .expect(specialStatus)
+}
+
+function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
+  const path = '/api/v1/videos/' + videoId + '/blacklist'
+
+  return request(url)
+    .put(path)
+    .send({ reason })
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(specialStatus)
+}
+
+function removeVideoFromBlacklist (url: string, token: string, videoId: number | string, specialStatus = 204) {
+  const path = '/api/v1/videos/' + videoId + '/blacklist'
+
+  return request(url)
+          .delete(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + token)
+          .expect(specialStatus)
+}
+
+function getBlacklistedVideosList (parameters: {
+  url: string,
+  token: string,
+  sort?: string,
+  type?: VideoBlacklistType,
+  specialStatus?: number
+}) {
+  let { url, token, sort, type, specialStatus = 200 } = parameters
+  const path = '/api/v1/videos/blacklist/'
+
+  const query = { sort, type }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    token,
+    statusCodeExpected: specialStatus
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  addVideoToBlacklist,
+  removeVideoFromBlacklist,
+  getBlacklistedVideosList,
+  updateVideoBlacklist
+}
diff --git a/shared/extra-utils/videos/video-captions.ts b/shared/extra-utils/videos/video-captions.ts
new file mode 100644 (file)
index 0000000..8d67f61
--- /dev/null
@@ -0,0 +1,71 @@
+import { makeDeleteRequest, makeGetRequest, makeUploadRequest } from '../requests/requests'
+import * as request from 'supertest'
+import * as chai from 'chai'
+import { buildAbsoluteFixturePath } from '../miscs/miscs'
+
+const expect = chai.expect
+
+function createVideoCaption (args: {
+  url: string,
+  accessToken: string
+  videoId: string | number
+  language: string
+  fixture: string,
+  mimeType?: string,
+  statusCodeExpected?: number
+}) {
+  const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
+
+  const captionfile = buildAbsoluteFixturePath(args.fixture)
+  const captionfileAttach = args.mimeType ? [ captionfile, { contentType: args.mimeType } ] : captionfile
+
+  return makeUploadRequest({
+    method: 'PUT',
+    url: args.url,
+    path,
+    token: args.accessToken,
+    fields: {},
+    attaches: {
+      captionfile: captionfileAttach
+    },
+    statusCodeExpected: args.statusCodeExpected || 204
+  })
+}
+
+function listVideoCaptions (url: string, videoId: string | number) {
+  const path = '/api/v1/videos/' + videoId + '/captions'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function deleteVideoCaption (url: string, token: string, videoId: string | number, language: string) {
+  const path = '/api/v1/videos/' + videoId + '/captions/' + language
+
+  return makeDeleteRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected: 204
+  })
+}
+
+async function testCaptionFile (url: string, captionPath: string, containsString: string) {
+  const res = await request(url)
+    .get(captionPath)
+    .expect(200)
+
+  expect(res.text).to.contain(containsString)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  createVideoCaption,
+  listVideoCaptions,
+  testCaptionFile,
+  deleteVideoCaption
+}
diff --git a/shared/extra-utils/videos/video-change-ownership.ts b/shared/extra-utils/videos/video-change-ownership.ts
new file mode 100644 (file)
index 0000000..371d020
--- /dev/null
@@ -0,0 +1,54 @@
+import * as request from 'supertest'
+
+function changeVideoOwnership (url: string, token: string, videoId: number | string, username, expectedStatus = 204) {
+  const path = '/api/v1/videos/' + videoId + '/give-ownership'
+
+  return request(url)
+    .post(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .send({ username })
+    .expect(expectedStatus)
+}
+
+function getVideoChangeOwnershipList (url: string, token: string) {
+  const path = '/api/v1/videos/ownership'
+
+  return request(url)
+    .get(path)
+    .query({ sort: '-createdAt' })
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function acceptChangeOwnership (url: string, token: string, ownershipId: string, channelId: number, expectedStatus = 204) {
+  const path = '/api/v1/videos/ownership/' + ownershipId + '/accept'
+
+  return request(url)
+    .post(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .send({ channelId })
+    .expect(expectedStatus)
+}
+
+function refuseChangeOwnership (url: string, token: string, ownershipId: string, expectedStatus = 204) {
+  const path = '/api/v1/videos/ownership/' + ownershipId + '/refuse'
+
+  return request(url)
+    .post(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  changeVideoOwnership,
+  getVideoChangeOwnershipList,
+  acceptChangeOwnership,
+  refuseChangeOwnership
+}
diff --git a/shared/extra-utils/videos/video-channels.ts b/shared/extra-utils/videos/video-channels.ts
new file mode 100644 (file)
index 0000000..93a257b
--- /dev/null
@@ -0,0 +1,134 @@
+import * as request from 'supertest'
+import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos'
+import { updateAvatarRequest } from '../requests/requests'
+import { getMyUserInformation, ServerInfo } from '..'
+import { User } from '../..'
+
+function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/video-channels'
+
+  const req = request(url)
+    .get(path)
+    .query({ start: start })
+    .query({ count: count })
+
+  if (sort) req.query({ sort })
+
+  return req.set('Accept', 'application/json')
+            .expect(200)
+            .expect('Content-Type', /json/)
+}
+
+function getAccountVideoChannelsList (url: string, accountName: string, specialStatus = 200) {
+  const path = '/api/v1/accounts/' + accountName + '/video-channels'
+
+  return request(url)
+    .get(path)
+    .set('Accept', 'application/json')
+    .expect(specialStatus)
+    .expect('Content-Type', /json/)
+}
+
+function addVideoChannel (
+  url: string,
+  token: string,
+  videoChannelAttributesArg: VideoChannelCreate,
+  expectedStatus = 200
+) {
+  const path = '/api/v1/video-channels/'
+
+  // Default attributes
+  let attributes = {
+    displayName: 'my super video channel',
+    description: 'my super channel description',
+    support: 'my super channel support'
+  }
+  attributes = Object.assign(attributes, videoChannelAttributesArg)
+
+  return request(url)
+    .post(path)
+    .send(attributes)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+function updateVideoChannel (
+  url: string,
+  token: string,
+  channelName: string,
+  attributes: VideoChannelUpdate,
+  expectedStatus = 204
+) {
+  const body = {}
+  const path = '/api/v1/video-channels/' + channelName
+
+  if (attributes.displayName) body['displayName'] = attributes.displayName
+  if (attributes.description) body['description'] = attributes.description
+  if (attributes.support) body['support'] = attributes.support
+
+  return request(url)
+    .put(path)
+    .send(body)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+function deleteVideoChannel (url: string, token: string, channelName: string, expectedStatus = 204) {
+  const path = '/api/v1/video-channels/' + channelName
+
+  return request(url)
+    .delete(path)
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+function getVideoChannel (url: string, channelName: string) {
+  const path = '/api/v1/video-channels/' + channelName
+
+  return request(url)
+    .get(path)
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function updateVideoChannelAvatar (options: {
+  url: string,
+  accessToken: string,
+  fixture: string,
+  videoChannelName: string | number
+}) {
+
+  const path = '/api/v1/video-channels/' + options.videoChannelName + '/avatar/pick'
+
+  return updateAvatarRequest(Object.assign(options, { path }))
+}
+
+function setDefaultVideoChannel (servers: ServerInfo[]) {
+  const tasks: Promise<any>[] = []
+
+  for (const server of servers) {
+    const p = getMyUserInformation(server.url, server.accessToken)
+      .then(res => server.videoChannel = (res.body as User).videoChannels[0])
+
+    tasks.push(p)
+  }
+
+  return Promise.all(tasks)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  updateVideoChannelAvatar,
+  getVideoChannelsList,
+  getAccountVideoChannelsList,
+  addVideoChannel,
+  updateVideoChannel,
+  deleteVideoChannel,
+  getVideoChannel,
+  setDefaultVideoChannel
+}
diff --git a/shared/extra-utils/videos/video-comments.ts b/shared/extra-utils/videos/video-comments.ts
new file mode 100644 (file)
index 0000000..0ebf69c
--- /dev/null
@@ -0,0 +1,87 @@
+import * as request from 'supertest'
+import { makeDeleteRequest } from '../requests/requests'
+
+function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string, token?: string) {
+  const path = '/api/v1/videos/' + videoId + '/comment-threads'
+
+  const req = request(url)
+    .get(path)
+    .query({ start: start })
+    .query({ count: count })
+
+  if (sort) req.query({ sort })
+  if (token) req.set('Authorization', 'Bearer ' + token)
+
+  return req.set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getVideoThreadComments (url: string, videoId: number | string, threadId: number, token?: string) {
+  const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId
+
+  const req = request(url)
+    .get(path)
+    .set('Accept', 'application/json')
+
+  if (token) req.set('Authorization', 'Bearer ' + token)
+
+  return req.expect(200)
+            .expect('Content-Type', /json/)
+}
+
+function addVideoCommentThread (url: string, token: string, videoId: number | string, text: string, expectedStatus = 200) {
+  const path = '/api/v1/videos/' + videoId + '/comment-threads'
+
+  return request(url)
+    .post(path)
+    .send({ text })
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+function addVideoCommentReply (
+  url: string,
+  token: string,
+  videoId: number | string,
+  inReplyToCommentId: number,
+  text: string,
+  expectedStatus = 200
+) {
+  const path = '/api/v1/videos/' + videoId + '/comments/' + inReplyToCommentId
+
+  return request(url)
+    .post(path)
+    .send({ text })
+    .set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + token)
+    .expect(expectedStatus)
+}
+
+function deleteVideoComment (
+  url: string,
+  token: string,
+  videoId: number | string,
+  commentId: number,
+  statusCodeExpected = 204
+) {
+  const path = '/api/v1/videos/' + videoId + '/comments/' + commentId
+
+  return makeDeleteRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getVideoCommentThreads,
+  getVideoThreadComments,
+  addVideoCommentThread,
+  addVideoCommentReply,
+  deleteVideoComment
+}
diff --git a/shared/extra-utils/videos/video-history.ts b/shared/extra-utils/videos/video-history.ts
new file mode 100644 (file)
index 0000000..dc7095b
--- /dev/null
@@ -0,0 +1,39 @@
+import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
+
+function userWatchVideo (url: string, token: string, videoId: number | string, currentTime: number, statusCodeExpected = 204) {
+  const path = '/api/v1/videos/' + videoId + '/watching'
+  const fields = { currentTime }
+
+  return makePutBodyRequest({ url, path, token, fields, statusCodeExpected })
+}
+
+function listMyVideosHistory (url: string, token: string) {
+  const path = '/api/v1/users/me/history/videos'
+
+  return makeGetRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected: 200
+  })
+}
+
+function removeMyVideosHistory (url: string, token: string, beforeDate?: string) {
+  const path = '/api/v1/users/me/history/videos/remove'
+
+  return makePostBodyRequest({
+    url,
+    path,
+    token,
+    fields: beforeDate ? { beforeDate } : {},
+    statusCodeExpected: 204
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  userWatchVideo,
+  listMyVideosHistory,
+  removeMyVideosHistory
+}
diff --git a/shared/extra-utils/videos/video-imports.ts b/shared/extra-utils/videos/video-imports.ts
new file mode 100644 (file)
index 0000000..ec77cdc
--- /dev/null
@@ -0,0 +1,57 @@
+
+import { VideoImportCreate } from '../../models/videos'
+import { makeGetRequest, makeUploadRequest } from '../requests/requests'
+
+function getYoutubeVideoUrl () {
+  return 'https://youtu.be/msX3jv1XdvM'
+}
+
+function getMagnetURI () {
+  // tslint:disable:max-line-length
+  return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
+}
+
+function getBadVideoUrl () {
+  return 'https://download.cpy.re/peertube/bad_video.mp4'
+}
+
+function importVideo (url: string, token: string, attributes: VideoImportCreate) {
+  const path = '/api/v1/videos/imports'
+
+  let attaches: any = {}
+  if (attributes.torrentfile) attaches = { torrentfile: attributes.torrentfile }
+
+  return makeUploadRequest({
+    url,
+    path,
+    token,
+    attaches,
+    fields: attributes,
+    statusCodeExpected: 200
+  })
+}
+
+function getMyVideoImports (url: string, token: string, sort?: string) {
+  const path = '/api/v1/users/me/videos/imports'
+
+  const query = {}
+  if (sort) query['sort'] = sort
+
+  return makeGetRequest({
+    url,
+    query,
+    path,
+    token,
+    statusCodeExpected: 200
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getBadVideoUrl,
+  getYoutubeVideoUrl,
+  importVideo,
+  getMagnetURI,
+  getMyVideoImports
+}
diff --git a/shared/extra-utils/videos/video-playlists.ts b/shared/extra-utils/videos/video-playlists.ts
new file mode 100644 (file)
index 0000000..4d110a1
--- /dev/null
@@ -0,0 +1,318 @@
+import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests'
+import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model'
+import { omit } from 'lodash'
+import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model'
+import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model'
+import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model'
+import { videoUUIDToId } from './videos'
+import { join } from 'path'
+import { root } from '..'
+import { readdir } from 'fs-extra'
+import { expect } from 'chai'
+import { VideoPlaylistType } from '../../models/videos/playlist/video-playlist-type.model'
+
+function getVideoPlaylistsList (url: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/video-playlists'
+
+  const query = {
+    start,
+    count,
+    sort
+  }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoChannelPlaylistsList (url: string, videoChannelName: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/video-channels/' + videoChannelName + '/video-playlists'
+
+  const query = {
+    start,
+    count,
+    sort
+  }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+function getAccountPlaylistsList (url: string, accountName: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/accounts/' + accountName + '/video-playlists'
+
+  const query = {
+    start,
+    count,
+    sort
+  }
+
+  return makeGetRequest({
+    url,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+function getAccountPlaylistsListWithToken (
+  url: string,
+  token: string,
+  accountName: string,
+  start: number,
+  count: number,
+  playlistType?: VideoPlaylistType,
+  sort?: string
+) {
+  const path = '/api/v1/accounts/' + accountName + '/video-playlists'
+
+  const query = {
+    start,
+    count,
+    playlistType,
+    sort
+  }
+
+  return makeGetRequest({
+    url,
+    token,
+    path,
+    query,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoPlaylist (url: string, playlistId: number | string, statusCodeExpected = 200) {
+  const path = '/api/v1/video-playlists/' + playlistId
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected
+  })
+}
+
+function getVideoPlaylistWithToken (url: string, token: string, playlistId: number | string, statusCodeExpected = 200) {
+  const path = '/api/v1/video-playlists/' + playlistId
+
+  return makeGetRequest({
+    url,
+    token,
+    path,
+    statusCodeExpected
+  })
+}
+
+function deleteVideoPlaylist (url: string, token: string, playlistId: number | string, statusCodeExpected = 204) {
+  const path = '/api/v1/video-playlists/' + playlistId
+
+  return makeDeleteRequest({
+    url,
+    path,
+    token,
+    statusCodeExpected
+  })
+}
+
+function createVideoPlaylist (options: {
+  url: string,
+  token: string,
+  playlistAttrs: VideoPlaylistCreate,
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/video-playlists'
+
+  const fields = omit(options.playlistAttrs, 'thumbnailfile')
+
+  const attaches = options.playlistAttrs.thumbnailfile
+    ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
+    : {}
+
+  return makeUploadRequest({
+    method: 'POST',
+    url: options.url,
+    path,
+    token: options.token,
+    fields,
+    attaches,
+    statusCodeExpected: options.expectedStatus || 200
+  })
+}
+
+function updateVideoPlaylist (options: {
+  url: string,
+  token: string,
+  playlistAttrs: VideoPlaylistUpdate,
+  playlistId: number | string,
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/video-playlists/' + options.playlistId
+
+  const fields = omit(options.playlistAttrs, 'thumbnailfile')
+
+  const attaches = options.playlistAttrs.thumbnailfile
+    ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
+    : {}
+
+  return makeUploadRequest({
+    method: 'PUT',
+    url: options.url,
+    path,
+    token: options.token,
+    fields,
+    attaches,
+    statusCodeExpected: options.expectedStatus || 204
+  })
+}
+
+async function addVideoInPlaylist (options: {
+  url: string,
+  token: string,
+  playlistId: number | string,
+  elementAttrs: VideoPlaylistElementCreate | { videoId: string }
+  expectedStatus?: number
+}) {
+  options.elementAttrs.videoId = await videoUUIDToId(options.url, options.elementAttrs.videoId)
+
+  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos'
+
+  return makePostBodyRequest({
+    url: options.url,
+    path,
+    token: options.token,
+    fields: options.elementAttrs,
+    statusCodeExpected: options.expectedStatus || 200
+  })
+}
+
+function updateVideoPlaylistElement (options: {
+  url: string,
+  token: string,
+  playlistId: number | string,
+  videoId: number | string,
+  elementAttrs: VideoPlaylistElementUpdate,
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
+
+  return makePutBodyRequest({
+    url: options.url,
+    path,
+    token: options.token,
+    fields: options.elementAttrs,
+    statusCodeExpected: options.expectedStatus || 204
+  })
+}
+
+function removeVideoFromPlaylist (options: {
+  url: string,
+  token: string,
+  playlistId: number | string,
+  videoId: number | string,
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
+
+  return makeDeleteRequest({
+    url: options.url,
+    path,
+    token: options.token,
+    statusCodeExpected: options.expectedStatus || 204
+  })
+}
+
+function reorderVideosPlaylist (options: {
+  url: string,
+  token: string,
+  playlistId: number | string,
+  elementAttrs: {
+    startPosition: number,
+    insertAfterPosition: number,
+    reorderLength?: number
+  },
+  expectedStatus?: number
+}) {
+  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
+
+  return makePostBodyRequest({
+    url: options.url,
+    path,
+    token: options.token,
+    fields: options.elementAttrs,
+    statusCodeExpected: options.expectedStatus || 204
+  })
+}
+
+async function checkPlaylistFilesWereRemoved (
+  playlistUUID: string,
+  serverNumber: number,
+  directories = [ 'thumbnails' ]
+) {
+  const testDirectory = 'test' + serverNumber
+
+  for (const directory of directories) {
+    const directoryPath = join(root(), testDirectory, directory)
+
+    const files = await readdir(directoryPath)
+    for (const file of files) {
+      expect(file).to.not.contain(playlistUUID)
+    }
+  }
+}
+
+function getVideoPlaylistPrivacies (url: string) {
+  const path = '/api/v1/video-playlists/privacies'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function doVideosExistInMyPlaylist (url: string, token: string, videoIds: number[]) {
+  const path = '/api/v1/users/me/video-playlists/videos-exist'
+
+  return makeGetRequest({
+    url,
+    token,
+    path,
+    query: { videoIds },
+    statusCodeExpected: 200
+  })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getVideoPlaylistPrivacies,
+
+  getVideoPlaylistsList,
+  getVideoChannelPlaylistsList,
+  getAccountPlaylistsList,
+  getAccountPlaylistsListWithToken,
+
+  getVideoPlaylist,
+  getVideoPlaylistWithToken,
+
+  createVideoPlaylist,
+  updateVideoPlaylist,
+  deleteVideoPlaylist,
+
+  addVideoInPlaylist,
+  updateVideoPlaylistElement,
+  removeVideoFromPlaylist,
+
+  reorderVideosPlaylist,
+
+  checkPlaylistFilesWereRemoved,
+
+  doVideosExistInMyPlaylist
+}
diff --git a/shared/extra-utils/videos/video-streaming-playlists.ts b/shared/extra-utils/videos/video-streaming-playlists.ts
new file mode 100644 (file)
index 0000000..eb25011
--- /dev/null
@@ -0,0 +1,51 @@
+import { makeRawRequest } from '../requests/requests'
+import { sha256 } from '../../../server/helpers/core-utils'
+import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model'
+import { expect } from 'chai'
+
+function getPlaylist (url: string, statusCodeExpected = 200) {
+  return makeRawRequest(url, statusCodeExpected)
+}
+
+function getSegment (url: string, statusCodeExpected = 200, range?: string) {
+  return makeRawRequest(url, statusCodeExpected, range)
+}
+
+function getSegmentSha256 (url: string, statusCodeExpected = 200) {
+  return makeRawRequest(url, statusCodeExpected)
+}
+
+async function checkSegmentHash (
+  baseUrlPlaylist: string,
+  baseUrlSegment: string,
+  videoUUID: string,
+  resolution: number,
+  hlsPlaylist: VideoStreamingPlaylist
+) {
+  const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`)
+  const playlist = res.text
+
+  const videoName = `${videoUUID}-${resolution}-fragmented.mp4`
+
+  const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
+
+  const length = parseInt(matches[1], 10)
+  const offset = parseInt(matches[2], 10)
+  const range = `${offset}-${offset + length - 1}`
+
+  const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, 206, `bytes=${range}`)
+
+  const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
+
+  const sha256Server = resSha.body[ videoName ][range]
+  expect(sha256(res2.body)).to.equal(sha256Server)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getPlaylist,
+  getSegment,
+  getSegmentSha256,
+  checkSegmentHash
+}
diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts
new file mode 100644 (file)
index 0000000..b5a07b7
--- /dev/null
@@ -0,0 +1,648 @@
+/* tslint:disable:no-unused-expression */
+
+import { expect } from 'chai'
+import { pathExists, readdir, readFile } from 'fs-extra'
+import * as parseTorrent from 'parse-torrent'
+import { extname, join } from 'path'
+import * as request from 'supertest'
+import {
+  buildAbsoluteFixturePath,
+  getMyUserInformation,
+  immutableAssign,
+  makeGetRequest,
+  makePutBodyRequest,
+  makeUploadRequest,
+  root,
+  ServerInfo,
+  testImage
+} from '../'
+import * as validator from 'validator'
+import { VideoDetails, VideoPrivacy } from '../../models/videos'
+import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, loadLanguages, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants'
+import { dateIsValid, webtorrentAdd } from '../miscs/miscs'
+
+loadLanguages()
+
+type VideoAttributes = {
+  name?: string
+  category?: number
+  licence?: number
+  language?: string
+  nsfw?: boolean
+  commentsEnabled?: boolean
+  downloadEnabled?: boolean
+  waitTranscoding?: boolean
+  description?: string
+  originallyPublishedAt?: string
+  tags?: string[]
+  channelId?: number
+  privacy?: VideoPrivacy
+  fixture?: string
+  thumbnailfile?: string
+  previewfile?: string
+  scheduleUpdate?: {
+    updateAt: string
+    privacy?: VideoPrivacy
+  }
+}
+
+function getVideoCategories (url: string) {
+  const path = '/api/v1/videos/categories'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoLicences (url: string) {
+  const path = '/api/v1/videos/licences'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoLanguages (url: string) {
+  const path = '/api/v1/videos/languages'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoPrivacies (url: string) {
+  const path = '/api/v1/videos/privacies'
+
+  return makeGetRequest({
+    url,
+    path,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideo (url: string, id: number | string, expectedStatus = 200) {
+  const path = '/api/v1/videos/' + id
+
+  return request(url)
+          .get(path)
+          .set('Accept', 'application/json')
+          .expect(expectedStatus)
+}
+
+function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) {
+  const path = '/api/v1/videos/' + id + '/views'
+
+  const req = request(url)
+    .post(path)
+    .set('Accept', 'application/json')
+
+  if (xForwardedFor) {
+    req.set('X-Forwarded-For', xForwardedFor)
+  }
+
+  return req.expect(expectedStatus)
+}
+
+function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
+  const path = '/api/v1/videos/' + id
+
+  return request(url)
+    .get(path)
+    .set('Authorization', 'Bearer ' + token)
+    .set('Accept', 'application/json')
+    .expect(expectedStatus)
+}
+
+function getVideoDescription (url: string, descriptionPath: string) {
+  return request(url)
+    .get(descriptionPath)
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getVideosList (url: string) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+          .get(path)
+          .query({ sort: 'name' })
+          .set('Accept', 'application/json')
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function getVideosListWithToken (url: string, token: string, query: { nsfw?: boolean } = {}) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+    .get(path)
+    .set('Authorization', 'Bearer ' + token)
+    .query(immutableAssign(query, { sort: 'name' }))
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getLocalVideos (url: string) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+    .get(path)
+    .query({ sort: 'name', filter: 'local' })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/users/me/videos'
+
+  const req = request(url)
+    .get(path)
+    .query({ start: start })
+    .query({ count: count })
+
+  if (sort) req.query({ sort })
+
+  return req.set('Accept', 'application/json')
+    .set('Authorization', 'Bearer ' + accessToken)
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function getAccountVideos (
+  url: string,
+  accessToken: string,
+  accountName: string,
+  start: number,
+  count: number,
+  sort?: string,
+  query: { nsfw?: boolean } = {}
+) {
+  const path = '/api/v1/accounts/' + accountName + '/videos'
+
+  return makeGetRequest({
+    url,
+    path,
+    query: immutableAssign(query, {
+      start,
+      count,
+      sort
+    }),
+    token: accessToken,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideoChannelVideos (
+  url: string,
+  accessToken: string,
+  videoChannelName: string,
+  start: number,
+  count: number,
+  sort?: string,
+  query: { nsfw?: boolean } = {}
+) {
+  const path = '/api/v1/video-channels/' + videoChannelName + '/videos'
+
+  return makeGetRequest({
+    url,
+    path,
+    query: immutableAssign(query, {
+      start,
+      count,
+      sort
+    }),
+    token: accessToken,
+    statusCodeExpected: 200
+  })
+}
+
+function getPlaylistVideos (
+  url: string,
+  accessToken: string,
+  playlistId: number | string,
+  start: number,
+  count: number,
+  query: { nsfw?: boolean } = {}
+) {
+  const path = '/api/v1/video-playlists/' + playlistId + '/videos'
+
+  return makeGetRequest({
+    url,
+    path,
+    query: immutableAssign(query, {
+      start,
+      count
+    }),
+    token: accessToken,
+    statusCodeExpected: 200
+  })
+}
+
+function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
+  const path = '/api/v1/videos'
+
+  const req = request(url)
+              .get(path)
+              .query({ start: start })
+              .query({ count: count })
+
+  if (sort) req.query({ sort })
+
+  return req.set('Accept', 'application/json')
+           .expect(200)
+           .expect('Content-Type', /json/)
+}
+
+function getVideosListSort (url: string, sort: string) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+          .get(path)
+          .query({ sort: sort })
+          .set('Accept', 'application/json')
+          .expect(200)
+          .expect('Content-Type', /json/)
+}
+
+function getVideosWithFilters (url: string, query: { tagsAllOf: string[], categoryOneOf: number[] | number }) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+    .get(path)
+    .query(query)
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
+function removeVideo (url: string, token: string, id: number | string, expectedStatus = 204) {
+  const path = '/api/v1/videos'
+
+  return request(url)
+          .delete(path + '/' + id)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + token)
+          .expect(expectedStatus)
+}
+
+async function checkVideoFilesWereRemoved (
+  videoUUID: string,
+  serverNumber: number,
+  directories = [
+    'redundancy',
+    'videos',
+    'thumbnails',
+    'torrents',
+    'previews',
+    'captions',
+    join('playlists', 'hls'),
+    join('redundancy', 'hls')
+  ]
+) {
+  const testDirectory = 'test' + serverNumber
+
+  for (const directory of directories) {
+    const directoryPath = join(root(), testDirectory, directory)
+
+    const directoryExists = await pathExists(directoryPath)
+    if (directoryExists === false) continue
+
+    const files = await readdir(directoryPath)
+    for (const file of files) {
+      expect(file).to.not.contain(videoUUID)
+    }
+  }
+}
+
+async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = 200) {
+  const path = '/api/v1/videos/upload'
+  let defaultChannelId = '1'
+
+  try {
+    const res = await getMyUserInformation(url, accessToken)
+    defaultChannelId = res.body.videoChannels[0].id
+  } catch (e) { /* empty */ }
+
+  // Override default attributes
+  const attributes = Object.assign({
+    name: 'my super video',
+    category: 5,
+    licence: 4,
+    language: 'zh',
+    channelId: defaultChannelId,
+    nsfw: true,
+    waitTranscoding: false,
+    description: 'my super description',
+    support: 'my super support text',
+    tags: [ 'tag' ],
+    privacy: VideoPrivacy.PUBLIC,
+    commentsEnabled: true,
+    downloadEnabled: true,
+    fixture: 'video_short.webm'
+  }, videoAttributesArg)
+
+  const req = request(url)
+              .post(path)
+              .set('Accept', 'application/json')
+              .set('Authorization', 'Bearer ' + accessToken)
+              .field('name', attributes.name)
+              .field('nsfw', JSON.stringify(attributes.nsfw))
+              .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
+              .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
+              .field('waitTranscoding', JSON.stringify(attributes.waitTranscoding))
+              .field('privacy', attributes.privacy.toString())
+              .field('channelId', attributes.channelId)
+
+  if (attributes.description !== undefined) {
+    req.field('description', attributes.description)
+  }
+  if (attributes.language !== undefined) {
+    req.field('language', attributes.language.toString())
+  }
+  if (attributes.category !== undefined) {
+    req.field('category', attributes.category.toString())
+  }
+  if (attributes.licence !== undefined) {
+    req.field('licence', attributes.licence.toString())
+  }
+
+  for (let i = 0; i < attributes.tags.length; i++) {
+    req.field('tags[' + i + ']', attributes.tags[i])
+  }
+
+  if (attributes.thumbnailfile !== undefined) {
+    req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
+  }
+  if (attributes.previewfile !== undefined) {
+    req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
+  }
+
+  if (attributes.scheduleUpdate) {
+    req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt)
+
+    if (attributes.scheduleUpdate.privacy) {
+      req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy)
+    }
+  }
+
+  if (attributes.originallyPublishedAt !== undefined) {
+    req.field('originallyPublishedAt', attributes.originallyPublishedAt)
+  }
+
+  return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
+            .expect(specialStatus)
+}
+
+function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, statusCodeExpected = 204) {
+  const path = '/api/v1/videos/' + id
+  const body = {}
+
+  if (attributes.name) body['name'] = attributes.name
+  if (attributes.category) body['category'] = attributes.category
+  if (attributes.licence) body['licence'] = attributes.licence
+  if (attributes.language) body['language'] = attributes.language
+  if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
+  if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
+  if (attributes.downloadEnabled !== undefined) body['downloadEnabled'] = JSON.stringify(attributes.downloadEnabled)
+  if (attributes.originallyPublishedAt !== undefined) body['originallyPublishedAt'] = attributes.originallyPublishedAt
+  if (attributes.description) body['description'] = attributes.description
+  if (attributes.tags) body['tags'] = attributes.tags
+  if (attributes.privacy) body['privacy'] = attributes.privacy
+  if (attributes.channelId) body['channelId'] = attributes.channelId
+  if (attributes.scheduleUpdate) body['scheduleUpdate'] = attributes.scheduleUpdate
+
+  // Upload request
+  if (attributes.thumbnailfile || attributes.previewfile) {
+    const attaches: any = {}
+    if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
+    if (attributes.previewfile) attaches.previewfile = attributes.previewfile
+
+    return makeUploadRequest({
+      url,
+      method: 'PUT',
+      path,
+      token: accessToken,
+      fields: body,
+      attaches,
+      statusCodeExpected
+    })
+  }
+
+  return makePutBodyRequest({
+    url,
+    path,
+    fields: body,
+    token: accessToken,
+    statusCodeExpected
+  })
+}
+
+function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
+  const path = '/api/v1/videos/' + id + '/rate'
+
+  return request(url)
+          .put(path)
+          .set('Accept', 'application/json')
+          .set('Authorization', 'Bearer ' + accessToken)
+          .send({ rating })
+          .expect(specialStatus)
+}
+
+function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
+  return new Promise<any>((res, rej) => {
+    const torrentName = videoUUID + '-' + resolution + '.torrent'
+    const torrentPath = join(root(), 'test' + server.serverNumber, 'torrents', torrentName)
+    readFile(torrentPath, (err, data) => {
+      if (err) return rej(err)
+
+      return res(parseTorrent(data))
+    })
+  })
+}
+
+async function completeVideoCheck (
+  url: string,
+  video: any,
+  attributes: {
+    name: string
+    category: number
+    licence: number
+    language: string
+    nsfw: boolean
+    commentsEnabled: boolean
+    downloadEnabled: boolean
+    description: string
+    publishedAt?: string
+    support: string
+    originallyPublishedAt?: string,
+    account: {
+      name: string
+      host: string
+    }
+    isLocal: boolean
+    tags: string[]
+    privacy: number
+    likes?: number
+    dislikes?: number
+    duration: number
+    channel: {
+      displayName: string
+      name: string
+      description
+      isLocal: boolean
+    }
+    fixture: string
+    files: {
+      resolution: number
+      size: number
+    }[],
+    thumbnailfile?: string
+    previewfile?: string
+  }
+) {
+  if (!attributes.likes) attributes.likes = 0
+  if (!attributes.dislikes) attributes.dislikes = 0
+
+  expect(video.name).to.equal(attributes.name)
+  expect(video.category.id).to.equal(attributes.category)
+  expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Misc')
+  expect(video.licence.id).to.equal(attributes.licence)
+  expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown')
+  expect(video.language.id).to.equal(attributes.language)
+  expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown')
+  expect(video.privacy.id).to.deep.equal(attributes.privacy)
+  expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
+  expect(video.nsfw).to.equal(attributes.nsfw)
+  expect(video.description).to.equal(attributes.description)
+  expect(video.account.id).to.be.a('number')
+  expect(video.account.uuid).to.be.a('string')
+  expect(video.account.host).to.equal(attributes.account.host)
+  expect(video.account.name).to.equal(attributes.account.name)
+  expect(video.channel.displayName).to.equal(attributes.channel.displayName)
+  expect(video.channel.name).to.equal(attributes.channel.name)
+  expect(video.likes).to.equal(attributes.likes)
+  expect(video.dislikes).to.equal(attributes.dislikes)
+  expect(video.isLocal).to.equal(attributes.isLocal)
+  expect(video.duration).to.equal(attributes.duration)
+  expect(dateIsValid(video.createdAt)).to.be.true
+  expect(dateIsValid(video.publishedAt)).to.be.true
+  expect(dateIsValid(video.updatedAt)).to.be.true
+
+  if (attributes.publishedAt) {
+    expect(video.publishedAt).to.equal(attributes.publishedAt)
+  }
+
+  if (attributes.originallyPublishedAt) {
+    expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt)
+  } else {
+    expect(video.originallyPublishedAt).to.be.null
+  }
+
+  const res = await getVideo(url, video.uuid)
+  const videoDetails: VideoDetails = res.body
+
+  expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
+  expect(videoDetails.tags).to.deep.equal(attributes.tags)
+  expect(videoDetails.account.name).to.equal(attributes.account.name)
+  expect(videoDetails.account.host).to.equal(attributes.account.host)
+  expect(video.channel.displayName).to.equal(attributes.channel.displayName)
+  expect(video.channel.name).to.equal(attributes.channel.name)
+  expect(videoDetails.channel.host).to.equal(attributes.account.host)
+  expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
+  expect(dateIsValid(videoDetails.channel.createdAt.toString())).to.be.true
+  expect(dateIsValid(videoDetails.channel.updatedAt.toString())).to.be.true
+  expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
+  expect(videoDetails.downloadEnabled).to.equal(attributes.downloadEnabled)
+
+  for (const attributeFile of attributes.files) {
+    const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution)
+    expect(file).not.to.be.undefined
+
+    let extension = extname(attributes.fixture)
+    // Transcoding enabled on server 2, extension will always be .mp4
+    if (attributes.account.host === 'localhost:9002') extension = '.mp4'
+
+    const magnetUri = file.magnetUri
+    expect(file.magnetUri).to.have.lengthOf.above(2)
+    expect(file.torrentUrl).to.equal(`http://${attributes.account.host}/static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
+    expect(file.fileUrl).to.equal(`http://${attributes.account.host}/static/webseed/${videoDetails.uuid}-${file.resolution.id}${extension}`)
+    expect(file.resolution.id).to.equal(attributeFile.resolution)
+    expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
+
+    const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
+    const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
+    expect(file.size,
+           'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')')
+      .to.be.above(minSize).and.below(maxSize)
+
+    {
+      await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
+    }
+
+    if (attributes.previewfile) {
+      await testImage(url, attributes.previewfile, videoDetails.previewPath)
+    }
+
+    const torrent = await webtorrentAdd(magnetUri, true)
+    expect(torrent.files).to.be.an('array')
+    expect(torrent.files.length).to.equal(1)
+    expect(torrent.files[0].path).to.exist.and.to.not.equal('')
+  }
+}
+
+async function videoUUIDToId (url: string, id: number | string) {
+  if (validator.isUUID('' + id) === false) return id
+
+  const res = await getVideo(url, id)
+  return res.body.id
+}
+
+async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) {
+  const videoAttrs: any = { name: options.videoName }
+  if (options.nsfw) videoAttrs.nsfw = options.nsfw
+
+  const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
+
+  return { id: res.body.video.id, uuid: res.body.video.uuid }
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+  getVideoDescription,
+  getVideoCategories,
+  getVideoLicences,
+  videoUUIDToId,
+  getVideoPrivacies,
+  getVideoLanguages,
+  getMyVideos,
+  getAccountVideos,
+  getVideoChannelVideos,
+  getVideo,
+  getVideoWithToken,
+  getVideosList,
+  getVideosListPagination,
+  getVideosListSort,
+  removeVideo,
+  getVideosListWithToken,
+  uploadVideo,
+  getVideosWithFilters,
+  updateVideo,
+  rateVideo,
+  viewVideo,
+  parseTorrentVideo,
+  getLocalVideos,
+  completeVideoCheck,
+  checkVideoFilesWereRemoved,
+  getPlaylistVideos,
+  uploadVideoAndGetId
+}
diff --git a/shared/utils/cli/cli.ts b/shared/utils/cli/cli.ts
deleted file mode 100644 (file)
index 54d05e9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-import { exec } from 'child_process'
-
-import { ServerInfo } from '../server/servers'
-
-function getEnvCli (server?: ServerInfo) {
-  return `NODE_ENV=test NODE_APP_INSTANCE=${server.serverNumber}`
-}
-
-async function execCLI (command: string) {
-  return new Promise<string>((res, rej) => {
-    exec(command, (err, stdout, stderr) => {
-      if (err) return rej(err)
-
-      return res(stdout)
-    })
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  execCLI,
-  getEnvCli
-}
diff --git a/shared/utils/feeds/feeds.ts b/shared/utils/feeds/feeds.ts
deleted file mode 100644 (file)
index af6df2b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-import * as request from 'supertest'
-
-type FeedType = 'videos' | 'video-comments'
-
-function getXMLfeed (url: string, feed: FeedType, format?: string) {
-  const path = '/feeds/' + feed + '.xml'
-
-  return request(url)
-          .get(path)
-          .query((format) ? { format: format } : {})
-          .set('Accept', 'application/xml')
-          .expect(200)
-          .expect('Content-Type', /xml/)
-}
-
-function getJSONfeed (url: string, feed: FeedType, query: any = {}) {
-  const path = '/feeds/' + feed + '.json'
-
-  return request(url)
-          .get(path)
-          .query(query)
-          .set('Accept', 'application/json')
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getXMLfeed,
-  getJSONfeed
-}
diff --git a/shared/utils/index.ts b/shared/utils/index.ts
deleted file mode 100644 (file)
index 9d0bbaa..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-export * from './server/activitypub'
-export * from './cli/cli'
-export * from './server/clients'
-export * from './server/config'
-export * from './server/jobs'
-export * from './users/login'
-export * from './miscs/miscs'
-export * from './miscs/stubs'
-export * from './miscs/sql'
-export * from './server/follows'
-export * from './requests/requests'
-export * from './requests/check-api-params'
-export * from './server/servers'
-export * from './videos/services'
-export * from './videos/video-playlists'
-export * from './users/users'
-export * from './users/accounts'
-export * from './videos/video-abuses'
-export * from './videos/video-blacklist'
-export * from './videos/video-channels'
-export * from './videos/video-comments'
-export * from './videos/video-streaming-playlists'
-export * from './videos/videos'
-export * from './videos/video-change-ownership'
-export * from './feeds/feeds'
-export * from './search/videos'
diff --git a/shared/utils/logs/logs.ts b/shared/utils/logs/logs.ts
deleted file mode 100644 (file)
index cbb1afb..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-import { makeGetRequest } from '../requests/requests'
-import { LogLevel } from '../../models/server/log-level.type'
-
-function getLogs (url: string, accessToken: string, startDate: Date, endDate?: Date, level?: LogLevel) {
-  const path = '/api/v1/server/logs'
-
-  return makeGetRequest({
-    url,
-    path,
-    token: accessToken,
-    query: { startDate, endDate, level },
-    statusCodeExpected: 200
-  })
-}
-
-export {
-  getLogs
-}
diff --git a/shared/utils/miscs/email-child-process.js b/shared/utils/miscs/email-child-process.js
deleted file mode 100644 (file)
index 40ae37d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-const MailDev = require('maildev')
-
-// must run maildev as forked ChildProcess
-// failed instantiation stops main process with exit code 0
-process.on('message', (msg) => {
-  if (msg.start) {
-    const maildev = new MailDev({
-      ip: '127.0.0.1',
-      smtp: 1025,
-      disableWeb: true,
-      silent: true
-    })
-
-    maildev.on('new', email => {
-      process.send({ email })
-    })
-
-    maildev.listen(err => {
-      if (err) {
-        // cannot send as Error object
-        return process.send({ err: err.message })
-      }
-
-      return process.send({ err: null })
-    })
-  }
-})
diff --git a/shared/utils/miscs/email.ts b/shared/utils/miscs/email.ts
deleted file mode 100644 (file)
index f9f1bd9..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-import { fork, ChildProcess } from 'child_process'
-
-class MockSmtpServer {
-
-  private static instance: MockSmtpServer
-  private started = false
-  private emailChildProcess: ChildProcess
-  private emails: object[]
-
-  private constructor () {
-    this.emailChildProcess = fork(`${__dirname}/email-child-process`, [])
-
-    this.emailChildProcess.on('message', (msg) => {
-      if (msg.email) {
-        return this.emails.push(msg.email)
-      }
-    })
-
-    process.on('exit', () => this.kill())
-  }
-
-  collectEmails (emailsCollection: object[]) {
-    return new Promise((res, rej) => {
-      if (this.started) {
-        this.emails = emailsCollection
-        return res()
-      }
-
-      // ensure maildev isn't started until
-      // unexpected exit can be reported to test runner
-      this.emailChildProcess.send({ start: true })
-      this.emailChildProcess.on('exit', () => {
-        return rej(new Error('maildev exited unexpectedly, confirm port not in use'))
-      })
-      this.emailChildProcess.on('message', (msg) => {
-        if (msg.err) {
-          return rej(new Error(msg.err))
-        }
-        this.started = true
-        this.emails = emailsCollection
-        return res()
-      })
-    })
-  }
-
-  kill () {
-    if (!this.emailChildProcess) return
-
-    process.kill(this.emailChildProcess.pid)
-
-    this.emailChildProcess = null
-    MockSmtpServer.instance = null
-  }
-
-  static get Instance () {
-    return this.instance || (this.instance = new this())
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  MockSmtpServer
-}
diff --git a/shared/utils/miscs/miscs.ts b/shared/utils/miscs/miscs.ts
deleted file mode 100644 (file)
index 91a93b6..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import * as chai from 'chai'
-import { isAbsolute, join } from 'path'
-import * as request from 'supertest'
-import * as WebTorrent from 'webtorrent'
-import { pathExists, readFile } from 'fs-extra'
-import * as ffmpeg from 'fluent-ffmpeg'
-
-const expect = chai.expect
-let webtorrent = new WebTorrent()
-
-function immutableAssign <T, U> (target: T, source: U) {
-  return Object.assign<{}, T, U>({}, target, source)
-}
-
-  // Default interval -> 5 minutes
-function dateIsValid (dateString: string, interval = 300000) {
-  const dateToCheck = new Date(dateString)
-  const now = new Date()
-
-  return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval
-}
-
-function wait (milliseconds: number) {
-  return new Promise(resolve => setTimeout(resolve, milliseconds))
-}
-
-function webtorrentAdd (torrent: string, refreshWebTorrent = false) {
-  if (refreshWebTorrent === true) webtorrent = new WebTorrent()
-
-  return new Promise<WebTorrent.Torrent>(res => webtorrent.add(torrent, res))
-}
-
-function root () {
-  // We are in /shared/utils/miscs
-  return join(__dirname, '..', '..', '..')
-}
-
-async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') {
-  const res = await request(url)
-    .get(imagePath)
-    .expect(200)
-
-  const body = res.body
-
-  const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension))
-  const minLength = body.length - ((20 * body.length) / 100)
-  const maxLength = body.length + ((20 * body.length) / 100)
-
-  expect(data.length).to.be.above(minLength)
-  expect(data.length).to.be.below(maxLength)
-}
-
-function buildAbsoluteFixturePath (path: string, customTravisPath = false) {
-  if (isAbsolute(path)) {
-    return path
-  }
-
-  if (customTravisPath && process.env.TRAVIS) return join(process.env.HOME, 'fixtures', path)
-
-  return join(root(), 'server', 'tests', 'fixtures', path)
-}
-
-async function generateHighBitrateVideo () {
-  const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true)
-
-  const exists = await pathExists(tempFixturePath)
-  if (!exists) {
-
-    // Generate a random, high bitrate video on the fly, so we don't have to include
-    // a large file in the repo. The video needs to have a certain minimum length so
-    // that FFmpeg properly applies bitrate limits.
-    // https://stackoverflow.com/a/15795112
-    return new Promise<string>(async (res, rej) => {
-      ffmpeg()
-        .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
-        .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
-        .outputOptions([ '-maxrate 10M', '-bufsize 10M' ])
-        .output(tempFixturePath)
-        .on('error', rej)
-        .on('end', () => res(tempFixturePath))
-        .run()
-    })
-  }
-
-  return tempFixturePath
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  dateIsValid,
-  wait,
-  webtorrentAdd,
-  immutableAssign,
-  testImage,
-  buildAbsoluteFixturePath,
-  root,
-  generateHighBitrateVideo
-}
diff --git a/shared/utils/miscs/sql.ts b/shared/utils/miscs/sql.ts
deleted file mode 100644 (file)
index b281471..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-import * as Sequelize from 'sequelize'
-
-let sequelizes: { [ id: number ]: Sequelize.Sequelize } = {}
-
-function getSequelize (serverNumber: number) {
-  if (sequelizes[serverNumber]) return sequelizes[serverNumber]
-
-  const dbname = 'peertube_test' + serverNumber
-  const username = 'peertube'
-  const password = 'peertube'
-  const host = 'localhost'
-  const port = 5432
-
-  const seq = new Sequelize(dbname, username, password, {
-    dialect: 'postgres',
-    host,
-    port,
-    operatorsAliases: false,
-    logging: false
-  })
-
-  sequelizes[serverNumber] = seq
-
-  return seq
-}
-
-function setActorField (serverNumber: number, to: string, field: string, value: string) {
-  const seq = getSequelize(serverNumber)
-
-  const options = { type: Sequelize.QueryTypes.UPDATE }
-
-  return seq.query(`UPDATE actor SET "${field}" = '${value}' WHERE url = '${to}'`, options)
-}
-
-function setVideoField (serverNumber: number, uuid: string, field: string, value: string) {
-  const seq = getSequelize(serverNumber)
-
-  const options = { type: Sequelize.QueryTypes.UPDATE }
-
-  return seq.query(`UPDATE video SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
-}
-
-function setPlaylistField (serverNumber: number, uuid: string, field: string, value: string) {
-  const seq = getSequelize(serverNumber)
-
-  const options = { type: Sequelize.QueryTypes.UPDATE }
-
-  return seq.query(`UPDATE "videoPlaylist" SET "${field}" = '${value}' WHERE uuid = '${uuid}'`, options)
-}
-
-async function countVideoViewsOf (serverNumber: number, uuid: string) {
-  const seq = getSequelize(serverNumber)
-
-  // tslint:disable
-  const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
-
-  const options = { type: Sequelize.QueryTypes.SELECT }
-  const [ { total } ] = await seq.query(query, options)
-
-  if (!total) return 0
-
-  return parseInt(total, 10)
-}
-
-async function closeAllSequelize (servers: any[]) {
-  for (let i = 1; i <= servers.length; i++) {
-    if (sequelizes[ i ]) {
-      await sequelizes[ i ].close()
-      delete sequelizes[ i ]
-    }
-  }
-}
-
-export {
-  setVideoField,
-  setPlaylistField,
-  setActorField,
-  countVideoViewsOf,
-  closeAllSequelize
-}
diff --git a/shared/utils/miscs/stubs.ts b/shared/utils/miscs/stubs.ts
deleted file mode 100644 (file)
index d1eb0e3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-function buildRequestStub (): any {
-  return { }
-}
-
-function buildResponseStub (): any {
-  return {
-    locals: {}
-  }
-}
-
-export {
-  buildResponseStub,
-  buildRequestStub
-}
diff --git a/shared/utils/overviews/overviews.ts b/shared/utils/overviews/overviews.ts
deleted file mode 100644 (file)
index 23e3ceb..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-import { makeGetRequest } from '../requests/requests'
-
-function getVideosOverview (url: string, useCache = false) {
-  const path = '/api/v1/overviews/videos'
-
-  const query = {
-    t: useCache ? undefined : new Date().getTime()
-  }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-export { getVideosOverview }
diff --git a/shared/utils/requests/activitypub.ts b/shared/utils/requests/activitypub.ts
deleted file mode 100644 (file)
index 4762a86..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-import { doRequest } from '../../../server/helpers/requests'
-import { HTTP_SIGNATURE } from '../../../server/initializers/constants'
-import { buildGlobalHeaders } from '../../../server/lib/job-queue/handlers/utils/activitypub-http-utils'
-import { activityPubContextify } from '../../../server/helpers/activitypub'
-
-function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) {
-  const options = {
-    method: 'POST',
-    uri: url,
-    json: body,
-    httpSignature,
-    headers
-  }
-
-  return doRequest(options)
-}
-
-async function makeFollowRequest (to: { url: string }, by: { url: string, privateKey }) {
-  const follow = {
-    type: 'Follow',
-    id: by.url + '/toto',
-    actor: by.url,
-    object: to.url
-  }
-
-  const body = activityPubContextify(follow)
-
-  const httpSignature = {
-    algorithm: HTTP_SIGNATURE.ALGORITHM,
-    authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME,
-    keyId: by.url,
-    key: by.privateKey,
-    headers: HTTP_SIGNATURE.HEADERS_TO_SIGN
-  }
-  const headers = buildGlobalHeaders(body)
-
-  return makePOSTAPRequest(to.url, body, httpSignature, headers)
-}
-
-export {
-  makePOSTAPRequest,
-  makeFollowRequest
-}
diff --git a/shared/utils/requests/check-api-params.ts b/shared/utils/requests/check-api-params.ts
deleted file mode 100644 (file)
index a2a5496..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-import { makeGetRequest } from './requests'
-import { immutableAssign } from '../miscs/miscs'
-
-function checkBadStartPagination (url: string, path: string, token?: string, query = {}) {
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    query: immutableAssign(query, { start: 'hello' }),
-    statusCodeExpected: 400
-  })
-}
-
-function checkBadCountPagination (url: string, path: string, token?: string, query = {}) {
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    query: immutableAssign(query, { count: 'hello' }),
-    statusCodeExpected: 400
-  })
-}
-
-function checkBadSortPagination (url: string, path: string, token?: string, query = {}) {
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    query: immutableAssign(query, { sort: 'hello' }),
-    statusCodeExpected: 400
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  checkBadStartPagination,
-  checkBadCountPagination,
-  checkBadSortPagination
-}
diff --git a/shared/utils/requests/requests.ts b/shared/utils/requests/requests.ts
deleted file mode 100644 (file)
index 3532fb4..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-import * as request from 'supertest'
-import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
-import { isAbsolute, join } from 'path'
-import { parse } from 'url'
-
-function get4KFileUrl () {
-  return 'https://download.cpy.re/peertube/4k_file.txt'
-}
-
-function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
-  const { host, protocol, pathname } = parse(url)
-
-  return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
-}
-
-function makeGetRequest (options: {
-  url: string,
-  path?: string,
-  query?: any,
-  token?: string,
-  statusCodeExpected?: number,
-  contentType?: string,
-  range?: string
-}) {
-  if (!options.statusCodeExpected) options.statusCodeExpected = 400
-  if (options.contentType === undefined) options.contentType = 'application/json'
-
-  const req = request(options.url).get(options.path)
-
-  if (options.contentType) req.set('Accept', options.contentType)
-  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
-  if (options.query) req.query(options.query)
-  if (options.range) req.set('Range', options.range)
-
-  return req.expect(options.statusCodeExpected)
-}
-
-function makeDeleteRequest (options: {
-  url: string,
-  path: string,
-  token?: string,
-  statusCodeExpected?: number
-}) {
-  if (!options.statusCodeExpected) options.statusCodeExpected = 400
-
-  const req = request(options.url)
-    .delete(options.path)
-    .set('Accept', 'application/json')
-
-  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
-
-  return req.expect(options.statusCodeExpected)
-}
-
-function makeUploadRequest (options: {
-  url: string,
-  method?: 'POST' | 'PUT',
-  path: string,
-  token?: string,
-  fields: { [ fieldName: string ]: any },
-  attaches: { [ attachName: string ]: any | any[] },
-  statusCodeExpected?: number
-}) {
-  if (!options.statusCodeExpected) options.statusCodeExpected = 400
-
-  let req: request.Test
-  if (options.method === 'PUT') {
-    req = request(options.url).put(options.path)
-  } else {
-    req = request(options.url).post(options.path)
-  }
-
-  req.set('Accept', 'application/json')
-
-  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
-
-  Object.keys(options.fields).forEach(field => {
-    const value = options.fields[field]
-
-    if (value === undefined) return
-
-    if (Array.isArray(value)) {
-      for (let i = 0; i < value.length; i++) {
-        req.field(field + '[' + i + ']', value[i])
-      }
-    } else {
-      req.field(field, value)
-    }
-  })
-
-  Object.keys(options.attaches).forEach(attach => {
-    const value = options.attaches[attach]
-    if (Array.isArray(value)) {
-      req.attach(attach, buildAbsoluteFixturePath(value[0]), value[1])
-    } else {
-      req.attach(attach, buildAbsoluteFixturePath(value))
-    }
-  })
-
-  return req.expect(options.statusCodeExpected)
-}
-
-function makePostBodyRequest (options: {
-  url: string,
-  path: string,
-  token?: string,
-  fields?: { [ fieldName: string ]: any },
-  statusCodeExpected?: number
-}) {
-  if (!options.fields) options.fields = {}
-  if (!options.statusCodeExpected) options.statusCodeExpected = 400
-
-  const req = request(options.url)
-                .post(options.path)
-                .set('Accept', 'application/json')
-
-  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
-
-  return req.send(options.fields)
-            .expect(options.statusCodeExpected)
-}
-
-function makePutBodyRequest (options: {
-  url: string,
-  path: string,
-  token?: string,
-  fields: { [ fieldName: string ]: any },
-  statusCodeExpected?: number
-}) {
-  if (!options.statusCodeExpected) options.statusCodeExpected = 400
-
-  const req = request(options.url)
-                .put(options.path)
-                .set('Accept', 'application/json')
-
-  if (options.token) req.set('Authorization', 'Bearer ' + options.token)
-
-  return req.send(options.fields)
-            .expect(options.statusCodeExpected)
-}
-
-function makeHTMLRequest (url: string, path: string) {
-  return request(url)
-    .get(path)
-    .set('Accept', 'text/html')
-    .expect(200)
-}
-
-function updateAvatarRequest (options: {
-  url: string,
-  path: string,
-  accessToken: string,
-  fixture: string
-}) {
-  let filePath = ''
-  if (isAbsolute(options.fixture)) {
-    filePath = options.fixture
-  } else {
-    filePath = join(root(), 'server', 'tests', 'fixtures', options.fixture)
-  }
-
-  return makeUploadRequest({
-    url: options.url,
-    path: options.path,
-    token: options.accessToken,
-    fields: {},
-    attaches: { avatarfile: filePath },
-    statusCodeExpected: 200
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  get4KFileUrl,
-  makeHTMLRequest,
-  makeGetRequest,
-  makeUploadRequest,
-  makePostBodyRequest,
-  makePutBodyRequest,
-  makeDeleteRequest,
-  makeRawRequest,
-  updateAvatarRequest
-}
diff --git a/shared/utils/search/video-channels.ts b/shared/utils/search/video-channels.ts
deleted file mode 100644 (file)
index 0532134..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-import { makeGetRequest } from '../requests/requests'
-
-function searchVideoChannel (url: string, search: string, token?: string, statusCodeExpected = 200) {
-  const path = '/api/v1/search/video-channels'
-
-  return makeGetRequest({
-    url,
-    path,
-    query: {
-      sort: '-createdAt',
-      search
-    },
-    token,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  searchVideoChannel
-}
diff --git a/shared/utils/search/videos.ts b/shared/utils/search/videos.ts
deleted file mode 100644 (file)
index ba46270..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import * as request from 'supertest'
-import { VideosSearchQuery } from '../../models/search'
-import { immutableAssign } from '../miscs/miscs'
-
-function searchVideo (url: string, search: string) {
-  const path = '/api/v1/search/videos'
-  const req = request(url)
-    .get(path)
-    .query({ sort: '-publishedAt', search })
-    .set('Accept', 'application/json')
-
-  return req.expect(200)
-            .expect('Content-Type', /json/)
-}
-
-function searchVideoWithToken (url: string, search: string, token: string, query: { nsfw?: boolean } = {}) {
-  const path = '/api/v1/search/videos'
-  const req = request(url)
-    .get(path)
-    .set('Authorization', 'Bearer ' + token)
-    .query(immutableAssign(query, { sort: '-publishedAt', search }))
-    .set('Accept', 'application/json')
-
-  return req.expect(200)
-            .expect('Content-Type', /json/)
-}
-
-function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/search/videos'
-
-  const req = request(url)
-    .get(path)
-    .query({ start })
-    .query({ search })
-    .query({ count })
-
-  if (sort) req.query({ sort })
-
-  return req.set('Accept', 'application/json')
-            .expect(200)
-            .expect('Content-Type', /json/)
-}
-
-function searchVideoWithSort (url: string, search: string, sort: string) {
-  const path = '/api/v1/search/videos'
-
-  return request(url)
-    .get(path)
-    .query({ search })
-    .query({ sort })
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function advancedVideosSearch (url: string, options: VideosSearchQuery) {
-  const path = '/api/v1/search/videos'
-
-  return request(url)
-    .get(path)
-    .query(options)
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  searchVideo,
-  advancedVideosSearch,
-  searchVideoWithToken,
-  searchVideoWithPagination,
-  searchVideoWithSort
-}
diff --git a/shared/utils/server/activitypub.ts b/shared/utils/server/activitypub.ts
deleted file mode 100644 (file)
index eccb198..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-import * as request from 'supertest'
-
-function makeActivityPubGetRequest (url: string, path: string, expectedStatus = 200) {
-  return request(url)
-    .get(path)
-    .set('Accept', 'application/activity+json,text/html;q=0.9,\\*/\\*;q=0.8')
-    .expect(expectedStatus)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  makeActivityPubGetRequest
-}
diff --git a/shared/utils/server/clients.ts b/shared/utils/server/clients.ts
deleted file mode 100644 (file)
index 273aac7..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as request from 'supertest'
-import * as urlUtil from 'url'
-
-function getClient (url: string) {
-  const path = '/api/v1/oauth-clients/local'
-
-  return request(url)
-          .get(path)
-          .set('Host', urlUtil.parse(url).host)
-          .set('Accept', 'application/json')
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getClient
-}
diff --git a/shared/utils/server/config.ts b/shared/utils/server/config.ts
deleted file mode 100644 (file)
index deb77e9..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-import { makeDeleteRequest, makeGetRequest, makePutBodyRequest } from '../requests/requests'
-import { CustomConfig } from '../../models/server/custom-config.model'
-
-function getConfig (url: string) {
-  const path = '/api/v1/config'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getAbout (url: string) {
-  const path = '/api/v1/config/about'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getCustomConfig (url: string, token: string, statusCodeExpected = 200) {
-  const path = '/api/v1/config/custom'
-
-  return makeGetRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-function updateCustomConfig (url: string, token: string, newCustomConfig: CustomConfig, statusCodeExpected = 200) {
-  const path = '/api/v1/config/custom'
-
-  return makePutBodyRequest({
-    url,
-    token,
-    path,
-    fields: newCustomConfig,
-    statusCodeExpected
-  })
-}
-
-function updateCustomSubConfig (url: string, token: string, newConfig: any) {
-  const updateParams: CustomConfig = {
-    instance: {
-      name: 'PeerTube updated',
-      shortDescription: 'my short description',
-      description: 'my super description',
-      terms: 'my super terms',
-      defaultClientRoute: '/videos/recently-added',
-      isNSFW: true,
-      defaultNSFWPolicy: 'blur',
-      customizations: {
-        javascript: 'alert("coucou")',
-        css: 'body { background-color: red; }'
-      }
-    },
-    services: {
-      twitter: {
-        username: '@MySuperUsername',
-        whitelisted: true
-      }
-    },
-    cache: {
-      previews: {
-        size: 2
-      },
-      captions: {
-        size: 3
-      }
-    },
-    signup: {
-      enabled: false,
-      limit: 5,
-      requiresEmailVerification: false
-    },
-    admin: {
-      email: 'superadmin1@example.com'
-    },
-    contactForm: {
-      enabled: true
-    },
-    user: {
-      videoQuota: 5242881,
-      videoQuotaDaily: 318742
-    },
-    transcoding: {
-      enabled: true,
-      allowAdditionalExtensions: true,
-      threads: 1,
-      resolutions: {
-        '240p': false,
-        '360p': true,
-        '480p': true,
-        '720p': false,
-        '1080p': false
-      },
-      hls: {
-        enabled: false
-      }
-    },
-    import: {
-      videos: {
-        http: {
-          enabled: false
-        },
-        torrent: {
-          enabled: false
-        }
-      }
-    },
-    autoBlacklist: {
-      videos: {
-        ofUsers: {
-          enabled: false
-        }
-      }
-    },
-    followers: {
-      instance: {
-        enabled: true,
-        manualApproval: false
-      }
-    }
-  }
-
-  Object.assign(updateParams, newConfig)
-
-  return updateCustomConfig(url, token, updateParams)
-}
-
-function deleteCustomConfig (url: string, token: string, statusCodeExpected = 200) {
-  const path = '/api/v1/config/custom'
-
-  return makeDeleteRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getConfig,
-  getCustomConfig,
-  updateCustomConfig,
-  getAbout,
-  deleteCustomConfig,
-  updateCustomSubConfig
-}
diff --git a/shared/utils/server/contact-form.ts b/shared/utils/server/contact-form.ts
deleted file mode 100644 (file)
index 80394cf..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as request from 'supertest'
-import { ContactForm } from '../../models/server'
-
-function sendContactForm (options: {
-  url: string,
-  fromEmail: string,
-  fromName: string,
-  body: string,
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/server/contact'
-
-  const body: ContactForm = {
-    fromEmail: options.fromEmail,
-    fromName: options.fromName,
-    body: options.body
-  }
-  return request(options.url)
-    .post(path)
-    .send(body)
-    .expect(options.expectedStatus || 204)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  sendContactForm
-}
diff --git a/shared/utils/server/follows.ts b/shared/utils/server/follows.ts
deleted file mode 100644 (file)
index 1505804..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-import * as request from 'supertest'
-import { ServerInfo } from './servers'
-import { waitJobs } from './jobs'
-import { makeGetRequest, makePostBodyRequest } from '..'
-
-function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
-  const path = '/api/v1/server/followers'
-
-  return request(url)
-    .get(path)
-    .query({ start })
-    .query({ count })
-    .query({ sort })
-    .query({ search })
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function acceptFollower (url: string, token: string, follower: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/followers/' + follower + '/accept'
-
-  return makePostBodyRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-function rejectFollower (url: string, token: string, follower: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/followers/' + follower + '/reject'
-
-  return makePostBodyRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
-  const path = '/api/v1/server/following'
-
-  return request(url)
-    .get(path)
-    .query({ start })
-    .query({ count })
-    .query({ sort })
-    .query({ search })
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function follow (follower: string, following: string[], accessToken: string, expectedStatus = 204) {
-  const path = '/api/v1/server/following'
-
-  const followingHosts = following.map(f => f.replace(/^http:\/\//, ''))
-  return request(follower)
-    .post(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .send({ 'hosts': followingHosts })
-    .expect(expectedStatus)
-}
-
-async function unfollow (url: string, accessToken: string, target: ServerInfo, expectedStatus = 204) {
-  const path = '/api/v1/server/following/' + target.host
-
-  return request(url)
-    .delete(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(expectedStatus)
-}
-
-function removeFollower (url: string, accessToken: string, follower: ServerInfo, expectedStatus = 204) {
-  const path = '/api/v1/server/followers/peertube@' + follower.host
-
-  return request(url)
-    .delete(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(expectedStatus)
-}
-
-async function doubleFollow (server1: ServerInfo, server2: ServerInfo) {
-  await Promise.all([
-    follow(server1.url, [ server2.url ], server1.accessToken),
-    follow(server2.url, [ server1.url ], server2.accessToken)
-  ])
-
-  // Wait request propagation
-  await waitJobs([ server1, server2 ])
-
-  return true
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getFollowersListPaginationAndSort,
-  getFollowingListPaginationAndSort,
-  unfollow,
-  removeFollower,
-  follow,
-  doubleFollow,
-  acceptFollower,
-  rejectFollower
-}
diff --git a/shared/utils/server/jobs.ts b/shared/utils/server/jobs.ts
deleted file mode 100644 (file)
index 692b5e2..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-import * as request from 'supertest'
-import { Job, JobState } from '../../models'
-import { wait } from '../miscs/miscs'
-import { ServerInfo } from './servers'
-
-function getJobsList (url: string, accessToken: string, state: JobState) {
-  const path = '/api/v1/jobs/' + state
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function getJobsListPaginationAndSort (url: string, accessToken: string, state: JobState, start: number, count: number, sort: string) {
-  const path = '/api/v1/jobs/' + state
-
-  return request(url)
-          .get(path)
-          .query({ start })
-          .query({ count })
-          .query({ sort })
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-async function waitJobs (serversArg: ServerInfo[] | ServerInfo) {
-  const pendingJobWait = process.env.NODE_PENDING_JOB_WAIT ? parseInt(process.env.NODE_PENDING_JOB_WAIT, 10) : 2000
-  let servers: ServerInfo[]
-
-  if (Array.isArray(serversArg) === false) servers = [ serversArg as ServerInfo ]
-  else servers = serversArg as ServerInfo[]
-
-  const states: JobState[] = [ 'waiting', 'active', 'delayed' ]
-  let pendingRequests = false
-
-  function tasksBuilder () {
-    const tasks: Promise<any>[] = []
-    pendingRequests = false
-
-    // Check if each server has pending request
-    for (const server of servers) {
-      for (const state of states) {
-        const p = getJobsListPaginationAndSort(server.url, server.accessToken, state, 0, 10, '-createdAt')
-          .then(res => res.body.data)
-          .then((jobs: Job[]) => jobs.filter(j => j.type !== 'videos-views'))
-          .then(jobs => {
-            if (jobs.length !== 0) pendingRequests = true
-          })
-        tasks.push(p)
-      }
-    }
-
-    return tasks
-  }
-
-  do {
-    await Promise.all(tasksBuilder())
-
-    // Retry, in case of new jobs were created
-    if (pendingRequests === false) {
-      await wait(pendingJobWait)
-      await Promise.all(tasksBuilder())
-    }
-
-    if (pendingRequests) {
-      await wait(1000)
-    }
-  } while (pendingRequests)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getJobsList,
-  waitJobs,
-  getJobsListPaginationAndSort
-}
diff --git a/shared/utils/server/redundancy.ts b/shared/utils/server/redundancy.ts
deleted file mode 100644 (file)
index c39ff2c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-import { makePutBodyRequest } from '../requests/requests'
-
-async function updateRedundancy (url: string, accessToken: string, host: string, redundancyAllowed: boolean, expectedStatus = 204) {
-  const path = '/api/v1/server/redundancy/' + host
-
-  return makePutBodyRequest({
-    url,
-    path,
-    token: accessToken,
-    fields: { redundancyAllowed },
-    statusCodeExpected: expectedStatus
-  })
-}
-
-export {
-  updateRedundancy
-}
diff --git a/shared/utils/server/servers.ts b/shared/utils/server/servers.ts
deleted file mode 100644 (file)
index 5288d25..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import { ChildProcess, exec, fork } from 'child_process'
-import { join } from 'path'
-import { root, wait } from '../miscs/miscs'
-import { readdir, readFile } from 'fs-extra'
-import { existsSync } from 'fs'
-import { expect } from 'chai'
-import { VideoChannel } from '../../models/videos'
-
-interface ServerInfo {
-  app: ChildProcess,
-  url: string
-  host: string
-  serverNumber: number
-
-  client: {
-    id: string,
-    secret: string
-  }
-
-  user: {
-    username: string,
-    password: string,
-    email?: string
-  }
-
-  accessToken?: string
-  videoChannel?: VideoChannel
-
-  video?: {
-    id: number
-    uuid: string
-    name: string
-    account: {
-      name: string
-    }
-  }
-
-  remoteVideo?: {
-    id: number
-    uuid: string
-  }
-
-  videos?: { id: number, uuid: string }[]
-}
-
-function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
-  let apps = []
-  let i = 0
-
-  return new Promise<ServerInfo[]>(res => {
-    function anotherServerDone (serverNumber, app) {
-      apps[serverNumber - 1] = app
-      i++
-      if (i === totalServers) {
-        return res(apps)
-      }
-    }
-
-    flushTests()
-      .then(() => {
-        for (let j = 1; j <= totalServers; j++) {
-          runServer(j, configOverride).then(app => anotherServerDone(j, app))
-        }
-      })
-  })
-}
-
-function flushTests () {
-  return new Promise<void>((res, rej) => {
-    return exec('npm run clean:server:test', err => {
-      if (err) return rej(err)
-
-      return res()
-    })
-  })
-}
-
-function runServer (serverNumber: number, configOverride?: Object, args = []) {
-  const server: ServerInfo = {
-    app: null,
-    serverNumber: serverNumber,
-    url: `http://localhost:${9000 + serverNumber}`,
-    host: `localhost:${9000 + serverNumber}`,
-    client: {
-      id: null,
-      secret: null
-    },
-    user: {
-      username: null,
-      password: null
-    }
-  }
-
-  // These actions are async so we need to be sure that they have both been done
-  const serverRunString = {
-    'Server listening': false
-  }
-  const key = 'Database peertube_test' + serverNumber + ' is ready'
-  serverRunString[key] = false
-
-  const regexps = {
-    client_id: 'Client id: (.+)',
-    client_secret: 'Client secret: (.+)',
-    user_username: 'Username: (.+)',
-    user_password: 'User password: (.+)'
-  }
-
-  // Share the environment
-  const env = Object.create(process.env)
-  env['NODE_ENV'] = 'test'
-  env['NODE_APP_INSTANCE'] = serverNumber.toString()
-
-  if (configOverride !== undefined) {
-    env['NODE_CONFIG'] = JSON.stringify(configOverride)
-  }
-
-  const options = {
-    silent: true,
-    env: env,
-    detached: true
-  }
-
-  return new Promise<ServerInfo>(res => {
-    server.app = fork(join(root(), 'dist', 'server.js'), args, options)
-    server.app.stdout.on('data', function onStdout (data) {
-      let dontContinue = false
-
-      // Capture things if we want to
-      for (const key of Object.keys(regexps)) {
-        const regexp = regexps[key]
-        const matches = data.toString().match(regexp)
-        if (matches !== null) {
-          if (key === 'client_id') server.client.id = matches[1]
-          else if (key === 'client_secret') server.client.secret = matches[1]
-          else if (key === 'user_username') server.user.username = matches[1]
-          else if (key === 'user_password') server.user.password = matches[1]
-        }
-      }
-
-      // Check if all required sentences are here
-      for (const key of Object.keys(serverRunString)) {
-        if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
-        if (serverRunString[key] === false) dontContinue = true
-      }
-
-      // If no, there is maybe one thing not already initialized (client/user credentials generation...)
-      if (dontContinue === true) return
-
-      server.app.stdout.removeListener('data', onStdout)
-
-      process.on('exit', () => {
-        try {
-          process.kill(server.app.pid)
-        } catch { /* empty */ }
-      })
-
-      res(server)
-    })
-
-  })
-}
-
-async function reRunServer (server: ServerInfo, configOverride?: any) {
-  const newServer = await runServer(server.serverNumber, configOverride)
-  server.app = newServer.app
-
-  return server
-}
-
-async function checkTmpIsEmpty (server: ServerInfo) {
-  return checkDirectoryIsEmpty(server, 'tmp')
-}
-
-async function checkDirectoryIsEmpty (server: ServerInfo, directory: string) {
-  const testDirectory = 'test' + server.serverNumber
-
-  const directoryPath = join(root(), testDirectory, directory)
-
-  const directoryExists = existsSync(directoryPath)
-  expect(directoryExists).to.be.true
-
-  const files = await readdir(directoryPath)
-  expect(files).to.have.lengthOf(0)
-}
-
-function killallServers (servers: ServerInfo[]) {
-  for (const server of servers) {
-    process.kill(-server.app.pid)
-  }
-}
-
-async function waitUntilLog (server: ServerInfo, str: string, count = 1) {
-  const logfile = join(root(), 'test' + server.serverNumber, 'logs/peertube.log')
-
-  while (true) {
-    const buf = await readFile(logfile)
-
-    const matches = buf.toString().match(new RegExp(str, 'g'))
-    if (matches && matches.length === count) return
-
-    await wait(1000)
-  }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  checkDirectoryIsEmpty,
-  checkTmpIsEmpty,
-  ServerInfo,
-  flushAndRunMultipleServers,
-  flushTests,
-  runServer,
-  killallServers,
-  reRunServer,
-  waitUntilLog
-}
diff --git a/shared/utils/server/stats.ts b/shared/utils/server/stats.ts
deleted file mode 100644 (file)
index 6f079ad..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-import { makeGetRequest } from '../requests/requests'
-
-function getStats (url: string, useCache = false) {
-  const path = '/api/v1/server/stats'
-
-  const query = {
-    t: useCache ? undefined : new Date().getTime()
-  }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getStats
-}
diff --git a/shared/utils/socket/socket-io.ts b/shared/utils/socket/socket-io.ts
deleted file mode 100644 (file)
index 854ab71..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import * as io from 'socket.io-client'
-
-function getUserNotificationSocket (serverUrl: string, accessToken: string) {
-  return io(serverUrl + '/user-notifications', {
-    query: { accessToken }
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getUserNotificationSocket
-}
diff --git a/shared/utils/users/accounts.ts b/shared/utils/users/accounts.ts
deleted file mode 100644 (file)
index f64a2db..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import * as request from 'supertest'
-import { expect } from 'chai'
-import { existsSync, readdir } from 'fs-extra'
-import { join } from 'path'
-import { Account } from '../../models/actors'
-import { root } from '../miscs/miscs'
-import { makeGetRequest } from '../requests/requests'
-import { VideoRateType } from '../../models/videos'
-
-function getAccountsList (url: string, sort = '-createdAt', statusCodeExpected = 200) {
-  const path = '/api/v1/accounts'
-
-  return makeGetRequest({
-    url,
-    query: { sort },
-    path,
-    statusCodeExpected
-  })
-}
-
-function getAccount (url: string, accountName: string, statusCodeExpected = 200) {
-  const path = '/api/v1/accounts/' + accountName
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected
-  })
-}
-
-async function expectAccountFollows (url: string, nameWithDomain: string, followersCount: number, followingCount: number) {
-  const res = await getAccountsList(url)
-  const account = res.body.data.find((a: Account) => a.name + '@' + a.host === nameWithDomain)
-
-  const message = `${nameWithDomain} on ${url}`
-  expect(account.followersCount).to.equal(followersCount, message)
-  expect(account.followingCount).to.equal(followingCount, message)
-}
-
-async function checkActorFilesWereRemoved (actorUUID: string, serverNumber: number) {
-  const testDirectory = 'test' + serverNumber
-
-  for (const directory of [ 'avatars' ]) {
-    const directoryPath = join(root(), testDirectory, directory)
-
-    const directoryExists = existsSync(directoryPath)
-    expect(directoryExists).to.be.true
-
-    const files = await readdir(directoryPath)
-    for (const file of files) {
-      expect(file).to.not.contain(actorUUID)
-    }
-  }
-}
-
-function getAccountRatings (url: string, accountName: string, accessToken: string, rating?: VideoRateType, statusCodeExpected = 200) {
-  const path = '/api/v1/accounts/' + accountName + '/ratings'
-
-  const query = rating ? { rating } : {}
-
-  return request(url)
-          .get(path)
-          .query(query)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(statusCodeExpected)
-          .expect('Content-Type', /json/)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getAccount,
-  expectAccountFollows,
-  getAccountsList,
-  checkActorFilesWereRemoved,
-  getAccountRatings
-}
diff --git a/shared/utils/users/blocklist.ts b/shared/utils/users/blocklist.ts
deleted file mode 100644 (file)
index 5feb841..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } 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
-  })
-}
-
-function getAccountBlocklistByServer (
-  url: string,
-  token: string,
-  start: number,
-  count: number,
-  sort = '-createdAt',
-  statusCodeExpected = 200
-) {
-  const path = '/api/v1/server/blocklist/accounts'
-
-  return makeGetRequest({
-    url,
-    token,
-    query: { start, count, sort },
-    path,
-    statusCodeExpected
-  })
-}
-
-function addAccountToServerBlocklist (url: string, token: string, accountToBlock: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/blocklist/accounts'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    fields: {
-      accountName: accountToBlock
-    },
-    statusCodeExpected
-  })
-}
-
-function removeAccountFromServerBlocklist (url: string, token: string, accountToUnblock: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/blocklist/accounts/' + accountToUnblock
-
-  return makeDeleteRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-function getServerBlocklistByServer (
-  url: string,
-  token: string,
-  start: number,
-  count: number,
-  sort = '-createdAt',
-  statusCodeExpected = 200
-) {
-  const path = '/api/v1/server/blocklist/servers'
-
-  return makeGetRequest({
-    url,
-    token,
-    query: { start, count, sort },
-    path,
-    statusCodeExpected
-  })
-}
-
-function addServerToServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/blocklist/servers'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    fields: {
-      host: serverToBlock
-    },
-    statusCodeExpected
-  })
-}
-
-function removeServerFromServerBlocklist (url: string, token: string, serverToBlock: string, statusCodeExpected = 204) {
-  const path = '/api/v1/server/blocklist/servers/' + serverToBlock
-
-  return makeDeleteRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getAccountBlocklistByAccount,
-  addAccountToAccountBlocklist,
-  removeAccountFromAccountBlocklist,
-  getServerBlocklistByAccount,
-  addServerToAccountBlocklist,
-  removeServerFromAccountBlocklist,
-
-  getAccountBlocklistByServer,
-  addAccountToServerBlocklist,
-  removeAccountFromServerBlocklist,
-  getServerBlocklistByServer,
-  addServerToServerBlocklist,
-  removeServerFromServerBlocklist
-}
diff --git a/shared/utils/users/login.ts b/shared/utils/users/login.ts
deleted file mode 100644 (file)
index ddeb9df..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-import * as request from 'supertest'
-
-import { ServerInfo } from '../server/servers'
-
-type Client = { id: string, secret: string }
-type User = { username: string, password: string }
-type Server = { url: string, client: Client, user: User }
-
-function login (url: string, client: Client, user: User, expectedStatus = 200) {
-  const path = '/api/v1/users/token'
-
-  const body = {
-    client_id: client.id,
-    client_secret: client.secret,
-    username: user.username,
-    password: user.password,
-    response_type: 'code',
-    grant_type: 'password',
-    scope: 'upload'
-  }
-
-  return request(url)
-          .post(path)
-          .type('form')
-          .send(body)
-          .expect(expectedStatus)
-}
-
-async function serverLogin (server: Server) {
-  const res = await login(server.url, server.client, server.user, 200)
-
-  return res.body.access_token as string
-}
-
-async function userLogin (server: Server, user: User, expectedStatus = 200) {
-  const res = await login(server.url, server.client, user, expectedStatus)
-
-  return res.body.access_token as string
-}
-
-function setAccessTokensToServers (servers: ServerInfo[]) {
-  const tasks: Promise<any>[] = []
-
-  for (const server of servers) {
-    const p = serverLogin(server).then(t => server.accessToken = t)
-    tasks.push(p)
-  }
-
-  return Promise.all(tasks)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  login,
-  serverLogin,
-  userLogin,
-  setAccessTokensToServers,
-  Server,
-  Client,
-  User
-}
diff --git a/shared/utils/users/user-notifications.ts b/shared/utils/users/user-notifications.ts
deleted file mode 100644 (file)
index 495ff80..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
-import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
-import { ServerInfo } from '..'
-import { expect } from 'chai'
-import { inspect } from 'util'
-
-function updateMyNotificationSettings (url: string, token: string, settings: UserNotificationSetting, statusCodeExpected = 204) {
-  const path = '/api/v1/users/me/notification-settings'
-
-  return makePutBodyRequest({
-    url,
-    path,
-    token,
-    fields: settings,
-    statusCodeExpected
-  })
-}
-
-async function getUserNotifications (
-  url: string,
-  token: string,
-  start: number,
-  count: number,
-  unread?: boolean,
-  sort = '-createdAt',
-  statusCodeExpected = 200
-) {
-  const path = '/api/v1/users/me/notifications'
-
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    query: {
-      start,
-      count,
-      sort,
-      unread
-    },
-    statusCodeExpected
-  })
-}
-
-function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = 204) {
-  const path = '/api/v1/users/me/notifications/read'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    fields: { ids },
-    statusCodeExpected
-  })
-}
-function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
-  const path = '/api/v1/users/me/notifications/read-all'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-async function getLastNotification (serverUrl: string, accessToken: string) {
-  const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt')
-
-  if (res.body.total === 0) return undefined
-
-  return res.body.data[0] as UserNotification
-}
-
-type CheckerBaseParams = {
-  server: ServerInfo
-  emails: object[]
-  socketNotifications: UserNotification[]
-  token: string,
-  check?: { web: boolean, mail: boolean }
-}
-
-type CheckerType = 'presence' | 'absence'
-
-async function checkNotification (
-  base: CheckerBaseParams,
-  notificationChecker: (notification: UserNotification, type: CheckerType) => void,
-  emailNotificationFinder: (email: object) => boolean,
-  checkType: CheckerType
-) {
-  const check = base.check || { web: true, mail: true }
-
-  if (check.web) {
-    const notification = await getLastNotification(base.server.url, base.token)
-
-    if (notification || checkType !== 'absence') {
-      notificationChecker(notification, checkType)
-    }
-
-    const socketNotification = base.socketNotifications.find(n => {
-      try {
-        notificationChecker(n, 'presence')
-        return true
-      } catch {
-        return false
-      }
-    })
-
-    if (checkType === 'presence') {
-      const obj = inspect(base.socketNotifications, { depth: 5 })
-      expect(socketNotification, 'The socket notification is absent. ' + obj).to.not.be.undefined
-    } else {
-      const obj = inspect(socketNotification, { depth: 5 })
-      expect(socketNotification, 'The socket notification is present. ' + obj).to.be.undefined
-    }
-  }
-
-  if (check.mail) {
-    // Last email
-    const email = base.emails
-                      .slice()
-                      .reverse()
-                      .find(e => emailNotificationFinder(e))
-
-    if (checkType === 'presence') {
-      expect(email, 'The email is absent. ' + inspect(base.emails)).to.not.be.undefined
-    } else {
-      expect(email, 'The email is present. ' + inspect(email)).to.be.undefined
-    }
-  }
-}
-
-function checkVideo (video: any, videoName?: string, videoUUID?: string) {
-  expect(video.name).to.be.a('string')
-  expect(video.name).to.not.be.empty
-  if (videoName) expect(video.name).to.equal(videoName)
-
-  expect(video.uuid).to.be.a('string')
-  expect(video.uuid).to.not.be.empty
-  if (videoUUID) expect(video.uuid).to.equal(videoUUID)
-
-  expect(video.id).to.be.a('number')
-}
-
-function checkActor (actor: any) {
-  expect(actor.displayName).to.be.a('string')
-  expect(actor.displayName).to.not.be.empty
-  expect(actor.host).to.not.be.undefined
-}
-
-function checkComment (comment: any, commentId: number, threadId: number) {
-  expect(comment.id).to.equal(commentId)
-  expect(comment.threadId).to.equal(threadId)
-}
-
-async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
-  const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkVideo(notification.video, videoName, videoUUID)
-      checkActor(notification.video.channel)
-    } else {
-      expect(notification).to.satisfy((n: UserNotification) => {
-        return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
-      })
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text = email[ 'text' ]
-    return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
-  const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkVideo(notification.video, videoName, videoUUID)
-      checkActor(notification.video.channel)
-    } else {
-      expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-    return text.includes(videoUUID) && text.includes('Your video')
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkMyVideoImportIsFinished (
-  base: CheckerBaseParams,
-  videoName: string,
-  videoUUID: string,
-  url: string,
-  success: boolean,
-  type: CheckerType
-) {
-  const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      expect(notification.videoImport.targetUrl).to.equal(url)
-
-      if (success) checkVideo(notification.videoImport.video, videoName, videoUUID)
-    } else {
-      expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-    const toFind = success ? ' finished' : ' error'
-
-    return text.includes(url) && text.includes(toFind)
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
-  const notificationType = UserNotificationType.NEW_USER_REGISTRATION
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkActor(notification.account)
-      expect(notification.account.name).to.equal(username)
-    } else {
-      expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-
-    return text.includes(' registered ') && text.includes(username)
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkNewActorFollow (
-  base: CheckerBaseParams,
-  followType: 'channel' | 'account',
-  followerName: string,
-  followerDisplayName: string,
-  followingDisplayName: string,
-  type: CheckerType
-) {
-  const notificationType = UserNotificationType.NEW_FOLLOW
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkActor(notification.actorFollow.follower)
-      expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
-      expect(notification.actorFollow.follower.name).to.equal(followerName)
-      expect(notification.actorFollow.follower.host).to.not.be.undefined
-
-      expect(notification.actorFollow.following.displayName).to.equal(followingDisplayName)
-      expect(notification.actorFollow.following.type).to.equal(followType)
-    } else {
-      expect(notification).to.satisfy(n => {
-        return n.type !== notificationType ||
-          (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
-      })
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-
-    return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkNewInstanceFollower (base: CheckerBaseParams, followerHost: string, type: CheckerType) {
-  const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkActor(notification.actorFollow.follower)
-      expect(notification.actorFollow.follower.name).to.equal('peertube')
-      expect(notification.actorFollow.follower.host).to.equal(followerHost)
-
-      expect(notification.actorFollow.following.name).to.equal('peertube')
-    } else {
-      expect(notification).to.satisfy(n => {
-        return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
-      })
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-
-    return text.includes('instance has a new follower') && text.includes(followerHost)
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkCommentMention (
-  base: CheckerBaseParams,
-  uuid: string,
-  commentId: number,
-  threadId: number,
-  byAccountDisplayName: string,
-  type: CheckerType
-) {
-  const notificationType = UserNotificationType.COMMENT_MENTION
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkComment(notification.comment, commentId, threadId)
-      checkActor(notification.comment.account)
-      expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
-
-      checkVideo(notification.comment.video, undefined, uuid)
-    } else {
-      expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text: string = email[ 'text' ]
-
-    return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-let lastEmailCount = 0
-async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
-  const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      checkComment(notification.comment, commentId, threadId)
-      checkActor(notification.comment.account)
-      checkVideo(notification.comment.video, undefined, uuid)
-    } else {
-      expect(notification).to.satisfy((n: UserNotification) => {
-        return n === undefined || n.comment === undefined || n.comment.id !== commentId
-      })
-    }
-  }
-
-  const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
-  function emailFinder (email: object) {
-    return email[ 'text' ].indexOf(commentUrl) !== -1
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-
-  if (type === 'presence') {
-    // We cannot detect email duplicates, so check we received another email
-    expect(base.emails).to.have.length.above(lastEmailCount)
-    lastEmailCount = base.emails.length
-  }
-}
-
-async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
-  const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      expect(notification.videoAbuse.id).to.be.a('number')
-      checkVideo(notification.videoAbuse.video, videoName, videoUUID)
-    } else {
-      expect(notification).to.satisfy((n: UserNotification) => {
-        return n === undefined || n.videoAbuse === undefined || n.videoAbuse.video.uuid !== videoUUID
-      })
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text = email[ 'text' ]
-    return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
-  const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
-
-  function notificationChecker (notification: UserNotification, type: CheckerType) {
-    if (type === 'presence') {
-      expect(notification).to.not.be.undefined
-      expect(notification.type).to.equal(notificationType)
-
-      expect(notification.video.id).to.be.a('number')
-      checkVideo(notification.video, videoName, videoUUID)
-    } else {
-      expect(notification).to.satisfy((n: UserNotification) => {
-        return n === undefined || n.video === undefined || n.video.uuid !== videoUUID
-      })
-    }
-  }
-
-  function emailFinder (email: object) {
-    const text = email[ 'text' ]
-    return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, type)
-}
-
-async function checkNewBlacklistOnMyVideo (
-  base: CheckerBaseParams,
-  videoUUID: string,
-  videoName: string,
-  blacklistType: 'blacklist' | 'unblacklist'
-) {
-  const notificationType = blacklistType === 'blacklist'
-    ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
-    : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
-
-  function notificationChecker (notification: UserNotification) {
-    expect(notification).to.not.be.undefined
-    expect(notification.type).to.equal(notificationType)
-
-    const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
-
-    checkVideo(video, videoName, videoUUID)
-  }
-
-  function emailFinder (email: object) {
-    const text = email[ 'text' ]
-    return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
-  }
-
-  await checkNotification(base, notificationChecker, emailFinder, 'presence')
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  CheckerBaseParams,
-  CheckerType,
-  checkNotification,
-  markAsReadAllNotifications,
-  checkMyVideoImportIsFinished,
-  checkUserRegistered,
-  checkVideoIsPublished,
-  checkNewVideoFromSubscription,
-  checkNewActorFollow,
-  checkNewCommentOnMyVideo,
-  checkNewBlacklistOnMyVideo,
-  checkCommentMention,
-  updateMyNotificationSettings,
-  checkNewVideoAbuseForModerators,
-  checkVideoAutoBlacklistForModerators,
-  getUserNotifications,
-  markAsReadNotifications,
-  getLastNotification,
-  checkNewInstanceFollower
-}
diff --git a/shared/utils/users/user-subscriptions.ts b/shared/utils/users/user-subscriptions.ts
deleted file mode 100644 (file)
index 7148fbf..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-import { makeDeleteRequest, makeGetRequest, makePostBodyRequest } from '../requests/requests'
-
-function addUserSubscription (url: string, token: string, targetUri: string, statusCodeExpected = 204) {
-  const path = '/api/v1/users/me/subscriptions'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected,
-    fields: { uri: targetUri }
-  })
-}
-
-function listUserSubscriptions (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
-  const path = '/api/v1/users/me/subscriptions'
-
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected,
-    query: { sort }
-  })
-}
-
-function listUserSubscriptionVideos (url: string, token: string, sort = '-createdAt', statusCodeExpected = 200) {
-  const path = '/api/v1/users/me/subscriptions/videos'
-
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected,
-    query: { sort }
-  })
-}
-
-function getUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 200) {
-  const path = '/api/v1/users/me/subscriptions/' + uri
-
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-function removeUserSubscription (url: string, token: string, uri: string, statusCodeExpected = 204) {
-  const path = '/api/v1/users/me/subscriptions/' + uri
-
-  return makeDeleteRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-function areSubscriptionsExist (url: string, token: string, uris: string[], statusCodeExpected = 200) {
-  const path = '/api/v1/users/me/subscriptions/exist'
-
-  return makeGetRequest({
-    url,
-    path,
-    query: { 'uris[]': uris },
-    token,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  areSubscriptionsExist,
-  addUserSubscription,
-  listUserSubscriptions,
-  getUserSubscription,
-  listUserSubscriptionVideos,
-  removeUserSubscription
-}
diff --git a/shared/utils/users/users.ts b/shared/utils/users/users.ts
deleted file mode 100644 (file)
index 2bd37b8..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-import * as request from 'supertest'
-import { makePostBodyRequest, makePutBodyRequest, updateAvatarRequest } from '../requests/requests'
-
-import { UserRole } from '../../index'
-import { NSFWPolicyType } from '../../models/videos/nsfw-policy.type'
-import { ServerInfo, userLogin } from '..'
-import { UserAdminFlag } from '../../models/users/user-flag.model'
-
-type CreateUserArgs = { url: string,
-  accessToken: string,
-  username: string,
-  password: string,
-  videoQuota?: number,
-  videoQuotaDaily?: number,
-  role?: UserRole,
-  adminFlags?: UserAdminFlag,
-  specialStatus?: number
-}
-function createUser (parameters: CreateUserArgs) {
-  const {
-    url,
-    accessToken,
-    username,
-    adminFlags,
-    password = 'password',
-    videoQuota = 1000000,
-    videoQuotaDaily = -1,
-    role = UserRole.USER,
-    specialStatus = 200
-  } = parameters
-
-  const path = '/api/v1/users'
-  const body = {
-    username,
-    password,
-    role,
-    adminFlags,
-    email: username + '@example.com',
-    videoQuota,
-    videoQuotaDaily
-  }
-
-  return request(url)
-          .post(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .send(body)
-          .expect(specialStatus)
-}
-
-async function generateUserAccessToken (server: ServerInfo, username: string) {
-  const password = 'my super password'
-  await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
-
-  return userLogin(server, { username, password })
-}
-
-function registerUser (url: string, username: string, password: string, specialStatus = 204) {
-  const path = '/api/v1/users/register'
-  const body = {
-    username,
-    password,
-    email: username + '@example.com'
-  }
-
-  return request(url)
-          .post(path)
-          .set('Accept', 'application/json')
-          .send(body)
-          .expect(specialStatus)
-}
-
-function getMyUserInformation (url: string, accessToken: string, specialStatus = 200) {
-  const path = '/api/v1/users/me'
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(specialStatus)
-          .expect('Content-Type', /json/)
-}
-
-function deleteMe (url: string, accessToken: string, specialStatus = 204) {
-  const path = '/api/v1/users/me'
-
-  return request(url)
-    .delete(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(specialStatus)
-}
-
-function getMyUserVideoQuotaUsed (url: string, accessToken: string, specialStatus = 200) {
-  const path = '/api/v1/users/me/video-quota-used'
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(specialStatus)
-          .expect('Content-Type', /json/)
-}
-
-function getUserInformation (url: string, accessToken: string, userId: number) {
-  const path = '/api/v1/users/' + userId
-
-  return request(url)
-    .get(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getMyUserVideoRating (url: string, accessToken: string, videoId: number | string, specialStatus = 200) {
-  const path = '/api/v1/users/me/videos/' + videoId + '/rating'
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(specialStatus)
-          .expect('Content-Type', /json/)
-}
-
-function getUsersList (url: string, accessToken: string) {
-  const path = '/api/v1/users'
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function getUsersListPaginationAndSort (url: string, accessToken: string, start: number, count: number, sort: string, search?: string) {
-  const path = '/api/v1/users'
-
-  return request(url)
-          .get(path)
-          .query({ start })
-          .query({ count })
-          .query({ sort })
-          .query({ search })
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function removeUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
-  const path = '/api/v1/users'
-
-  return request(url)
-          .delete(path + '/' + userId)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .expect(expectedStatus)
-}
-
-function blockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204, reason?: string) {
-  const path = '/api/v1/users'
-  let body: any
-  if (reason) body = { reason }
-
-  return request(url)
-    .post(path + '/' + userId + '/block')
-    .send(body)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(expectedStatus)
-}
-
-function unblockUser (url: string, userId: number | string, accessToken: string, expectedStatus = 204) {
-  const path = '/api/v1/users'
-
-  return request(url)
-    .post(path + '/' + userId + '/unblock')
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(expectedStatus)
-}
-
-function updateMyUser (options: {
-  url: string
-  accessToken: string
-  currentPassword?: string
-  newPassword?: string
-  nsfwPolicy?: NSFWPolicyType
-  email?: string
-  autoPlayVideo?: boolean
-  displayName?: string
-  description?: string
-  videosHistoryEnabled?: boolean
-}) {
-  const path = '/api/v1/users/me'
-
-  const toSend = {}
-  if (options.currentPassword !== undefined && options.currentPassword !== null) toSend['currentPassword'] = options.currentPassword
-  if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword
-  if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend['nsfwPolicy'] = options.nsfwPolicy
-  if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo
-  if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
-  if (options.description !== undefined && options.description !== null) toSend['description'] = options.description
-  if (options.displayName !== undefined && options.displayName !== null) toSend['displayName'] = options.displayName
-  if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) {
-    toSend['videosHistoryEnabled'] = options.videosHistoryEnabled
-  }
-
-  return makePutBodyRequest({
-    url: options.url,
-    path,
-    token: options.accessToken,
-    fields: toSend,
-    statusCodeExpected: 204
-  })
-}
-
-function updateMyAvatar (options: {
-  url: string,
-  accessToken: string,
-  fixture: string
-}) {
-  const path = '/api/v1/users/me/avatar/pick'
-
-  return updateAvatarRequest(Object.assign(options, { path }))
-}
-
-function updateUser (options: {
-  url: string
-  userId: number,
-  accessToken: string,
-  email?: string,
-  emailVerified?: boolean,
-  videoQuota?: number,
-  videoQuotaDaily?: number,
-  password?: string,
-  adminFlags?: UserAdminFlag,
-  role?: UserRole
-}) {
-  const path = '/api/v1/users/' + options.userId
-
-  const toSend = {}
-  if (options.password !== undefined && options.password !== null) toSend['password'] = options.password
-  if (options.email !== undefined && options.email !== null) toSend['email'] = options.email
-  if (options.emailVerified !== undefined && options.emailVerified !== null) toSend['emailVerified'] = options.emailVerified
-  if (options.videoQuota !== undefined && options.videoQuota !== null) toSend['videoQuota'] = options.videoQuota
-  if (options.videoQuotaDaily !== undefined && options.videoQuotaDaily !== null) toSend['videoQuotaDaily'] = options.videoQuotaDaily
-  if (options.role !== undefined && options.role !== null) toSend['role'] = options.role
-  if (options.adminFlags !== undefined && options.adminFlags !== null) toSend['adminFlags'] = options.adminFlags
-
-  return makePutBodyRequest({
-    url: options.url,
-    path,
-    token: options.accessToken,
-    fields: toSend,
-    statusCodeExpected: 204
-  })
-}
-
-function askResetPassword (url: string, email: string) {
-  const path = '/api/v1/users/ask-reset-password'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    fields: { email },
-    statusCodeExpected: 204
-  })
-}
-
-function resetPassword (url: string, userId: number, verificationString: string, password: string, statusCodeExpected = 204) {
-  const path = '/api/v1/users/' + userId + '/reset-password'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    fields: { password, verificationString },
-    statusCodeExpected
-  })
-}
-
-function askSendVerifyEmail (url: string, email: string) {
-  const path = '/api/v1/users/ask-send-verify-email'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    fields: { email },
-    statusCodeExpected: 204
-  })
-}
-
-function verifyEmail (url: string, userId: number, verificationString: string, statusCodeExpected = 204) {
-  const path = '/api/v1/users/' + userId + '/verify-email'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    fields: { verificationString },
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  createUser,
-  registerUser,
-  getMyUserInformation,
-  getMyUserVideoRating,
-  deleteMe,
-  getMyUserVideoQuotaUsed,
-  getUsersList,
-  getUsersListPaginationAndSort,
-  removeUser,
-  updateUser,
-  updateMyUser,
-  getUserInformation,
-  blockUser,
-  unblockUser,
-  askResetPassword,
-  resetPassword,
-  updateMyAvatar,
-  askSendVerifyEmail,
-  generateUserAccessToken,
-  verifyEmail
-}
diff --git a/shared/utils/videos/services.ts b/shared/utils/videos/services.ts
deleted file mode 100644 (file)
index 1a53dd4..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import * as request from 'supertest'
-
-function getOEmbed (url: string, oembedUrl: string, format?: string, maxHeight?: number, maxWidth?: number) {
-  const path = '/services/oembed'
-  const query = {
-    url: oembedUrl,
-    format,
-    maxheight: maxHeight,
-    maxwidth: maxWidth
-  }
-
-  return request(url)
-          .get(path)
-          .query(query)
-          .set('Accept', 'application/json')
-          .expect(200)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getOEmbed
-}
diff --git a/shared/utils/videos/video-abuses.ts b/shared/utils/videos/video-abuses.ts
deleted file mode 100644 (file)
index 7f011ec..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-import * as request from 'supertest'
-import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model'
-import { makeDeleteRequest, makePutBodyRequest } from '../requests/requests'
-
-function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) {
-  const path = '/api/v1/videos/' + videoId + '/abuse'
-
-  return request(url)
-          .post(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + token)
-          .send({ reason })
-          .expect(specialStatus)
-}
-
-function getVideoAbusesList (url: string, token: string) {
-  const path = '/api/v1/videos/abuse'
-
-  return request(url)
-          .get(path)
-          .query({ sort: 'createdAt' })
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + token)
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function updateVideoAbuse (
-  url: string,
-  token: string,
-  videoId: string | number,
-  videoAbuseId: number,
-  body: VideoAbuseUpdate,
-  statusCodeExpected = 204
-) {
-  const path = '/api/v1/videos/' + videoId + '/abuse/' + videoAbuseId
-
-  return makePutBodyRequest({
-    url,
-    token,
-    path,
-    fields: body,
-    statusCodeExpected
-  })
-}
-
-function deleteVideoAbuse (url: string, token: string, videoId: string | number, videoAbuseId: number, statusCodeExpected = 204) {
-  const path = '/api/v1/videos/' + videoId + '/abuse/' + videoAbuseId
-
-  return makeDeleteRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  reportVideoAbuse,
-  getVideoAbusesList,
-  updateVideoAbuse,
-  deleteVideoAbuse
-}
diff --git a/shared/utils/videos/video-blacklist.ts b/shared/utils/videos/video-blacklist.ts
deleted file mode 100644 (file)
index e25a292..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-import * as request from 'supertest'
-import { VideoBlacklistType } from '../../models/videos'
-import { makeGetRequest } from '..'
-
-function addVideoToBlacklist (
-  url: string,
-  token: string,
-  videoId: number | string,
-  reason?: string,
-  unfederate?: boolean,
-  specialStatus = 204
-) {
-  const path = '/api/v1/videos/' + videoId + '/blacklist'
-
-  return request(url)
-          .post(path)
-          .send({ reason, unfederate })
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + token)
-          .expect(specialStatus)
-}
-
-function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
-  const path = '/api/v1/videos/' + videoId + '/blacklist'
-
-  return request(url)
-    .put(path)
-    .send({ reason })
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(specialStatus)
-}
-
-function removeVideoFromBlacklist (url: string, token: string, videoId: number | string, specialStatus = 204) {
-  const path = '/api/v1/videos/' + videoId + '/blacklist'
-
-  return request(url)
-          .delete(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + token)
-          .expect(specialStatus)
-}
-
-function getBlacklistedVideosList (parameters: {
-  url: string,
-  token: string,
-  sort?: string,
-  type?: VideoBlacklistType,
-  specialStatus?: number
-}) {
-  let { url, token, sort, type, specialStatus = 200 } = parameters
-  const path = '/api/v1/videos/blacklist/'
-
-  const query = { sort, type }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    token,
-    statusCodeExpected: specialStatus
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  addVideoToBlacklist,
-  removeVideoFromBlacklist,
-  getBlacklistedVideosList,
-  updateVideoBlacklist
-}
diff --git a/shared/utils/videos/video-captions.ts b/shared/utils/videos/video-captions.ts
deleted file mode 100644 (file)
index 8d67f61..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-import { makeDeleteRequest, makeGetRequest, makeUploadRequest } from '../requests/requests'
-import * as request from 'supertest'
-import * as chai from 'chai'
-import { buildAbsoluteFixturePath } from '../miscs/miscs'
-
-const expect = chai.expect
-
-function createVideoCaption (args: {
-  url: string,
-  accessToken: string
-  videoId: string | number
-  language: string
-  fixture: string,
-  mimeType?: string,
-  statusCodeExpected?: number
-}) {
-  const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
-
-  const captionfile = buildAbsoluteFixturePath(args.fixture)
-  const captionfileAttach = args.mimeType ? [ captionfile, { contentType: args.mimeType } ] : captionfile
-
-  return makeUploadRequest({
-    method: 'PUT',
-    url: args.url,
-    path,
-    token: args.accessToken,
-    fields: {},
-    attaches: {
-      captionfile: captionfileAttach
-    },
-    statusCodeExpected: args.statusCodeExpected || 204
-  })
-}
-
-function listVideoCaptions (url: string, videoId: string | number) {
-  const path = '/api/v1/videos/' + videoId + '/captions'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function deleteVideoCaption (url: string, token: string, videoId: string | number, language: string) {
-  const path = '/api/v1/videos/' + videoId + '/captions/' + language
-
-  return makeDeleteRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected: 204
-  })
-}
-
-async function testCaptionFile (url: string, captionPath: string, containsString: string) {
-  const res = await request(url)
-    .get(captionPath)
-    .expect(200)
-
-  expect(res.text).to.contain(containsString)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  createVideoCaption,
-  listVideoCaptions,
-  testCaptionFile,
-  deleteVideoCaption
-}
diff --git a/shared/utils/videos/video-change-ownership.ts b/shared/utils/videos/video-change-ownership.ts
deleted file mode 100644 (file)
index 371d020..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import * as request from 'supertest'
-
-function changeVideoOwnership (url: string, token: string, videoId: number | string, username, expectedStatus = 204) {
-  const path = '/api/v1/videos/' + videoId + '/give-ownership'
-
-  return request(url)
-    .post(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .send({ username })
-    .expect(expectedStatus)
-}
-
-function getVideoChangeOwnershipList (url: string, token: string) {
-  const path = '/api/v1/videos/ownership'
-
-  return request(url)
-    .get(path)
-    .query({ sort: '-createdAt' })
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function acceptChangeOwnership (url: string, token: string, ownershipId: string, channelId: number, expectedStatus = 204) {
-  const path = '/api/v1/videos/ownership/' + ownershipId + '/accept'
-
-  return request(url)
-    .post(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .send({ channelId })
-    .expect(expectedStatus)
-}
-
-function refuseChangeOwnership (url: string, token: string, ownershipId: string, expectedStatus = 204) {
-  const path = '/api/v1/videos/ownership/' + ownershipId + '/refuse'
-
-  return request(url)
-    .post(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  changeVideoOwnership,
-  getVideoChangeOwnershipList,
-  acceptChangeOwnership,
-  refuseChangeOwnership
-}
diff --git a/shared/utils/videos/video-channels.ts b/shared/utils/videos/video-channels.ts
deleted file mode 100644 (file)
index 93a257b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-import * as request from 'supertest'
-import { VideoChannelCreate, VideoChannelUpdate } from '../../models/videos'
-import { updateAvatarRequest } from '../requests/requests'
-import { getMyUserInformation, ServerInfo } from '..'
-import { User } from '../..'
-
-function getVideoChannelsList (url: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/video-channels'
-
-  const req = request(url)
-    .get(path)
-    .query({ start: start })
-    .query({ count: count })
-
-  if (sort) req.query({ sort })
-
-  return req.set('Accept', 'application/json')
-            .expect(200)
-            .expect('Content-Type', /json/)
-}
-
-function getAccountVideoChannelsList (url: string, accountName: string, specialStatus = 200) {
-  const path = '/api/v1/accounts/' + accountName + '/video-channels'
-
-  return request(url)
-    .get(path)
-    .set('Accept', 'application/json')
-    .expect(specialStatus)
-    .expect('Content-Type', /json/)
-}
-
-function addVideoChannel (
-  url: string,
-  token: string,
-  videoChannelAttributesArg: VideoChannelCreate,
-  expectedStatus = 200
-) {
-  const path = '/api/v1/video-channels/'
-
-  // Default attributes
-  let attributes = {
-    displayName: 'my super video channel',
-    description: 'my super channel description',
-    support: 'my super channel support'
-  }
-  attributes = Object.assign(attributes, videoChannelAttributesArg)
-
-  return request(url)
-    .post(path)
-    .send(attributes)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-function updateVideoChannel (
-  url: string,
-  token: string,
-  channelName: string,
-  attributes: VideoChannelUpdate,
-  expectedStatus = 204
-) {
-  const body = {}
-  const path = '/api/v1/video-channels/' + channelName
-
-  if (attributes.displayName) body['displayName'] = attributes.displayName
-  if (attributes.description) body['description'] = attributes.description
-  if (attributes.support) body['support'] = attributes.support
-
-  return request(url)
-    .put(path)
-    .send(body)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-function deleteVideoChannel (url: string, token: string, channelName: string, expectedStatus = 204) {
-  const path = '/api/v1/video-channels/' + channelName
-
-  return request(url)
-    .delete(path)
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-function getVideoChannel (url: string, channelName: string) {
-  const path = '/api/v1/video-channels/' + channelName
-
-  return request(url)
-    .get(path)
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function updateVideoChannelAvatar (options: {
-  url: string,
-  accessToken: string,
-  fixture: string,
-  videoChannelName: string | number
-}) {
-
-  const path = '/api/v1/video-channels/' + options.videoChannelName + '/avatar/pick'
-
-  return updateAvatarRequest(Object.assign(options, { path }))
-}
-
-function setDefaultVideoChannel (servers: ServerInfo[]) {
-  const tasks: Promise<any>[] = []
-
-  for (const server of servers) {
-    const p = getMyUserInformation(server.url, server.accessToken)
-      .then(res => server.videoChannel = (res.body as User).videoChannels[0])
-
-    tasks.push(p)
-  }
-
-  return Promise.all(tasks)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  updateVideoChannelAvatar,
-  getVideoChannelsList,
-  getAccountVideoChannelsList,
-  addVideoChannel,
-  updateVideoChannel,
-  deleteVideoChannel,
-  getVideoChannel,
-  setDefaultVideoChannel
-}
diff --git a/shared/utils/videos/video-comments.ts b/shared/utils/videos/video-comments.ts
deleted file mode 100644 (file)
index 0ebf69c..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-import * as request from 'supertest'
-import { makeDeleteRequest } from '../requests/requests'
-
-function getVideoCommentThreads (url: string, videoId: number | string, start: number, count: number, sort?: string, token?: string) {
-  const path = '/api/v1/videos/' + videoId + '/comment-threads'
-
-  const req = request(url)
-    .get(path)
-    .query({ start: start })
-    .query({ count: count })
-
-  if (sort) req.query({ sort })
-  if (token) req.set('Authorization', 'Bearer ' + token)
-
-  return req.set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getVideoThreadComments (url: string, videoId: number | string, threadId: number, token?: string) {
-  const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId
-
-  const req = request(url)
-    .get(path)
-    .set('Accept', 'application/json')
-
-  if (token) req.set('Authorization', 'Bearer ' + token)
-
-  return req.expect(200)
-            .expect('Content-Type', /json/)
-}
-
-function addVideoCommentThread (url: string, token: string, videoId: number | string, text: string, expectedStatus = 200) {
-  const path = '/api/v1/videos/' + videoId + '/comment-threads'
-
-  return request(url)
-    .post(path)
-    .send({ text })
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-function addVideoCommentReply (
-  url: string,
-  token: string,
-  videoId: number | string,
-  inReplyToCommentId: number,
-  text: string,
-  expectedStatus = 200
-) {
-  const path = '/api/v1/videos/' + videoId + '/comments/' + inReplyToCommentId
-
-  return request(url)
-    .post(path)
-    .send({ text })
-    .set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + token)
-    .expect(expectedStatus)
-}
-
-function deleteVideoComment (
-  url: string,
-  token: string,
-  videoId: number | string,
-  commentId: number,
-  statusCodeExpected = 204
-) {
-  const path = '/api/v1/videos/' + videoId + '/comments/' + commentId
-
-  return makeDeleteRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getVideoCommentThreads,
-  getVideoThreadComments,
-  addVideoCommentThread,
-  addVideoCommentReply,
-  deleteVideoComment
-}
diff --git a/shared/utils/videos/video-history.ts b/shared/utils/videos/video-history.ts
deleted file mode 100644 (file)
index dc7095b..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
-
-function userWatchVideo (url: string, token: string, videoId: number | string, currentTime: number, statusCodeExpected = 204) {
-  const path = '/api/v1/videos/' + videoId + '/watching'
-  const fields = { currentTime }
-
-  return makePutBodyRequest({ url, path, token, fields, statusCodeExpected })
-}
-
-function listMyVideosHistory (url: string, token: string) {
-  const path = '/api/v1/users/me/history/videos'
-
-  return makeGetRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected: 200
-  })
-}
-
-function removeMyVideosHistory (url: string, token: string, beforeDate?: string) {
-  const path = '/api/v1/users/me/history/videos/remove'
-
-  return makePostBodyRequest({
-    url,
-    path,
-    token,
-    fields: beforeDate ? { beforeDate } : {},
-    statusCodeExpected: 204
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  userWatchVideo,
-  listMyVideosHistory,
-  removeMyVideosHistory
-}
diff --git a/shared/utils/videos/video-imports.ts b/shared/utils/videos/video-imports.ts
deleted file mode 100644 (file)
index ec77cdc..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-
-import { VideoImportCreate } from '../../models/videos'
-import { makeGetRequest, makeUploadRequest } from '../requests/requests'
-
-function getYoutubeVideoUrl () {
-  return 'https://youtu.be/msX3jv1XdvM'
-}
-
-function getMagnetURI () {
-  // tslint:disable:max-line-length
-  return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
-}
-
-function getBadVideoUrl () {
-  return 'https://download.cpy.re/peertube/bad_video.mp4'
-}
-
-function importVideo (url: string, token: string, attributes: VideoImportCreate) {
-  const path = '/api/v1/videos/imports'
-
-  let attaches: any = {}
-  if (attributes.torrentfile) attaches = { torrentfile: attributes.torrentfile }
-
-  return makeUploadRequest({
-    url,
-    path,
-    token,
-    attaches,
-    fields: attributes,
-    statusCodeExpected: 200
-  })
-}
-
-function getMyVideoImports (url: string, token: string, sort?: string) {
-  const path = '/api/v1/users/me/videos/imports'
-
-  const query = {}
-  if (sort) query['sort'] = sort
-
-  return makeGetRequest({
-    url,
-    query,
-    path,
-    token,
-    statusCodeExpected: 200
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getBadVideoUrl,
-  getYoutubeVideoUrl,
-  importVideo,
-  getMagnetURI,
-  getMyVideoImports
-}
diff --git a/shared/utils/videos/video-playlists.ts b/shared/utils/videos/video-playlists.ts
deleted file mode 100644 (file)
index 4d110a1..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests'
-import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model'
-import { omit } from 'lodash'
-import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model'
-import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model'
-import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model'
-import { videoUUIDToId } from './videos'
-import { join } from 'path'
-import { root } from '..'
-import { readdir } from 'fs-extra'
-import { expect } from 'chai'
-import { VideoPlaylistType } from '../../models/videos/playlist/video-playlist-type.model'
-
-function getVideoPlaylistsList (url: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/video-playlists'
-
-  const query = {
-    start,
-    count,
-    sort
-  }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoChannelPlaylistsList (url: string, videoChannelName: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/video-channels/' + videoChannelName + '/video-playlists'
-
-  const query = {
-    start,
-    count,
-    sort
-  }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-function getAccountPlaylistsList (url: string, accountName: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/accounts/' + accountName + '/video-playlists'
-
-  const query = {
-    start,
-    count,
-    sort
-  }
-
-  return makeGetRequest({
-    url,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-function getAccountPlaylistsListWithToken (
-  url: string,
-  token: string,
-  accountName: string,
-  start: number,
-  count: number,
-  playlistType?: VideoPlaylistType,
-  sort?: string
-) {
-  const path = '/api/v1/accounts/' + accountName + '/video-playlists'
-
-  const query = {
-    start,
-    count,
-    playlistType,
-    sort
-  }
-
-  return makeGetRequest({
-    url,
-    token,
-    path,
-    query,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoPlaylist (url: string, playlistId: number | string, statusCodeExpected = 200) {
-  const path = '/api/v1/video-playlists/' + playlistId
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected
-  })
-}
-
-function getVideoPlaylistWithToken (url: string, token: string, playlistId: number | string, statusCodeExpected = 200) {
-  const path = '/api/v1/video-playlists/' + playlistId
-
-  return makeGetRequest({
-    url,
-    token,
-    path,
-    statusCodeExpected
-  })
-}
-
-function deleteVideoPlaylist (url: string, token: string, playlistId: number | string, statusCodeExpected = 204) {
-  const path = '/api/v1/video-playlists/' + playlistId
-
-  return makeDeleteRequest({
-    url,
-    path,
-    token,
-    statusCodeExpected
-  })
-}
-
-function createVideoPlaylist (options: {
-  url: string,
-  token: string,
-  playlistAttrs: VideoPlaylistCreate,
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/video-playlists'
-
-  const fields = omit(options.playlistAttrs, 'thumbnailfile')
-
-  const attaches = options.playlistAttrs.thumbnailfile
-    ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
-    : {}
-
-  return makeUploadRequest({
-    method: 'POST',
-    url: options.url,
-    path,
-    token: options.token,
-    fields,
-    attaches,
-    statusCodeExpected: options.expectedStatus || 200
-  })
-}
-
-function updateVideoPlaylist (options: {
-  url: string,
-  token: string,
-  playlistAttrs: VideoPlaylistUpdate,
-  playlistId: number | string,
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/video-playlists/' + options.playlistId
-
-  const fields = omit(options.playlistAttrs, 'thumbnailfile')
-
-  const attaches = options.playlistAttrs.thumbnailfile
-    ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
-    : {}
-
-  return makeUploadRequest({
-    method: 'PUT',
-    url: options.url,
-    path,
-    token: options.token,
-    fields,
-    attaches,
-    statusCodeExpected: options.expectedStatus || 204
-  })
-}
-
-async function addVideoInPlaylist (options: {
-  url: string,
-  token: string,
-  playlistId: number | string,
-  elementAttrs: VideoPlaylistElementCreate | { videoId: string }
-  expectedStatus?: number
-}) {
-  options.elementAttrs.videoId = await videoUUIDToId(options.url, options.elementAttrs.videoId)
-
-  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos'
-
-  return makePostBodyRequest({
-    url: options.url,
-    path,
-    token: options.token,
-    fields: options.elementAttrs,
-    statusCodeExpected: options.expectedStatus || 200
-  })
-}
-
-function updateVideoPlaylistElement (options: {
-  url: string,
-  token: string,
-  playlistId: number | string,
-  videoId: number | string,
-  elementAttrs: VideoPlaylistElementUpdate,
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
-
-  return makePutBodyRequest({
-    url: options.url,
-    path,
-    token: options.token,
-    fields: options.elementAttrs,
-    statusCodeExpected: options.expectedStatus || 204
-  })
-}
-
-function removeVideoFromPlaylist (options: {
-  url: string,
-  token: string,
-  playlistId: number | string,
-  videoId: number | string,
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
-
-  return makeDeleteRequest({
-    url: options.url,
-    path,
-    token: options.token,
-    statusCodeExpected: options.expectedStatus || 204
-  })
-}
-
-function reorderVideosPlaylist (options: {
-  url: string,
-  token: string,
-  playlistId: number | string,
-  elementAttrs: {
-    startPosition: number,
-    insertAfterPosition: number,
-    reorderLength?: number
-  },
-  expectedStatus?: number
-}) {
-  const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
-
-  return makePostBodyRequest({
-    url: options.url,
-    path,
-    token: options.token,
-    fields: options.elementAttrs,
-    statusCodeExpected: options.expectedStatus || 204
-  })
-}
-
-async function checkPlaylistFilesWereRemoved (
-  playlistUUID: string,
-  serverNumber: number,
-  directories = [ 'thumbnails' ]
-) {
-  const testDirectory = 'test' + serverNumber
-
-  for (const directory of directories) {
-    const directoryPath = join(root(), testDirectory, directory)
-
-    const files = await readdir(directoryPath)
-    for (const file of files) {
-      expect(file).to.not.contain(playlistUUID)
-    }
-  }
-}
-
-function getVideoPlaylistPrivacies (url: string) {
-  const path = '/api/v1/video-playlists/privacies'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function doVideosExistInMyPlaylist (url: string, token: string, videoIds: number[]) {
-  const path = '/api/v1/users/me/video-playlists/videos-exist'
-
-  return makeGetRequest({
-    url,
-    token,
-    path,
-    query: { videoIds },
-    statusCodeExpected: 200
-  })
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getVideoPlaylistPrivacies,
-
-  getVideoPlaylistsList,
-  getVideoChannelPlaylistsList,
-  getAccountPlaylistsList,
-  getAccountPlaylistsListWithToken,
-
-  getVideoPlaylist,
-  getVideoPlaylistWithToken,
-
-  createVideoPlaylist,
-  updateVideoPlaylist,
-  deleteVideoPlaylist,
-
-  addVideoInPlaylist,
-  updateVideoPlaylistElement,
-  removeVideoFromPlaylist,
-
-  reorderVideosPlaylist,
-
-  checkPlaylistFilesWereRemoved,
-
-  doVideosExistInMyPlaylist
-}
diff --git a/shared/utils/videos/video-streaming-playlists.ts b/shared/utils/videos/video-streaming-playlists.ts
deleted file mode 100644 (file)
index eb25011..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-import { makeRawRequest } from '../requests/requests'
-import { sha256 } from '../../../server/helpers/core-utils'
-import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model'
-import { expect } from 'chai'
-
-function getPlaylist (url: string, statusCodeExpected = 200) {
-  return makeRawRequest(url, statusCodeExpected)
-}
-
-function getSegment (url: string, statusCodeExpected = 200, range?: string) {
-  return makeRawRequest(url, statusCodeExpected, range)
-}
-
-function getSegmentSha256 (url: string, statusCodeExpected = 200) {
-  return makeRawRequest(url, statusCodeExpected)
-}
-
-async function checkSegmentHash (
-  baseUrlPlaylist: string,
-  baseUrlSegment: string,
-  videoUUID: string,
-  resolution: number,
-  hlsPlaylist: VideoStreamingPlaylist
-) {
-  const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`)
-  const playlist = res.text
-
-  const videoName = `${videoUUID}-${resolution}-fragmented.mp4`
-
-  const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
-
-  const length = parseInt(matches[1], 10)
-  const offset = parseInt(matches[2], 10)
-  const range = `${offset}-${offset + length - 1}`
-
-  const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, 206, `bytes=${range}`)
-
-  const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
-
-  const sha256Server = resSha.body[ videoName ][range]
-  expect(sha256(res2.body)).to.equal(sha256Server)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getPlaylist,
-  getSegment,
-  getSegmentSha256,
-  checkSegmentHash
-}
diff --git a/shared/utils/videos/videos.ts b/shared/utils/videos/videos.ts
deleted file mode 100644 (file)
index b5a07b7..0000000
+++ /dev/null
@@ -1,648 +0,0 @@
-/* tslint:disable:no-unused-expression */
-
-import { expect } from 'chai'
-import { pathExists, readdir, readFile } from 'fs-extra'
-import * as parseTorrent from 'parse-torrent'
-import { extname, join } from 'path'
-import * as request from 'supertest'
-import {
-  buildAbsoluteFixturePath,
-  getMyUserInformation,
-  immutableAssign,
-  makeGetRequest,
-  makePutBodyRequest,
-  makeUploadRequest,
-  root,
-  ServerInfo,
-  testImage
-} from '../'
-import * as validator from 'validator'
-import { VideoDetails, VideoPrivacy } from '../../models/videos'
-import { VIDEO_CATEGORIES, VIDEO_LANGUAGES, loadLanguages, VIDEO_LICENCES, VIDEO_PRIVACIES } from '../../../server/initializers/constants'
-import { dateIsValid, webtorrentAdd } from '../miscs/miscs'
-
-loadLanguages()
-
-type VideoAttributes = {
-  name?: string
-  category?: number
-  licence?: number
-  language?: string
-  nsfw?: boolean
-  commentsEnabled?: boolean
-  downloadEnabled?: boolean
-  waitTranscoding?: boolean
-  description?: string
-  originallyPublishedAt?: string
-  tags?: string[]
-  channelId?: number
-  privacy?: VideoPrivacy
-  fixture?: string
-  thumbnailfile?: string
-  previewfile?: string
-  scheduleUpdate?: {
-    updateAt: string
-    privacy?: VideoPrivacy
-  }
-}
-
-function getVideoCategories (url: string) {
-  const path = '/api/v1/videos/categories'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoLicences (url: string) {
-  const path = '/api/v1/videos/licences'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoLanguages (url: string) {
-  const path = '/api/v1/videos/languages'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoPrivacies (url: string) {
-  const path = '/api/v1/videos/privacies'
-
-  return makeGetRequest({
-    url,
-    path,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideo (url: string, id: number | string, expectedStatus = 200) {
-  const path = '/api/v1/videos/' + id
-
-  return request(url)
-          .get(path)
-          .set('Accept', 'application/json')
-          .expect(expectedStatus)
-}
-
-function viewVideo (url: string, id: number | string, expectedStatus = 204, xForwardedFor?: string) {
-  const path = '/api/v1/videos/' + id + '/views'
-
-  const req = request(url)
-    .post(path)
-    .set('Accept', 'application/json')
-
-  if (xForwardedFor) {
-    req.set('X-Forwarded-For', xForwardedFor)
-  }
-
-  return req.expect(expectedStatus)
-}
-
-function getVideoWithToken (url: string, token: string, id: number | string, expectedStatus = 200) {
-  const path = '/api/v1/videos/' + id
-
-  return request(url)
-    .get(path)
-    .set('Authorization', 'Bearer ' + token)
-    .set('Accept', 'application/json')
-    .expect(expectedStatus)
-}
-
-function getVideoDescription (url: string, descriptionPath: string) {
-  return request(url)
-    .get(descriptionPath)
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getVideosList (url: string) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-          .get(path)
-          .query({ sort: 'name' })
-          .set('Accept', 'application/json')
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function getVideosListWithToken (url: string, token: string, query: { nsfw?: boolean } = {}) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-    .get(path)
-    .set('Authorization', 'Bearer ' + token)
-    .query(immutableAssign(query, { sort: 'name' }))
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getLocalVideos (url: string) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-    .get(path)
-    .query({ sort: 'name', filter: 'local' })
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getMyVideos (url: string, accessToken: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/users/me/videos'
-
-  const req = request(url)
-    .get(path)
-    .query({ start: start })
-    .query({ count: count })
-
-  if (sort) req.query({ sort })
-
-  return req.set('Accept', 'application/json')
-    .set('Authorization', 'Bearer ' + accessToken)
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function getAccountVideos (
-  url: string,
-  accessToken: string,
-  accountName: string,
-  start: number,
-  count: number,
-  sort?: string,
-  query: { nsfw?: boolean } = {}
-) {
-  const path = '/api/v1/accounts/' + accountName + '/videos'
-
-  return makeGetRequest({
-    url,
-    path,
-    query: immutableAssign(query, {
-      start,
-      count,
-      sort
-    }),
-    token: accessToken,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideoChannelVideos (
-  url: string,
-  accessToken: string,
-  videoChannelName: string,
-  start: number,
-  count: number,
-  sort?: string,
-  query: { nsfw?: boolean } = {}
-) {
-  const path = '/api/v1/video-channels/' + videoChannelName + '/videos'
-
-  return makeGetRequest({
-    url,
-    path,
-    query: immutableAssign(query, {
-      start,
-      count,
-      sort
-    }),
-    token: accessToken,
-    statusCodeExpected: 200
-  })
-}
-
-function getPlaylistVideos (
-  url: string,
-  accessToken: string,
-  playlistId: number | string,
-  start: number,
-  count: number,
-  query: { nsfw?: boolean } = {}
-) {
-  const path = '/api/v1/video-playlists/' + playlistId + '/videos'
-
-  return makeGetRequest({
-    url,
-    path,
-    query: immutableAssign(query, {
-      start,
-      count
-    }),
-    token: accessToken,
-    statusCodeExpected: 200
-  })
-}
-
-function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
-  const path = '/api/v1/videos'
-
-  const req = request(url)
-              .get(path)
-              .query({ start: start })
-              .query({ count: count })
-
-  if (sort) req.query({ sort })
-
-  return req.set('Accept', 'application/json')
-           .expect(200)
-           .expect('Content-Type', /json/)
-}
-
-function getVideosListSort (url: string, sort: string) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-          .get(path)
-          .query({ sort: sort })
-          .set('Accept', 'application/json')
-          .expect(200)
-          .expect('Content-Type', /json/)
-}
-
-function getVideosWithFilters (url: string, query: { tagsAllOf: string[], categoryOneOf: number[] | number }) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-    .get(path)
-    .query(query)
-    .set('Accept', 'application/json')
-    .expect(200)
-    .expect('Content-Type', /json/)
-}
-
-function removeVideo (url: string, token: string, id: number | string, expectedStatus = 204) {
-  const path = '/api/v1/videos'
-
-  return request(url)
-          .delete(path + '/' + id)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + token)
-          .expect(expectedStatus)
-}
-
-async function checkVideoFilesWereRemoved (
-  videoUUID: string,
-  serverNumber: number,
-  directories = [
-    'redundancy',
-    'videos',
-    'thumbnails',
-    'torrents',
-    'previews',
-    'captions',
-    join('playlists', 'hls'),
-    join('redundancy', 'hls')
-  ]
-) {
-  const testDirectory = 'test' + serverNumber
-
-  for (const directory of directories) {
-    const directoryPath = join(root(), testDirectory, directory)
-
-    const directoryExists = await pathExists(directoryPath)
-    if (directoryExists === false) continue
-
-    const files = await readdir(directoryPath)
-    for (const file of files) {
-      expect(file).to.not.contain(videoUUID)
-    }
-  }
-}
-
-async function uploadVideo (url: string, accessToken: string, videoAttributesArg: VideoAttributes, specialStatus = 200) {
-  const path = '/api/v1/videos/upload'
-  let defaultChannelId = '1'
-
-  try {
-    const res = await getMyUserInformation(url, accessToken)
-    defaultChannelId = res.body.videoChannels[0].id
-  } catch (e) { /* empty */ }
-
-  // Override default attributes
-  const attributes = Object.assign({
-    name: 'my super video',
-    category: 5,
-    licence: 4,
-    language: 'zh',
-    channelId: defaultChannelId,
-    nsfw: true,
-    waitTranscoding: false,
-    description: 'my super description',
-    support: 'my super support text',
-    tags: [ 'tag' ],
-    privacy: VideoPrivacy.PUBLIC,
-    commentsEnabled: true,
-    downloadEnabled: true,
-    fixture: 'video_short.webm'
-  }, videoAttributesArg)
-
-  const req = request(url)
-              .post(path)
-              .set('Accept', 'application/json')
-              .set('Authorization', 'Bearer ' + accessToken)
-              .field('name', attributes.name)
-              .field('nsfw', JSON.stringify(attributes.nsfw))
-              .field('commentsEnabled', JSON.stringify(attributes.commentsEnabled))
-              .field('downloadEnabled', JSON.stringify(attributes.downloadEnabled))
-              .field('waitTranscoding', JSON.stringify(attributes.waitTranscoding))
-              .field('privacy', attributes.privacy.toString())
-              .field('channelId', attributes.channelId)
-
-  if (attributes.description !== undefined) {
-    req.field('description', attributes.description)
-  }
-  if (attributes.language !== undefined) {
-    req.field('language', attributes.language.toString())
-  }
-  if (attributes.category !== undefined) {
-    req.field('category', attributes.category.toString())
-  }
-  if (attributes.licence !== undefined) {
-    req.field('licence', attributes.licence.toString())
-  }
-
-  for (let i = 0; i < attributes.tags.length; i++) {
-    req.field('tags[' + i + ']', attributes.tags[i])
-  }
-
-  if (attributes.thumbnailfile !== undefined) {
-    req.attach('thumbnailfile', buildAbsoluteFixturePath(attributes.thumbnailfile))
-  }
-  if (attributes.previewfile !== undefined) {
-    req.attach('previewfile', buildAbsoluteFixturePath(attributes.previewfile))
-  }
-
-  if (attributes.scheduleUpdate) {
-    req.field('scheduleUpdate[updateAt]', attributes.scheduleUpdate.updateAt)
-
-    if (attributes.scheduleUpdate.privacy) {
-      req.field('scheduleUpdate[privacy]', attributes.scheduleUpdate.privacy)
-    }
-  }
-
-  if (attributes.originallyPublishedAt !== undefined) {
-    req.field('originallyPublishedAt', attributes.originallyPublishedAt)
-  }
-
-  return req.attach('videofile', buildAbsoluteFixturePath(attributes.fixture))
-            .expect(specialStatus)
-}
-
-function updateVideo (url: string, accessToken: string, id: number | string, attributes: VideoAttributes, statusCodeExpected = 204) {
-  const path = '/api/v1/videos/' + id
-  const body = {}
-
-  if (attributes.name) body['name'] = attributes.name
-  if (attributes.category) body['category'] = attributes.category
-  if (attributes.licence) body['licence'] = attributes.licence
-  if (attributes.language) body['language'] = attributes.language
-  if (attributes.nsfw !== undefined) body['nsfw'] = JSON.stringify(attributes.nsfw)
-  if (attributes.commentsEnabled !== undefined) body['commentsEnabled'] = JSON.stringify(attributes.commentsEnabled)
-  if (attributes.downloadEnabled !== undefined) body['downloadEnabled'] = JSON.stringify(attributes.downloadEnabled)
-  if (attributes.originallyPublishedAt !== undefined) body['originallyPublishedAt'] = attributes.originallyPublishedAt
-  if (attributes.description) body['description'] = attributes.description
-  if (attributes.tags) body['tags'] = attributes.tags
-  if (attributes.privacy) body['privacy'] = attributes.privacy
-  if (attributes.channelId) body['channelId'] = attributes.channelId
-  if (attributes.scheduleUpdate) body['scheduleUpdate'] = attributes.scheduleUpdate
-
-  // Upload request
-  if (attributes.thumbnailfile || attributes.previewfile) {
-    const attaches: any = {}
-    if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile
-    if (attributes.previewfile) attaches.previewfile = attributes.previewfile
-
-    return makeUploadRequest({
-      url,
-      method: 'PUT',
-      path,
-      token: accessToken,
-      fields: body,
-      attaches,
-      statusCodeExpected
-    })
-  }
-
-  return makePutBodyRequest({
-    url,
-    path,
-    fields: body,
-    token: accessToken,
-    statusCodeExpected
-  })
-}
-
-function rateVideo (url: string, accessToken: string, id: number, rating: string, specialStatus = 204) {
-  const path = '/api/v1/videos/' + id + '/rate'
-
-  return request(url)
-          .put(path)
-          .set('Accept', 'application/json')
-          .set('Authorization', 'Bearer ' + accessToken)
-          .send({ rating })
-          .expect(specialStatus)
-}
-
-function parseTorrentVideo (server: ServerInfo, videoUUID: string, resolution: number) {
-  return new Promise<any>((res, rej) => {
-    const torrentName = videoUUID + '-' + resolution + '.torrent'
-    const torrentPath = join(root(), 'test' + server.serverNumber, 'torrents', torrentName)
-    readFile(torrentPath, (err, data) => {
-      if (err) return rej(err)
-
-      return res(parseTorrent(data))
-    })
-  })
-}
-
-async function completeVideoCheck (
-  url: string,
-  video: any,
-  attributes: {
-    name: string
-    category: number
-    licence: number
-    language: string
-    nsfw: boolean
-    commentsEnabled: boolean
-    downloadEnabled: boolean
-    description: string
-    publishedAt?: string
-    support: string
-    originallyPublishedAt?: string,
-    account: {
-      name: string
-      host: string
-    }
-    isLocal: boolean
-    tags: string[]
-    privacy: number
-    likes?: number
-    dislikes?: number
-    duration: number
-    channel: {
-      displayName: string
-      name: string
-      description
-      isLocal: boolean
-    }
-    fixture: string
-    files: {
-      resolution: number
-      size: number
-    }[],
-    thumbnailfile?: string
-    previewfile?: string
-  }
-) {
-  if (!attributes.likes) attributes.likes = 0
-  if (!attributes.dislikes) attributes.dislikes = 0
-
-  expect(video.name).to.equal(attributes.name)
-  expect(video.category.id).to.equal(attributes.category)
-  expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Misc')
-  expect(video.licence.id).to.equal(attributes.licence)
-  expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown')
-  expect(video.language.id).to.equal(attributes.language)
-  expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown')
-  expect(video.privacy.id).to.deep.equal(attributes.privacy)
-  expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
-  expect(video.nsfw).to.equal(attributes.nsfw)
-  expect(video.description).to.equal(attributes.description)
-  expect(video.account.id).to.be.a('number')
-  expect(video.account.uuid).to.be.a('string')
-  expect(video.account.host).to.equal(attributes.account.host)
-  expect(video.account.name).to.equal(attributes.account.name)
-  expect(video.channel.displayName).to.equal(attributes.channel.displayName)
-  expect(video.channel.name).to.equal(attributes.channel.name)
-  expect(video.likes).to.equal(attributes.likes)
-  expect(video.dislikes).to.equal(attributes.dislikes)
-  expect(video.isLocal).to.equal(attributes.isLocal)
-  expect(video.duration).to.equal(attributes.duration)
-  expect(dateIsValid(video.createdAt)).to.be.true
-  expect(dateIsValid(video.publishedAt)).to.be.true
-  expect(dateIsValid(video.updatedAt)).to.be.true
-
-  if (attributes.publishedAt) {
-    expect(video.publishedAt).to.equal(attributes.publishedAt)
-  }
-
-  if (attributes.originallyPublishedAt) {
-    expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt)
-  } else {
-    expect(video.originallyPublishedAt).to.be.null
-  }
-
-  const res = await getVideo(url, video.uuid)
-  const videoDetails: VideoDetails = res.body
-
-  expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
-  expect(videoDetails.tags).to.deep.equal(attributes.tags)
-  expect(videoDetails.account.name).to.equal(attributes.account.name)
-  expect(videoDetails.account.host).to.equal(attributes.account.host)
-  expect(video.channel.displayName).to.equal(attributes.channel.displayName)
-  expect(video.channel.name).to.equal(attributes.channel.name)
-  expect(videoDetails.channel.host).to.equal(attributes.account.host)
-  expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal)
-  expect(dateIsValid(videoDetails.channel.createdAt.toString())).to.be.true
-  expect(dateIsValid(videoDetails.channel.updatedAt.toString())).to.be.true
-  expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
-  expect(videoDetails.downloadEnabled).to.equal(attributes.downloadEnabled)
-
-  for (const attributeFile of attributes.files) {
-    const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution)
-    expect(file).not.to.be.undefined
-
-    let extension = extname(attributes.fixture)
-    // Transcoding enabled on server 2, extension will always be .mp4
-    if (attributes.account.host === 'localhost:9002') extension = '.mp4'
-
-    const magnetUri = file.magnetUri
-    expect(file.magnetUri).to.have.lengthOf.above(2)
-    expect(file.torrentUrl).to.equal(`http://${attributes.account.host}/static/torrents/${videoDetails.uuid}-${file.resolution.id}.torrent`)
-    expect(file.fileUrl).to.equal(`http://${attributes.account.host}/static/webseed/${videoDetails.uuid}-${file.resolution.id}${extension}`)
-    expect(file.resolution.id).to.equal(attributeFile.resolution)
-    expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
-
-    const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
-    const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
-    expect(file.size,
-           'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')')
-      .to.be.above(minSize).and.below(maxSize)
-
-    {
-      await testImage(url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath)
-    }
-
-    if (attributes.previewfile) {
-      await testImage(url, attributes.previewfile, videoDetails.previewPath)
-    }
-
-    const torrent = await webtorrentAdd(magnetUri, true)
-    expect(torrent.files).to.be.an('array')
-    expect(torrent.files.length).to.equal(1)
-    expect(torrent.files[0].path).to.exist.and.to.not.equal('')
-  }
-}
-
-async function videoUUIDToId (url: string, id: number | string) {
-  if (validator.isUUID('' + id) === false) return id
-
-  const res = await getVideo(url, id)
-  return res.body.id
-}
-
-async function uploadVideoAndGetId (options: { server: ServerInfo, videoName: string, nsfw?: boolean, token?: string }) {
-  const videoAttrs: any = { name: options.videoName }
-  if (options.nsfw) videoAttrs.nsfw = options.nsfw
-
-  const res = await uploadVideo(options.server.url, options.token || options.server.accessToken, videoAttrs)
-
-  return { id: res.body.video.id, uuid: res.body.video.uuid }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
-  getVideoDescription,
-  getVideoCategories,
-  getVideoLicences,
-  videoUUIDToId,
-  getVideoPrivacies,
-  getVideoLanguages,
-  getMyVideos,
-  getAccountVideos,
-  getVideoChannelVideos,
-  getVideo,
-  getVideoWithToken,
-  getVideosList,
-  getVideosListPagination,
-  getVideosListSort,
-  removeVideo,
-  getVideosListWithToken,
-  uploadVideo,
-  getVideosWithFilters,
-  updateVideo,
-  rateVideo,
-  viewVideo,
-  parseTorrentVideo,
-  getLocalVideos,
-  completeVideoCheck,
-  checkVideoFilesWereRemoved,
-  getPlaylistVideos,
-  uploadVideoAndGetId
-}