diff options
Diffstat (limited to 'server')
373 files changed, 4659 insertions, 1667 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index c4e3cec6b..4e6bd5e25 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -20,7 +20,8 @@ import { | |||
20 | asyncMiddleware, | 20 | asyncMiddleware, |
21 | executeIfActivityPub, | 21 | executeIfActivityPub, |
22 | localAccountValidator, | 22 | localAccountValidator, |
23 | localVideoChannelValidator, | 23 | videoChannelsNameWithHostValidator, |
24 | ensureIsLocalChannel, | ||
24 | videosCustomGetValidator, | 25 | videosCustomGetValidator, |
25 | videosShareValidator | 26 | videosShareValidator |
26 | } from '../../middlewares' | 27 | } from '../../middlewares' |
@@ -123,24 +124,28 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity | |||
123 | ) | 124 | ) |
124 | 125 | ||
125 | activityPubClientRouter.get( | 126 | activityPubClientRouter.get( |
126 | [ '/video-channels/:name', '/video-channels/:name/videos', '/c/:name', '/c/:name/videos' ], | 127 | [ '/video-channels/:nameWithHost', '/video-channels/:nameWithHost/videos', '/c/:nameWithHost', '/c/:nameWithHost/videos' ], |
127 | executeIfActivityPub, | 128 | executeIfActivityPub, |
128 | asyncMiddleware(localVideoChannelValidator), | 129 | asyncMiddleware(videoChannelsNameWithHostValidator), |
130 | ensureIsLocalChannel, | ||
129 | videoChannelController | 131 | videoChannelController |
130 | ) | 132 | ) |
131 | activityPubClientRouter.get('/video-channels/:name/followers', | 133 | activityPubClientRouter.get('/video-channels/:nameWithHost/followers', |
132 | executeIfActivityPub, | 134 | executeIfActivityPub, |
133 | asyncMiddleware(localVideoChannelValidator), | 135 | asyncMiddleware(videoChannelsNameWithHostValidator), |
136 | ensureIsLocalChannel, | ||
134 | asyncMiddleware(videoChannelFollowersController) | 137 | asyncMiddleware(videoChannelFollowersController) |
135 | ) | 138 | ) |
136 | activityPubClientRouter.get('/video-channels/:name/following', | 139 | activityPubClientRouter.get('/video-channels/:nameWithHost/following', |
137 | executeIfActivityPub, | 140 | executeIfActivityPub, |
138 | asyncMiddleware(localVideoChannelValidator), | 141 | asyncMiddleware(videoChannelsNameWithHostValidator), |
142 | ensureIsLocalChannel, | ||
139 | asyncMiddleware(videoChannelFollowingController) | 143 | asyncMiddleware(videoChannelFollowingController) |
140 | ) | 144 | ) |
141 | activityPubClientRouter.get('/video-channels/:name/playlists', | 145 | activityPubClientRouter.get('/video-channels/:nameWithHost/playlists', |
142 | executeIfActivityPub, | 146 | executeIfActivityPub, |
143 | asyncMiddleware(localVideoChannelValidator), | 147 | asyncMiddleware(videoChannelsNameWithHostValidator), |
148 | ensureIsLocalChannel, | ||
144 | asyncMiddleware(videoChannelPlaylistsController) | 149 | asyncMiddleware(videoChannelPlaylistsController) |
145 | ) | 150 | ) |
146 | 151 | ||
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index ece4edff0..66a38e055 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts | |||
@@ -1,10 +1,17 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { InboxManager } from '@server/lib/activitypub/inbox-manager' | 2 | import { InboxManager } from '@server/lib/activitypub/inbox-manager' |
3 | import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, RootActivity } from '../../../shared' | 3 | import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, RootActivity } from '@shared/models' |
4 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 4 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' |
5 | import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity' | 5 | import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity' |
6 | import { logger } from '../../helpers/logger' | 6 | import { logger } from '../../helpers/logger' |
7 | import { asyncMiddleware, checkSignature, localAccountValidator, localVideoChannelValidator, signatureValidator } from '../../middlewares' | 7 | import { |
8 | asyncMiddleware, | ||
9 | checkSignature, | ||
10 | ensureIsLocalChannel, | ||
11 | localAccountValidator, | ||
12 | signatureValidator, | ||
13 | videoChannelsNameWithHostValidator | ||
14 | } from '../../middlewares' | ||
8 | import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' | 15 | import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' |
9 | 16 | ||
10 | const inboxRouter = express.Router() | 17 | const inboxRouter = express.Router() |
@@ -23,10 +30,11 @@ inboxRouter.post('/accounts/:name/inbox', | |||
23 | asyncMiddleware(activityPubValidator), | 30 | asyncMiddleware(activityPubValidator), |
24 | inboxController | 31 | inboxController |
25 | ) | 32 | ) |
26 | inboxRouter.post('/video-channels/:name/inbox', | 33 | inboxRouter.post('/video-channels/:nameWithHost/inbox', |
27 | signatureValidator, | 34 | signatureValidator, |
28 | asyncMiddleware(checkSignature), | 35 | asyncMiddleware(checkSignature), |
29 | asyncMiddleware(localVideoChannelValidator), | 36 | asyncMiddleware(videoChannelsNameWithHostValidator), |
37 | ensureIsLocalChannel, | ||
30 | asyncMiddleware(activityPubValidator), | 38 | asyncMiddleware(activityPubValidator), |
31 | inboxController | 39 | inboxController |
32 | ) | 40 | ) |
diff --git a/server/controllers/activitypub/outbox.ts b/server/controllers/activitypub/outbox.ts index bdf9d138b..cdef8e969 100644 --- a/server/controllers/activitypub/outbox.ts +++ b/server/controllers/activitypub/outbox.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { MActorLight } from '@server/types/models' | ||
2 | import { Activity } from '../../../shared/models/activitypub/activity' | 3 | import { Activity } from '../../../shared/models/activitypub/activity' |
3 | import { VideoPrivacy } from '../../../shared/models/videos' | 4 | import { VideoPrivacy } from '../../../shared/models/videos' |
4 | import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' | 5 | import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' |
5 | import { logger } from '../../helpers/logger' | 6 | import { logger } from '../../helpers/logger' |
6 | import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send' | ||
7 | import { buildAudience } from '../../lib/activitypub/audience' | 7 | import { buildAudience } from '../../lib/activitypub/audience' |
8 | import { asyncMiddleware, localAccountValidator, localVideoChannelValidator } from '../../middlewares' | 8 | import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send' |
9 | import { asyncMiddleware, ensureIsLocalChannel, localAccountValidator, videoChannelsNameWithHostValidator } from '../../middlewares' | ||
10 | import { apPaginationValidator } from '../../middlewares/validators/activitypub' | ||
9 | import { VideoModel } from '../../models/video/video' | 11 | import { VideoModel } from '../../models/video/video' |
10 | import { activityPubResponse } from './utils' | 12 | import { activityPubResponse } from './utils' |
11 | import { MActorLight } from '@server/types/models' | ||
12 | import { apPaginationValidator } from '../../middlewares/validators/activitypub' | ||
13 | 13 | ||
14 | const outboxRouter = express.Router() | 14 | const outboxRouter = express.Router() |
15 | 15 | ||
@@ -19,9 +19,10 @@ outboxRouter.get('/accounts/:name/outbox', | |||
19 | asyncMiddleware(outboxController) | 19 | asyncMiddleware(outboxController) |
20 | ) | 20 | ) |
21 | 21 | ||
22 | outboxRouter.get('/video-channels/:name/outbox', | 22 | outboxRouter.get('/video-channels/:nameWithHost/outbox', |
23 | apPaginationValidator, | 23 | apPaginationValidator, |
24 | localVideoChannelValidator, | 24 | asyncMiddleware(videoChannelsNameWithHostValidator), |
25 | ensureIsLocalChannel, | ||
25 | asyncMiddleware(outboxController) | 26 | asyncMiddleware(outboxController) |
26 | ) | 27 | ) |
27 | 28 | ||
diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts index 72c418e74..d6211cc83 100644 --- a/server/controllers/api/abuse.ts +++ b/server/controllers/api/abuse.ts | |||
@@ -6,8 +6,7 @@ import { AbuseModel } from '@server/models/abuse/abuse' | |||
6 | import { AbuseMessageModel } from '@server/models/abuse/abuse-message' | 6 | import { AbuseMessageModel } from '@server/models/abuse/abuse-message' |
7 | import { getServerActor } from '@server/models/application/application' | 7 | import { getServerActor } from '@server/models/application/application' |
8 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | 8 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' |
9 | import { HttpStatusCode } from '@shared/models' | 9 | import { AbuseCreate, AbuseState, HttpStatusCode, UserRight } from '@shared/models' |
10 | import { AbuseCreate, AbuseState, UserRight } from '../../../shared' | ||
11 | import { getFormattedObjects } from '../../helpers/utils' | 10 | import { getFormattedObjects } from '../../helpers/utils' |
12 | import { sequelizeTypescript } from '../../initializers/database' | 11 | import { sequelizeTypescript } from '../../initializers/database' |
13 | import { | 12 | import { |
@@ -167,7 +166,11 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
167 | const body: AbuseCreate = req.body | 166 | const body: AbuseCreate = req.body |
168 | 167 | ||
169 | const { id } = await sequelizeTypescript.transaction(async t => { | 168 | const { id } = await sequelizeTypescript.transaction(async t => { |
170 | const reporterAccount = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) | 169 | const user = res.locals.oauth.token.User |
170 | // Don't send abuse notification if reporter is an admin/moderator | ||
171 | const skipNotification = user.hasRight(UserRight.MANAGE_ABUSES) | ||
172 | |||
173 | const reporterAccount = await AccountModel.load(user.Account.id, t) | ||
171 | const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) | 174 | const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) |
172 | 175 | ||
173 | const baseAbuse = { | 176 | const baseAbuse = { |
@@ -184,7 +187,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
184 | reporterAccount, | 187 | reporterAccount, |
185 | transaction: t, | 188 | transaction: t, |
186 | startAt: body.video.startAt, | 189 | startAt: body.video.startAt, |
187 | endAt: body.video.endAt | 190 | endAt: body.video.endAt, |
191 | skipNotification | ||
188 | }) | 192 | }) |
189 | } | 193 | } |
190 | 194 | ||
@@ -193,7 +197,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
193 | baseAbuse, | 197 | baseAbuse, |
194 | commentInstance, | 198 | commentInstance, |
195 | reporterAccount, | 199 | reporterAccount, |
196 | transaction: t | 200 | transaction: t, |
201 | skipNotification | ||
197 | }) | 202 | }) |
198 | } | 203 | } |
199 | 204 | ||
@@ -202,7 +207,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { | |||
202 | baseAbuse, | 207 | baseAbuse, |
203 | accountInstance, | 208 | accountInstance, |
204 | reporterAccount, | 209 | reporterAccount, |
205 | transaction: t | 210 | transaction: t, |
211 | skipNotification | ||
206 | }) | 212 | }) |
207 | }) | 213 | }) |
208 | 214 | ||
diff --git a/server/controllers/api/blocklist.ts b/server/controllers/api/blocklist.ts new file mode 100644 index 000000000..1e936ad10 --- /dev/null +++ b/server/controllers/api/blocklist.ts | |||
@@ -0,0 +1,108 @@ | |||
1 | import express from 'express' | ||
2 | import { handleToNameAndHost } from '@server/helpers/actors' | ||
3 | import { AccountBlocklistModel } from '@server/models/account/account-blocklist' | ||
4 | import { getServerActor } from '@server/models/application/application' | ||
5 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' | ||
6 | import { MActorAccountId, MUserAccountId } from '@server/types/models' | ||
7 | import { BlockStatus } from '@shared/models' | ||
8 | import { asyncMiddleware, blocklistStatusValidator, optionalAuthenticate } from '../../middlewares' | ||
9 | import { logger } from '@server/helpers/logger' | ||
10 | |||
11 | const blocklistRouter = express.Router() | ||
12 | |||
13 | blocklistRouter.get('/status', | ||
14 | optionalAuthenticate, | ||
15 | blocklistStatusValidator, | ||
16 | asyncMiddleware(getBlocklistStatus) | ||
17 | ) | ||
18 | |||
19 | // --------------------------------------------------------------------------- | ||
20 | |||
21 | export { | ||
22 | blocklistRouter | ||
23 | } | ||
24 | |||
25 | // --------------------------------------------------------------------------- | ||
26 | |||
27 | async function getBlocklistStatus (req: express.Request, res: express.Response) { | ||
28 | const hosts = req.query.hosts as string[] | ||
29 | const accounts = req.query.accounts as string[] | ||
30 | const user = res.locals.oauth?.token.User | ||
31 | |||
32 | const serverActor = await getServerActor() | ||
33 | |||
34 | const byAccountIds = [ serverActor.Account.id ] | ||
35 | if (user) byAccountIds.push(user.Account.id) | ||
36 | |||
37 | const status: BlockStatus = { | ||
38 | accounts: {}, | ||
39 | hosts: {} | ||
40 | } | ||
41 | |||
42 | const baseOptions = { | ||
43 | byAccountIds, | ||
44 | user, | ||
45 | serverActor, | ||
46 | status | ||
47 | } | ||
48 | |||
49 | await Promise.all([ | ||
50 | populateServerBlocklistStatus({ ...baseOptions, hosts }), | ||
51 | populateAccountBlocklistStatus({ ...baseOptions, accounts }) | ||
52 | ]) | ||
53 | |||
54 | return res.json(status) | ||
55 | } | ||
56 | |||
57 | async function populateServerBlocklistStatus (options: { | ||
58 | byAccountIds: number[] | ||
59 | user?: MUserAccountId | ||
60 | serverActor: MActorAccountId | ||
61 | hosts: string[] | ||
62 | status: BlockStatus | ||
63 | }) { | ||
64 | const { byAccountIds, user, serverActor, hosts, status } = options | ||
65 | |||
66 | if (!hosts || hosts.length === 0) return | ||
67 | |||
68 | const serverBlocklistStatus = await ServerBlocklistModel.getBlockStatus(byAccountIds, hosts) | ||
69 | |||
70 | logger.debug('Got server blocklist status.', { serverBlocklistStatus, byAccountIds, hosts }) | ||
71 | |||
72 | for (const host of hosts) { | ||
73 | const block = serverBlocklistStatus.find(b => b.host === host) | ||
74 | |||
75 | status.hosts[host] = getStatus(block, serverActor, user) | ||
76 | } | ||
77 | } | ||
78 | |||
79 | async function populateAccountBlocklistStatus (options: { | ||
80 | byAccountIds: number[] | ||
81 | user?: MUserAccountId | ||
82 | serverActor: MActorAccountId | ||
83 | accounts: string[] | ||
84 | status: BlockStatus | ||
85 | }) { | ||
86 | const { byAccountIds, user, serverActor, accounts, status } = options | ||
87 | |||
88 | if (!accounts || accounts.length === 0) return | ||
89 | |||
90 | const accountBlocklistStatus = await AccountBlocklistModel.getBlockStatus(byAccountIds, accounts) | ||
91 | |||
92 | logger.debug('Got account blocklist status.', { accountBlocklistStatus, byAccountIds, accounts }) | ||
93 | |||
94 | for (const account of accounts) { | ||
95 | const sanitizedHandle = handleToNameAndHost(account) | ||
96 | |||
97 | const block = accountBlocklistStatus.find(b => b.name === sanitizedHandle.name && b.host === sanitizedHandle.host) | ||
98 | |||
99 | status.accounts[sanitizedHandle.handle] = getStatus(block, serverActor, user) | ||
100 | } | ||
101 | } | ||
102 | |||
103 | function getStatus (block: { accountId: number }, serverActor: MActorAccountId, user?: MUserAccountId) { | ||
104 | return { | ||
105 | blockedByServer: !!(block && block.accountId === serverActor.Account.id), | ||
106 | blockedByUser: !!(block && user && block.accountId === user.Account.id) | ||
107 | } | ||
108 | } | ||
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 805ad99c7..4e3dd4d80 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -3,9 +3,7 @@ import { remove, writeJSON } from 'fs-extra' | |||
3 | import { snakeCase } from 'lodash' | 3 | import { snakeCase } from 'lodash' |
4 | import validator from 'validator' | 4 | import validator from 'validator' |
5 | import { ServerConfigManager } from '@server/lib/server-config-manager' | 5 | import { ServerConfigManager } from '@server/lib/server-config-manager' |
6 | import { UserRight } from '../../../shared' | 6 | import { About, CustomConfig, UserRight } from '@shared/models' |
7 | import { About } from '../../../shared/models/server/about.model' | ||
8 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' | ||
9 | import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' | 7 | import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' |
10 | import { objectConverter } from '../../helpers/core-utils' | 8 | import { objectConverter } from '../../helpers/core-utils' |
11 | import { CONFIG, reloadConfig } from '../../initializers/config' | 9 | import { CONFIG, reloadConfig } from '../../initializers/config' |
@@ -169,6 +167,18 @@ function customConfig (): CustomConfig { | |||
169 | whitelisted: CONFIG.SERVICES.TWITTER.WHITELISTED | 167 | whitelisted: CONFIG.SERVICES.TWITTER.WHITELISTED |
170 | } | 168 | } |
171 | }, | 169 | }, |
170 | client: { | ||
171 | videos: { | ||
172 | miniature: { | ||
173 | preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME | ||
174 | } | ||
175 | }, | ||
176 | menu: { | ||
177 | login: { | ||
178 | redirectOnSingleExternalAuth: CONFIG.CLIENT.MENU.LOGIN.REDIRECT_ON_SINGLE_EXTERNAL_AUTH | ||
179 | } | ||
180 | } | ||
181 | }, | ||
172 | cache: { | 182 | cache: { |
173 | previews: { | 183 | previews: { |
174 | size: CONFIG.CACHE.PREVIEWS.SIZE | 184 | size: CONFIG.CACHE.PREVIEWS.SIZE |
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 9949b378a..5f49336b1 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -6,6 +6,7 @@ import { badRequest } from '../../helpers/express-utils' | |||
6 | import { CONFIG } from '../../initializers/config' | 6 | import { CONFIG } from '../../initializers/config' |
7 | import { abuseRouter } from './abuse' | 7 | import { abuseRouter } from './abuse' |
8 | import { accountsRouter } from './accounts' | 8 | import { accountsRouter } from './accounts' |
9 | import { blocklistRouter } from './blocklist' | ||
9 | import { bulkRouter } from './bulk' | 10 | import { bulkRouter } from './bulk' |
10 | import { configRouter } from './config' | 11 | import { configRouter } from './config' |
11 | import { customPageRouter } from './custom-page' | 12 | import { customPageRouter } from './custom-page' |
@@ -49,6 +50,7 @@ apiRouter.use('/search', searchRouter) | |||
49 | apiRouter.use('/overviews', overviewsRouter) | 50 | apiRouter.use('/overviews', overviewsRouter) |
50 | apiRouter.use('/plugins', pluginRouter) | 51 | apiRouter.use('/plugins', pluginRouter) |
51 | apiRouter.use('/custom-pages', customPageRouter) | 52 | apiRouter.use('/custom-pages', customPageRouter) |
53 | apiRouter.use('/blocklist', blocklistRouter) | ||
52 | apiRouter.use('/ping', pong) | 54 | apiRouter.use('/ping', pong) |
53 | apiRouter.use('/*', badRequest) | 55 | apiRouter.use('/*', badRequest) |
54 | 56 | ||
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts index 7001674bb..eebd195b0 100644 --- a/server/controllers/api/jobs.ts +++ b/server/controllers/api/jobs.ts | |||
@@ -1,7 +1,5 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { ResultList } from '../../../shared' | 2 | import { Job, JobState, JobType, ResultList, UserRight } from '@shared/models' |
3 | import { Job, JobState, JobType } from '../../../shared/models' | ||
4 | import { UserRight } from '../../../shared/models/users' | ||
5 | import { isArray } from '../../helpers/custom-validators/misc' | 3 | import { isArray } from '../../helpers/custom-validators/misc' |
6 | import { JobQueue } from '../../lib/job-queue' | 4 | import { JobQueue } from '../../lib/job-queue' |
7 | import { | 5 | import { |
diff --git a/server/controllers/api/oauth-clients.ts b/server/controllers/api/oauth-clients.ts index 4990fb0df..2d847bdc1 100644 --- a/server/controllers/api/oauth-clients.ts +++ b/server/controllers/api/oauth-clients.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { OAuthClientLocal } from '../../../shared' | 2 | import { OAuthClientModel } from '@server/models/oauth/oauth-client' |
3 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 3 | import { HttpStatusCode, OAuthClientLocal } from '@shared/models' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { CONFIG } from '../../initializers/config' | 5 | import { CONFIG } from '../../initializers/config' |
6 | import { asyncMiddleware, openapiOperationDoc } from '../../middlewares' | 6 | import { asyncMiddleware, openapiOperationDoc } from '../../middlewares' |
7 | import { OAuthClientModel } from '../../models/oauth/oauth-client' | ||
8 | 7 | ||
9 | const oauthClientsRouter = express.Router() | 8 | const oauthClientsRouter = express.Router() |
10 | 9 | ||
diff --git a/server/controllers/api/plugins.ts b/server/controllers/api/plugins.ts index 2de7fe41f..de9e055dc 100644 --- a/server/controllers/api/plugins.ts +++ b/server/controllers/api/plugins.ts | |||
@@ -144,8 +144,13 @@ async function installPlugin (req: express.Request, res: express.Response) { | |||
144 | 144 | ||
145 | const fromDisk = !!body.path | 145 | const fromDisk = !!body.path |
146 | const toInstall = body.npmName || body.path | 146 | const toInstall = body.npmName || body.path |
147 | |||
148 | const pluginVersion = body.pluginVersion && body.npmName | ||
149 | ? body.pluginVersion | ||
150 | : undefined | ||
151 | |||
147 | try { | 152 | try { |
148 | const plugin = await PluginManager.Instance.install(toInstall, undefined, fromDisk) | 153 | const plugin = await PluginManager.Instance.install(toInstall, pluginVersion, fromDisk) |
149 | 154 | ||
150 | return res.json(plugin.toFormattedJSON()) | 155 | return res.json(plugin.toFormattedJSON()) |
151 | } catch (err) { | 156 | } catch (err) { |
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index d661144ca..2ab398f4d 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts | |||
@@ -3,6 +3,7 @@ import { StatsManager } from '@server/lib/stat-manager' | |||
3 | import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' | 3 | import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' |
4 | import { asyncMiddleware } from '../../../middlewares' | 4 | import { asyncMiddleware } from '../../../middlewares' |
5 | import { cacheRoute } from '../../../middlewares/cache/cache' | 5 | import { cacheRoute } from '../../../middlewares/cache/cache' |
6 | import { Hooks } from '@server/lib/plugins/hooks' | ||
6 | 7 | ||
7 | const statsRouter = express.Router() | 8 | const statsRouter = express.Router() |
8 | 9 | ||
@@ -12,7 +13,8 @@ statsRouter.get('/stats', | |||
12 | ) | 13 | ) |
13 | 14 | ||
14 | async function getStats (_req: express.Request, res: express.Response) { | 15 | async function getStats (_req: express.Request, res: express.Response) { |
15 | const data = await StatsManager.Instance.getStats() | 16 | let data = await StatsManager.Instance.getStats() |
17 | data = await Hooks.wrapObject(data, 'filter:api.server.stats.get.result') | ||
16 | 18 | ||
17 | return res.json(data) | 19 | return res.json(data) |
18 | } | 20 | } |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index 11d3525e4..7efc3a137 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -4,10 +4,7 @@ import { tokensRouter } from '@server/controllers/api/users/token' | |||
4 | import { Hooks } from '@server/lib/plugins/hooks' | 4 | import { Hooks } from '@server/lib/plugins/hooks' |
5 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' | 5 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' |
6 | import { MUser, MUserAccountDefault } from '@server/types/models' | 6 | import { MUser, MUserAccountDefault } from '@server/types/models' |
7 | import { UserCreate, UserCreateResult, UserRight, UserRole, UserUpdate } from '../../../../shared' | 7 | import { HttpStatusCode, UserAdminFlag, UserCreate, UserCreateResult, UserRegister, UserRight, UserRole, UserUpdate } from '@shared/models' |
8 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
9 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | ||
10 | import { UserRegister } from '../../../../shared/models/users/user-register.model' | ||
11 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' | 8 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger' |
12 | import { logger } from '../../../helpers/logger' | 9 | import { logger } from '../../../helpers/logger' |
13 | import { generateRandomString, getFormattedObjects } from '../../../helpers/utils' | 10 | import { generateRandomString, getFormattedObjects } from '../../../helpers/utils' |
@@ -183,6 +180,7 @@ async function createUser (req: express.Request, res: express.Response) { | |||
183 | password: body.password, | 180 | password: body.password, |
184 | email: body.email, | 181 | email: body.email, |
185 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 182 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
183 | p2pEnabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED, | ||
186 | autoPlayVideo: true, | 184 | autoPlayVideo: true, |
187 | role: body.role, | 185 | role: body.role, |
188 | videoQuota: body.videoQuota, | 186 | videoQuota: body.videoQuota, |
@@ -209,7 +207,7 @@ async function createUser (req: express.Request, res: express.Response) { | |||
209 | logger.info('Sending to user %s a create password email', body.username) | 207 | logger.info('Sending to user %s a create password email', body.username) |
210 | const verificationString = await Redis.Instance.setCreatePasswordVerificationString(user.id) | 208 | const verificationString = await Redis.Instance.setCreatePasswordVerificationString(user.id) |
211 | const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString | 209 | const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString |
212 | await Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url) | 210 | Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url) |
213 | } | 211 | } |
214 | 212 | ||
215 | Hooks.runAction('action:api.user.created', { body, user, account, videoChannel, req, res }) | 213 | Hooks.runAction('action:api.user.created', { body, user, account, videoChannel, req, res }) |
@@ -232,6 +230,7 @@ async function registerUser (req: express.Request, res: express.Response) { | |||
232 | password: body.password, | 230 | password: body.password, |
233 | email: body.email, | 231 | email: body.email, |
234 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 232 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
233 | p2pEnabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED, | ||
235 | autoPlayVideo: true, | 234 | autoPlayVideo: true, |
236 | role: UserRole.USER, | 235 | role: UserRole.USER, |
237 | videoQuota: CONFIG.USER.VIDEO_QUOTA, | 236 | videoQuota: CONFIG.USER.VIDEO_QUOTA, |
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index 6bacdbbb6..878dd5a84 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -2,10 +2,8 @@ import 'multer' | |||
2 | import express from 'express' | 2 | import express from 'express' |
3 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '@server/helpers/audit-logger' | 3 | import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '@server/helpers/audit-logger' |
4 | import { Hooks } from '@server/lib/plugins/hooks' | 4 | import { Hooks } from '@server/lib/plugins/hooks' |
5 | import { AttributesOnly } from '@shared/core-utils' | 5 | import { ActorImageType, HttpStatusCode, UserUpdateMe, UserVideoQuota, UserVideoRate as FormattedUserVideoRate } from '@shared/models' |
6 | import { ActorImageType, UserUpdateMe, UserVideoRate as FormattedUserVideoRate } from '../../../../shared' | 6 | import { AttributesOnly } from '@shared/typescript-utils' |
7 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
8 | import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model' | ||
9 | import { createReqFiles } from '../../../helpers/express-utils' | 7 | import { createReqFiles } from '../../../helpers/express-utils' |
10 | import { getFormattedObjects } from '../../../helpers/utils' | 8 | import { getFormattedObjects } from '../../../helpers/utils' |
11 | import { CONFIG } from '../../../initializers/config' | 9 | import { CONFIG } from '../../../initializers/config' |
@@ -197,7 +195,7 @@ async function updateMe (req: express.Request, res: express.Response) { | |||
197 | const keysToUpdate: (keyof UserUpdateMe & keyof AttributesOnly<UserModel>)[] = [ | 195 | const keysToUpdate: (keyof UserUpdateMe & keyof AttributesOnly<UserModel>)[] = [ |
198 | 'password', | 196 | 'password', |
199 | 'nsfwPolicy', | 197 | 'nsfwPolicy', |
200 | 'webTorrentEnabled', | 198 | 'p2pEnabled', |
201 | 'autoPlayVideo', | 199 | 'autoPlayVideo', |
202 | 'autoPlayNextVideo', | 200 | 'autoPlayNextVideo', |
203 | 'autoPlayNextVideoPlaylist', | 201 | 'autoPlayNextVideoPlaylist', |
@@ -213,6 +211,12 @@ async function updateMe (req: express.Request, res: express.Response) { | |||
213 | if (body[key] !== undefined) user.set(key, body[key]) | 211 | if (body[key] !== undefined) user.set(key, body[key]) |
214 | } | 212 | } |
215 | 213 | ||
214 | if (body.p2pEnabled !== undefined) { | ||
215 | user.set('p2pEnabled', body.p2pEnabled) | ||
216 | } else if (body.webTorrentEnabled !== undefined) { // FIXME: deprecated in 4.1 | ||
217 | user.set('p2pEnabled', body.webTorrentEnabled) | ||
218 | } | ||
219 | |||
216 | if (body.email !== undefined) { | 220 | if (body.email !== undefined) { |
217 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { | 221 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { |
218 | user.pendingEmail = body.email | 222 | user.pendingEmail = body.email |
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts index 6799ca8c5..fb1f68635 100644 --- a/server/controllers/api/users/my-subscriptions.ts +++ b/server/controllers/api/users/my-subscriptions.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import 'multer' | 1 | import 'multer' |
2 | import express from 'express' | 2 | import express from 'express' |
3 | import { handlesToNameAndHost } from '@server/helpers/actors' | ||
3 | import { pickCommonVideoQuery } from '@server/helpers/query' | 4 | import { pickCommonVideoQuery } from '@server/helpers/query' |
4 | import { sendUndoFollow } from '@server/lib/activitypub/send' | 5 | import { sendUndoFollow } from '@server/lib/activitypub/send' |
5 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' | 6 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' |
@@ -7,7 +8,6 @@ import { VideoChannelModel } from '@server/models/video/video-channel' | |||
7 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 8 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' |
8 | import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' | 9 | import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' |
9 | import { getFormattedObjects } from '../../../helpers/utils' | 10 | import { getFormattedObjects } from '../../../helpers/utils' |
10 | import { WEBSERVER } from '../../../initializers/constants' | ||
11 | import { sequelizeTypescript } from '../../../initializers/database' | 11 | import { sequelizeTypescript } from '../../../initializers/database' |
12 | import { JobQueue } from '../../../lib/job-queue' | 12 | import { JobQueue } from '../../../lib/job-queue' |
13 | import { | 13 | import { |
@@ -89,28 +89,23 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons | |||
89 | const uris = req.query.uris as string[] | 89 | const uris = req.query.uris as string[] |
90 | const user = res.locals.oauth.token.User | 90 | const user = res.locals.oauth.token.User |
91 | 91 | ||
92 | const handles = uris.map(u => { | 92 | const sanitizedHandles = handlesToNameAndHost(uris) |
93 | let [ name, host ] = u.split('@') | ||
94 | if (host === WEBSERVER.HOST) host = null | ||
95 | 93 | ||
96 | return { name, host, uri: u } | 94 | const results = await ActorFollowModel.listSubscriptionsOf(user.Account.Actor.id, sanitizedHandles) |
97 | }) | ||
98 | |||
99 | const results = await ActorFollowModel.listSubscriptionsOf(user.Account.Actor.id, handles) | ||
100 | 95 | ||
101 | const existObject: { [id: string ]: boolean } = {} | 96 | const existObject: { [id: string ]: boolean } = {} |
102 | for (const handle of handles) { | 97 | for (const sanitizedHandle of sanitizedHandles) { |
103 | const obj = results.find(r => { | 98 | const obj = results.find(r => { |
104 | const server = r.ActorFollowing.Server | 99 | const server = r.ActorFollowing.Server |
105 | 100 | ||
106 | return r.ActorFollowing.preferredUsername === handle.name && | 101 | return r.ActorFollowing.preferredUsername === sanitizedHandle.name && |
107 | ( | 102 | ( |
108 | (!server && !handle.host) || | 103 | (!server && !sanitizedHandle.host) || |
109 | (server.host === handle.host) | 104 | (server.host === sanitizedHandle.host) |
110 | ) | 105 | ) |
111 | }) | 106 | }) |
112 | 107 | ||
113 | existObject[handle.uri] = obj !== undefined | 108 | existObject[sanitizedHandle.handle] = obj !== undefined |
114 | } | 109 | } |
115 | 110 | ||
116 | return res.json(existObject) | 111 | return res.json(existObject) |
diff --git a/server/controllers/api/users/token.ts b/server/controllers/api/users/token.ts index 1d4004ce0..258b50fe9 100644 --- a/server/controllers/api/users/token.ts +++ b/server/controllers/api/users/token.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import RateLimit from 'express-rate-limit' | 2 | import RateLimit from 'express-rate-limit' |
3 | import { logger } from '@server/helpers/logger' | 3 | import { logger } from '@server/helpers/logger' |
4 | import { buildUUID } from '@server/helpers/uuid' | ||
5 | import { CONFIG } from '@server/initializers/config' | 4 | import { CONFIG } from '@server/initializers/config' |
6 | import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth' | 5 | import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth' |
7 | import { handleOAuthToken } from '@server/lib/auth/oauth' | 6 | import { handleOAuthToken } from '@server/lib/auth/oauth' |
8 | import { BypassLogin, revokeToken } from '@server/lib/auth/oauth-model' | 7 | import { BypassLogin, revokeToken } from '@server/lib/auth/oauth-model' |
9 | import { Hooks } from '@server/lib/plugins/hooks' | 8 | import { Hooks } from '@server/lib/plugins/hooks' |
10 | import { asyncMiddleware, authenticate, openapiOperationDoc } from '@server/middlewares' | 9 | import { asyncMiddleware, authenticate, openapiOperationDoc } from '@server/middlewares' |
10 | import { buildUUID } from '@shared/extra-utils' | ||
11 | import { ScopedToken } from '@shared/models/users/user-scoped-token' | 11 | import { ScopedToken } from '@shared/models/users/user-scoped-token' |
12 | 12 | ||
13 | const tokensRouter = express.Router() | 13 | const tokensRouter = express.Router() |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index d1a1e6473..e65550a22 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -5,8 +5,7 @@ import { ActorFollowModel } from '@server/models/actor/actor-follow' | |||
5 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
6 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' | 6 | import { guessAdditionalAttributesFromQuery } from '@server/models/video/formatter/video-format-utils' |
7 | import { MChannelBannerAccountDefault } from '@server/types/models' | 7 | import { MChannelBannerAccountDefault } from '@server/types/models' |
8 | import { ActorImageType, VideoChannelCreate, VideoChannelUpdate } from '../../../shared' | 8 | import { ActorImageType, HttpStatusCode, VideoChannelCreate, VideoChannelUpdate } from '@shared/models' |
9 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | ||
10 | import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger' | 9 | import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger' |
11 | import { resetSequelizeInstance } from '../../helpers/database-utils' | 10 | import { resetSequelizeInstance } from '../../helpers/database-utils' |
12 | import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' | 11 | import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
@@ -24,6 +23,7 @@ import { | |||
24 | asyncRetryTransactionMiddleware, | 23 | asyncRetryTransactionMiddleware, |
25 | authenticate, | 24 | authenticate, |
26 | commonVideosFiltersValidator, | 25 | commonVideosFiltersValidator, |
26 | ensureCanManageChannel, | ||
27 | optionalAuthenticate, | 27 | optionalAuthenticate, |
28 | paginationValidator, | 28 | paginationValidator, |
29 | setDefaultPagination, | 29 | setDefaultPagination, |
@@ -36,7 +36,7 @@ import { | |||
36 | videoPlaylistsSortValidator | 36 | videoPlaylistsSortValidator |
37 | } from '../../middlewares' | 37 | } from '../../middlewares' |
38 | import { | 38 | import { |
39 | ensureAuthUserOwnsChannelValidator, | 39 | ensureIsLocalChannel, |
40 | videoChannelsFollowersSortValidator, | 40 | videoChannelsFollowersSortValidator, |
41 | videoChannelsListValidator, | 41 | videoChannelsListValidator, |
42 | videoChannelsNameWithHostValidator, | 42 | videoChannelsNameWithHostValidator, |
@@ -74,7 +74,8 @@ videoChannelRouter.post('/:nameWithHost/avatar/pick', | |||
74 | authenticate, | 74 | authenticate, |
75 | reqAvatarFile, | 75 | reqAvatarFile, |
76 | asyncMiddleware(videoChannelsNameWithHostValidator), | 76 | asyncMiddleware(videoChannelsNameWithHostValidator), |
77 | ensureAuthUserOwnsChannelValidator, | 77 | ensureIsLocalChannel, |
78 | ensureCanManageChannel, | ||
78 | updateAvatarValidator, | 79 | updateAvatarValidator, |
79 | asyncMiddleware(updateVideoChannelAvatar) | 80 | asyncMiddleware(updateVideoChannelAvatar) |
80 | ) | 81 | ) |
@@ -83,7 +84,8 @@ videoChannelRouter.post('/:nameWithHost/banner/pick', | |||
83 | authenticate, | 84 | authenticate, |
84 | reqBannerFile, | 85 | reqBannerFile, |
85 | asyncMiddleware(videoChannelsNameWithHostValidator), | 86 | asyncMiddleware(videoChannelsNameWithHostValidator), |
86 | ensureAuthUserOwnsChannelValidator, | 87 | ensureIsLocalChannel, |
88 | ensureCanManageChannel, | ||
87 | updateBannerValidator, | 89 | updateBannerValidator, |
88 | asyncMiddleware(updateVideoChannelBanner) | 90 | asyncMiddleware(updateVideoChannelBanner) |
89 | ) | 91 | ) |
@@ -91,27 +93,33 @@ videoChannelRouter.post('/:nameWithHost/banner/pick', | |||
91 | videoChannelRouter.delete('/:nameWithHost/avatar', | 93 | videoChannelRouter.delete('/:nameWithHost/avatar', |
92 | authenticate, | 94 | authenticate, |
93 | asyncMiddleware(videoChannelsNameWithHostValidator), | 95 | asyncMiddleware(videoChannelsNameWithHostValidator), |
94 | ensureAuthUserOwnsChannelValidator, | 96 | ensureIsLocalChannel, |
97 | ensureCanManageChannel, | ||
95 | asyncMiddleware(deleteVideoChannelAvatar) | 98 | asyncMiddleware(deleteVideoChannelAvatar) |
96 | ) | 99 | ) |
97 | 100 | ||
98 | videoChannelRouter.delete('/:nameWithHost/banner', | 101 | videoChannelRouter.delete('/:nameWithHost/banner', |
99 | authenticate, | 102 | authenticate, |
100 | asyncMiddleware(videoChannelsNameWithHostValidator), | 103 | asyncMiddleware(videoChannelsNameWithHostValidator), |
101 | ensureAuthUserOwnsChannelValidator, | 104 | ensureIsLocalChannel, |
105 | ensureCanManageChannel, | ||
102 | asyncMiddleware(deleteVideoChannelBanner) | 106 | asyncMiddleware(deleteVideoChannelBanner) |
103 | ) | 107 | ) |
104 | 108 | ||
105 | videoChannelRouter.put('/:nameWithHost', | 109 | videoChannelRouter.put('/:nameWithHost', |
106 | authenticate, | 110 | authenticate, |
107 | asyncMiddleware(videoChannelsNameWithHostValidator), | 111 | asyncMiddleware(videoChannelsNameWithHostValidator), |
108 | ensureAuthUserOwnsChannelValidator, | 112 | ensureIsLocalChannel, |
113 | ensureCanManageChannel, | ||
109 | videoChannelsUpdateValidator, | 114 | videoChannelsUpdateValidator, |
110 | asyncRetryTransactionMiddleware(updateVideoChannel) | 115 | asyncRetryTransactionMiddleware(updateVideoChannel) |
111 | ) | 116 | ) |
112 | 117 | ||
113 | videoChannelRouter.delete('/:nameWithHost', | 118 | videoChannelRouter.delete('/:nameWithHost', |
114 | authenticate, | 119 | authenticate, |
120 | asyncMiddleware(videoChannelsNameWithHostValidator), | ||
121 | ensureIsLocalChannel, | ||
122 | ensureCanManageChannel, | ||
115 | asyncMiddleware(videoChannelsRemoveValidator), | 123 | asyncMiddleware(videoChannelsRemoveValidator), |
116 | asyncRetryTransactionMiddleware(removeVideoChannel) | 124 | asyncRetryTransactionMiddleware(removeVideoChannel) |
117 | ) | 125 | ) |
@@ -145,7 +153,7 @@ videoChannelRouter.get('/:nameWithHost/videos', | |||
145 | videoChannelRouter.get('/:nameWithHost/followers', | 153 | videoChannelRouter.get('/:nameWithHost/followers', |
146 | authenticate, | 154 | authenticate, |
147 | asyncMiddleware(videoChannelsNameWithHostValidator), | 155 | asyncMiddleware(videoChannelsNameWithHostValidator), |
148 | ensureAuthUserOwnsChannelValidator, | 156 | ensureCanManageChannel, |
149 | paginationValidator, | 157 | paginationValidator, |
150 | videoChannelsFollowersSortValidator, | 158 | videoChannelsFollowersSortValidator, |
151 | setDefaultSort, | 159 | setDefaultSort, |
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index 8b7a76718..795e14e73 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { uuidToShort } from '@server/helpers/uuid' | ||
4 | import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists' | 3 | import { scheduleRefreshIfNeeded } from '@server/lib/activitypub/playlists' |
5 | import { Hooks } from '@server/lib/plugins/hooks' | 4 | import { Hooks } from '@server/lib/plugins/hooks' |
6 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
7 | import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models' | 6 | import { MVideoPlaylistFull, MVideoPlaylistThumbnail, MVideoThumbnail } from '@server/types/models' |
7 | import { uuidToShort } from '@shared/extra-utils' | ||
8 | import { VideoPlaylistCreateResult, VideoPlaylistElementCreateResult } from '@shared/models' | 8 | import { VideoPlaylistCreateResult, VideoPlaylistElementCreateResult } from '@shared/models' |
9 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 9 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' |
10 | import { VideoPlaylistCreate } from '../../../shared/models/videos/playlist/video-playlist-create.model' | 10 | import { VideoPlaylistCreate } from '../../../shared/models/videos/playlist/video-playlist-create.model' |
diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index de65c74f1..4103bb063 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { blacklistVideo, unblacklistVideo } from '@server/lib/video-blacklist' | 2 | import { blacklistVideo, unblacklistVideo } from '@server/lib/video-blacklist' |
3 | import { UserRight, VideoBlacklistCreate } from '../../../../shared' | 3 | import { HttpStatusCode, UserRight, VideoBlacklistCreate } from '@shared/models' |
4 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
5 | import { logger } from '../../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
6 | import { getFormattedObjects } from '../../../helpers/utils' | 5 | import { getFormattedObjects } from '../../../helpers/utils' |
7 | import { sequelizeTypescript } from '../../../initializers/database' | 6 | import { sequelizeTypescript } from '../../../initializers/database' |
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts index aa7259ee9..2a9a9d233 100644 --- a/server/controllers/api/videos/captions.ts +++ b/server/controllers/api/videos/captions.ts | |||
@@ -12,6 +12,7 @@ import { federateVideoIfNeeded } from '../../../lib/activitypub/videos' | |||
12 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' | 12 | import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate } from '../../../middlewares' |
13 | import { addVideoCaptionValidator, deleteVideoCaptionValidator, listVideoCaptionsValidator } from '../../../middlewares/validators' | 13 | import { addVideoCaptionValidator, deleteVideoCaptionValidator, listVideoCaptionsValidator } from '../../../middlewares/validators' |
14 | import { VideoCaptionModel } from '../../../models/video/video-caption' | 14 | import { VideoCaptionModel } from '../../../models/video/video-caption' |
15 | import { Hooks } from '@server/lib/plugins/hooks' | ||
15 | 16 | ||
16 | const reqVideoCaptionAdd = createReqFiles( | 17 | const reqVideoCaptionAdd = createReqFiles( |
17 | [ 'captionfile' ], | 18 | [ 'captionfile' ], |
@@ -75,6 +76,8 @@ async function addVideoCaption (req: express.Request, res: express.Response) { | |||
75 | await federateVideoIfNeeded(video, false, t) | 76 | await federateVideoIfNeeded(video, false, t) |
76 | }) | 77 | }) |
77 | 78 | ||
79 | Hooks.runAction('action:api.video-caption.created', { caption: videoCaption, req, res }) | ||
80 | |||
78 | return res.status(HttpStatusCode.NO_CONTENT_204).end() | 81 | return res.status(HttpStatusCode.NO_CONTENT_204).end() |
79 | } | 82 | } |
80 | 83 | ||
@@ -91,5 +94,7 @@ async function deleteVideoCaption (req: express.Request, res: express.Response) | |||
91 | 94 | ||
92 | logger.info('Video caption %s of video %s deleted.', videoCaption.language, video.uuid) | 95 | logger.info('Video caption %s of video %s deleted.', videoCaption.language, video.uuid) |
93 | 96 | ||
97 | Hooks.runAction('action:api.video-caption.deleted', { caption: videoCaption, req, res }) | ||
98 | |||
94 | return res.type('json').status(HttpStatusCode.NO_CONTENT_204).end() | 99 | return res.type('json').status(HttpStatusCode.NO_CONTENT_204).end() |
95 | } | 100 | } |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index eddb9b32d..08d69827b 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -4,6 +4,7 @@ import { decode } from 'magnet-uri' | |||
4 | import parseTorrent, { Instance } from 'parse-torrent' | 4 | import parseTorrent, { Instance } from 'parse-torrent' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { isVideoFileExtnameValid } from '@server/helpers/custom-validators/videos' | 6 | import { isVideoFileExtnameValid } from '@server/helpers/custom-validators/videos' |
7 | import { Hooks } from '@server/lib/plugins/hooks' | ||
7 | import { ServerConfigManager } from '@server/lib/server-config-manager' | 8 | import { ServerConfigManager } from '@server/lib/server-config-manager' |
8 | import { setVideoTags } from '@server/lib/video' | 9 | import { setVideoTags } from '@server/lib/video' |
9 | import { FilteredModelAttributes } from '@server/types' | 10 | import { FilteredModelAttributes } from '@server/types' |
@@ -18,15 +19,14 @@ import { | |||
18 | MVideoWithBlacklistLight | 19 | MVideoWithBlacklistLight |
19 | } from '@server/types/models' | 20 | } from '@server/types/models' |
20 | import { MVideoImportFormattable } from '@server/types/models/video/video-import' | 21 | import { MVideoImportFormattable } from '@server/types/models/video/video-import' |
21 | import { ServerErrorCode, VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '../../../../shared' | 22 | import { ServerErrorCode, ThumbnailType, VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '@shared/models' |
22 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | ||
23 | import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' | 23 | import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' |
24 | import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils' | 24 | import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils' |
25 | import { isArray } from '../../../helpers/custom-validators/misc' | 25 | import { isArray } from '../../../helpers/custom-validators/misc' |
26 | import { cleanUpReqFiles, createReqFiles } from '../../../helpers/express-utils' | 26 | import { cleanUpReqFiles, createReqFiles } from '../../../helpers/express-utils' |
27 | import { logger } from '../../../helpers/logger' | 27 | import { logger } from '../../../helpers/logger' |
28 | import { getSecureTorrentName } from '../../../helpers/utils' | 28 | import { getSecureTorrentName } from '../../../helpers/utils' |
29 | import { YoutubeDLWrapper, YoutubeDLInfo } from '../../../helpers/youtube-dl' | 29 | import { YoutubeDLInfo, YoutubeDLWrapper } from '../../../helpers/youtube-dl' |
30 | import { CONFIG } from '../../../initializers/config' | 30 | import { CONFIG } from '../../../initializers/config' |
31 | import { MIMETYPES } from '../../../initializers/constants' | 31 | import { MIMETYPES } from '../../../initializers/constants' |
32 | import { sequelizeTypescript } from '../../../initializers/database' | 32 | import { sequelizeTypescript } from '../../../initializers/database' |
@@ -94,7 +94,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
94 | videoName = result.name | 94 | videoName = result.name |
95 | } | 95 | } |
96 | 96 | ||
97 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) | 97 | const video = await buildVideo(res.locals.videoChannel.id, body, { name: videoName }) |
98 | 98 | ||
99 | const thumbnailModel = await processThumbnail(req, video) | 99 | const thumbnailModel = await processThumbnail(req, video) |
100 | const previewModel = await processPreview(req, video) | 100 | const previewModel = await processPreview(req, video) |
@@ -151,7 +151,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
151 | }) | 151 | }) |
152 | } | 152 | } |
153 | 153 | ||
154 | const video = buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) | 154 | const video = await buildVideo(res.locals.videoChannel.id, body, youtubeDLInfo) |
155 | 155 | ||
156 | // Process video thumbnail from request.files | 156 | // Process video thumbnail from request.files |
157 | let thumbnailModel = await processThumbnail(req, video) | 157 | let thumbnailModel = await processThumbnail(req, video) |
@@ -210,15 +210,15 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
210 | return res.json(videoImport.toFormattedJSON()).end() | 210 | return res.json(videoImport.toFormattedJSON()).end() |
211 | } | 211 | } |
212 | 212 | ||
213 | function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): MVideoThumbnail { | 213 | async function buildVideo (channelId: number, body: VideoImportCreate, importData: YoutubeDLInfo): Promise<MVideoThumbnail> { |
214 | const videoData = { | 214 | let videoData = { |
215 | name: body.name || importData.name || 'Unknown name', | 215 | name: body.name || importData.name || 'Unknown name', |
216 | remote: false, | 216 | remote: false, |
217 | category: body.category || importData.category, | 217 | category: body.category || importData.category, |
218 | licence: body.licence || importData.licence, | 218 | licence: body.licence ?? importData.licence ?? CONFIG.DEFAULTS.PUBLISH.LICENCE, |
219 | language: body.language || importData.language, | 219 | language: body.language || importData.language, |
220 | commentsEnabled: body.commentsEnabled !== false, // If the value is not "false", the default is "true" | 220 | commentsEnabled: body.commentsEnabled ?? CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED, |
221 | downloadEnabled: body.downloadEnabled !== false, | 221 | downloadEnabled: body.downloadEnabled ?? CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED, |
222 | waitTranscoding: body.waitTranscoding || false, | 222 | waitTranscoding: body.waitTranscoding || false, |
223 | state: VideoState.TO_IMPORT, | 223 | state: VideoState.TO_IMPORT, |
224 | nsfw: body.nsfw || importData.nsfw || false, | 224 | nsfw: body.nsfw || importData.nsfw || false, |
@@ -231,6 +231,14 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You | |||
231 | ? new Date(body.originallyPublishedAt) | 231 | ? new Date(body.originallyPublishedAt) |
232 | : importData.originallyPublishedAt | 232 | : importData.originallyPublishedAt |
233 | } | 233 | } |
234 | |||
235 | videoData = await Hooks.wrapObject( | ||
236 | videoData, | ||
237 | body.targetUrl | ||
238 | ? 'filter:api.video.import-url.video-attribute.result' | ||
239 | : 'filter:api.video.import-torrent.video-attribute.result' | ||
240 | ) | ||
241 | |||
234 | const video = new VideoModel(videoData) | 242 | const video = new VideoModel(videoData) |
235 | video.url = getLocalVideoActivityPubUrl(video) | 243 | video.url = getLocalVideoActivityPubUrl(video) |
236 | 244 | ||
diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts index e29615ff5..8b8cacff9 100644 --- a/server/controllers/api/videos/live.ts +++ b/server/controllers/api/videos/live.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { createReqFiles } from '@server/helpers/express-utils' | 2 | import { createReqFiles } from '@server/helpers/express-utils' |
3 | import { buildUUID, uuidToShort } from '@server/helpers/uuid' | ||
4 | import { CONFIG } from '@server/initializers/config' | 3 | import { CONFIG } from '@server/initializers/config' |
5 | import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants' | 4 | import { ASSETS_PATH, MIMETYPES } from '@server/initializers/constants' |
6 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' | 5 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' |
@@ -10,8 +9,8 @@ import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } fro | |||
10 | import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator } from '@server/middlewares/validators/videos/video-live' | 9 | import { videoLiveAddValidator, videoLiveGetValidator, videoLiveUpdateValidator } from '@server/middlewares/validators/videos/video-live' |
11 | import { VideoLiveModel } from '@server/models/video/video-live' | 10 | import { VideoLiveModel } from '@server/models/video/video-live' |
12 | import { MVideoDetails, MVideoFullLight } from '@server/types/models' | 11 | import { MVideoDetails, MVideoFullLight } from '@server/types/models' |
13 | import { LiveVideoCreate, LiveVideoUpdate, VideoState } from '../../../../shared' | 12 | import { buildUUID, uuidToShort } from '@shared/extra-utils' |
14 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 13 | import { HttpStatusCode, LiveVideoCreate, LiveVideoUpdate, VideoState } from '@shared/models' |
15 | import { logger } from '../../../helpers/logger' | 14 | import { logger } from '../../../helpers/logger' |
16 | import { sequelizeTypescript } from '../../../initializers/database' | 15 | import { sequelizeTypescript } from '../../../initializers/database' |
17 | import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' | 16 | import { updateVideoMiniatureFromExisting } from '../../../lib/thumbnail' |
@@ -83,7 +82,9 @@ async function addLiveVideo (req: express.Request, res: express.Response) { | |||
83 | const videoInfo: LiveVideoCreate = req.body | 82 | const videoInfo: LiveVideoCreate = req.body |
84 | 83 | ||
85 | // Prepare data so we don't block the transaction | 84 | // Prepare data so we don't block the transaction |
86 | const videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) | 85 | let videoData = buildLocalVideoFromReq(videoInfo, res.locals.videoChannel.id) |
86 | videoData = await Hooks.wrapObject(videoData, 'filter:api.video.live.video-attribute.result') | ||
87 | |||
87 | videoData.isLive = true | 88 | videoData.isLive = true |
88 | videoData.state = VideoState.WAITING_FOR_LIVE | 89 | videoData.state = VideoState.WAITING_FOR_LIVE |
89 | videoData.duration = 0 | 90 | videoData.duration = 0 |
diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index c9cc16644..6b26a8eee 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { UserVideoRateUpdate } from '../../../../shared' | 2 | import { HttpStatusCode, UserVideoRateUpdate } from '@shared/models' |
3 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
4 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
5 | import { VIDEO_RATE_TYPES } from '../../../initializers/constants' | 4 | import { VIDEO_RATE_TYPES } from '../../../initializers/constants' |
6 | import { sequelizeTypescript } from '../../../initializers/database' | 5 | import { sequelizeTypescript } from '../../../initializers/database' |
diff --git a/server/controllers/api/videos/transcoding.ts b/server/controllers/api/videos/transcoding.ts index dd6fbd3de..388689c8a 100644 --- a/server/controllers/api/videos/transcoding.ts +++ b/server/controllers/api/videos/transcoding.ts | |||
@@ -29,7 +29,7 @@ async function createTranscoding (req: express.Request, res: express.Response) { | |||
29 | 29 | ||
30 | const body: VideoTranscodingCreate = req.body | 30 | const body: VideoTranscodingCreate = req.body |
31 | 31 | ||
32 | const { resolution: maxResolution, isPortraitMode } = await video.getMaxQualityResolution() | 32 | const { resolution: maxResolution, isPortraitMode, audioStream } = await video.getMaxQualityFileInfo() |
33 | const resolutions = computeLowerResolutionsToTranscode(maxResolution, 'vod').concat([ maxResolution ]) | 33 | const resolutions = computeLowerResolutionsToTranscode(maxResolution, 'vod').concat([ maxResolution ]) |
34 | 34 | ||
35 | video.state = VideoState.TO_TRANSCODE | 35 | video.state = VideoState.TO_TRANSCODE |
@@ -42,6 +42,7 @@ async function createTranscoding (req: express.Request, res: express.Response) { | |||
42 | videoUUID: video.uuid, | 42 | videoUUID: video.uuid, |
43 | resolution, | 43 | resolution, |
44 | isPortraitMode, | 44 | isPortraitMode, |
45 | hasAudio: !!audioStream, | ||
45 | copyCodecs: false, | 46 | copyCodecs: false, |
46 | isNewVideo: false, | 47 | isNewVideo: false, |
47 | autoDeleteWebTorrentIfNeeded: false, | 48 | autoDeleteWebTorrentIfNeeded: false, |
@@ -53,6 +54,7 @@ async function createTranscoding (req: express.Request, res: express.Response) { | |||
53 | videoUUID: video.uuid, | 54 | videoUUID: video.uuid, |
54 | isNewVideo: false, | 55 | isNewVideo: false, |
55 | resolution: resolution, | 56 | resolution: resolution, |
57 | hasAudio: !!audioStream, | ||
56 | isPortraitMode | 58 | isPortraitMode |
57 | }) | 59 | }) |
58 | } | 60 | } |
diff --git a/server/controllers/api/videos/update.ts b/server/controllers/api/videos/update.ts index 3fcff3e86..f600847d4 100644 --- a/server/controllers/api/videos/update.ts +++ b/server/controllers/api/videos/update.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { Transaction } from 'sequelize/types' | 2 | import { Transaction } from 'sequelize/types' |
3 | import { updateTorrentMetadata } from '@server/helpers/webtorrent' | ||
3 | import { changeVideoChannelShare } from '@server/lib/activitypub/share' | 4 | import { changeVideoChannelShare } from '@server/lib/activitypub/share' |
4 | import { buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' | 5 | import { buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' |
5 | import { openapiOperationDoc } from '@server/middlewares/doc' | 6 | import { openapiOperationDoc } from '@server/middlewares/doc' |
6 | import { FilteredModelAttributes } from '@server/types' | 7 | import { FilteredModelAttributes } from '@server/types' |
7 | import { MVideoFullLight } from '@server/types/models' | 8 | import { MVideoFullLight } from '@server/types/models' |
8 | import { VideoUpdate } from '../../../../shared' | 9 | import { HttpStatusCode, VideoUpdate } from '@shared/models' |
9 | import { HttpStatusCode } from '../../../../shared/models' | ||
10 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 10 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
11 | import { resetSequelizeInstance } from '../../../helpers/database-utils' | 11 | import { resetSequelizeInstance } from '../../../helpers/database-utils' |
12 | import { createReqFiles } from '../../../helpers/express-utils' | 12 | import { createReqFiles } from '../../../helpers/express-utils' |
@@ -68,7 +68,7 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
68 | }) | 68 | }) |
69 | 69 | ||
70 | try { | 70 | try { |
71 | const videoInstanceUpdated = await sequelizeTypescript.transaction(async t => { | 71 | const { videoInstanceUpdated, isNewVideo } = await sequelizeTypescript.transaction(async t => { |
72 | // Refresh video since thumbnails to prevent concurrent updates | 72 | // Refresh video since thumbnails to prevent concurrent updates |
73 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t) | 73 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t) |
74 | 74 | ||
@@ -137,8 +137,6 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
137 | transaction: t | 137 | transaction: t |
138 | }) | 138 | }) |
139 | 139 | ||
140 | await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t) | ||
141 | |||
142 | auditLogger.update( | 140 | auditLogger.update( |
143 | getAuditIdFromRes(res), | 141 | getAuditIdFromRes(res), |
144 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), | 142 | new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), |
@@ -146,12 +144,14 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
146 | ) | 144 | ) |
147 | logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid)) | 145 | logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid)) |
148 | 146 | ||
149 | return videoInstanceUpdated | 147 | return { videoInstanceUpdated, isNewVideo } |
150 | }) | 148 | }) |
151 | 149 | ||
152 | if (wasConfidentialVideo) { | 150 | if (videoInfoToUpdate.name) await updateTorrentsMetadata(videoInstanceUpdated) |
153 | Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated) | 151 | |
154 | } | 152 | await sequelizeTypescript.transaction(t => federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)) |
153 | |||
154 | if (wasConfidentialVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated) | ||
155 | 155 | ||
156 | Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res }) | 156 | Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res }) |
157 | } catch (err) { | 157 | } catch (err) { |
@@ -199,3 +199,20 @@ function updateSchedule (videoInstance: MVideoFullLight, videoInfoToUpdate: Vide | |||
199 | return ScheduleVideoUpdateModel.deleteByVideoId(videoInstance.id, transaction) | 199 | return ScheduleVideoUpdateModel.deleteByVideoId(videoInstance.id, transaction) |
200 | } | 200 | } |
201 | } | 201 | } |
202 | |||
203 | async function updateTorrentsMetadata (video: MVideoFullLight) { | ||
204 | for (const file of (video.VideoFiles || [])) { | ||
205 | await updateTorrentMetadata(video, file) | ||
206 | |||
207 | await file.save() | ||
208 | } | ||
209 | |||
210 | const hls = video.getHLSPlaylist() | ||
211 | if (!hls) return | ||
212 | |||
213 | for (const file of (hls.VideoFiles || [])) { | ||
214 | await updateTorrentMetadata(hls, file) | ||
215 | |||
216 | await file.save() | ||
217 | } | ||
218 | } | ||
diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts index 6773b500f..89787f20b 100644 --- a/server/controllers/api/videos/upload.ts +++ b/server/controllers/api/videos/upload.ts | |||
@@ -1,13 +1,12 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { move } from 'fs-extra' | 2 | import { move } from 'fs-extra' |
3 | import { basename } from 'path' | 3 | import { basename } from 'path' |
4 | import { getLowercaseExtension } from '@server/helpers/core-utils' | ||
5 | import { getResumableUploadPath } from '@server/helpers/upload' | 4 | import { getResumableUploadPath } from '@server/helpers/upload' |
6 | import { uuidToShort } from '@server/helpers/uuid' | ||
7 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 5 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
8 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' | 6 | import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url' |
9 | import { generateWebTorrentVideoFilename } from '@server/lib/paths' | 7 | import { generateWebTorrentVideoFilename } from '@server/lib/paths' |
10 | import { Redis } from '@server/lib/redis' | 8 | import { Redis } from '@server/lib/redis' |
9 | import { uploadx } from '@server/lib/uploadx' | ||
11 | import { | 10 | import { |
12 | addMoveToObjectStorageJob, | 11 | addMoveToObjectStorageJob, |
13 | addOptimizeOrMergeAudioJob, | 12 | addOptimizeOrMergeAudioJob, |
@@ -19,16 +18,16 @@ import { VideoPathManager } from '@server/lib/video-path-manager' | |||
19 | import { buildNextVideoState } from '@server/lib/video-state' | 18 | import { buildNextVideoState } from '@server/lib/video-state' |
20 | import { openapiOperationDoc } from '@server/middlewares/doc' | 19 | import { openapiOperationDoc } from '@server/middlewares/doc' |
21 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' | 20 | import { MVideo, MVideoFile, MVideoFullLight } from '@server/types/models' |
22 | import { Uploadx } from '@uploadx/core' | 21 | import { getLowercaseExtension } from '@shared/core-utils' |
23 | import { VideoCreate, VideoState } from '../../../../shared' | 22 | import { isAudioFile, uuidToShort } from '@shared/extra-utils' |
24 | import { HttpStatusCode } from '../../../../shared/models' | 23 | import { HttpStatusCode, VideoCreate, VideoResolution, VideoState } from '@shared/models' |
25 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 24 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
26 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 25 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
27 | import { createReqFiles } from '../../../helpers/express-utils' | 26 | import { createReqFiles } from '../../../helpers/express-utils' |
28 | import { getMetadataFromFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' | 27 | import { ffprobePromise, getMetadataFromFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' |
29 | import { logger, loggerTagsFactory } from '../../../helpers/logger' | 28 | import { logger, loggerTagsFactory } from '../../../helpers/logger' |
30 | import { CONFIG } from '../../../initializers/config' | 29 | import { CONFIG } from '../../../initializers/config' |
31 | import { DEFAULT_AUDIO_RESOLUTION, MIMETYPES } from '../../../initializers/constants' | 30 | import { MIMETYPES } from '../../../initializers/constants' |
32 | import { sequelizeTypescript } from '../../../initializers/database' | 31 | import { sequelizeTypescript } from '../../../initializers/database' |
33 | import { federateVideoIfNeeded } from '../../../lib/activitypub/videos' | 32 | import { federateVideoIfNeeded } from '../../../lib/activitypub/videos' |
34 | import { Notifier } from '../../../lib/notifier' | 33 | import { Notifier } from '../../../lib/notifier' |
@@ -41,8 +40,8 @@ import { | |||
41 | authenticate, | 40 | authenticate, |
42 | videosAddLegacyValidator, | 41 | videosAddLegacyValidator, |
43 | videosAddResumableInitValidator, | 42 | videosAddResumableInitValidator, |
44 | videosResumableUploadIdValidator, | 43 | videosAddResumableValidator, |
45 | videosAddResumableValidator | 44 | videosResumableUploadIdValidator |
46 | } from '../../../middlewares' | 45 | } from '../../../middlewares' |
47 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' | 46 | import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' |
48 | import { VideoModel } from '../../../models/video/video' | 47 | import { VideoModel } from '../../../models/video/video' |
@@ -52,9 +51,6 @@ const lTags = loggerTagsFactory('api', 'video') | |||
52 | const auditLogger = auditLoggerFactory('videos') | 51 | const auditLogger = auditLoggerFactory('videos') |
53 | const uploadRouter = express.Router() | 52 | const uploadRouter = express.Router() |
54 | 53 | ||
55 | const uploadx = new Uploadx({ directory: getResumableUploadPath() }) | ||
56 | uploadx.getUserId = (_, res: express.Response) => res.locals.oauth?.token.user.id | ||
57 | |||
58 | const reqVideoFileAdd = createReqFiles( | 54 | const reqVideoFileAdd = createReqFiles( |
59 | [ 'videofile', 'thumbnailfile', 'previewfile' ], | 55 | [ 'videofile', 'thumbnailfile', 'previewfile' ], |
60 | Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), | 56 | Object.assign({}, MIMETYPES.VIDEO.MIMETYPE_EXT, MIMETYPES.IMAGE.MIMETYPE_EXT), |
@@ -156,7 +152,8 @@ async function addVideo (options: { | |||
156 | const videoChannel = res.locals.videoChannel | 152 | const videoChannel = res.locals.videoChannel |
157 | const user = res.locals.oauth.token.User | 153 | const user = res.locals.oauth.token.User |
158 | 154 | ||
159 | const videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) | 155 | let videoData = buildLocalVideoFromReq(videoInfo, videoChannel.id) |
156 | videoData = await Hooks.wrapObject(videoData, 'filter:api.video.upload.video-attribute.result') | ||
160 | 157 | ||
161 | videoData.state = buildNextVideoState() | 158 | videoData.state = buildNextVideoState() |
162 | videoData.duration = videoPhysicalFile.duration // duration was added by a previous middleware | 159 | videoData.duration = videoPhysicalFile.duration // duration was added by a previous middleware |
@@ -255,11 +252,13 @@ async function buildNewFile (videoPhysicalFile: express.VideoUploadFile) { | |||
255 | metadata: await getMetadataFromFile(videoPhysicalFile.path) | 252 | metadata: await getMetadataFromFile(videoPhysicalFile.path) |
256 | }) | 253 | }) |
257 | 254 | ||
258 | if (videoFile.isAudio()) { | 255 | const probe = await ffprobePromise(videoPhysicalFile.path) |
259 | videoFile.resolution = DEFAULT_AUDIO_RESOLUTION | 256 | |
257 | if (await isAudioFile(videoPhysicalFile.path, probe)) { | ||
258 | videoFile.resolution = VideoResolution.H_NOVIDEO | ||
260 | } else { | 259 | } else { |
261 | videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path) | 260 | videoFile.fps = await getVideoFileFPS(videoPhysicalFile.path, probe) |
262 | videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path)).resolution | 261 | videoFile.resolution = (await getVideoFileResolution(videoPhysicalFile.path, probe)).resolution |
263 | } | 262 | } |
264 | 263 | ||
265 | videoFile.filename = generateWebTorrentVideoFilename(videoFile.resolution, videoFile.extname) | 264 | videoFile.filename = generateWebTorrentVideoFilename(videoFile.resolution, videoFile.extname) |
diff --git a/server/controllers/api/videos/watching.ts b/server/controllers/api/videos/watching.ts index e8c28b613..3fd22caac 100644 --- a/server/controllers/api/videos/watching.ts +++ b/server/controllers/api/videos/watching.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { UserWatchingVideo } from '../../../../shared' | 2 | import { HttpStatusCode, UserWatchingVideo } from '@shared/models' |
3 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
4 | import { | 3 | import { |
5 | asyncMiddleware, | 4 | asyncMiddleware, |
6 | asyncRetryTransactionMiddleware, | 5 | asyncRetryTransactionMiddleware, |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 2157ae533..8a56f2f75 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -7,7 +7,7 @@ import { CONFIG } from '@server/initializers/config' | |||
7 | import { Hooks } from '@server/lib/plugins/hooks' | 7 | import { Hooks } from '@server/lib/plugins/hooks' |
8 | import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '@shared/core-utils/i18n' | 8 | import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '@shared/core-utils/i18n' |
9 | import { HttpStatusCode } from '@shared/models' | 9 | import { HttpStatusCode } from '@shared/models' |
10 | import { root } from '../helpers/core-utils' | 10 | import { root } from '@shared/core-utils' |
11 | import { STATIC_MAX_AGE } from '../initializers/constants' | 11 | import { STATIC_MAX_AGE } from '../initializers/constants' |
12 | import { ClientHtml, sendHTML, serveIndexHTML } from '../lib/client-html' | 12 | import { ClientHtml, sendHTML, serveIndexHTML } from '../lib/client-html' |
13 | import { asyncMiddleware, embedCSP } from '../middlewares' | 13 | import { asyncMiddleware, embedCSP } from '../middlewares' |
diff --git a/server/controllers/static.ts b/server/controllers/static.ts index 0d94cac9b..87bceba7a 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts | |||
@@ -5,7 +5,7 @@ import { serveIndexHTML } from '@server/lib/client-html' | |||
5 | import { ServerConfigManager } from '@server/lib/server-config-manager' | 5 | import { ServerConfigManager } from '@server/lib/server-config-manager' |
6 | import { HttpStatusCode } from '@shared/models' | 6 | import { HttpStatusCode } from '@shared/models' |
7 | import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo/nodeinfo.model' | 7 | import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo/nodeinfo.model' |
8 | import { root } from '../helpers/core-utils' | 8 | import { root } from '@shared/core-utils' |
9 | import { CONFIG, isEmailEnabled } from '../initializers/config' | 9 | import { CONFIG, isEmailEnabled } from '../initializers/config' |
10 | import { | 10 | import { |
11 | CONSTRAINTS_FIELDS, | 11 | CONSTRAINTS_FIELDS, |
diff --git a/server/helpers/actors.ts b/server/helpers/actors.ts new file mode 100644 index 000000000..c31fe6f8e --- /dev/null +++ b/server/helpers/actors.ts | |||
@@ -0,0 +1,17 @@ | |||
1 | import { WEBSERVER } from '@server/initializers/constants' | ||
2 | |||
3 | function handleToNameAndHost (handle: string) { | ||
4 | let [ name, host ] = handle.split('@') | ||
5 | if (host === WEBSERVER.HOST) host = null | ||
6 | |||
7 | return { name, host, handle } | ||
8 | } | ||
9 | |||
10 | function handlesToNameAndHost (handles: string[]) { | ||
11 | return handles.map(h => handleToNameAndHost(h)) | ||
12 | } | ||
13 | |||
14 | export { | ||
15 | handleToNameAndHost, | ||
16 | handlesToNameAndHost | ||
17 | } | ||
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 5f2e870e3..79ef44be1 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -5,9 +5,7 @@ import { chain } from 'lodash' | |||
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { addColors, config, createLogger, format, transports } from 'winston' | 6 | import { addColors, config, createLogger, format, transports } from 'winston' |
7 | import { AUDIT_LOG_FILENAME } from '@server/initializers/constants' | 7 | import { AUDIT_LOG_FILENAME } from '@server/initializers/constants' |
8 | import { AdminAbuse, User, VideoChannel, VideoDetails, VideoImport } from '../../shared' | 8 | import { AdminAbuse, CustomConfig, User, VideoChannel, VideoComment, VideoDetails, VideoImport } from '@shared/models' |
9 | import { CustomConfig } from '../../shared/models/server/custom-config.model' | ||
10 | import { VideoComment } from '../../shared/models/videos/comment/video-comment.model' | ||
11 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
12 | import { jsonLoggerFormat, labelFormatter } from './logger' | 10 | import { jsonLoggerFormat, labelFormatter } from './logger' |
13 | 11 | ||
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index 2cbf0f8fe..531ccfba9 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -6,9 +6,8 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | import { exec, ExecOptions } from 'child_process' | 8 | import { exec, ExecOptions } from 'child_process' |
9 | import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto' | 9 | import { randomBytes } from 'crypto' |
10 | import { truncate } from 'lodash' | 10 | import { truncate } from 'lodash' |
11 | import { basename, extname, isAbsolute, join, resolve } from 'path' | ||
12 | import { createPrivateKey as createPrivateKey_1, getPublicKey as getPublicKey_1 } from 'pem' | 11 | import { createPrivateKey as createPrivateKey_1, getPublicKey as getPublicKey_1 } from 'pem' |
13 | import { pipeline } from 'stream' | 12 | import { pipeline } from 'stream' |
14 | import { URL } from 'url' | 13 | import { URL } from 'url' |
@@ -159,34 +158,6 @@ function getAppNumber () { | |||
159 | 158 | ||
160 | // --------------------------------------------------------------------------- | 159 | // --------------------------------------------------------------------------- |
161 | 160 | ||
162 | let rootPath: string | ||
163 | |||
164 | function root () { | ||
165 | if (rootPath) return rootPath | ||
166 | |||
167 | rootPath = __dirname | ||
168 | |||
169 | if (basename(rootPath) === 'helpers') rootPath = resolve(rootPath, '..') | ||
170 | if (basename(rootPath) === 'server') rootPath = resolve(rootPath, '..') | ||
171 | if (basename(rootPath) === 'dist') rootPath = resolve(rootPath, '..') | ||
172 | |||
173 | return rootPath | ||
174 | } | ||
175 | |||
176 | function buildPath (path: string) { | ||
177 | if (isAbsolute(path)) return path | ||
178 | |||
179 | return join(root(), path) | ||
180 | } | ||
181 | |||
182 | function getLowercaseExtension (filename: string) { | ||
183 | const ext = extname(filename) || '' | ||
184 | |||
185 | return ext.toLowerCase() | ||
186 | } | ||
187 | |||
188 | // --------------------------------------------------------------------------- | ||
189 | |||
190 | // Consistent with .length, lodash truncate function is not | 161 | // Consistent with .length, lodash truncate function is not |
191 | function peertubeTruncate (str: string, options: { length: number, separator?: RegExp, omission?: string }) { | 162 | function peertubeTruncate (str: string, options: { length: number, separator?: RegExp, omission?: string }) { |
192 | const truncatedStr = truncate(str, options) | 163 | const truncatedStr = truncate(str, options) |
@@ -221,16 +192,6 @@ function parseSemVersion (s: string) { | |||
221 | 192 | ||
222 | // --------------------------------------------------------------------------- | 193 | // --------------------------------------------------------------------------- |
223 | 194 | ||
224 | function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { | ||
225 | return createHash('sha256').update(str).digest(encoding) | ||
226 | } | ||
227 | |||
228 | function sha1 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { | ||
229 | return createHash('sha1').update(str).digest(encoding) | ||
230 | } | ||
231 | |||
232 | // --------------------------------------------------------------------------- | ||
233 | |||
234 | function execShell (command: string, options?: ExecOptions) { | 195 | function execShell (command: string, options?: ExecOptions) { |
235 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { | 196 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { |
236 | exec(command, options, (err, stdout, stderr) => { | 197 | exec(command, options, (err, stdout, stderr) => { |
@@ -298,9 +259,6 @@ export { | |||
298 | objectConverter, | 259 | objectConverter, |
299 | mapToJSON, | 260 | mapToJSON, |
300 | 261 | ||
301 | root, | ||
302 | buildPath, | ||
303 | getLowercaseExtension, | ||
304 | sanitizeUrl, | 262 | sanitizeUrl, |
305 | sanitizeHost, | 263 | sanitizeHost, |
306 | 264 | ||
@@ -309,9 +267,6 @@ export { | |||
309 | pageToStartAndCount, | 267 | pageToStartAndCount, |
310 | peertubeTruncate, | 268 | peertubeTruncate, |
311 | 269 | ||
312 | sha256, | ||
313 | sha1, | ||
314 | |||
315 | promisify0, | 270 | promisify0, |
316 | promisify1, | 271 | promisify1, |
317 | promisify2, | 272 | promisify2, |
diff --git a/server/helpers/custom-validators/activitypub/playlist.ts b/server/helpers/custom-validators/activitypub/playlist.ts index 72c5b80e9..49bcadcfd 100644 --- a/server/helpers/custom-validators/activitypub/playlist.ts +++ b/server/helpers/custom-validators/activitypub/playlist.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import validator from 'validator' | 1 | import validator from 'validator' |
2 | import { PlaylistElementObject } from '../../../../shared/models/activitypub/objects/playlist-element-object' | 2 | import { PlaylistElementObject, PlaylistObject } from '@shared/models' |
3 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | ||
4 | import { exists, isDateValid, isUUIDValid } from '../misc' | 3 | import { exists, isDateValid, isUUIDValid } from '../misc' |
5 | import { isVideoPlaylistNameValid } from '../video-playlists' | 4 | import { isVideoPlaylistNameValid } from '../video-playlists' |
6 | import { isActivityPubUrlValid } from './misc' | 5 | import { isActivityPubUrlValid } from './misc' |
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index c19a3e5eb..81a60ee66 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts | |||
@@ -2,7 +2,7 @@ import 'multer' | |||
2 | import { UploadFilesForCheck } from 'express' | 2 | import { UploadFilesForCheck } from 'express' |
3 | import { sep } from 'path' | 3 | import { sep } from 'path' |
4 | import validator from 'validator' | 4 | import validator from 'validator' |
5 | import { isShortUUID, shortToUUID } from '../uuid' | 5 | import { isShortUUID, shortToUUID } from '@shared/extra-utils' |
6 | 6 | ||
7 | function exists (value: any) { | 7 | function exists (value: any) { |
8 | return value !== undefined && value !== null | 8 | return value !== undefined && value !== null |
diff --git a/server/helpers/custom-validators/plugins.ts b/server/helpers/custom-validators/plugins.ts index f2d4efb32..60b29dc89 100644 --- a/server/helpers/custom-validators/plugins.ts +++ b/server/helpers/custom-validators/plugins.ts | |||
@@ -2,7 +2,7 @@ import { exists, isArray, isSafePath } from './misc' | |||
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 3 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 4 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
5 | import { PluginPackageJson } from '../../../shared/models/plugins/plugin-package-json.model' | 5 | import { PluginPackageJSON } from '../../../shared/models/plugins/plugin-package-json.model' |
6 | import { isUrlValid } from './activitypub/misc' | 6 | import { isUrlValid } from './activitypub/misc' |
7 | 7 | ||
8 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS | 8 | const PLUGINS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.PLUGINS |
@@ -84,7 +84,7 @@ function isThemeNameValid (name: string) { | |||
84 | return isPluginNameValid(name) | 84 | return isPluginNameValid(name) |
85 | } | 85 | } |
86 | 86 | ||
87 | function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginType) { | 87 | function isPackageJSONValid (packageJSON: PluginPackageJSON, pluginType: PluginType) { |
88 | let result = true | 88 | let result = true |
89 | const badFields: string[] = [] | 89 | const badFields: string[] = [] |
90 | 90 | ||
diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index f52c60b60..b04970108 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { UserRole } from '../../../shared' | 3 | import { UserRole } from '@shared/models' |
4 | import { isEmailEnabled } from '../../initializers/config' | 4 | import { isEmailEnabled } from '../../initializers/config' |
5 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers/constants' | 5 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers/constants' |
6 | import { exists, isArray, isBooleanValid } from './misc' | 6 | import { exists, isArray, isBooleanValid } from './misc' |
@@ -49,7 +49,7 @@ function isUserNSFWPolicyValid (value: any) { | |||
49 | return exists(value) && nsfwPolicies.includes(value) | 49 | return exists(value) && nsfwPolicies.includes(value) |
50 | } | 50 | } |
51 | 51 | ||
52 | function isUserWebTorrentEnabledValid (value: any) { | 52 | function isUserP2PEnabledValid (value: any) { |
53 | return isBooleanValid(value) | 53 | return isBooleanValid(value) |
54 | } | 54 | } |
55 | 55 | ||
@@ -90,7 +90,7 @@ function isUserBlockedReasonValid (value: any) { | |||
90 | } | 90 | } |
91 | 91 | ||
92 | function isUserRoleValid (value: any) { | 92 | function isUserRoleValid (value: any) { |
93 | return exists(value) && validator.isInt('' + value) && UserRole[value] !== undefined | 93 | return exists(value) && validator.isInt('' + value) && [ UserRole.ADMINISTRATOR, UserRole.MODERATOR, UserRole.USER ].includes(value) |
94 | } | 94 | } |
95 | 95 | ||
96 | // --------------------------------------------------------------------------- | 96 | // --------------------------------------------------------------------------- |
@@ -109,7 +109,7 @@ export { | |||
109 | isUserAdminFlagsValid, | 109 | isUserAdminFlagsValid, |
110 | isUserEmailVerifiedValid, | 110 | isUserEmailVerifiedValid, |
111 | isUserNSFWPolicyValid, | 111 | isUserNSFWPolicyValid, |
112 | isUserWebTorrentEnabledValid, | 112 | isUserP2PEnabledValid, |
113 | isUserAutoPlayVideoValid, | 113 | isUserAutoPlayVideoValid, |
114 | isUserAutoPlayNextVideoValid, | 114 | isUserAutoPlayNextVideoValid, |
115 | isUserAutoPlayNextVideoPlaylistValid, | 115 | isUserAutoPlayNextVideoPlaylistValid, |
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 1d56ade6f..e526c4284 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -2,8 +2,7 @@ import { UploadFilesForCheck } from 'express' | |||
2 | import { values } from 'lodash' | 2 | import { values } from 'lodash' |
3 | import magnetUtil from 'magnet-uri' | 3 | import magnetUtil from 'magnet-uri' |
4 | import validator from 'validator' | 4 | import validator from 'validator' |
5 | import { VideoInclude } from '@shared/models' | 5 | import { VideoFilter, VideoInclude, VideoPrivacy, VideoRateType } from '@shared/models' |
6 | import { VideoFilter, VideoPrivacy, VideoRateType } from '../../../shared' | ||
7 | import { | 6 | import { |
8 | CONSTRAINTS_FIELDS, | 7 | CONSTRAINTS_FIELDS, |
9 | MIMETYPES, | 8 | MIMETYPES, |
diff --git a/server/helpers/decache.ts b/server/helpers/decache.ts new file mode 100644 index 000000000..e31973b7a --- /dev/null +++ b/server/helpers/decache.ts | |||
@@ -0,0 +1,78 @@ | |||
1 | // Thanks: https://github.com/dwyl/decache | ||
2 | // We reuse this file to also uncache plugin base path | ||
3 | |||
4 | import { extname } from 'path' | ||
5 | |||
6 | function decachePlugin (pluginPath: string, libraryPath: string) { | ||
7 | const moduleName = find(libraryPath) | ||
8 | |||
9 | if (!moduleName) return | ||
10 | |||
11 | searchCache(moduleName, function (mod) { | ||
12 | delete require.cache[mod.id] | ||
13 | }) | ||
14 | |||
15 | removeCachedPath(pluginPath) | ||
16 | } | ||
17 | |||
18 | function decacheModule (name: string) { | ||
19 | const moduleName = find(name) | ||
20 | |||
21 | if (!moduleName) return | ||
22 | |||
23 | searchCache(moduleName, function (mod) { | ||
24 | delete require.cache[mod.id] | ||
25 | }) | ||
26 | |||
27 | removeCachedPath(moduleName) | ||
28 | } | ||
29 | |||
30 | // --------------------------------------------------------------------------- | ||
31 | |||
32 | export { | ||
33 | decacheModule, | ||
34 | decachePlugin | ||
35 | } | ||
36 | |||
37 | // --------------------------------------------------------------------------- | ||
38 | |||
39 | function find (moduleName: string) { | ||
40 | try { | ||
41 | return require.resolve(moduleName) | ||
42 | } catch { | ||
43 | return '' | ||
44 | } | ||
45 | } | ||
46 | |||
47 | function searchCache (moduleName: string, callback: (current: NodeModule) => void) { | ||
48 | const resolvedModule = require.resolve(moduleName) | ||
49 | let mod: NodeModule | ||
50 | const visited = {} | ||
51 | |||
52 | if (resolvedModule && ((mod = require.cache[resolvedModule]) !== undefined)) { | ||
53 | // Recursively go over the results | ||
54 | (function run (current) { | ||
55 | visited[current.id] = true | ||
56 | |||
57 | current.children.forEach(function (child) { | ||
58 | if (extname(child.filename) !== '.node' && !visited[child.id]) { | ||
59 | run(child) | ||
60 | } | ||
61 | }) | ||
62 | |||
63 | // Call the specified callback providing the | ||
64 | // found module | ||
65 | callback(current) | ||
66 | })(mod) | ||
67 | } | ||
68 | }; | ||
69 | |||
70 | function removeCachedPath (pluginPath: string) { | ||
71 | const pathCache = (module.constructor as any)._pathCache | ||
72 | |||
73 | Object.keys(pathCache).forEach(function (cacheKey) { | ||
74 | if (cacheKey.includes(pluginPath)) { | ||
75 | delete pathCache[cacheKey] | ||
76 | } | ||
77 | }) | ||
78 | } | ||
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 7b81ed71b..780fd6345 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import express from 'express' | 1 | import express, { RequestHandler } from 'express' |
2 | import multer, { diskStorage } from 'multer' | 2 | import multer, { diskStorage } from 'multer' |
3 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' | 3 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' |
4 | import { CONFIG } from '../initializers/config' | 4 | import { CONFIG } from '../initializers/config' |
5 | import { REMOTE_SCHEME } from '../initializers/constants' | 5 | import { REMOTE_SCHEME } from '../initializers/constants' |
6 | import { getLowercaseExtension } from './core-utils' | 6 | import { getLowercaseExtension } from '@shared/core-utils' |
7 | import { isArray } from './custom-validators/misc' | 7 | import { isArray } from './custom-validators/misc' |
8 | import { logger } from './logger' | 8 | import { logger } from './logger' |
9 | import { deleteFileAndCatch, generateRandomString } from './utils' | 9 | import { deleteFileAndCatch, generateRandomString } from './utils' |
@@ -69,7 +69,7 @@ function createReqFiles ( | |||
69 | fieldNames: string[], | 69 | fieldNames: string[], |
70 | mimeTypes: { [id: string]: string | string[] }, | 70 | mimeTypes: { [id: string]: string | string[] }, |
71 | destinations: { [fieldName: string]: string } | 71 | destinations: { [fieldName: string]: string } |
72 | ) { | 72 | ): RequestHandler { |
73 | const storage = diskStorage({ | 73 | const storage = diskStorage({ |
74 | destination: (req, file, cb) => { | 74 | destination: (req, file, cb) => { |
75 | cb(null, destinations[file.fieldname]) | 75 | cb(null, destinations[file.fieldname]) |
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index ab29d4691..78ee5fa7f 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -287,8 +287,8 @@ async function getLiveTranscodingCommand (options: { | |||
287 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) | 287 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) |
288 | 288 | ||
289 | logger.debug( | 289 | logger.debug( |
290 | 'Apply ffmpeg live video params from %s using %s profile.', builderResult.encoder, profile, builderResult, | 290 | 'Apply ffmpeg live video params from %s using %s profile.', builderResult.encoder, profile, |
291 | { fps: resolutionFPS, resolution, ...lTags() } | 291 | { builderResult, fps: resolutionFPS, resolution, ...lTags() } |
292 | ) | 292 | ) |
293 | 293 | ||
294 | command.outputOption(`${buildStreamSuffix('-c:v', i)} ${builderResult.encoder}`) | 294 | command.outputOption(`${buildStreamSuffix('-c:v', i)} ${builderResult.encoder}`) |
@@ -314,8 +314,8 @@ async function getLiveTranscodingCommand (options: { | |||
314 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) | 314 | addDefaultEncoderParams({ command, encoder: builderResult.encoder, fps: resolutionFPS, streamNum: i }) |
315 | 315 | ||
316 | logger.debug( | 316 | logger.debug( |
317 | 'Apply ffmpeg live audio params from %s using %s profile.', builderResult.encoder, profile, builderResult, | 317 | 'Apply ffmpeg live audio params from %s using %s profile.', builderResult.encoder, profile, |
318 | { fps: resolutionFPS, resolution, ...lTags() } | 318 | { builderResult, fps: resolutionFPS, resolution, ...lTags() } |
319 | ) | 319 | ) |
320 | 320 | ||
321 | command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`) | 321 | command.outputOption(`${buildStreamSuffix('-c:a', i)} ${builderResult.encoder}`) |
@@ -368,10 +368,6 @@ function addDefaultEncoderGlobalParams (options: { | |||
368 | command.outputOption('-max_muxing_queue_size 1024') | 368 | command.outputOption('-max_muxing_queue_size 1024') |
369 | // strip all metadata | 369 | // strip all metadata |
370 | .outputOption('-map_metadata -1') | 370 | .outputOption('-map_metadata -1') |
371 | // NOTE: b-strategy 1 - heuristic algorithm, 16 is optimal B-frames for it | ||
372 | .outputOption('-b_strategy 1') | ||
373 | // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16 | ||
374 | .outputOption('-bf 16') | ||
375 | // allows import of source material with incompatible pixel formats (e.g. MJPEG video) | 371 | // allows import of source material with incompatible pixel formats (e.g. MJPEG video) |
376 | .outputOption('-pix_fmt yuv420p') | 372 | .outputOption('-pix_fmt yuv420p') |
377 | } | 373 | } |
@@ -627,8 +623,8 @@ async function presetVideo (options: { | |||
627 | 623 | ||
628 | logger.debug( | 624 | logger.debug( |
629 | 'Apply ffmpeg params from %s for %s stream of input %s using %s profile.', | 625 | 'Apply ffmpeg params from %s for %s stream of input %s using %s profile.', |
630 | builderResult.encoder, streamType, input, profile, builderResult, | 626 | builderResult.encoder, streamType, input, profile, |
631 | { resolution, fps, ...lTags() } | 627 | { builderResult, resolution, fps, ...lTags() } |
632 | ) | 628 | ) |
633 | 629 | ||
634 | if (streamType === 'video') { | 630 | if (streamType === 'video') { |
@@ -734,7 +730,7 @@ async function runCommand (options: { | |||
734 | command.on('start', cmdline => { shellCommand = cmdline }) | 730 | command.on('start', cmdline => { shellCommand = cmdline }) |
735 | 731 | ||
736 | command.on('error', (err, stdout, stderr) => { | 732 | command.on('error', (err, stdout, stderr) => { |
737 | if (silent !== true) logger.error('Error in ffmpeg.', { stdout, stderr, ...lTags() }) | 733 | if (silent !== true) logger.error('Error in ffmpeg.', { stdout, stderr, shellCommand, ...lTags() }) |
738 | 734 | ||
739 | rej(err) | 735 | rej(err) |
740 | }) | 736 | }) |
diff --git a/server/helpers/ffprobe-utils.ts b/server/helpers/ffprobe-utils.ts index e15628e2a..595112bce 100644 --- a/server/helpers/ffprobe-utils.ts +++ b/server/helpers/ffprobe-utils.ts | |||
@@ -1,9 +1,22 @@ | |||
1 | import { ffprobe, FfprobeData } from 'fluent-ffmpeg' | 1 | import { FfprobeData } from 'fluent-ffmpeg' |
2 | import { getMaxBitrate } from '@shared/core-utils' | 2 | import { getMaxBitrate } from '@shared/core-utils' |
3 | import { VideoFileMetadata, VideoResolution, VideoTranscodingFPS } from '../../shared/models/videos' | 3 | import { VideoResolution, VideoTranscodingFPS } from '../../shared/models/videos' |
4 | import { CONFIG } from '../initializers/config' | 4 | import { CONFIG } from '../initializers/config' |
5 | import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' | 5 | import { VIDEO_TRANSCODING_FPS } from '../initializers/constants' |
6 | import { logger } from './logger' | 6 | import { logger } from './logger' |
7 | import { | ||
8 | canDoQuickAudioTranscode, | ||
9 | ffprobePromise, | ||
10 | getDurationFromVideoFile, | ||
11 | getAudioStream, | ||
12 | getMaxAudioBitrate, | ||
13 | getMetadataFromFile, | ||
14 | getVideoFileBitrate, | ||
15 | getVideoFileFPS, | ||
16 | getVideoFileResolution, | ||
17 | getVideoStreamFromFile, | ||
18 | getVideoStreamSize | ||
19 | } from '@shared/extra-utils/ffprobe' | ||
7 | 20 | ||
8 | /** | 21 | /** |
9 | * | 22 | * |
@@ -11,79 +24,6 @@ import { logger } from './logger' | |||
11 | * | 24 | * |
12 | */ | 25 | */ |
13 | 26 | ||
14 | function ffprobePromise (path: string) { | ||
15 | return new Promise<FfprobeData>((res, rej) => { | ||
16 | ffprobe(path, (err, data) => { | ||
17 | if (err) return rej(err) | ||
18 | |||
19 | return res(data) | ||
20 | }) | ||
21 | }) | ||
22 | } | ||
23 | |||
24 | async function getAudioStream (videoPath: string, existingProbe?: FfprobeData) { | ||
25 | // without position, ffprobe considers the last input only | ||
26 | // we make it consider the first input only | ||
27 | // if you pass a file path to pos, then ffprobe acts on that file directly | ||
28 | const data = existingProbe || await ffprobePromise(videoPath) | ||
29 | |||
30 | if (Array.isArray(data.streams)) { | ||
31 | const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio') | ||
32 | |||
33 | if (audioStream) { | ||
34 | return { | ||
35 | absolutePath: data.format.filename, | ||
36 | audioStream, | ||
37 | bitrate: parseInt(audioStream['bit_rate'] + '', 10) | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | return { absolutePath: data.format.filename } | ||
43 | } | ||
44 | |||
45 | function getMaxAudioBitrate (type: 'aac' | 'mp3' | string, bitrate: number) { | ||
46 | const maxKBitrate = 384 | ||
47 | const kToBits = (kbits: number) => kbits * 1000 | ||
48 | |||
49 | // If we did not manage to get the bitrate, use an average value | ||
50 | if (!bitrate) return 256 | ||
51 | |||
52 | if (type === 'aac') { | ||
53 | switch (true) { | ||
54 | case bitrate > kToBits(maxKBitrate): | ||
55 | return maxKBitrate | ||
56 | |||
57 | default: | ||
58 | return -1 // we interpret it as a signal to copy the audio stream as is | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac. | ||
64 | That's why, when using aac, we can go to lower kbit/sec. The equivalences | ||
65 | made here are not made to be accurate, especially with good mp3 encoders. | ||
66 | */ | ||
67 | switch (true) { | ||
68 | case bitrate <= kToBits(192): | ||
69 | return 128 | ||
70 | |||
71 | case bitrate <= kToBits(384): | ||
72 | return 256 | ||
73 | |||
74 | default: | ||
75 | return maxKBitrate | ||
76 | } | ||
77 | } | ||
78 | |||
79 | async function getVideoStreamSize (path: string, existingProbe?: FfprobeData): Promise<{ width: number, height: number }> { | ||
80 | const videoStream = await getVideoStreamFromFile(path, existingProbe) | ||
81 | |||
82 | return videoStream === null | ||
83 | ? { width: 0, height: 0 } | ||
84 | : { width: videoStream.width, height: videoStream.height } | ||
85 | } | ||
86 | |||
87 | async function getVideoStreamCodec (path: string) { | 27 | async function getVideoStreamCodec (path: string) { |
88 | const videoStream = await getVideoStreamFromFile(path) | 28 | const videoStream = await getVideoStreamFromFile(path) |
89 | 29 | ||
@@ -143,69 +83,6 @@ async function getAudioStreamCodec (path: string, existingProbe?: FfprobeData) { | |||
143 | return 'mp4a.40.2' // Fallback | 83 | return 'mp4a.40.2' // Fallback |
144 | } | 84 | } |
145 | 85 | ||
146 | async function getVideoFileResolution (path: string, existingProbe?: FfprobeData) { | ||
147 | const size = await getVideoStreamSize(path, existingProbe) | ||
148 | |||
149 | return { | ||
150 | width: size.width, | ||
151 | height: size.height, | ||
152 | ratio: Math.max(size.height, size.width) / Math.min(size.height, size.width), | ||
153 | resolution: Math.min(size.height, size.width), | ||
154 | isPortraitMode: size.height > size.width | ||
155 | } | ||
156 | } | ||
157 | |||
158 | async function getVideoFileFPS (path: string, existingProbe?: FfprobeData) { | ||
159 | const videoStream = await getVideoStreamFromFile(path, existingProbe) | ||
160 | if (videoStream === null) return 0 | ||
161 | |||
162 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { | ||
163 | const valuesText: string = videoStream[key] | ||
164 | if (!valuesText) continue | ||
165 | |||
166 | const [ frames, seconds ] = valuesText.split('/') | ||
167 | if (!frames || !seconds) continue | ||
168 | |||
169 | const result = parseInt(frames, 10) / parseInt(seconds, 10) | ||
170 | if (result > 0) return Math.round(result) | ||
171 | } | ||
172 | |||
173 | return 0 | ||
174 | } | ||
175 | |||
176 | async function getMetadataFromFile (path: string, existingProbe?: FfprobeData) { | ||
177 | const metadata = existingProbe || await ffprobePromise(path) | ||
178 | |||
179 | return new VideoFileMetadata(metadata) | ||
180 | } | ||
181 | |||
182 | async function getVideoFileBitrate (path: string, existingProbe?: FfprobeData): Promise<number> { | ||
183 | const metadata = await getMetadataFromFile(path, existingProbe) | ||
184 | |||
185 | let bitrate = metadata.format.bit_rate as number | ||
186 | if (bitrate && !isNaN(bitrate)) return bitrate | ||
187 | |||
188 | const videoStream = await getVideoStreamFromFile(path, existingProbe) | ||
189 | if (!videoStream) return undefined | ||
190 | |||
191 | bitrate = videoStream?.bit_rate | ||
192 | if (bitrate && !isNaN(bitrate)) return bitrate | ||
193 | |||
194 | return undefined | ||
195 | } | ||
196 | |||
197 | async function getDurationFromVideoFile (path: string, existingProbe?: FfprobeData) { | ||
198 | const metadata = await getMetadataFromFile(path, existingProbe) | ||
199 | |||
200 | return Math.round(metadata.format.duration) | ||
201 | } | ||
202 | |||
203 | async function getVideoStreamFromFile (path: string, existingProbe?: FfprobeData) { | ||
204 | const metadata = await getMetadataFromFile(path, existingProbe) | ||
205 | |||
206 | return metadata.streams.find(s => s.codec_type === 'video') || null | ||
207 | } | ||
208 | |||
209 | function computeLowerResolutionsToTranscode (videoFileResolution: number, type: 'vod' | 'live') { | 86 | function computeLowerResolutionsToTranscode (videoFileResolution: number, type: 'vod' | 'live') { |
210 | const configResolutions = type === 'vod' | 87 | const configResolutions = type === 'vod' |
211 | ? CONFIG.TRANSCODING.RESOLUTIONS | 88 | ? CONFIG.TRANSCODING.RESOLUTIONS |
@@ -263,26 +140,6 @@ async function canDoQuickVideoTranscode (path: string, probe?: FfprobeData): Pro | |||
263 | return true | 140 | return true |
264 | } | 141 | } |
265 | 142 | ||
266 | async function canDoQuickAudioTranscode (path: string, probe?: FfprobeData): Promise<boolean> { | ||
267 | const parsedAudio = await getAudioStream(path, probe) | ||
268 | |||
269 | if (!parsedAudio.audioStream) return true | ||
270 | |||
271 | if (parsedAudio.audioStream['codec_name'] !== 'aac') return false | ||
272 | |||
273 | const audioBitrate = parsedAudio.bitrate | ||
274 | if (!audioBitrate) return false | ||
275 | |||
276 | const maxAudioBitrate = getMaxAudioBitrate('aac', audioBitrate) | ||
277 | if (maxAudioBitrate !== -1 && audioBitrate > maxAudioBitrate) return false | ||
278 | |||
279 | const channelLayout = parsedAudio.audioStream['channel_layout'] | ||
280 | // Causes playback issues with Chrome | ||
281 | if (!channelLayout || channelLayout === 'unknown') return false | ||
282 | |||
283 | return true | ||
284 | } | ||
285 | |||
286 | function getClosestFramerateStandard <K extends keyof Pick<VideoTranscodingFPS, 'HD_STANDARD' | 'STANDARD'>> (fps: number, type: K) { | 143 | function getClosestFramerateStandard <K extends keyof Pick<VideoTranscodingFPS, 'HD_STANDARD' | 'STANDARD'>> (fps: number, type: K) { |
287 | return VIDEO_TRANSCODING_FPS[type].slice(0) | 144 | return VIDEO_TRANSCODING_FPS[type].slice(0) |
288 | .sort((a, b) => fps % a - fps % b)[0] | 145 | .sort((a, b) => fps % a - fps % b)[0] |
diff --git a/server/helpers/image-utils.ts b/server/helpers/image-utils.ts index 4305584d5..b174ae436 100644 --- a/server/helpers/image-utils.ts +++ b/server/helpers/image-utils.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { copy, readFile, remove, rename } from 'fs-extra' | 1 | import { copy, readFile, remove, rename } from 'fs-extra' |
2 | import Jimp, { read } from 'jimp' | 2 | import Jimp, { read } from 'jimp' |
3 | import { getLowercaseExtension } from './core-utils' | 3 | import { getLowercaseExtension } from '@shared/core-utils' |
4 | import { buildUUID } from '@shared/extra-utils' | ||
4 | import { convertWebPToJPG, processGIF } from './ffmpeg-utils' | 5 | import { convertWebPToJPG, processGIF } from './ffmpeg-utils' |
5 | import { logger } from './logger' | 6 | import { logger } from './logger' |
6 | import { buildUUID } from './uuid' | ||
7 | 7 | ||
8 | function generateImageFilename (extension = '.jpg') { | 8 | function generateImageFilename (extension = '.jpg') { |
9 | return buildUUID() + extension | 9 | return buildUUID() + extension |
diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts index 44d90d9f1..b8f7c782a 100644 --- a/server/helpers/peertube-crypto.ts +++ b/server/helpers/peertube-crypto.ts | |||
@@ -2,9 +2,10 @@ import { compare, genSalt, hash } from 'bcrypt' | |||
2 | import { createSign, createVerify } from 'crypto' | 2 | import { createSign, createVerify } from 'crypto' |
3 | import { Request } from 'express' | 3 | import { Request } from 'express' |
4 | import { cloneDeep } from 'lodash' | 4 | import { cloneDeep } from 'lodash' |
5 | import { sha256 } from '@shared/extra-utils' | ||
5 | import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants' | 6 | import { BCRYPT_SALT_SIZE, HTTP_SIGNATURE, PRIVATE_RSA_KEY_SIZE } from '../initializers/constants' |
6 | import { MActor } from '../types/models' | 7 | import { MActor } from '../types/models' |
7 | import { createPrivateKey, getPublicKey, promisify1, promisify2, sha256 } from './core-utils' | 8 | import { createPrivateKey, getPublicKey, promisify1, promisify2 } from './core-utils' |
8 | import { jsonld } from './custom-jsonld-signature' | 9 | import { jsonld } from './custom-jsonld-signature' |
9 | import { logger } from './logger' | 10 | import { logger } from './logger' |
10 | 11 | ||
diff --git a/server/helpers/register-ts-paths.ts b/server/helpers/register-ts-paths.ts deleted file mode 100644 index eec7fed3e..000000000 --- a/server/helpers/register-ts-paths.ts +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | import { resolve } from 'path' | ||
2 | import tsConfigPaths = require('tsconfig-paths') | ||
3 | |||
4 | const tsConfig = require('../../tsconfig.json') | ||
5 | |||
6 | function registerTSPaths () { | ||
7 | // Thanks: https://github.com/dividab/tsconfig-paths/issues/75#issuecomment-458936883 | ||
8 | tsConfigPaths.register({ | ||
9 | baseUrl: resolve(tsConfig.compilerOptions.baseUrl || '', tsConfig.compilerOptions.outDir || ''), | ||
10 | paths: tsConfig.compilerOptions.paths | ||
11 | }) | ||
12 | } | ||
13 | |||
14 | export { | ||
15 | registerTSPaths | ||
16 | } | ||
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index 6c95a43b6..6b9333b53 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -1,9 +1,10 @@ | |||
1 | import { remove } from 'fs-extra' | 1 | import { remove } from 'fs-extra' |
2 | import { Instance as ParseTorrent } from 'parse-torrent' | 2 | import { Instance as ParseTorrent } from 'parse-torrent' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { ResultList } from '../../shared' | 4 | import { sha256 } from '@shared/extra-utils' |
5 | import { ResultList } from '@shared/models' | ||
5 | import { CONFIG } from '../initializers/config' | 6 | import { CONFIG } from '../initializers/config' |
6 | import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils' | 7 | import { execPromise, execPromise2, randomBytesPromise } from './core-utils' |
7 | import { logger } from './logger' | 8 | import { logger } from './logger' |
8 | 9 | ||
9 | function deleteFileAndCatch (path: string) { | 10 | function deleteFileAndCatch (path: string) { |
diff --git a/server/helpers/uuid.ts b/server/helpers/uuid.ts deleted file mode 100644 index f3c80e046..000000000 --- a/server/helpers/uuid.ts +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | import short, { uuid } from 'short-uuid' | ||
2 | |||
3 | const translator = short() | ||
4 | |||
5 | function buildUUID () { | ||
6 | return uuid() | ||
7 | } | ||
8 | |||
9 | function uuidToShort (uuid: string) { | ||
10 | if (!uuid) return uuid | ||
11 | |||
12 | return translator.fromUUID(uuid) | ||
13 | } | ||
14 | |||
15 | function shortToUUID (shortUUID: string) { | ||
16 | if (!shortUUID) return shortUUID | ||
17 | |||
18 | return translator.toUUID(shortUUID) | ||
19 | } | ||
20 | |||
21 | function isShortUUID (value: string) { | ||
22 | if (!value) return false | ||
23 | |||
24 | return value.length === translator.maxLength | ||
25 | } | ||
26 | |||
27 | export { | ||
28 | buildUUID, | ||
29 | uuidToShort, | ||
30 | shortToUUID, | ||
31 | isShortUUID | ||
32 | } | ||
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index c75c058e4..68d532c48 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -13,6 +13,7 @@ import { VideoPathManager } from '@server/lib/video-path-manager' | |||
13 | import { MVideo } from '@server/types/models/video/video' | 13 | import { MVideo } from '@server/types/models/video/video' |
14 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/types/models/video/video-file' | 14 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/types/models/video/video-file' |
15 | import { MStreamingPlaylistVideo } from '@server/types/models/video/video-streaming-playlist' | 15 | import { MStreamingPlaylistVideo } from '@server/types/models/video/video-streaming-playlist' |
16 | import { sha1 } from '@shared/extra-utils' | ||
16 | import { CONFIG } from '../initializers/config' | 17 | import { CONFIG } from '../initializers/config' |
17 | import { promisify2 } from './core-utils' | 18 | import { promisify2 } from './core-utils' |
18 | import { logger } from './logger' | 19 | import { logger } from './logger' |
@@ -94,7 +95,7 @@ function createTorrentAndSetInfoHash (videoOrPlaylist: MVideo | MStreamingPlayli | |||
94 | 95 | ||
95 | const options = { | 96 | const options = { |
96 | // Keep the extname, it's used by the client to stream the file inside a web browser | 97 | // Keep the extname, it's used by the client to stream the file inside a web browser |
97 | name: `${video.name} ${videoFile.resolution}p${videoFile.extname}`, | 98 | name: buildInfoName(video, videoFile), |
98 | createdBy: 'PeerTube', | 99 | createdBy: 'PeerTube', |
99 | announceList: buildAnnounceList(), | 100 | announceList: buildAnnounceList(), |
100 | urlList: buildUrlList(video, videoFile) | 101 | urlList: buildUrlList(video, videoFile) |
@@ -120,7 +121,7 @@ function createTorrentAndSetInfoHash (videoOrPlaylist: MVideo | MStreamingPlayli | |||
120 | }) | 121 | }) |
121 | } | 122 | } |
122 | 123 | ||
123 | async function updateTorrentUrls (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { | 124 | async function updateTorrentMetadata (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { |
124 | const video = extractVideo(videoOrPlaylist) | 125 | const video = extractVideo(videoOrPlaylist) |
125 | 126 | ||
126 | const oldTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename) | 127 | const oldTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename) |
@@ -133,15 +134,19 @@ async function updateTorrentUrls (videoOrPlaylist: MVideo | MStreamingPlaylistVi | |||
133 | 134 | ||
134 | decoded['url-list'] = buildUrlList(video, videoFile) | 135 | decoded['url-list'] = buildUrlList(video, videoFile) |
135 | 136 | ||
137 | decoded.info.name = buildInfoName(video, videoFile) | ||
138 | decoded['creation date'] = Math.ceil(Date.now() / 1000) | ||
139 | |||
136 | const newTorrentFilename = generateTorrentFileName(videoOrPlaylist, videoFile.resolution) | 140 | const newTorrentFilename = generateTorrentFileName(videoOrPlaylist, videoFile.resolution) |
137 | const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, newTorrentFilename) | 141 | const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, newTorrentFilename) |
138 | 142 | ||
139 | logger.info('Updating torrent URLs %s -> %s.', oldTorrentPath, newTorrentPath) | 143 | logger.info('Updating torrent metadata %s -> %s.', oldTorrentPath, newTorrentPath) |
140 | 144 | ||
141 | await writeFile(newTorrentPath, encode(decoded)) | 145 | await writeFile(newTorrentPath, encode(decoded)) |
142 | await remove(join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename)) | 146 | await remove(join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename)) |
143 | 147 | ||
144 | videoFile.torrentFilename = newTorrentFilename | 148 | videoFile.torrentFilename = newTorrentFilename |
149 | videoFile.infoHash = sha1(encode(decoded.info)) | ||
145 | } | 150 | } |
146 | 151 | ||
147 | function generateMagnetUri ( | 152 | function generateMagnetUri ( |
@@ -171,7 +176,7 @@ function generateMagnetUri ( | |||
171 | 176 | ||
172 | export { | 177 | export { |
173 | createTorrentPromise, | 178 | createTorrentPromise, |
174 | updateTorrentUrls, | 179 | updateTorrentMetadata, |
175 | createTorrentAndSetInfoHash, | 180 | createTorrentAndSetInfoHash, |
176 | generateMagnetUri, | 181 | generateMagnetUri, |
177 | downloadWebTorrentVideo | 182 | downloadWebTorrentVideo |
@@ -226,3 +231,7 @@ function buildAnnounceList () { | |||
226 | function buildUrlList (video: MVideo, videoFile: MVideoFile) { | 231 | function buildUrlList (video: MVideo, videoFile: MVideoFile) { |
227 | return [ videoFile.getFileUrl(video) ] | 232 | return [ videoFile.getFileUrl(video) ] |
228 | } | 233 | } |
234 | |||
235 | function buildInfoName (video: MVideo, videoFile: MVideoFile) { | ||
236 | return `${video.name} ${videoFile.resolution}p${videoFile.extname}` | ||
237 | } | ||
diff --git a/server/helpers/youtube-dl/youtube-dl-cli.ts b/server/helpers/youtube-dl/youtube-dl-cli.ts index 559f92984..293acff43 100644 --- a/server/helpers/youtube-dl/youtube-dl-cli.ts +++ b/server/helpers/youtube-dl/youtube-dl-cli.ts | |||
@@ -153,7 +153,8 @@ export class YoutubeDLCLI { | |||
153 | completeArgs = this.wrapWithIPOptions(completeArgs) | 153 | completeArgs = this.wrapWithIPOptions(completeArgs) |
154 | completeArgs = this.wrapWithFFmpegOptions(completeArgs) | 154 | completeArgs = this.wrapWithFFmpegOptions(completeArgs) |
155 | 155 | ||
156 | const output = await execa('python', [ youtubeDLBinaryPath, ...completeArgs, url ], processOptions) | 156 | const { PYTHON_PATH } = CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE |
157 | const output = await execa(PYTHON_PATH, [ youtubeDLBinaryPath, ...completeArgs, url ], processOptions) | ||
157 | 158 | ||
158 | logger.debug('Runned youtube-dl command.', { command: output.command, ...lTags() }) | 159 | logger.debug('Runned youtube-dl command.', { command: output.command, ...lTags() }) |
159 | 160 | ||
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 51c396548..458005b98 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -33,6 +33,8 @@ function checkMissedConfig () { | |||
33 | 'transcoding.resolutions.2160p', | 33 | 'transcoding.resolutions.2160p', |
34 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled', | 34 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'auto_blacklist.videos.of_users.enabled', |
35 | 'trending.videos.interval_days', | 35 | 'trending.videos.interval_days', |
36 | 'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth', | ||
37 | 'defaults.publish.download_enabled', 'defaults.publish.comments_enabled', 'defaults.publish.privacy', 'defaults.publish.licence', | ||
36 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', | 38 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', |
37 | 'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', | 39 | 'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', |
38 | 'services.twitter.username', 'services.twitter.whitelisted', | 40 | 'services.twitter.username', 'services.twitter.whitelisted', |
@@ -115,7 +117,11 @@ function checkNodeVersion () { | |||
115 | logger.debug('Checking NodeJS version %s.', v) | 117 | logger.debug('Checking NodeJS version %s.', v) |
116 | 118 | ||
117 | if (major <= 10) { | 119 | if (major <= 10) { |
118 | logger.warn('Your NodeJS version %s is deprecated. Please upgrade.', v) | 120 | throw new Error('Your NodeJS version ' + v + ' is not supported. Please upgrade.') |
121 | } | ||
122 | |||
123 | if (major <= 12) { | ||
124 | logger.warn('Your NodeJS version ' + v + ' is deprecated. Please upgrade.') | ||
119 | } | 125 | } |
120 | } | 126 | } |
121 | 127 | ||
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index dadda2a77..fb6f7ae62 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -1,12 +1,13 @@ | |||
1 | import bytes from 'bytes' | 1 | import bytes from 'bytes' |
2 | import { IConfig } from 'config' | 2 | import { IConfig } from 'config' |
3 | import decache from 'decache' | ||
4 | import { dirname, join } from 'path' | 3 | import { dirname, join } from 'path' |
4 | import { decacheModule } from '@server/helpers/decache' | ||
5 | import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' | 5 | import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' |
6 | import { BroadcastMessageLevel } from '@shared/models/server' | 6 | import { BroadcastMessageLevel } from '@shared/models/server' |
7 | import { VideosRedundancyStrategy } from '../../shared/models' | 7 | import { VideoPrivacy, VideosRedundancyStrategy } from '../../shared/models' |
8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
9 | import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils' | 9 | import { buildPath, root } from '../../shared/core-utils' |
10 | import { parseBytes, parseDurationToMs } from '../helpers/core-utils' | ||
10 | 11 | ||
11 | // Use a variable to reload the configuration if we need | 12 | // Use a variable to reload the configuration if we need |
12 | let config: IConfig = require('config') | 13 | let config: IConfig = require('config') |
@@ -63,6 +64,28 @@ const CONFIG = { | |||
63 | MINIATURE: { | 64 | MINIATURE: { |
64 | get PREFER_AUTHOR_DISPLAY_NAME () { return config.get<boolean>('client.videos.miniature.prefer_author_display_name') } | 65 | get PREFER_AUTHOR_DISPLAY_NAME () { return config.get<boolean>('client.videos.miniature.prefer_author_display_name') } |
65 | } | 66 | } |
67 | }, | ||
68 | MENU: { | ||
69 | LOGIN: { | ||
70 | get REDIRECT_ON_SINGLE_EXTERNAL_AUTH () { return config.get<boolean>('client.menu.login.redirect_on_single_external_auth') } | ||
71 | } | ||
72 | } | ||
73 | }, | ||
74 | |||
75 | DEFAULTS: { | ||
76 | PUBLISH: { | ||
77 | DOWNLOAD_ENABLED: config.get<boolean>('defaults.publish.download_enabled'), | ||
78 | COMMENTS_ENABLED: config.get<boolean>('defaults.publish.comments_enabled'), | ||
79 | PRIVACY: config.get<VideoPrivacy>('defaults.publish.privacy'), | ||
80 | LICENCE: config.get<number>('defaults.publish.licence') | ||
81 | }, | ||
82 | P2P: { | ||
83 | WEBAPP: { | ||
84 | ENABLED: config.get<boolean>('defaults.p2p.webapp.enabled') | ||
85 | }, | ||
86 | EMBED: { | ||
87 | ENABLED: config.get<boolean>('defaults.p2p.embed.enabled') | ||
88 | } | ||
66 | } | 89 | } |
67 | }, | 90 | }, |
68 | 91 | ||
@@ -310,7 +333,8 @@ const CONFIG = { | |||
310 | 333 | ||
311 | YOUTUBE_DL_RELEASE: { | 334 | YOUTUBE_DL_RELEASE: { |
312 | get URL () { return config.get<string>('import.videos.http.youtube_dl_release.url') }, | 335 | get URL () { return config.get<string>('import.videos.http.youtube_dl_release.url') }, |
313 | get NAME () { return config.get<string>('import.videos.http.youtube_dl_release.name') } | 336 | get NAME () { return config.get<string>('import.videos.http.youtube_dl_release.name') }, |
337 | get PYTHON_PATH () { return config.get<string>('import.videos.http.youtube_dl_release.python_path') } | ||
314 | }, | 338 | }, |
315 | 339 | ||
316 | get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') } | 340 | get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') } |
@@ -497,7 +521,7 @@ export function reloadConfig () { | |||
497 | delete require.cache[fileName] | 521 | delete require.cache[fileName] |
498 | } | 522 | } |
499 | 523 | ||
500 | decache('config') | 524 | decacheModule('config') |
501 | } | 525 | } |
502 | 526 | ||
503 | purge() | 527 | purge() |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index b8633e83e..c899812a6 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -2,7 +2,7 @@ import { CronRepeatOptions, EveryRepeatOptions } from 'bull' | |||
2 | import { randomBytes } from 'crypto' | 2 | import { randomBytes } from 'crypto' |
3 | import { invert } from 'lodash' | 3 | import { invert } from 'lodash' |
4 | import { join } from 'path' | 4 | import { join } from 'path' |
5 | import { randomInt } from '../../shared/core-utils/common/miscs' | 5 | import { randomInt, root } from '@shared/core-utils' |
6 | import { | 6 | import { |
7 | AbuseState, | 7 | AbuseState, |
8 | JobType, | 8 | JobType, |
@@ -19,12 +19,12 @@ import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | |||
19 | import { VideoPlaylistPrivacy } from '../../shared/models/videos/playlist/video-playlist-privacy.model' | 19 | import { VideoPlaylistPrivacy } from '../../shared/models/videos/playlist/video-playlist-privacy.model' |
20 | import { VideoPlaylistType } from '../../shared/models/videos/playlist/video-playlist-type.model' | 20 | import { VideoPlaylistType } from '../../shared/models/videos/playlist/video-playlist-type.model' |
21 | // Do not use barrels, remain constants as independent as possible | 21 | // Do not use barrels, remain constants as independent as possible |
22 | import { isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' | 22 | import { isTestInstance, parseDurationToMs, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' |
23 | import { CONFIG, registerConfigChangedHandler } from './config' | 23 | import { CONFIG, registerConfigChangedHandler } from './config' |
24 | 24 | ||
25 | // --------------------------------------------------------------------------- | 25 | // --------------------------------------------------------------------------- |
26 | 26 | ||
27 | const LAST_MIGRATION_VERSION = 670 | 27 | const LAST_MIGRATION_VERSION = 675 |
28 | 28 | ||
29 | // --------------------------------------------------------------------------- | 29 | // --------------------------------------------------------------------------- |
30 | 30 | ||
@@ -200,8 +200,14 @@ const JOB_PRIORITY = { | |||
200 | } | 200 | } |
201 | 201 | ||
202 | const BROADCAST_CONCURRENCY = 30 // How many requests in parallel we do in activitypub-http-broadcast job | 202 | const BROADCAST_CONCURRENCY = 30 // How many requests in parallel we do in activitypub-http-broadcast job |
203 | const AP_CLEANER_CONCURRENCY = 10 // How many requests in parallel we do in activitypub-cleaner job | ||
204 | const CRAWL_REQUEST_CONCURRENCY = 1 // How many requests in parallel to fetch remote data (likes, shares...) | 203 | const CRAWL_REQUEST_CONCURRENCY = 1 // How many requests in parallel to fetch remote data (likes, shares...) |
204 | |||
205 | const AP_CLEANER = { | ||
206 | CONCURRENCY: 10, // How many requests in parallel we do in activitypub-cleaner job | ||
207 | UNAVAILABLE_TRESHOLD: 3, // How many attemps we do before removing an unavailable remote resource | ||
208 | PERIOD: parseDurationToMs('1 week') // /!\ Has to be sync with REPEAT_JOBS | ||
209 | } | ||
210 | |||
205 | const REQUEST_TIMEOUTS = { | 211 | const REQUEST_TIMEOUTS = { |
206 | DEFAULT: 7000, // 7 seconds | 212 | DEFAULT: 7000, // 7 seconds |
207 | FILE: 30000, // 30 seconds | 213 | FILE: 30000, // 30 seconds |
@@ -223,7 +229,7 @@ const SCHEDULER_INTERVALS_MS = { | |||
223 | REMOVE_OLD_VIEWS: 60000 * 60 * 24, // 1 day | 229 | REMOVE_OLD_VIEWS: 60000 * 60 * 24, // 1 day |
224 | REMOVE_OLD_HISTORY: 60000 * 60 * 24, // 1 day | 230 | REMOVE_OLD_HISTORY: 60000 * 60 * 24, // 1 day |
225 | UPDATE_INBOX_STATS: 1000 * 60, // 1 minute | 231 | UPDATE_INBOX_STATS: 1000 * 60, // 1 minute |
226 | REMOVE_DANGLING_RESUMABLE_UPLOADS: 60000 * 60 * 16 // 16 hours | 232 | REMOVE_DANGLING_RESUMABLE_UPLOADS: 60000 * 60 // 1 hour |
227 | } | 233 | } |
228 | 234 | ||
229 | // --------------------------------------------------------------------------- | 235 | // --------------------------------------------------------------------------- |
@@ -427,7 +433,8 @@ const VIDEO_STATES: { [ id in VideoState ]: string } = { | |||
427 | [VideoState.WAITING_FOR_LIVE]: 'Waiting for livestream', | 433 | [VideoState.WAITING_FOR_LIVE]: 'Waiting for livestream', |
428 | [VideoState.LIVE_ENDED]: 'Livestream ended', | 434 | [VideoState.LIVE_ENDED]: 'Livestream ended', |
429 | [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE]: 'To move to an external storage', | 435 | [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE]: 'To move to an external storage', |
430 | [VideoState.TRANSCODING_FAILED]: 'Transcoding failed' | 436 | [VideoState.TRANSCODING_FAILED]: 'Transcoding failed', |
437 | [VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED]: 'External storage move failed' | ||
431 | } | 438 | } |
432 | 439 | ||
433 | const VIDEO_IMPORT_STATES: { [ id in VideoImportState ]: string } = { | 440 | const VIDEO_IMPORT_STATES: { [ id in VideoImportState ]: string } = { |
@@ -795,8 +802,11 @@ if (isTestInstance() === true) { | |||
795 | SCHEDULER_INTERVALS_MS.AUTO_FOLLOW_INDEX_INSTANCES = 5000 | 802 | SCHEDULER_INTERVALS_MS.AUTO_FOLLOW_INDEX_INSTANCES = 5000 |
796 | SCHEDULER_INTERVALS_MS.UPDATE_INBOX_STATS = 5000 | 803 | SCHEDULER_INTERVALS_MS.UPDATE_INBOX_STATS = 5000 |
797 | SCHEDULER_INTERVALS_MS.CHECK_PEERTUBE_VERSION = 2000 | 804 | SCHEDULER_INTERVALS_MS.CHECK_PEERTUBE_VERSION = 2000 |
805 | |||
798 | REPEAT_JOBS['videos-views-stats'] = { every: 5000 } | 806 | REPEAT_JOBS['videos-views-stats'] = { every: 5000 } |
807 | |||
799 | REPEAT_JOBS['activitypub-cleaner'] = { every: 5000 } | 808 | REPEAT_JOBS['activitypub-cleaner'] = { every: 5000 } |
809 | AP_CLEANER.PERIOD = 5000 | ||
800 | 810 | ||
801 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 | 811 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 |
802 | 812 | ||
@@ -857,7 +867,7 @@ export { | |||
857 | REDUNDANCY, | 867 | REDUNDANCY, |
858 | JOB_CONCURRENCY, | 868 | JOB_CONCURRENCY, |
859 | JOB_ATTEMPTS, | 869 | JOB_ATTEMPTS, |
860 | AP_CLEANER_CONCURRENCY, | 870 | AP_CLEANER, |
861 | LAST_MIGRATION_VERSION, | 871 | LAST_MIGRATION_VERSION, |
862 | OAUTH_LIFETIME, | 872 | OAUTH_LIFETIME, |
863 | CUSTOM_HTML_TAG_COMMENTS, | 873 | CUSTOM_HTML_TAG_COMMENTS, |
@@ -1075,7 +1085,9 @@ function buildLanguages () { | |||
1075 | epo: true, // Esperanto | 1085 | epo: true, // Esperanto |
1076 | tlh: true, // Klingon | 1086 | tlh: true, // Klingon |
1077 | jbo: true, // Lojban | 1087 | jbo: true, // Lojban |
1078 | avk: true // Kotava | 1088 | avk: true, // Kotava |
1089 | |||
1090 | zxx: true // No linguistic content (ISO-639-2) | ||
1079 | } | 1091 | } |
1080 | 1092 | ||
1081 | // Only add ISO639-1 languages and some sign languages (ISO639-3) | 1093 | // Only add ISO639-1 languages and some sign languages (ISO639-3) |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 75daeb5d8..7e321fb76 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { ensureDir, remove } from 'fs-extra' | 1 | import { ensureDir, remove } from 'fs-extra' |
2 | import passwordGenerator from 'password-generator' | 2 | import passwordGenerator from 'password-generator' |
3 | import { UserRole } from '../../shared' | 3 | import { UserRole } from '@shared/models' |
4 | import { logger } from '../helpers/logger' | 4 | import { logger } from '../helpers/logger' |
5 | import { createApplicationActor, createUserAccountAndChannelAndPlaylist } from '../lib/user' | 5 | import { createApplicationActor, createUserAccountAndChannelAndPlaylist } from '../lib/user' |
6 | import { ApplicationModel } from '../models/application/application' | 6 | import { ApplicationModel } from '../models/application/application' |
@@ -144,6 +144,7 @@ async function createOAuthAdminIfNotExist () { | |||
144 | role, | 144 | role, |
145 | verified: true, | 145 | verified: true, |
146 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 146 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
147 | p2pEnabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED, | ||
147 | videoQuota: -1, | 148 | videoQuota: -1, |
148 | videoQuotaDaily: -1 | 149 | videoQuotaDaily: -1 |
149 | } | 150 | } |
diff --git a/server/initializers/migrations/0080-video-channels.ts b/server/initializers/migrations/0080-video-channels.ts index 0e6952350..ef3e15968 100644 --- a/server/initializers/migrations/0080-video-channels.ts +++ b/server/initializers/migrations/0080-video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { buildUUID } from '@server/helpers/uuid' | 1 | import { buildUUID } from '@shared/extra-utils' |
2 | import * as Sequelize from 'sequelize' | 2 | import * as Sequelize from 'sequelize' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
diff --git a/server/initializers/migrations/0345-video-playlists.ts b/server/initializers/migrations/0345-video-playlists.ts index 8dd631dff..4bf3100e4 100644 --- a/server/initializers/migrations/0345-video-playlists.ts +++ b/server/initializers/migrations/0345-video-playlists.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { buildUUID } from '@server/helpers/uuid' | 2 | import { buildUUID } from '@shared/extra-utils' |
3 | import { VideoPlaylistPrivacy, VideoPlaylistType } from '../../../shared/models/videos' | 3 | import { VideoPlaylistPrivacy, VideoPlaylistType } from '../../../shared/models/videos' |
4 | import { WEBSERVER } from '../constants' | 4 | import { WEBSERVER } from '../constants' |
5 | 5 | ||
diff --git a/server/initializers/migrations/0560-user-feed-token.ts b/server/initializers/migrations/0560-user-feed-token.ts index 042301352..4c85b04f7 100644 --- a/server/initializers/migrations/0560-user-feed-token.ts +++ b/server/initializers/migrations/0560-user-feed-token.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { buildUUID } from '@server/helpers/uuid' | 2 | import { buildUUID } from '@shared/extra-utils' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction | 5 | transaction: Sequelize.Transaction |
diff --git a/server/initializers/migrations/0675-p2p-enabled.ts b/server/initializers/migrations/0675-p2p-enabled.ts new file mode 100644 index 000000000..b4f53381e --- /dev/null +++ b/server/initializers/migrations/0675-p2p-enabled.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction | ||
5 | queryInterface: Sequelize.QueryInterface | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | db: any | ||
8 | }): Promise<void> { | ||
9 | await utils.queryInterface.renameColumn('user', 'webTorrentEnabled', 'p2pEnabled') | ||
10 | |||
11 | await utils.sequelize.query('ALTER TABLE "user" ALTER COLUMN "p2pEnabled" DROP DEFAULT') | ||
12 | } | ||
13 | |||
14 | function down (options) { | ||
15 | throw new Error('Not implemented.') | ||
16 | } | ||
17 | |||
18 | export { | ||
19 | up, | ||
20 | down | ||
21 | } | ||
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 7d7c9f8cb..7ac20127e 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts | |||
@@ -65,7 +65,7 @@ async function getMigrationScripts () { | |||
65 | }[] = [] | 65 | }[] = [] |
66 | 66 | ||
67 | files | 67 | files |
68 | .filter(file => file.endsWith('.js.map') === false) | 68 | .filter(file => file.endsWith('.js')) |
69 | .forEach(file => { | 69 | .forEach(file => { |
70 | // Filename is something like 'version-blabla.js' | 70 | // Filename is something like 'version-blabla.js' |
71 | const version = file.split('-')[0] | 71 | const version = file.split('-')[0] |
diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts index 8681ea02a..4200ddb4d 100644 --- a/server/lib/activitypub/actors/get.ts +++ b/server/lib/activitypub/actors/get.ts | |||
@@ -68,9 +68,28 @@ async function getOrCreateAPActor ( | |||
68 | return actorRefreshed | 68 | return actorRefreshed |
69 | } | 69 | } |
70 | 70 | ||
71 | function getOrCreateAPOwner (actorObject: ActivityPubActor, actorUrl: string) { | ||
72 | const accountAttributedTo = actorObject.attributedTo.find(a => a.type === 'Person') | ||
73 | if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actorUrl) | ||
74 | |||
75 | if (checkUrlsSameHost(accountAttributedTo.id, actorUrl) !== true) { | ||
76 | throw new Error(`Account attributed to ${accountAttributedTo.id} does not have the same host than actor url ${actorUrl}`) | ||
77 | } | ||
78 | |||
79 | try { | ||
80 | // Don't recurse another time | ||
81 | const recurseIfNeeded = false | ||
82 | return getOrCreateAPActor(accountAttributedTo.id, 'all', recurseIfNeeded) | ||
83 | } catch (err) { | ||
84 | logger.error('Cannot get or create account attributed to video channel ' + actorUrl) | ||
85 | throw new Error(err) | ||
86 | } | ||
87 | } | ||
88 | |||
71 | // --------------------------------------------------------------------------- | 89 | // --------------------------------------------------------------------------- |
72 | 90 | ||
73 | export { | 91 | export { |
92 | getOrCreateAPOwner, | ||
74 | getOrCreateAPActor | 93 | getOrCreateAPActor |
75 | } | 94 | } |
76 | 95 | ||
@@ -88,24 +107,6 @@ async function loadActorFromDB (actorUrl: string, fetchType: ActorLoadByUrlType) | |||
88 | return actor | 107 | return actor |
89 | } | 108 | } |
90 | 109 | ||
91 | function getOrCreateAPOwner (actorObject: ActivityPubActor, actorUrl: string) { | ||
92 | const accountAttributedTo = actorObject.attributedTo.find(a => a.type === 'Person') | ||
93 | if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actorUrl) | ||
94 | |||
95 | if (checkUrlsSameHost(accountAttributedTo.id, actorUrl) !== true) { | ||
96 | throw new Error(`Account attributed to ${accountAttributedTo.id} does not have the same host than actor url ${actorUrl}`) | ||
97 | } | ||
98 | |||
99 | try { | ||
100 | // Don't recurse another time | ||
101 | const recurseIfNeeded = false | ||
102 | return getOrCreateAPActor(accountAttributedTo.id, 'all', recurseIfNeeded) | ||
103 | } catch (err) { | ||
104 | logger.error('Cannot get or create account attributed to video channel ' + actorUrl) | ||
105 | throw new Error(err) | ||
106 | } | ||
107 | } | ||
108 | |||
109 | async function scheduleOutboxFetchIfNeeded (actor: MActor, created: boolean, refreshed: boolean, updateCollections: boolean) { | 110 | async function scheduleOutboxFetchIfNeeded (actor: MActor, created: boolean, refreshed: boolean, updateCollections: boolean) { |
110 | if ((created === true || refreshed === true) && updateCollections === true) { | 111 | if ((created === true || refreshed === true) && updateCollections === true) { |
111 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } | 112 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } |
diff --git a/server/lib/activitypub/actors/shared/object-to-model-attributes.ts b/server/lib/activitypub/actors/shared/object-to-model-attributes.ts index 1612b3ad0..23bc972e5 100644 --- a/server/lib/activitypub/actors/shared/object-to-model-attributes.ts +++ b/server/lib/activitypub/actors/shared/object-to-model-attributes.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { getLowercaseExtension } from '@server/helpers/core-utils' | ||
2 | import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc' | 1 | import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc' |
3 | import { buildUUID } from '@server/helpers/uuid' | ||
4 | import { MIMETYPES } from '@server/initializers/constants' | 2 | import { MIMETYPES } from '@server/initializers/constants' |
5 | import { ActorModel } from '@server/models/actor/actor' | 3 | import { ActorModel } from '@server/models/actor/actor' |
6 | import { FilteredModelAttributes } from '@server/types' | 4 | import { FilteredModelAttributes } from '@server/types' |
5 | import { getLowercaseExtension } from '@shared/core-utils' | ||
6 | import { buildUUID } from '@shared/extra-utils' | ||
7 | import { ActivityPubActor, ActorImageType } from '@shared/models' | 7 | import { ActivityPubActor, ActorImageType } from '@shared/models' |
8 | 8 | ||
9 | function getActorAttributesFromObject ( | 9 | function getActorAttributesFromObject ( |
diff --git a/server/lib/activitypub/actors/updater.ts b/server/lib/activitypub/actors/updater.ts index de5e03eee..042438d9c 100644 --- a/server/lib/activitypub/actors/updater.ts +++ b/server/lib/activitypub/actors/updater.ts | |||
@@ -1,8 +1,10 @@ | |||
1 | import { resetSequelizeInstance, runInReadCommittedTransaction } from '@server/helpers/database-utils' | 1 | import { resetSequelizeInstance, runInReadCommittedTransaction } from '@server/helpers/database-utils' |
2 | import { logger } from '@server/helpers/logger' | 2 | import { logger } from '@server/helpers/logger' |
3 | import { AccountModel } from '@server/models/account/account' | ||
3 | import { VideoChannelModel } from '@server/models/video/video-channel' | 4 | import { VideoChannelModel } from '@server/models/video/video-channel' |
4 | import { MAccount, MActor, MActorFull, MChannel } from '@server/types/models' | 5 | import { MAccount, MActor, MActorFull, MChannel } from '@server/types/models' |
5 | import { ActivityPubActor, ActorImageType } from '@shared/models' | 6 | import { ActivityPubActor, ActorImageType } from '@shared/models' |
7 | import { getOrCreateAPOwner } from './get' | ||
6 | import { updateActorImageInstance } from './image' | 8 | import { updateActorImageInstance } from './image' |
7 | import { fetchActorFollowsCount } from './shared' | 9 | import { fetchActorFollowsCount } from './shared' |
8 | import { getImageInfoFromObject } from './shared/object-to-model-attributes' | 10 | import { getImageInfoFromObject } from './shared/object-to-model-attributes' |
@@ -36,7 +38,13 @@ export class APActorUpdater { | |||
36 | this.accountOrChannel.name = this.actorObject.name || this.actorObject.preferredUsername | 38 | this.accountOrChannel.name = this.actorObject.name || this.actorObject.preferredUsername |
37 | this.accountOrChannel.description = this.actorObject.summary | 39 | this.accountOrChannel.description = this.actorObject.summary |
38 | 40 | ||
39 | if (this.accountOrChannel instanceof VideoChannelModel) this.accountOrChannel.support = this.actorObject.support | 41 | if (this.accountOrChannel instanceof VideoChannelModel) { |
42 | const owner = await getOrCreateAPOwner(this.actorObject, this.actorObject.url) | ||
43 | this.accountOrChannel.accountId = owner.Account.id | ||
44 | this.accountOrChannel.Account = owner.Account as AccountModel | ||
45 | |||
46 | this.accountOrChannel.support = this.actorObject.support | ||
47 | } | ||
40 | 48 | ||
41 | await runInReadCommittedTransaction(async t => { | 49 | await runInReadCommittedTransaction(async t => { |
42 | await updateActorImageInstance(this.actor, ActorImageType.AVATAR, avatarInfo, t) | 50 | await updateActorImageInstance(this.actor, ActorImageType.AVATAR, avatarInfo, t) |
diff --git a/server/lib/activitypub/cache-file.ts b/server/lib/activitypub/cache-file.ts index a16d2cd93..c3acd7112 100644 --- a/server/lib/activitypub/cache-file.ts +++ b/server/lib/activitypub/cache-file.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { MActorId, MVideoRedundancy, MVideoWithAllFiles } from '@server/types/models' | 2 | import { MActorId, MVideoRedundancy, MVideoWithAllFiles } from '@server/types/models' |
3 | import { CacheFileObject } from '../../../shared/index' | 3 | import { CacheFileObject, VideoStreamingPlaylistType } from '@shared/models' |
4 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | ||
5 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 4 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
6 | 5 | ||
7 | async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) { | 6 | async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) { |
diff --git a/server/lib/activitypub/playlists/create-update.ts b/server/lib/activitypub/playlists/create-update.ts index b152d709c..ef572c803 100644 --- a/server/lib/activitypub/playlists/create-update.ts +++ b/server/lib/activitypub/playlists/create-update.ts | |||
@@ -9,7 +9,7 @@ import { VideoPlaylistModel } from '@server/models/video/video-playlist' | |||
9 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' | 9 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' |
10 | import { FilteredModelAttributes } from '@server/types' | 10 | import { FilteredModelAttributes } from '@server/types' |
11 | import { MThumbnail, MVideoPlaylist, MVideoPlaylistFull, MVideoPlaylistVideosLength } from '@server/types/models' | 11 | import { MThumbnail, MVideoPlaylist, MVideoPlaylistFull, MVideoPlaylistVideosLength } from '@server/types/models' |
12 | import { AttributesOnly } from '@shared/core-utils' | 12 | import { AttributesOnly } from '@shared/typescript-utils' |
13 | import { PlaylistObject } from '@shared/models' | 13 | import { PlaylistObject } from '@shared/models' |
14 | import { getOrCreateAPActor } from '../actors' | 14 | import { getOrCreateAPActor } from '../actors' |
15 | import { crawlCollectionPage } from '../crawl' | 15 | import { crawlCollectionPage } from '../crawl' |
diff --git a/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts b/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts index 70fd335bc..753b5e660 100644 --- a/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts +++ b/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts | |||
@@ -2,7 +2,7 @@ import { ACTIVITY_PUB } from '@server/initializers/constants' | |||
2 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | 2 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' |
3 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' | 3 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' |
4 | import { MVideoId, MVideoPlaylistId } from '@server/types/models' | 4 | import { MVideoId, MVideoPlaylistId } from '@server/types/models' |
5 | import { AttributesOnly } from '@shared/core-utils' | 5 | import { AttributesOnly } from '@shared/typescript-utils' |
6 | import { PlaylistElementObject, PlaylistObject, VideoPlaylistPrivacy } from '@shared/models' | 6 | import { PlaylistElementObject, PlaylistObject, VideoPlaylistPrivacy } from '@shared/models' |
7 | 7 | ||
8 | function playlistObjectToDBAttributes (playlistObject: PlaylistObject, to: string[]) { | 8 | function playlistObjectToDBAttributes (playlistObject: PlaylistObject, to: string[]) { |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 93f1d1c59..3e8ad184c 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import { isBlockedByServerOrAccount } from '@server/lib/blocklist' | 1 | import { isBlockedByServerOrAccount } from '@server/lib/blocklist' |
2 | import { isRedundancyAccepted } from '@server/lib/redundancy' | 2 | import { isRedundancyAccepted } from '@server/lib/redundancy' |
3 | import { ActivityCreate, CacheFileObject, VideoObject } from '../../../../shared' | 3 | import { ActivityCreate, CacheFileObject, PlaylistObject, VideoCommentObject, VideoObject } from '@shared/models' |
4 | import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' | ||
5 | import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object' | ||
6 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 4 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
7 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
8 | import { sequelizeTypescript } from '../../../initializers/database' | 6 | import { sequelizeTypescript } from '../../../initializers/database' |
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index ecc57cd10..2f46b83d1 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | import { ActivityCreate, ActivityDislike } from '../../../../shared' | 1 | import { ActivityCreate, ActivityDislike, DislikeObject } from '@shared/models' |
2 | import { DislikeObject } from '../../../../shared/models/activitypub/objects' | ||
3 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 2 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
4 | import { sequelizeTypescript } from '../../../initializers/database' | 3 | import { sequelizeTypescript } from '../../../initializers/database' |
5 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 4 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 7ed409d0e..a15d07a62 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts | |||
@@ -3,7 +3,7 @@ import { AccountModel } from '@server/models/account/account' | |||
3 | import { VideoModel } from '@server/models/video/video' | 3 | import { VideoModel } from '@server/models/video/video' |
4 | import { VideoCommentModel } from '@server/models/video/video-comment' | 4 | import { VideoCommentModel } from '@server/models/video/video-comment' |
5 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | 5 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' |
6 | import { AbuseObject, AbuseState, ActivityCreate, ActivityFlag } from '../../../../shared' | 6 | import { AbuseObject, AbuseState, ActivityCreate, ActivityFlag } from '@shared/models' |
7 | import { getAPId } from '../../../helpers/activitypub' | 7 | import { getAPId } from '../../../helpers/activitypub' |
8 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 8 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
9 | import { logger } from '../../../helpers/logger' | 9 | import { logger } from '../../../helpers/logger' |
@@ -75,7 +75,8 @@ async function processCreateAbuse (activity: ActivityCreate | ActivityFlag, byAc | |||
75 | endAt, | 75 | endAt, |
76 | reporterAccount, | 76 | reporterAccount, |
77 | transaction: t, | 77 | transaction: t, |
78 | videoInstance: video | 78 | videoInstance: video, |
79 | skipNotification: false | ||
79 | }) | 80 | }) |
80 | } | 81 | } |
81 | 82 | ||
@@ -84,7 +85,8 @@ async function processCreateAbuse (activity: ActivityCreate | ActivityFlag, byAc | |||
84 | baseAbuse, | 85 | baseAbuse, |
85 | reporterAccount, | 86 | reporterAccount, |
86 | transaction: t, | 87 | transaction: t, |
87 | commentInstance: videoComment | 88 | commentInstance: videoComment, |
89 | skipNotification: false | ||
88 | }) | 90 | }) |
89 | } | 91 | } |
90 | 92 | ||
@@ -92,7 +94,8 @@ async function processCreateAbuse (activity: ActivityCreate | ActivityFlag, byAc | |||
92 | baseAbuse, | 94 | baseAbuse, |
93 | reporterAccount, | 95 | reporterAccount, |
94 | transaction: t, | 96 | transaction: t, |
95 | accountInstance: flaggedAccount | 97 | accountInstance: flaggedAccount, |
98 | skipNotification: false | ||
96 | }) | 99 | }) |
97 | }) | 100 | }) |
98 | } catch (err) { | 101 | } catch (err) { |
diff --git a/server/lib/auth/oauth-model.ts b/server/lib/auth/oauth-model.ts index f2ef0a78a..b68cce6d2 100644 --- a/server/lib/auth/oauth-model.ts +++ b/server/lib/auth/oauth-model.ts | |||
@@ -226,6 +226,7 @@ async function createUserFromExternal (pluginAuth: string, options: { | |||
226 | password: null, | 226 | password: null, |
227 | email: options.email, | 227 | email: options.email, |
228 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | 228 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
229 | p2pEnabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED, | ||
229 | autoPlayVideo: true, | 230 | autoPlayVideo: true, |
230 | role: options.role, | 231 | role: options.role, |
231 | videoQuota: CONFIG.USER.VIDEO_QUOTA, | 232 | videoQuota: CONFIG.USER.VIDEO_QUOTA, |
diff --git a/server/lib/auth/oauth.ts b/server/lib/auth/oauth.ts index 497773536..2bf7a6361 100644 --- a/server/lib/auth/oauth.ts +++ b/server/lib/auth/oauth.ts | |||
@@ -8,8 +8,9 @@ import { | |||
8 | UnauthorizedClientError, | 8 | UnauthorizedClientError, |
9 | UnsupportedGrantTypeError | 9 | UnsupportedGrantTypeError |
10 | } from 'oauth2-server' | 10 | } from 'oauth2-server' |
11 | import { randomBytesPromise, sha1 } from '@server/helpers/core-utils' | 11 | import { randomBytesPromise } from '@server/helpers/core-utils' |
12 | import { MOAuthClient } from '@server/types/models' | 12 | import { MOAuthClient } from '@server/types/models' |
13 | import { sha1 } from '@shared/extra-utils' | ||
13 | import { OAUTH_LIFETIME } from '../../initializers/constants' | 14 | import { OAUTH_LIFETIME } from '../../initializers/constants' |
14 | import { BypassLogin, getClient, getRefreshToken, getUser, revokeToken, saveToken } from './oauth-model' | 15 | import { BypassLogin, getClient, getRefreshToken, getUser, revokeToken, saveToken } from './oauth-model' |
15 | 16 | ||
diff --git a/server/lib/blocklist.ts b/server/lib/blocklist.ts index d6b684015..98273a6ea 100644 --- a/server/lib/blocklist.ts +++ b/server/lib/blocklist.ts | |||
@@ -40,12 +40,12 @@ async function isBlockedByServerOrAccount (targetAccount: MAccountServer, userAc | |||
40 | 40 | ||
41 | if (userAccount) sourceAccounts.push(userAccount.id) | 41 | if (userAccount) sourceAccounts.push(userAccount.id) |
42 | 42 | ||
43 | const accountMutedHash = await AccountBlocklistModel.isAccountMutedByMulti(sourceAccounts, targetAccount.id) | 43 | const accountMutedHash = await AccountBlocklistModel.isAccountMutedByAccounts(sourceAccounts, targetAccount.id) |
44 | if (accountMutedHash[serverAccountId] || (userAccount && accountMutedHash[userAccount.id])) { | 44 | if (accountMutedHash[serverAccountId] || (userAccount && accountMutedHash[userAccount.id])) { |
45 | return true | 45 | return true |
46 | } | 46 | } |
47 | 47 | ||
48 | const instanceMutedHash = await ServerBlocklistModel.isServerMutedByMulti(sourceAccounts, targetAccount.Actor.serverId) | 48 | const instanceMutedHash = await ServerBlocklistModel.isServerMutedByAccounts(sourceAccounts, targetAccount.Actor.serverId) |
49 | if (instanceMutedHash[serverAccountId] || (userAccount && instanceMutedHash[userAccount.id])) { | 49 | if (instanceMutedHash[serverAccountId] || (userAccount && instanceMutedHash[userAccount.id])) { |
50 | return true | 50 | return true |
51 | } | 51 | } |
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 360b4667f..74788af52 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -3,12 +3,14 @@ import { readFile } from 'fs-extra' | |||
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import validator from 'validator' | 4 | import validator from 'validator' |
5 | import { toCompleteUUID } from '@server/helpers/custom-validators/misc' | 5 | import { toCompleteUUID } from '@server/helpers/custom-validators/misc' |
6 | import { root } from '@shared/core-utils' | ||
6 | import { escapeHTML } from '@shared/core-utils/renderer' | 7 | import { escapeHTML } from '@shared/core-utils/renderer' |
8 | import { sha256 } from '@shared/extra-utils' | ||
7 | import { HTMLServerConfig } from '@shared/models' | 9 | import { HTMLServerConfig } from '@shared/models' |
8 | import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n' | 10 | import { buildFileLocale, getDefaultLocale, is18nLocale, POSSIBLE_LOCALES } from '../../shared/core-utils/i18n/i18n' |
9 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' | 11 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' |
10 | import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos' | 12 | import { VideoPlaylistPrivacy, VideoPrivacy } from '../../shared/models/videos' |
11 | import { isTestInstance, sha256 } from '../helpers/core-utils' | 13 | import { isTestInstance } from '../helpers/core-utils' |
12 | import { logger } from '../helpers/logger' | 14 | import { logger } from '../helpers/logger' |
13 | import { mdToPlainText } from '../helpers/markdown' | 15 | import { mdToPlainText } from '../helpers/markdown' |
14 | import { CONFIG } from '../initializers/config' | 16 | import { CONFIG } from '../initializers/config' |
@@ -343,15 +345,11 @@ class ClientHtml { | |||
343 | { cookie: req.cookies?.clientLanguage, paramLang, acceptLanguage: req.headers['accept-language'] } | 345 | { cookie: req.cookies?.clientLanguage, paramLang, acceptLanguage: req.headers['accept-language'] } |
344 | ) | 346 | ) |
345 | 347 | ||
346 | return join(__dirname, '../../../client/dist/' + buildFileLocale(lang) + '/index.html') | 348 | return join(root(), 'client', 'dist', buildFileLocale(lang), 'index.html') |
347 | } | 349 | } |
348 | 350 | ||
349 | private static getEmbedPath () { | 351 | private static getEmbedPath () { |
350 | return join(__dirname, '../../../client/dist/standalone/videos/embed.html') | 352 | return join(root(), 'client', 'dist', 'standalone', 'videos', 'embed.html') |
351 | } | ||
352 | |||
353 | private static addHtmlLang (htmlStringPage: string, paramLang: string) { | ||
354 | return htmlStringPage.replace('<html>', `<html lang="${paramLang}">`) | ||
355 | } | 353 | } |
356 | 354 | ||
357 | private static addManifestContentHash (htmlStringPage: string) { | 355 | private static addManifestContentHash (htmlStringPage: string) { |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 60284ea28..ebad43650 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -4,7 +4,8 @@ import { createTransport, Transporter } from 'nodemailer' | |||
4 | import { join } from 'path' | 4 | import { join } from 'path' |
5 | import { EmailPayload } from '@shared/models' | 5 | import { EmailPayload } from '@shared/models' |
6 | import { SendEmailDefaultOptions } from '../../shared/models/server/emailer.model' | 6 | import { SendEmailDefaultOptions } from '../../shared/models/server/emailer.model' |
7 | import { isTestInstance, root } from '../helpers/core-utils' | 7 | import { isTestInstance } from '../helpers/core-utils' |
8 | import { root } from '@shared/core-utils' | ||
8 | import { bunyanLogger, logger } from '../helpers/logger' | 9 | import { bunyanLogger, logger } from '../helpers/logger' |
9 | import { CONFIG, isEmailEnabled } from '../initializers/config' | 10 | import { CONFIG, isEmailEnabled } from '../initializers/config' |
10 | import { WEBSERVER } from '../initializers/constants' | 11 | import { WEBSERVER } from '../initializers/constants' |
diff --git a/server/lib/hls.ts b/server/lib/hls.ts index f2fe893a9..1574ff27b 100644 --- a/server/lib/hls.ts +++ b/server/lib/hls.ts | |||
@@ -2,7 +2,7 @@ import { close, ensureDir, move, open, outputJSON, read, readFile, remove, stat, | |||
2 | import { flatten, uniq } from 'lodash' | 2 | import { flatten, uniq } from 'lodash' |
3 | import { basename, dirname, join } from 'path' | 3 | import { basename, dirname, join } from 'path' |
4 | import { MStreamingPlaylistFilesVideo, MVideo, MVideoUUID } from '@server/types/models' | 4 | import { MStreamingPlaylistFilesVideo, MVideo, MVideoUUID } from '@server/types/models' |
5 | import { sha256 } from '../helpers/core-utils' | 5 | import { sha256 } from '@shared/extra-utils' |
6 | import { getAudioStreamCodec, getVideoStreamCodec, getVideoStreamSize } from '../helpers/ffprobe-utils' | 6 | import { getAudioStreamCodec, getVideoStreamCodec, getVideoStreamSize } from '../helpers/ffprobe-utils' |
7 | import { logger } from '../helpers/logger' | 7 | import { logger } from '../helpers/logger' |
8 | import { doRequest, doRequestAndSaveToFile } from '../helpers/requests' | 8 | import { doRequest, doRequestAndSaveToFile } from '../helpers/requests' |
diff --git a/server/lib/job-queue/handlers/activitypub-cleaner.ts b/server/lib/job-queue/handlers/activitypub-cleaner.ts index d5e4508fe..509dd1cb5 100644 --- a/server/lib/job-queue/handlers/activitypub-cleaner.ts +++ b/server/lib/job-queue/handlers/activitypub-cleaner.ts | |||
@@ -8,36 +8,35 @@ import { | |||
8 | } from '@server/helpers/custom-validators/activitypub/activity' | 8 | } from '@server/helpers/custom-validators/activitypub/activity' |
9 | import { sanitizeAndCheckVideoCommentObject } from '@server/helpers/custom-validators/activitypub/video-comments' | 9 | import { sanitizeAndCheckVideoCommentObject } from '@server/helpers/custom-validators/activitypub/video-comments' |
10 | import { doJSONRequest, PeerTubeRequestError } from '@server/helpers/requests' | 10 | import { doJSONRequest, PeerTubeRequestError } from '@server/helpers/requests' |
11 | import { AP_CLEANER_CONCURRENCY } from '@server/initializers/constants' | 11 | import { AP_CLEANER } from '@server/initializers/constants' |
12 | import { Redis } from '@server/lib/redis' | ||
12 | import { VideoModel } from '@server/models/video/video' | 13 | import { VideoModel } from '@server/models/video/video' |
13 | import { VideoCommentModel } from '@server/models/video/video-comment' | 14 | import { VideoCommentModel } from '@server/models/video/video-comment' |
14 | import { VideoShareModel } from '@server/models/video/video-share' | 15 | import { VideoShareModel } from '@server/models/video/video-share' |
15 | import { HttpStatusCode } from '@shared/models' | 16 | import { HttpStatusCode } from '@shared/models' |
16 | import { logger } from '../../../helpers/logger' | 17 | import { logger, loggerTagsFactory } from '../../../helpers/logger' |
17 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' | 18 | import { AccountVideoRateModel } from '../../../models/account/account-video-rate' |
18 | 19 | ||
20 | const lTags = loggerTagsFactory('ap-cleaner') | ||
21 | |||
19 | // Job to clean remote interactions off local videos | 22 | // Job to clean remote interactions off local videos |
20 | 23 | ||
21 | async function processActivityPubCleaner (_job: Job) { | 24 | async function processActivityPubCleaner (_job: Job) { |
22 | logger.info('Processing ActivityPub cleaner.') | 25 | logger.info('Processing ActivityPub cleaner.', lTags()) |
23 | 26 | ||
24 | { | 27 | { |
25 | const rateUrls = await AccountVideoRateModel.listRemoteRateUrlsOfLocalVideos() | 28 | const rateUrls = await AccountVideoRateModel.listRemoteRateUrlsOfLocalVideos() |
26 | const { bodyValidator, deleter, updater } = rateOptionsFactory() | 29 | const { bodyValidator, deleter, updater } = rateOptionsFactory() |
27 | 30 | ||
28 | await map(rateUrls, async rateUrl => { | 31 | await map(rateUrls, async rateUrl => { |
29 | try { | 32 | const result = await updateObjectIfNeeded({ url: rateUrl, bodyValidator, updater, deleter }) |
30 | const result = await updateObjectIfNeeded(rateUrl, bodyValidator, updater, deleter) | ||
31 | 33 | ||
32 | if (result?.status === 'deleted') { | 34 | if (result?.status === 'deleted') { |
33 | const { videoId, type } = result.data | 35 | const { videoId, type } = result.data |
34 | 36 | ||
35 | await VideoModel.updateRatesOf(videoId, type, undefined) | 37 | await VideoModel.updateRatesOf(videoId, type, undefined) |
36 | } | ||
37 | } catch (err) { | ||
38 | logger.warn('Cannot update/delete remote AP rate %s.', rateUrl, { err }) | ||
39 | } | 38 | } |
40 | }, { concurrency: AP_CLEANER_CONCURRENCY }) | 39 | }, { concurrency: AP_CLEANER.CONCURRENCY }) |
41 | } | 40 | } |
42 | 41 | ||
43 | { | 42 | { |
@@ -45,12 +44,8 @@ async function processActivityPubCleaner (_job: Job) { | |||
45 | const { bodyValidator, deleter, updater } = shareOptionsFactory() | 44 | const { bodyValidator, deleter, updater } = shareOptionsFactory() |
46 | 45 | ||
47 | await map(shareUrls, async shareUrl => { | 46 | await map(shareUrls, async shareUrl => { |
48 | try { | 47 | await updateObjectIfNeeded({ url: shareUrl, bodyValidator, updater, deleter }) |
49 | await updateObjectIfNeeded(shareUrl, bodyValidator, updater, deleter) | 48 | }, { concurrency: AP_CLEANER.CONCURRENCY }) |
50 | } catch (err) { | ||
51 | logger.warn('Cannot update/delete remote AP share %s.', shareUrl, { err }) | ||
52 | } | ||
53 | }, { concurrency: AP_CLEANER_CONCURRENCY }) | ||
54 | } | 49 | } |
55 | 50 | ||
56 | { | 51 | { |
@@ -58,12 +53,8 @@ async function processActivityPubCleaner (_job: Job) { | |||
58 | const { bodyValidator, deleter, updater } = commentOptionsFactory() | 53 | const { bodyValidator, deleter, updater } = commentOptionsFactory() |
59 | 54 | ||
60 | await map(commentUrls, async commentUrl => { | 55 | await map(commentUrls, async commentUrl => { |
61 | try { | 56 | await updateObjectIfNeeded({ url: commentUrl, bodyValidator, updater, deleter }) |
62 | await updateObjectIfNeeded(commentUrl, bodyValidator, updater, deleter) | 57 | }, { concurrency: AP_CLEANER.CONCURRENCY }) |
63 | } catch (err) { | ||
64 | logger.warn('Cannot update/delete remote AP comment %s.', commentUrl, { err }) | ||
65 | } | ||
66 | }, { concurrency: AP_CLEANER_CONCURRENCY }) | ||
67 | } | 58 | } |
68 | } | 59 | } |
69 | 60 | ||
@@ -75,14 +66,16 @@ export { | |||
75 | 66 | ||
76 | // --------------------------------------------------------------------------- | 67 | // --------------------------------------------------------------------------- |
77 | 68 | ||
78 | async function updateObjectIfNeeded <T> ( | 69 | async function updateObjectIfNeeded <T> (options: { |
79 | url: string, | 70 | url: string |
80 | bodyValidator: (body: any) => boolean, | 71 | bodyValidator: (body: any) => boolean |
81 | updater: (url: string, newUrl: string) => Promise<T>, | 72 | updater: (url: string, newUrl: string) => Promise<T> |
82 | deleter: (url: string) => Promise<T> | 73 | deleter: (url: string) => Promise<T> } |
83 | ): Promise<{ data: T, status: 'deleted' | 'updated' } | null> { | 74 | ): Promise<{ data: T, status: 'deleted' | 'updated' } | null> { |
75 | const { url, bodyValidator, updater, deleter } = options | ||
76 | |||
84 | const on404OrTombstone = async () => { | 77 | const on404OrTombstone = async () => { |
85 | logger.info('Removing remote AP object %s.', url) | 78 | logger.info('Removing remote AP object %s.', url, lTags(url)) |
86 | const data = await deleter(url) | 79 | const data = await deleter(url) |
87 | 80 | ||
88 | return { status: 'deleted' as 'deleted', data } | 81 | return { status: 'deleted' as 'deleted', data } |
@@ -104,7 +97,7 @@ async function updateObjectIfNeeded <T> ( | |||
104 | throw new Error(`New url ${newUrl} has not the same host than old url ${url}`) | 97 | throw new Error(`New url ${newUrl} has not the same host than old url ${url}`) |
105 | } | 98 | } |
106 | 99 | ||
107 | logger.info('Updating remote AP object %s.', url) | 100 | logger.info('Updating remote AP object %s.', url, lTags(url)) |
108 | const data = await updater(url, newUrl) | 101 | const data = await updater(url, newUrl) |
109 | 102 | ||
110 | return { status: 'updated', data } | 103 | return { status: 'updated', data } |
@@ -117,7 +110,15 @@ async function updateObjectIfNeeded <T> ( | |||
117 | return on404OrTombstone() | 110 | return on404OrTombstone() |
118 | } | 111 | } |
119 | 112 | ||
120 | throw err | 113 | logger.debug('Remote AP object %s is unavailable.', url, lTags(url)) |
114 | |||
115 | const unavailability = await Redis.Instance.addAPUnavailability(url) | ||
116 | if (unavailability >= AP_CLEANER.UNAVAILABLE_TRESHOLD) { | ||
117 | logger.info('Removing unavailable AP resource %s.', url, lTags(url)) | ||
118 | return on404OrTombstone() | ||
119 | } | ||
120 | |||
121 | return null | ||
121 | } | 122 | } |
122 | } | 123 | } |
123 | 124 | ||
diff --git a/server/lib/job-queue/handlers/move-to-object-storage.ts b/server/lib/job-queue/handlers/move-to-object-storage.ts index 54a7c566b..9e39322a8 100644 --- a/server/lib/job-queue/handlers/move-to-object-storage.ts +++ b/server/lib/job-queue/handlers/move-to-object-storage.ts | |||
@@ -2,16 +2,16 @@ import { Job } from 'bull' | |||
2 | import { remove } from 'fs-extra' | 2 | import { remove } from 'fs-extra' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { logger } from '@server/helpers/logger' | 4 | import { logger } from '@server/helpers/logger' |
5 | import { updateTorrentUrls } from '@server/helpers/webtorrent' | 5 | import { updateTorrentMetadata } from '@server/helpers/webtorrent' |
6 | import { CONFIG } from '@server/initializers/config' | 6 | import { CONFIG } from '@server/initializers/config' |
7 | import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants' | 7 | import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants' |
8 | import { storeHLSFile, storeWebTorrentFile } from '@server/lib/object-storage' | 8 | import { storeHLSFile, storeWebTorrentFile } from '@server/lib/object-storage' |
9 | import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths' | 9 | import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths' |
10 | import { moveToNextState } from '@server/lib/video-state' | 10 | import { moveToFailedMoveToObjectStorageState, moveToNextState } from '@server/lib/video-state' |
11 | import { VideoModel } from '@server/models/video/video' | 11 | import { VideoModel } from '@server/models/video/video' |
12 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' | 12 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' |
13 | import { MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoWithAllFiles } from '@server/types/models' | 13 | import { MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoWithAllFiles } from '@server/types/models' |
14 | import { MoveObjectStoragePayload, VideoStorage } from '../../../../shared' | 14 | import { MoveObjectStoragePayload, VideoStorage } from '@shared/models' |
15 | 15 | ||
16 | export async function processMoveToObjectStorage (job: Job) { | 16 | export async function processMoveToObjectStorage (job: Job) { |
17 | const payload = job.data as MoveObjectStoragePayload | 17 | const payload = job.data as MoveObjectStoragePayload |
@@ -24,18 +24,25 @@ export async function processMoveToObjectStorage (job: Job) { | |||
24 | return undefined | 24 | return undefined |
25 | } | 25 | } |
26 | 26 | ||
27 | if (video.VideoFiles) { | 27 | try { |
28 | await moveWebTorrentFiles(video) | 28 | if (video.VideoFiles) { |
29 | } | 29 | await moveWebTorrentFiles(video) |
30 | } | ||
30 | 31 | ||
31 | if (video.VideoStreamingPlaylists) { | 32 | if (video.VideoStreamingPlaylists) { |
32 | await moveHLSFiles(video) | 33 | await moveHLSFiles(video) |
33 | } | 34 | } |
35 | |||
36 | const pendingMove = await VideoJobInfoModel.decrease(video.uuid, 'pendingMove') | ||
37 | if (pendingMove === 0) { | ||
38 | logger.info('Running cleanup after moving files to object storage (video %s in job %d)', video.uuid, job.id) | ||
39 | await doAfterLastJob(video, payload.isNewVideo) | ||
40 | } | ||
41 | } catch (err) { | ||
42 | logger.error('Cannot move video %s to object storage.', video.url, { err }) | ||
34 | 43 | ||
35 | const pendingMove = await VideoJobInfoModel.decrease(video.uuid, 'pendingMove') | 44 | await moveToFailedMoveToObjectStorageState(video) |
36 | if (pendingMove === 0) { | 45 | await VideoJobInfoModel.abortAllTasks(video.uuid, 'pendingMove') |
37 | logger.info('Running cleanup after moving files to object storage (video %s in job %d)', video.uuid, job.id) | ||
38 | await doAfterLastJob(video, payload.isNewVideo) | ||
39 | } | 46 | } |
40 | 47 | ||
41 | return payload.videoUUID | 48 | return payload.videoUUID |
@@ -113,7 +120,7 @@ async function onFileMoved (options: { | |||
113 | file.fileUrl = fileUrl | 120 | file.fileUrl = fileUrl |
114 | file.storage = VideoStorage.OBJECT_STORAGE | 121 | file.storage = VideoStorage.OBJECT_STORAGE |
115 | 122 | ||
116 | await updateTorrentUrls(videoOrPlaylist, file) | 123 | await updateTorrentMetadata(videoOrPlaylist, file) |
117 | await file.save() | 124 | await file.save() |
118 | 125 | ||
119 | logger.debug('Removing %s because it\'s now on object storage', oldPath) | 126 | logger.debug('Removing %s because it\'s now on object storage', oldPath) |
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index a91c2ef80..0d9e80cb8 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Job } from 'bull' | 1 | import { Job } from 'bull' |
2 | import { copy, stat } from 'fs-extra' | 2 | import { copy, stat } from 'fs-extra' |
3 | import { getLowercaseExtension } from '@server/helpers/core-utils' | 3 | import { getLowercaseExtension } from '@shared/core-utils' |
4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 4 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
5 | import { CONFIG } from '@server/initializers/config' | 5 | import { CONFIG } from '@server/initializers/config' |
6 | import { federateVideoIfNeeded } from '@server/lib/activitypub/videos' | 6 | import { federateVideoIfNeeded } from '@server/lib/activitypub/videos' |
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 4ce1a6c30..2f74e9fbd 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Job } from 'bull' | 1 | import { Job } from 'bull' |
2 | import { move, remove, stat } from 'fs-extra' | 2 | import { move, remove, stat } from 'fs-extra' |
3 | import { getLowercaseExtension } from '@server/helpers/core-utils' | ||
4 | import { retryTransactionWrapper } from '@server/helpers/database-utils' | 3 | import { retryTransactionWrapper } from '@server/helpers/database-utils' |
5 | import { YoutubeDLWrapper } from '@server/helpers/youtube-dl' | 4 | import { YoutubeDLWrapper } from '@server/helpers/youtube-dl' |
6 | import { isPostImportVideoAccepted } from '@server/lib/moderation' | 5 | import { isPostImportVideoAccepted } from '@server/lib/moderation' |
@@ -13,17 +12,20 @@ import { VideoPathManager } from '@server/lib/video-path-manager' | |||
13 | import { buildNextVideoState } from '@server/lib/video-state' | 12 | import { buildNextVideoState } from '@server/lib/video-state' |
14 | import { ThumbnailModel } from '@server/models/video/thumbnail' | 13 | import { ThumbnailModel } from '@server/models/video/thumbnail' |
15 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/types/models/video/video-import' | 14 | import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/types/models/video/video-import' |
15 | import { getLowercaseExtension } from '@shared/core-utils' | ||
16 | import { isAudioFile } from '@shared/extra-utils' | ||
16 | import { | 17 | import { |
18 | ThumbnailType, | ||
17 | VideoImportPayload, | 19 | VideoImportPayload, |
20 | VideoImportState, | ||
18 | VideoImportTorrentPayload, | 21 | VideoImportTorrentPayload, |
19 | VideoImportTorrentPayloadType, | 22 | VideoImportTorrentPayloadType, |
20 | VideoImportYoutubeDLPayload, | 23 | VideoImportYoutubeDLPayload, |
21 | VideoImportYoutubeDLPayloadType, | 24 | VideoImportYoutubeDLPayloadType, |
25 | VideoResolution, | ||
22 | VideoState | 26 | VideoState |
23 | } from '../../../../shared' | 27 | } from '@shared/models' |
24 | import { VideoImportState } from '../../../../shared/models/videos' | 28 | import { ffprobePromise, getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' |
25 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | ||
26 | import { getDurationFromVideoFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffprobe-utils' | ||
27 | import { logger } from '../../../helpers/logger' | 29 | import { logger } from '../../../helpers/logger' |
28 | import { getSecureTorrentName } from '../../../helpers/utils' | 30 | import { getSecureTorrentName } from '../../../helpers/utils' |
29 | import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' | 31 | import { createTorrentAndSetInfoHash, downloadWebTorrentVideo } from '../../../helpers/webtorrent' |
@@ -114,9 +116,14 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
114 | throw new Error('The user video quota is exceeded with this video to import.') | 116 | throw new Error('The user video quota is exceeded with this video to import.') |
115 | } | 117 | } |
116 | 118 | ||
117 | const { resolution } = await getVideoFileResolution(tempVideoPath) | 119 | const probe = await ffprobePromise(tempVideoPath) |
118 | const fps = await getVideoFileFPS(tempVideoPath) | 120 | |
119 | const duration = await getDurationFromVideoFile(tempVideoPath) | 121 | const { resolution } = await isAudioFile(tempVideoPath, probe) |
122 | ? { resolution: VideoResolution.H_NOVIDEO } | ||
123 | : await getVideoFileResolution(tempVideoPath) | ||
124 | |||
125 | const fps = await getVideoFileFPS(tempVideoPath, probe) | ||
126 | const duration = await getDurationFromVideoFile(tempVideoPath, probe) | ||
120 | 127 | ||
121 | // Prepare video file object for creation in database | 128 | // Prepare video file object for creation in database |
122 | const fileExt = getLowercaseExtension(tempVideoPath) | 129 | const fileExt = getLowercaseExtension(tempVideoPath) |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 0edcdcba3..02902b0b8 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -6,13 +6,15 @@ import { moveToFailedTranscodingState, moveToNextState } from '@server/lib/video | |||
6 | import { UserModel } from '@server/models/user/user' | 6 | import { UserModel } from '@server/models/user/user' |
7 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' | 7 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' |
8 | import { MUser, MUserId, MVideo, MVideoFullLight, MVideoWithFile } from '@server/types/models' | 8 | import { MUser, MUserId, MVideo, MVideoFullLight, MVideoWithFile } from '@server/types/models' |
9 | import { pick } from '@shared/core-utils' | ||
9 | import { | 10 | import { |
10 | HLSTranscodingPayload, | 11 | HLSTranscodingPayload, |
11 | MergeAudioTranscodingPayload, | 12 | MergeAudioTranscodingPayload, |
12 | NewResolutionTranscodingPayload, | 13 | NewResolutionTranscodingPayload, |
13 | OptimizeTranscodingPayload, | 14 | OptimizeTranscodingPayload, |
15 | VideoResolution, | ||
14 | VideoTranscodingPayload | 16 | VideoTranscodingPayload |
15 | } from '../../../../shared' | 17 | } from '@shared/models' |
16 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 18 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
17 | import { computeLowerResolutionsToTranscode } from '../../../helpers/ffprobe-utils' | 19 | import { computeLowerResolutionsToTranscode } from '../../../helpers/ffprobe-utils' |
18 | import { logger, loggerTagsFactory } from '../../../helpers/logger' | 20 | import { logger, loggerTagsFactory } from '../../../helpers/logger' |
@@ -159,6 +161,7 @@ async function onHlsPlaylistGeneration (video: MVideoFullLight, user: MUser, pay | |||
159 | user, | 161 | user, |
160 | videoFileResolution: payload.resolution, | 162 | videoFileResolution: payload.resolution, |
161 | isPortraitMode: payload.isPortraitMode, | 163 | isPortraitMode: payload.isPortraitMode, |
164 | hasAudio: payload.hasAudio, | ||
162 | isNewVideo: payload.isNewVideo ?? true, | 165 | isNewVideo: payload.isNewVideo ?? true, |
163 | type: 'hls' | 166 | type: 'hls' |
164 | }) | 167 | }) |
@@ -174,7 +177,7 @@ async function onVideoFirstWebTorrentTranscoding ( | |||
174 | transcodeType: TranscodeOptionsType, | 177 | transcodeType: TranscodeOptionsType, |
175 | user: MUserId | 178 | user: MUserId |
176 | ) { | 179 | ) { |
177 | const { resolution, isPortraitMode } = await videoArg.getMaxQualityResolution() | 180 | const { resolution, isPortraitMode, audioStream } = await videoArg.getMaxQualityFileInfo() |
178 | 181 | ||
179 | // Maybe the video changed in database, refresh it | 182 | // Maybe the video changed in database, refresh it |
180 | const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid) | 183 | const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid) |
@@ -186,6 +189,7 @@ async function onVideoFirstWebTorrentTranscoding ( | |||
186 | ...payload, | 189 | ...payload, |
187 | 190 | ||
188 | isPortraitMode, | 191 | isPortraitMode, |
192 | hasAudio: !!audioStream, | ||
189 | resolution: videoDatabase.getMaxQualityFile().resolution, | 193 | resolution: videoDatabase.getMaxQualityFile().resolution, |
190 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues | 194 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues |
191 | copyCodecs: transcodeType !== 'quick-transcode', | 195 | copyCodecs: transcodeType !== 'quick-transcode', |
@@ -196,6 +200,7 @@ async function onVideoFirstWebTorrentTranscoding ( | |||
196 | video: videoDatabase, | 200 | video: videoDatabase, |
197 | user, | 201 | user, |
198 | videoFileResolution: resolution, | 202 | videoFileResolution: resolution, |
203 | hasAudio: !!audioStream, | ||
199 | isPortraitMode, | 204 | isPortraitMode, |
200 | type: 'webtorrent', | 205 | type: 'webtorrent', |
201 | isNewVideo: payload.isNewVideo ?? true | 206 | isNewVideo: payload.isNewVideo ?? true |
@@ -214,7 +219,7 @@ async function onNewWebTorrentFileResolution ( | |||
214 | user: MUserId, | 219 | user: MUserId, |
215 | payload: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload | 220 | payload: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload |
216 | ) { | 221 | ) { |
217 | await createHlsJobIfEnabled(user, { ...payload, copyCodecs: true, isMaxQuality: false }) | 222 | await createHlsJobIfEnabled(user, { hasAudio: true, copyCodecs: true, isMaxQuality: false, ...payload }) |
218 | await VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode') | 223 | await VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode') |
219 | 224 | ||
220 | await retryTransactionWrapper(moveToNextState, video, payload.isNewVideo) | 225 | await retryTransactionWrapper(moveToNextState, video, payload.isNewVideo) |
@@ -225,6 +230,7 @@ async function onNewWebTorrentFileResolution ( | |||
225 | async function createHlsJobIfEnabled (user: MUserId, payload: { | 230 | async function createHlsJobIfEnabled (user: MUserId, payload: { |
226 | videoUUID: string | 231 | videoUUID: string |
227 | resolution: number | 232 | resolution: number |
233 | hasAudio: boolean | ||
228 | isPortraitMode?: boolean | 234 | isPortraitMode?: boolean |
229 | copyCodecs: boolean | 235 | copyCodecs: boolean |
230 | isMaxQuality: boolean | 236 | isMaxQuality: boolean |
@@ -238,13 +244,9 @@ async function createHlsJobIfEnabled (user: MUserId, payload: { | |||
238 | 244 | ||
239 | const hlsTranscodingPayload: HLSTranscodingPayload = { | 245 | const hlsTranscodingPayload: HLSTranscodingPayload = { |
240 | type: 'new-resolution-to-hls', | 246 | type: 'new-resolution-to-hls', |
241 | videoUUID: payload.videoUUID, | ||
242 | resolution: payload.resolution, | ||
243 | isPortraitMode: payload.isPortraitMode, | ||
244 | copyCodecs: payload.copyCodecs, | ||
245 | isMaxQuality: payload.isMaxQuality, | ||
246 | autoDeleteWebTorrentIfNeeded: true, | 247 | autoDeleteWebTorrentIfNeeded: true, |
247 | isNewVideo: payload.isNewVideo | 248 | |
249 | ...pick(payload, [ 'videoUUID', 'resolution', 'isPortraitMode', 'copyCodecs', 'isMaxQuality', 'isNewVideo', 'hasAudio' ]) | ||
248 | } | 250 | } |
249 | 251 | ||
250 | await addTranscodingJob(hlsTranscodingPayload, jobOptions) | 252 | await addTranscodingJob(hlsTranscodingPayload, jobOptions) |
@@ -257,16 +259,19 @@ async function createLowerResolutionsJobs (options: { | |||
257 | user: MUserId | 259 | user: MUserId |
258 | videoFileResolution: number | 260 | videoFileResolution: number |
259 | isPortraitMode: boolean | 261 | isPortraitMode: boolean |
262 | hasAudio: boolean | ||
260 | isNewVideo: boolean | 263 | isNewVideo: boolean |
261 | type: 'hls' | 'webtorrent' | 264 | type: 'hls' | 'webtorrent' |
262 | }) { | 265 | }) { |
263 | const { video, user, videoFileResolution, isPortraitMode, isNewVideo, type } = options | 266 | const { video, user, videoFileResolution, isPortraitMode, isNewVideo, hasAudio, type } = options |
264 | 267 | ||
265 | // Create transcoding jobs if there are enabled resolutions | 268 | // Create transcoding jobs if there are enabled resolutions |
266 | const resolutionsEnabled = computeLowerResolutionsToTranscode(videoFileResolution, 'vod') | 269 | const resolutionsEnabled = computeLowerResolutionsToTranscode(videoFileResolution, 'vod') |
267 | const resolutionCreated: string[] = [] | 270 | const resolutionCreated: string[] = [] |
268 | 271 | ||
269 | for (const resolution of resolutionsEnabled) { | 272 | for (const resolution of resolutionsEnabled) { |
273 | if (resolution === VideoResolution.H_NOVIDEO && hasAudio === false) continue | ||
274 | |||
270 | let dataInput: VideoTranscodingPayload | 275 | let dataInput: VideoTranscodingPayload |
271 | 276 | ||
272 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { | 277 | if (CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') { |
@@ -276,6 +281,7 @@ async function createLowerResolutionsJobs (options: { | |||
276 | videoUUID: video.uuid, | 281 | videoUUID: video.uuid, |
277 | resolution, | 282 | resolution, |
278 | isPortraitMode, | 283 | isPortraitMode, |
284 | hasAudio, | ||
279 | isNewVideo | 285 | isNewVideo |
280 | } | 286 | } |
281 | 287 | ||
@@ -288,6 +294,7 @@ async function createLowerResolutionsJobs (options: { | |||
288 | videoUUID: video.uuid, | 294 | videoUUID: video.uuid, |
289 | resolution, | 295 | resolution, |
290 | isPortraitMode, | 296 | isPortraitMode, |
297 | hasAudio, | ||
291 | copyCodecs: false, | 298 | copyCodecs: false, |
292 | isMaxQuality: false, | 299 | isMaxQuality: false, |
293 | autoDeleteWebTorrentIfNeeded: true, | 300 | autoDeleteWebTorrentIfNeeded: true, |
diff --git a/server/lib/live/shared/muxing-session.ts b/server/lib/live/shared/muxing-session.ts index eccaefcfa..22a47942a 100644 --- a/server/lib/live/shared/muxing-session.ts +++ b/server/lib/live/shared/muxing-session.ts | |||
@@ -229,7 +229,7 @@ class MuxingSession extends EventEmitter { | |||
229 | 229 | ||
230 | const playlistIdMatcher = /^([\d+])-/ | 230 | const playlistIdMatcher = /^([\d+])-/ |
231 | 231 | ||
232 | const addHandler = async segmentPath => { | 232 | const addHandler = async (segmentPath: string) => { |
233 | logger.debug('Live add handler of %s.', segmentPath, this.lTags()) | 233 | logger.debug('Live add handler of %s.', segmentPath, this.lTags()) |
234 | 234 | ||
235 | const playlistId = basename(segmentPath).match(playlistIdMatcher)[0] | 235 | const playlistId = basename(segmentPath).match(playlistIdMatcher)[0] |
diff --git a/server/lib/local-actor.ts b/server/lib/local-actor.ts index 821a92b91..c6826759b 100644 --- a/server/lib/local-actor.ts +++ b/server/lib/local-actor.ts | |||
@@ -2,9 +2,9 @@ import 'multer' | |||
2 | import { queue } from 'async' | 2 | import { queue } from 'async' |
3 | import LRUCache from 'lru-cache' | 3 | import LRUCache from 'lru-cache' |
4 | import { join } from 'path' | 4 | import { join } from 'path' |
5 | import { getLowercaseExtension } from '@server/helpers/core-utils' | ||
6 | import { buildUUID } from '@server/helpers/uuid' | ||
7 | import { ActorModel } from '@server/models/actor/actor' | 5 | import { ActorModel } from '@server/models/actor/actor' |
6 | import { getLowercaseExtension } from '@shared/core-utils' | ||
7 | import { buildUUID } from '@shared/extra-utils' | ||
8 | import { ActivityPubActorType, ActorImageType } from '@shared/models' | 8 | import { ActivityPubActorType, ActorImageType } from '@shared/models' |
9 | import { retryTransactionWrapper } from '../helpers/database-utils' | 9 | import { retryTransactionWrapper } from '../helpers/database-utils' |
10 | import { processImage } from '../helpers/image-utils' | 10 | import { processImage } from '../helpers/image-utils' |
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index 456b615b2..c2565f867 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts | |||
@@ -107,8 +107,9 @@ async function createVideoAbuse (options: { | |||
107 | endAt: number | 107 | endAt: number |
108 | transaction: Transaction | 108 | transaction: Transaction |
109 | reporterAccount: MAccountDefault | 109 | reporterAccount: MAccountDefault |
110 | skipNotification: boolean | ||
110 | }) { | 111 | }) { |
111 | const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount } = options | 112 | const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount, skipNotification } = options |
112 | 113 | ||
113 | const associateFun = async (abuseInstance: MAbuseFull) => { | 114 | const associateFun = async (abuseInstance: MAbuseFull) => { |
114 | const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({ | 115 | const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({ |
@@ -129,6 +130,7 @@ async function createVideoAbuse (options: { | |||
129 | reporterAccount, | 130 | reporterAccount, |
130 | flaggedAccount: videoInstance.VideoChannel.Account, | 131 | flaggedAccount: videoInstance.VideoChannel.Account, |
131 | transaction, | 132 | transaction, |
133 | skipNotification, | ||
132 | associateFun | 134 | associateFun |
133 | }) | 135 | }) |
134 | } | 136 | } |
@@ -138,8 +140,9 @@ function createVideoCommentAbuse (options: { | |||
138 | commentInstance: MCommentOwnerVideo | 140 | commentInstance: MCommentOwnerVideo |
139 | transaction: Transaction | 141 | transaction: Transaction |
140 | reporterAccount: MAccountDefault | 142 | reporterAccount: MAccountDefault |
143 | skipNotification: boolean | ||
141 | }) { | 144 | }) { |
142 | const { baseAbuse, commentInstance, transaction, reporterAccount } = options | 145 | const { baseAbuse, commentInstance, transaction, reporterAccount, skipNotification } = options |
143 | 146 | ||
144 | const associateFun = async (abuseInstance: MAbuseFull) => { | 147 | const associateFun = async (abuseInstance: MAbuseFull) => { |
145 | const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({ | 148 | const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({ |
@@ -158,6 +161,7 @@ function createVideoCommentAbuse (options: { | |||
158 | reporterAccount, | 161 | reporterAccount, |
159 | flaggedAccount: commentInstance.Account, | 162 | flaggedAccount: commentInstance.Account, |
160 | transaction, | 163 | transaction, |
164 | skipNotification, | ||
161 | associateFun | 165 | associateFun |
162 | }) | 166 | }) |
163 | } | 167 | } |
@@ -167,8 +171,9 @@ function createAccountAbuse (options: { | |||
167 | accountInstance: MAccountDefault | 171 | accountInstance: MAccountDefault |
168 | transaction: Transaction | 172 | transaction: Transaction |
169 | reporterAccount: MAccountDefault | 173 | reporterAccount: MAccountDefault |
174 | skipNotification: boolean | ||
170 | }) { | 175 | }) { |
171 | const { baseAbuse, accountInstance, transaction, reporterAccount } = options | 176 | const { baseAbuse, accountInstance, transaction, reporterAccount, skipNotification } = options |
172 | 177 | ||
173 | const associateFun = () => { | 178 | const associateFun = () => { |
174 | return Promise.resolve({ isOwned: accountInstance.isOwned() }) | 179 | return Promise.resolve({ isOwned: accountInstance.isOwned() }) |
@@ -179,6 +184,7 @@ function createAccountAbuse (options: { | |||
179 | reporterAccount, | 184 | reporterAccount, |
180 | flaggedAccount: accountInstance, | 185 | flaggedAccount: accountInstance, |
181 | transaction, | 186 | transaction, |
187 | skipNotification, | ||
182 | associateFun | 188 | associateFun |
183 | }) | 189 | }) |
184 | } | 190 | } |
@@ -207,9 +213,10 @@ async function createAbuse (options: { | |||
207 | reporterAccount: MAccountDefault | 213 | reporterAccount: MAccountDefault |
208 | flaggedAccount: MAccountLight | 214 | flaggedAccount: MAccountLight |
209 | associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean} > | 215 | associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean} > |
216 | skipNotification: boolean | ||
210 | transaction: Transaction | 217 | transaction: Transaction |
211 | }) { | 218 | }) { |
212 | const { base, reporterAccount, flaggedAccount, associateFun, transaction } = options | 219 | const { base, reporterAccount, flaggedAccount, associateFun, transaction, skipNotification } = options |
213 | const auditLogger = auditLoggerFactory('abuse') | 220 | const auditLogger = auditLoggerFactory('abuse') |
214 | 221 | ||
215 | const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id }) | 222 | const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id }) |
@@ -227,13 +234,15 @@ async function createAbuse (options: { | |||
227 | const abuseJSON = abuseInstance.toFormattedAdminJSON() | 234 | const abuseJSON = abuseInstance.toFormattedAdminJSON() |
228 | auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON)) | 235 | auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON)) |
229 | 236 | ||
230 | afterCommitIfTransaction(transaction, () => { | 237 | if (!skipNotification) { |
231 | Notifier.Instance.notifyOnNewAbuse({ | 238 | afterCommitIfTransaction(transaction, () => { |
232 | abuse: abuseJSON, | 239 | Notifier.Instance.notifyOnNewAbuse({ |
233 | abuseInstance, | 240 | abuse: abuseJSON, |
234 | reporter: reporterAccount.Actor.getIdentifier() | 241 | abuseInstance, |
242 | reporter: reporterAccount.Actor.getIdentifier() | ||
243 | }) | ||
235 | }) | 244 | }) |
236 | }) | 245 | } |
237 | 246 | ||
238 | logger.info('Abuse report %d created.', abuseInstance.id) | 247 | logger.info('Abuse report %d created.', abuseInstance.id) |
239 | 248 | ||
diff --git a/server/lib/notifier/shared/comment/comment-mention.ts b/server/lib/notifier/shared/comment/comment-mention.ts index 4f84d8dea..765cbaad9 100644 --- a/server/lib/notifier/shared/comment/comment-mention.ts +++ b/server/lib/notifier/shared/comment/comment-mention.ts | |||
@@ -47,8 +47,8 @@ export class CommentMention extends AbstractNotification <MCommentOwnerVideo, MU | |||
47 | 47 | ||
48 | const sourceAccounts = this.users.map(u => u.Account.id).concat([ this.serverAccountId ]) | 48 | const sourceAccounts = this.users.map(u => u.Account.id).concat([ this.serverAccountId ]) |
49 | 49 | ||
50 | this.accountMutedHash = await AccountBlocklistModel.isAccountMutedByMulti(sourceAccounts, this.payload.accountId) | 50 | this.accountMutedHash = await AccountBlocklistModel.isAccountMutedByAccounts(sourceAccounts, this.payload.accountId) |
51 | this.instanceMutedHash = await ServerBlocklistModel.isServerMutedByMulti(sourceAccounts, this.payload.Account.Actor.serverId) | 51 | this.instanceMutedHash = await ServerBlocklistModel.isServerMutedByAccounts(sourceAccounts, this.payload.Account.Actor.serverId) |
52 | } | 52 | } |
53 | 53 | ||
54 | log () { | 54 | log () { |
diff --git a/server/lib/paths.ts b/server/lib/paths.ts index 434e637c6..5a85bea42 100644 --- a/server/lib/paths.ts +++ b/server/lib/paths.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { buildUUID } from '@server/helpers/uuid' | ||
3 | import { CONFIG } from '@server/initializers/config' | 2 | import { CONFIG } from '@server/initializers/config' |
4 | import { HLS_REDUNDANCY_DIRECTORY, HLS_STREAMING_PLAYLIST_DIRECTORY } from '@server/initializers/constants' | 3 | import { HLS_REDUNDANCY_DIRECTORY, HLS_STREAMING_PLAYLIST_DIRECTORY } from '@server/initializers/constants' |
5 | import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoUUID } from '@server/types/models' | 4 | import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoUUID } from '@server/types/models' |
6 | import { removeFragmentedMP4Ext } from '@shared/core-utils' | 5 | import { removeFragmentedMP4Ext } from '@shared/core-utils' |
6 | import { buildUUID } from '@shared/extra-utils' | ||
7 | 7 | ||
8 | // ################## Video file name ################## | 8 | // ################## Video file name ################## |
9 | 9 | ||
diff --git a/server/lib/plugins/plugin-helpers-builder.ts b/server/lib/plugins/plugin-helpers-builder.ts index e26776f45..78e4a28ad 100644 --- a/server/lib/plugins/plugin-helpers-builder.ts +++ b/server/lib/plugins/plugin-helpers-builder.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { ffprobePromise } from '@server/helpers/ffprobe-utils' | ||
3 | import { buildLogger } from '@server/helpers/logger' | 4 | import { buildLogger } from '@server/helpers/logger' |
4 | import { CONFIG } from '@server/initializers/config' | 5 | import { CONFIG } from '@server/initializers/config' |
5 | import { WEBSERVER } from '@server/initializers/constants' | 6 | import { WEBSERVER } from '@server/initializers/constants' |
@@ -9,15 +10,16 @@ import { AccountBlocklistModel } from '@server/models/account/account-blocklist' | |||
9 | import { getServerActor } from '@server/models/application/application' | 10 | import { getServerActor } from '@server/models/application/application' |
10 | import { ServerModel } from '@server/models/server/server' | 11 | import { ServerModel } from '@server/models/server/server' |
11 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' | 12 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' |
13 | import { UserModel } from '@server/models/user/user' | ||
12 | import { VideoModel } from '@server/models/video/video' | 14 | import { VideoModel } from '@server/models/video/video' |
13 | import { VideoBlacklistModel } from '@server/models/video/video-blacklist' | 15 | import { VideoBlacklistModel } from '@server/models/video/video-blacklist' |
14 | import { MPlugin } from '@server/types/models' | 16 | import { MPlugin } from '@server/types/models' |
15 | import { PeerTubeHelpers } from '@server/types/plugins' | 17 | import { PeerTubeHelpers } from '@server/types/plugins' |
16 | import { VideoBlacklistCreate } from '@shared/models' | 18 | import { VideoBlacklistCreate, VideoStorage } from '@shared/models' |
17 | import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist' | 19 | import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist' |
18 | import { ServerConfigManager } from '../server-config-manager' | 20 | import { ServerConfigManager } from '../server-config-manager' |
19 | import { blacklistVideo, unblacklistVideo } from '../video-blacklist' | 21 | import { blacklistVideo, unblacklistVideo } from '../video-blacklist' |
20 | import { UserModel } from '@server/models/user/user' | 22 | import { VideoPathManager } from '../video-path-manager' |
21 | 23 | ||
22 | function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers { | 24 | function buildPluginHelpers (pluginModel: MPlugin, npmName: string): PeerTubeHelpers { |
23 | const logger = buildPluginLogger(npmName) | 25 | const logger = buildPluginLogger(npmName) |
@@ -85,6 +87,60 @@ function buildVideosHelpers () { | |||
85 | 87 | ||
86 | await video.destroy({ transaction: t }) | 88 | await video.destroy({ transaction: t }) |
87 | }) | 89 | }) |
90 | }, | ||
91 | |||
92 | ffprobe: (path: string) => { | ||
93 | return ffprobePromise(path) | ||
94 | }, | ||
95 | |||
96 | getFiles: async (id: number | string) => { | ||
97 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(id) | ||
98 | if (!video) return undefined | ||
99 | |||
100 | const webtorrentVideoFiles = (video.VideoFiles || []).map(f => ({ | ||
101 | path: f.storage === VideoStorage.FILE_SYSTEM | ||
102 | ? VideoPathManager.Instance.getFSVideoFileOutputPath(video, f) | ||
103 | : null, | ||
104 | url: f.getFileUrl(video), | ||
105 | |||
106 | resolution: f.resolution, | ||
107 | size: f.size, | ||
108 | fps: f.fps | ||
109 | })) | ||
110 | |||
111 | const hls = video.getHLSPlaylist() | ||
112 | |||
113 | const hlsVideoFiles = hls | ||
114 | ? (video.getHLSPlaylist().VideoFiles || []).map(f => { | ||
115 | return { | ||
116 | path: f.storage === VideoStorage.FILE_SYSTEM | ||
117 | ? VideoPathManager.Instance.getFSVideoFileOutputPath(hls, f) | ||
118 | : null, | ||
119 | url: f.getFileUrl(video), | ||
120 | resolution: f.resolution, | ||
121 | size: f.size, | ||
122 | fps: f.fps | ||
123 | } | ||
124 | }) | ||
125 | : [] | ||
126 | |||
127 | const thumbnails = video.Thumbnails.map(t => ({ | ||
128 | type: t.type, | ||
129 | url: t.getFileUrl(video), | ||
130 | path: t.getPath() | ||
131 | })) | ||
132 | |||
133 | return { | ||
134 | webtorrent: { | ||
135 | videoFiles: webtorrentVideoFiles | ||
136 | }, | ||
137 | |||
138 | hls: { | ||
139 | videoFiles: hlsVideoFiles | ||
140 | }, | ||
141 | |||
142 | thumbnails | ||
143 | } | ||
88 | } | 144 | } |
89 | } | 145 | } |
90 | } | 146 | } |
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts index d4d2a7edc..39e7f9a5b 100644 --- a/server/lib/plugins/plugin-manager.ts +++ b/server/lib/plugins/plugin-manager.ts | |||
@@ -1,11 +1,17 @@ | |||
1 | import decache from 'decache' | ||
2 | import express from 'express' | 1 | import express from 'express' |
3 | import { createReadStream, createWriteStream } from 'fs' | 2 | import { createReadStream, createWriteStream } from 'fs' |
4 | import { ensureDir, outputFile, readJSON } from 'fs-extra' | 3 | import { ensureDir, outputFile, readJSON } from 'fs-extra' |
5 | import { basename, join } from 'path' | 4 | import { basename, join } from 'path' |
5 | import { decachePlugin } from '@server/helpers/decache' | ||
6 | import { MOAuthTokenUser, MUser } from '@server/types/models' | 6 | import { MOAuthTokenUser, MUser } from '@server/types/models' |
7 | import { getCompleteLocale } from '@shared/core-utils' | 7 | import { getCompleteLocale } from '@shared/core-utils' |
8 | import { ClientScript, PluginPackageJson, PluginTranslation, PluginTranslationPaths, RegisterServerHookOptions } from '@shared/models' | 8 | import { |
9 | ClientScriptJSON, | ||
10 | PluginPackageJSON, | ||
11 | PluginTranslation, | ||
12 | PluginTranslationPathsJSON, | ||
13 | RegisterServerHookOptions | ||
14 | } from '@shared/models' | ||
9 | import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks' | 15 | import { getHookType, internalRunHook } from '../../../shared/core-utils/plugins/hooks' |
10 | import { PluginType } from '../../../shared/models/plugins/plugin.type' | 16 | import { PluginType } from '../../../shared/models/plugins/plugin.type' |
11 | import { ServerHook, ServerHookName } from '../../../shared/models/plugins/server/server-hook.model' | 17 | import { ServerHook, ServerHookName } from '../../../shared/models/plugins/server/server-hook.model' |
@@ -31,7 +37,7 @@ export interface RegisteredPlugin { | |||
31 | path: string | 37 | path: string |
32 | 38 | ||
33 | staticDirs: { [name: string]: string } | 39 | staticDirs: { [name: string]: string } |
34 | clientScripts: { [name: string]: ClientScript } | 40 | clientScripts: { [name: string]: ClientScriptJSON } |
35 | 41 | ||
36 | css: string[] | 42 | css: string[] |
37 | 43 | ||
@@ -392,7 +398,7 @@ export class PluginManager implements ServerHook { | |||
392 | registerHelpers = result.registerStore | 398 | registerHelpers = result.registerStore |
393 | } | 399 | } |
394 | 400 | ||
395 | const clientScripts: { [id: string]: ClientScript } = {} | 401 | const clientScripts: { [id: string]: ClientScriptJSON } = {} |
396 | for (const c of packageJSON.clientScripts) { | 402 | for (const c of packageJSON.clientScripts) { |
397 | clientScripts[c.script] = c | 403 | clientScripts[c.script] = c |
398 | } | 404 | } |
@@ -415,12 +421,12 @@ export class PluginManager implements ServerHook { | |||
415 | await this.addTranslations(plugin, npmName, packageJSON.translations) | 421 | await this.addTranslations(plugin, npmName, packageJSON.translations) |
416 | } | 422 | } |
417 | 423 | ||
418 | private async registerPlugin (plugin: PluginModel, pluginPath: string, packageJSON: PluginPackageJson) { | 424 | private async registerPlugin (plugin: PluginModel, pluginPath: string, packageJSON: PluginPackageJSON) { |
419 | const npmName = PluginModel.buildNpmName(plugin.name, plugin.type) | 425 | const npmName = PluginModel.buildNpmName(plugin.name, plugin.type) |
420 | 426 | ||
421 | // Delete cache if needed | 427 | // Delete cache if needed |
422 | const modulePath = join(pluginPath, packageJSON.library) | 428 | const modulePath = join(pluginPath, packageJSON.library) |
423 | decache(modulePath) | 429 | decachePlugin(pluginPath, modulePath) |
424 | const library: PluginLibrary = require(modulePath) | 430 | const library: PluginLibrary = require(modulePath) |
425 | 431 | ||
426 | if (!isLibraryCodeValid(library)) { | 432 | if (!isLibraryCodeValid(library)) { |
@@ -442,7 +448,7 @@ export class PluginManager implements ServerHook { | |||
442 | 448 | ||
443 | // ###################### Translations ###################### | 449 | // ###################### Translations ###################### |
444 | 450 | ||
445 | private async addTranslations (plugin: PluginModel, npmName: string, translationPaths: PluginTranslationPaths) { | 451 | private async addTranslations (plugin: PluginModel, npmName: string, translationPaths: PluginTranslationPathsJSON) { |
446 | for (const locale of Object.keys(translationPaths)) { | 452 | for (const locale of Object.keys(translationPaths)) { |
447 | const path = translationPaths[locale] | 453 | const path = translationPaths[locale] |
448 | const json = await readJSON(join(this.getPluginPath(plugin.name, plugin.type), path)) | 454 | const json = await readJSON(join(this.getPluginPath(plugin.name, plugin.type), path)) |
@@ -513,7 +519,7 @@ export class PluginManager implements ServerHook { | |||
513 | private getPackageJSON (pluginName: string, pluginType: PluginType) { | 519 | private getPackageJSON (pluginName: string, pluginType: PluginType) { |
514 | const pluginPath = join(this.getPluginPath(pluginName, pluginType), 'package.json') | 520 | const pluginPath = join(this.getPluginPath(pluginName, pluginType), 'package.json') |
515 | 521 | ||
516 | return readJSON(pluginPath) as Promise<PluginPackageJson> | 522 | return readJSON(pluginPath) as Promise<PluginPackageJSON> |
517 | } | 523 | } |
518 | 524 | ||
519 | private getPluginPath (pluginName: string, pluginType: PluginType) { | 525 | private getPluginPath (pluginName: string, pluginType: PluginType) { |
@@ -572,7 +578,7 @@ export class PluginManager implements ServerHook { | |||
572 | } | 578 | } |
573 | } | 579 | } |
574 | 580 | ||
575 | private sanitizeAndCheckPackageJSONOrThrow (packageJSON: PluginPackageJson, pluginType: PluginType) { | 581 | private sanitizeAndCheckPackageJSONOrThrow (packageJSON: PluginPackageJSON, pluginType: PluginType) { |
576 | if (!packageJSON.staticDirs) packageJSON.staticDirs = {} | 582 | if (!packageJSON.staticDirs) packageJSON.staticDirs = {} |
577 | if (!packageJSON.css) packageJSON.css = [] | 583 | if (!packageJSON.css) packageJSON.css = [] |
578 | if (!packageJSON.clientScripts) packageJSON.clientScripts = [] | 584 | if (!packageJSON.clientScripts) packageJSON.clientScripts = [] |
diff --git a/server/lib/redis.ts b/server/lib/redis.ts index 8aec4b793..52766663a 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts | |||
@@ -1,31 +1,30 @@ | |||
1 | import express from 'express' | 1 | import { createClient, RedisClientOptions, RedisModules } from 'redis' |
2 | import { createClient, RedisClient } from 'redis' | 2 | import { exists } from '@server/helpers/custom-validators/misc' |
3 | import { sha256 } from '@shared/extra-utils' | ||
3 | import { logger } from '../helpers/logger' | 4 | import { logger } from '../helpers/logger' |
4 | import { generateRandomString } from '../helpers/utils' | 5 | import { generateRandomString } from '../helpers/utils' |
6 | import { CONFIG } from '../initializers/config' | ||
5 | import { | 7 | import { |
8 | AP_CLEANER, | ||
6 | CONTACT_FORM_LIFETIME, | 9 | CONTACT_FORM_LIFETIME, |
10 | RESUMABLE_UPLOAD_SESSION_LIFETIME, | ||
11 | TRACKER_RATE_LIMITS, | ||
7 | USER_EMAIL_VERIFY_LIFETIME, | 12 | USER_EMAIL_VERIFY_LIFETIME, |
8 | USER_PASSWORD_RESET_LIFETIME, | ||
9 | USER_PASSWORD_CREATE_LIFETIME, | 13 | USER_PASSWORD_CREATE_LIFETIME, |
14 | USER_PASSWORD_RESET_LIFETIME, | ||
10 | VIEW_LIFETIME, | 15 | VIEW_LIFETIME, |
11 | WEBSERVER, | 16 | WEBSERVER |
12 | TRACKER_RATE_LIMITS, | ||
13 | RESUMABLE_UPLOAD_SESSION_LIFETIME | ||
14 | } from '../initializers/constants' | 17 | } from '../initializers/constants' |
15 | import { CONFIG } from '../initializers/config' | ||
16 | import { exists } from '@server/helpers/custom-validators/misc' | ||
17 | 18 | ||
18 | type CachedRoute = { | 19 | // Only used for typings |
19 | body: string | 20 | const redisClientWrapperForType = () => createClient<{}>() |
20 | contentType?: string | ||
21 | statusCode?: string | ||
22 | } | ||
23 | 21 | ||
24 | class Redis { | 22 | class Redis { |
25 | 23 | ||
26 | private static instance: Redis | 24 | private static instance: Redis |
27 | private initialized = false | 25 | private initialized = false |
28 | private client: RedisClient | 26 | private connected = false |
27 | private client: ReturnType<typeof redisClientWrapperForType> | ||
29 | private prefix: string | 28 | private prefix: string |
30 | 29 | ||
31 | private constructor () { | 30 | private constructor () { |
@@ -38,26 +37,43 @@ class Redis { | |||
38 | 37 | ||
39 | this.client = createClient(Redis.getRedisClientOptions()) | 38 | this.client = createClient(Redis.getRedisClientOptions()) |
40 | 39 | ||
41 | this.client.on('error', err => { | 40 | logger.info('Connecting to redis...') |
42 | logger.error('Error in Redis client.', { err }) | ||
43 | process.exit(-1) | ||
44 | }) | ||
45 | 41 | ||
46 | if (CONFIG.REDIS.AUTH) { | 42 | this.client.connect() |
47 | this.client.auth(CONFIG.REDIS.AUTH) | 43 | .then(() => { |
48 | } | 44 | logger.info('Connected to redis.') |
45 | |||
46 | this.connected = true | ||
47 | }).catch(err => { | ||
48 | logger.error('Cannot connect to redis', { err }) | ||
49 | process.exit(-1) | ||
50 | }) | ||
49 | 51 | ||
50 | this.prefix = 'redis-' + WEBSERVER.HOST + '-' | 52 | this.prefix = 'redis-' + WEBSERVER.HOST + '-' |
51 | } | 53 | } |
52 | 54 | ||
53 | static getRedisClientOptions () { | 55 | static getRedisClientOptions () { |
54 | return Object.assign({}, | 56 | let config: RedisClientOptions<RedisModules, {}> = { |
55 | (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, | 57 | socket: { |
56 | (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, | 58 | connectTimeout: 20000 // Could be slow since node use sync call to compile PeerTube |
57 | (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) | 59 | } |
58 | ? { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } | 60 | } |
59 | : { path: CONFIG.REDIS.SOCKET } | 61 | |
60 | ) | 62 | if (CONFIG.REDIS.AUTH) { |
63 | config = { ...config, password: CONFIG.REDIS.AUTH } | ||
64 | } | ||
65 | |||
66 | if (CONFIG.REDIS.DB) { | ||
67 | config = { ...config, database: CONFIG.REDIS.DB } | ||
68 | } | ||
69 | |||
70 | if (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) { | ||
71 | config.socket = { ...config.socket, host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } | ||
72 | } else { | ||
73 | config.socket = { ...config.socket, path: CONFIG.REDIS.SOCKET } | ||
74 | } | ||
75 | |||
76 | return config | ||
61 | } | 77 | } |
62 | 78 | ||
63 | getClient () { | 79 | getClient () { |
@@ -68,6 +84,10 @@ class Redis { | |||
68 | return this.prefix | 84 | return this.prefix |
69 | } | 85 | } |
70 | 86 | ||
87 | isConnected () { | ||
88 | return this.connected | ||
89 | } | ||
90 | |||
71 | /* ************ Forgot password ************ */ | 91 | /* ************ Forgot password ************ */ |
72 | 92 | ||
73 | async setResetPasswordVerificationString (userId: number) { | 93 | async setResetPasswordVerificationString (userId: number) { |
@@ -146,25 +166,6 @@ class Redis { | |||
146 | return this.exists(this.generateTrackerBlockIPKey(ip)) | 166 | return this.exists(this.generateTrackerBlockIPKey(ip)) |
147 | } | 167 | } |
148 | 168 | ||
149 | /* ************ API cache ************ */ | ||
150 | |||
151 | async getCachedRoute (req: express.Request) { | ||
152 | const cached = await this.getObject(this.generateCachedRouteKey(req)) | ||
153 | |||
154 | return cached as CachedRoute | ||
155 | } | ||
156 | |||
157 | setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { | ||
158 | const cached: CachedRoute = Object.assign( | ||
159 | {}, | ||
160 | { body: body.toString() }, | ||
161 | (contentType) ? { contentType } : null, | ||
162 | (statusCode) ? { statusCode: statusCode.toString() } : null | ||
163 | ) | ||
164 | |||
165 | return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) | ||
166 | } | ||
167 | |||
168 | /* ************ Video views stats ************ */ | 169 | /* ************ Video views stats ************ */ |
169 | 170 | ||
170 | addVideoViewStats (videoId: number) { | 171 | addVideoViewStats (videoId: number) { |
@@ -275,12 +276,19 @@ class Redis { | |||
275 | return this.deleteKey('resumable-upload-' + uploadId) | 276 | return this.deleteKey('resumable-upload-' + uploadId) |
276 | } | 277 | } |
277 | 278 | ||
278 | /* ************ Keys generation ************ */ | 279 | /* ************ AP ressource unavailability ************ */ |
279 | 280 | ||
280 | generateCachedRouteKey (req: express.Request) { | 281 | async addAPUnavailability (url: string) { |
281 | return req.method + '-' + req.originalUrl | 282 | const key = this.generateAPUnavailabilityKey(url) |
283 | |||
284 | const value = await this.increment(key) | ||
285 | await this.setExpiration(key, AP_CLEANER.PERIOD * 2) | ||
286 | |||
287 | return value | ||
282 | } | 288 | } |
283 | 289 | ||
290 | /* ************ Keys generation ************ */ | ||
291 | |||
284 | private generateLocalVideoViewsKeys (videoId?: Number) { | 292 | private generateLocalVideoViewsKeys (videoId?: Number) { |
285 | return { setKey: `local-video-views-buffer`, videoKey: `local-video-views-buffer-${videoId}` } | 293 | return { setKey: `local-video-views-buffer`, videoKey: `local-video-views-buffer-${videoId}` } |
286 | } | 294 | } |
@@ -317,128 +325,52 @@ class Redis { | |||
317 | return 'contact-form-' + ip | 325 | return 'contact-form-' + ip |
318 | } | 326 | } |
319 | 327 | ||
328 | private generateAPUnavailabilityKey (url: string) { | ||
329 | return 'ap-unavailability-' + sha256(url) | ||
330 | } | ||
331 | |||
320 | /* ************ Redis helpers ************ */ | 332 | /* ************ Redis helpers ************ */ |
321 | 333 | ||
322 | private getValue (key: string) { | 334 | private getValue (key: string) { |
323 | return new Promise<string>((res, rej) => { | 335 | return this.client.get(this.prefix + key) |
324 | this.client.get(this.prefix + key, (err, value) => { | ||
325 | if (err) return rej(err) | ||
326 | |||
327 | return res(value) | ||
328 | }) | ||
329 | }) | ||
330 | } | 336 | } |
331 | 337 | ||
332 | private getSet (key: string) { | 338 | private getSet (key: string) { |
333 | return new Promise<string[]>((res, rej) => { | 339 | return this.client.sMembers(this.prefix + key) |
334 | this.client.smembers(this.prefix + key, (err, value) => { | ||
335 | if (err) return rej(err) | ||
336 | |||
337 | return res(value) | ||
338 | }) | ||
339 | }) | ||
340 | } | 340 | } |
341 | 341 | ||
342 | private addToSet (key: string, value: string) { | 342 | private addToSet (key: string, value: string) { |
343 | return new Promise<void>((res, rej) => { | 343 | return this.client.sAdd(this.prefix + key, value) |
344 | this.client.sadd(this.prefix + key, value, err => err ? rej(err) : res()) | ||
345 | }) | ||
346 | } | 344 | } |
347 | 345 | ||
348 | private deleteFromSet (key: string, value: string) { | 346 | private deleteFromSet (key: string, value: string) { |
349 | return new Promise<void>((res, rej) => { | 347 | return this.client.sRem(this.prefix + key, value) |
350 | this.client.srem(this.prefix + key, value, err => err ? rej(err) : res()) | ||
351 | }) | ||
352 | } | 348 | } |
353 | 349 | ||
354 | private deleteKey (key: string) { | 350 | private deleteKey (key: string) { |
355 | return new Promise<void>((res, rej) => { | 351 | return this.client.del(this.prefix + key) |
356 | this.client.del(this.prefix + key, err => err ? rej(err) : res()) | ||
357 | }) | ||
358 | } | ||
359 | |||
360 | private deleteFieldInHash (key: string, field: string) { | ||
361 | return new Promise<void>((res, rej) => { | ||
362 | this.client.hdel(this.prefix + key, field, err => err ? rej(err) : res()) | ||
363 | }) | ||
364 | } | 352 | } |
365 | 353 | ||
366 | private setValue (key: string, value: string, expirationMilliseconds: number) { | 354 | private async setValue (key: string, value: string, expirationMilliseconds: number) { |
367 | return new Promise<void>((res, rej) => { | 355 | const result = await this.client.set(this.prefix + key, value, { PX: expirationMilliseconds }) |
368 | this.client.set(this.prefix + key, value, 'PX', expirationMilliseconds, (err, ok) => { | ||
369 | if (err) return rej(err) | ||
370 | 356 | ||
371 | if (ok !== 'OK') return rej(new Error('Redis set result is not OK.')) | 357 | if (result !== 'OK') throw new Error('Redis set result is not OK.') |
372 | |||
373 | return res() | ||
374 | }) | ||
375 | }) | ||
376 | } | 358 | } |
377 | 359 | ||
378 | private removeValue (key: string) { | 360 | private removeValue (key: string) { |
379 | return new Promise<void>((res, rej) => { | 361 | return this.client.del(this.prefix + key) |
380 | this.client.del(this.prefix + key, err => { | ||
381 | if (err) return rej(err) | ||
382 | |||
383 | return res() | ||
384 | }) | ||
385 | }) | ||
386 | } | ||
387 | |||
388 | private setObject (key: string, obj: { [id: string]: string }, expirationMilliseconds: number) { | ||
389 | return new Promise<void>((res, rej) => { | ||
390 | this.client.hmset(this.prefix + key, obj, (err, ok) => { | ||
391 | if (err) return rej(err) | ||
392 | if (!ok) return rej(new Error('Redis mset result is not OK.')) | ||
393 | |||
394 | this.client.pexpire(this.prefix + key, expirationMilliseconds, (err, ok) => { | ||
395 | if (err) return rej(err) | ||
396 | if (!ok) return rej(new Error('Redis expiration result is not OK.')) | ||
397 | |||
398 | return res() | ||
399 | }) | ||
400 | }) | ||
401 | }) | ||
402 | } | ||
403 | |||
404 | private getObject (key: string) { | ||
405 | return new Promise<{ [id: string]: string }>((res, rej) => { | ||
406 | this.client.hgetall(this.prefix + key, (err, value) => { | ||
407 | if (err) return rej(err) | ||
408 | |||
409 | return res(value) | ||
410 | }) | ||
411 | }) | ||
412 | } | ||
413 | |||
414 | private setValueInHash (key: string, field: string, value: string) { | ||
415 | return new Promise<void>((res, rej) => { | ||
416 | this.client.hset(this.prefix + key, field, value, (err) => { | ||
417 | if (err) return rej(err) | ||
418 | |||
419 | return res() | ||
420 | }) | ||
421 | }) | ||
422 | } | 362 | } |
423 | 363 | ||
424 | private increment (key: string) { | 364 | private increment (key: string) { |
425 | return new Promise<number>((res, rej) => { | 365 | return this.client.incr(this.prefix + key) |
426 | this.client.incr(this.prefix + key, (err, value) => { | ||
427 | if (err) return rej(err) | ||
428 | |||
429 | return res(value) | ||
430 | }) | ||
431 | }) | ||
432 | } | 366 | } |
433 | 367 | ||
434 | private exists (key: string) { | 368 | private exists (key: string) { |
435 | return new Promise<boolean>((res, rej) => { | 369 | return this.client.exists(this.prefix + key) |
436 | this.client.exists(this.prefix + key, (err, existsNumber) => { | 370 | } |
437 | if (err) return rej(err) | ||
438 | 371 | ||
439 | return res(existsNumber === 1) | 372 | private setExpiration (key: string, ms: number) { |
440 | }) | 373 | return this.client.expire(this.prefix + key, ms / 1000) |
441 | }) | ||
442 | } | 374 | } |
443 | 375 | ||
444 | static get Instance () { | 376 | static get Instance () { |
diff --git a/server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.ts b/server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.ts index d6e561cad..61e93eafa 100644 --- a/server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.ts +++ b/server/lib/schedulers/remove-dangling-resumable-uploads-scheduler.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | import { map } from 'bluebird' | 1 | |
2 | import { readdir, remove, stat } from 'fs-extra' | ||
3 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 2 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
4 | import { getResumableUploadPath } from '@server/helpers/upload' | ||
5 | import { SCHEDULER_INTERVALS_MS } from '@server/initializers/constants' | 3 | import { SCHEDULER_INTERVALS_MS } from '@server/initializers/constants' |
6 | import { METAFILE_EXTNAME } from '@uploadx/core' | 4 | import { uploadx } from '../uploadx' |
7 | import { AbstractScheduler } from './abstract-scheduler' | 5 | import { AbstractScheduler } from './abstract-scheduler' |
8 | 6 | ||
9 | const lTags = loggerTagsFactory('scheduler', 'resumable-upload', 'cleaner') | 7 | const lTags = loggerTagsFactory('scheduler', 'resumable-upload', 'cleaner') |
@@ -22,36 +20,17 @@ export class RemoveDanglingResumableUploadsScheduler extends AbstractScheduler { | |||
22 | } | 20 | } |
23 | 21 | ||
24 | protected async internalExecute () { | 22 | protected async internalExecute () { |
25 | const path = getResumableUploadPath() | 23 | logger.debug('Removing dangling resumable uploads', lTags()) |
26 | const files = await readdir(path) | ||
27 | |||
28 | const metafiles = files.filter(f => f.endsWith(METAFILE_EXTNAME)) | ||
29 | 24 | ||
30 | if (metafiles.length === 0) return | 25 | const now = new Date().getTime() |
31 | |||
32 | logger.debug('Reading resumable video upload folder %s with %d files', path, metafiles.length, lTags()) | ||
33 | 26 | ||
34 | try { | 27 | try { |
35 | await map(metafiles, metafile => { | 28 | // Remove files that were not updated since the last execution |
36 | return this.deleteIfOlderThan(metafile, this.lastExecutionTimeMs) | 29 | await uploadx.storage.purge(now - this.lastExecutionTimeMs) |
37 | }, { concurrency: 5 }) | ||
38 | } catch (error) { | 30 | } catch (error) { |
39 | logger.error('Failed to handle file during resumable video upload folder cleanup', { error, ...lTags() }) | 31 | logger.error('Failed to handle file during resumable video upload folder cleanup', { error, ...lTags() }) |
40 | } finally { | 32 | } finally { |
41 | this.lastExecutionTimeMs = new Date().getTime() | 33 | this.lastExecutionTimeMs = now |
42 | } | ||
43 | } | ||
44 | |||
45 | private async deleteIfOlderThan (metafile: string, olderThan: number) { | ||
46 | const metafilePath = getResumableUploadPath(metafile) | ||
47 | const statResult = await stat(metafilePath) | ||
48 | |||
49 | // Delete uploads that started since a long time | ||
50 | if (statResult.ctimeMs < olderThan) { | ||
51 | await remove(metafilePath) | ||
52 | |||
53 | const datafile = metafilePath.replace(new RegExp(`${METAFILE_EXTNAME}$`), '') | ||
54 | await remove(datafile) | ||
55 | } | 34 | } |
56 | } | 35 | } |
57 | 36 | ||
diff --git a/server/lib/server-config-manager.ts b/server/lib/server-config-manager.ts index bdf6492f9..d97f21eb7 100644 --- a/server/lib/server-config-manager.ts +++ b/server/lib/server-config-manager.ts | |||
@@ -3,6 +3,7 @@ import { CONFIG, isEmailEnabled } from '@server/initializers/config' | |||
3 | import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants' | 3 | import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants' |
4 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/lib/signup' | 4 | import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/lib/signup' |
5 | import { ActorCustomPageModel } from '@server/models/account/actor-custom-page' | 5 | import { ActorCustomPageModel } from '@server/models/account/actor-custom-page' |
6 | import { PluginModel } from '@server/models/server/plugin' | ||
6 | import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models' | 7 | import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models' |
7 | import { Hooks } from './plugins/hooks' | 8 | import { Hooks } from './plugins/hooks' |
8 | import { PluginManager } from './plugins/plugin-manager' | 9 | import { PluginManager } from './plugins/plugin-manager' |
@@ -47,6 +48,28 @@ class ServerConfigManager { | |||
47 | miniature: { | 48 | miniature: { |
48 | preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME | 49 | preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME |
49 | } | 50 | } |
51 | }, | ||
52 | menu: { | ||
53 | login: { | ||
54 | redirectOnSingleExternalAuth: CONFIG.CLIENT.MENU.LOGIN.REDIRECT_ON_SINGLE_EXTERNAL_AUTH | ||
55 | } | ||
56 | } | ||
57 | }, | ||
58 | |||
59 | defaults: { | ||
60 | publish: { | ||
61 | downloadEnabled: CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED, | ||
62 | commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED, | ||
63 | privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY, | ||
64 | licence: CONFIG.DEFAULTS.PUBLISH.LICENCE | ||
65 | }, | ||
66 | p2p: { | ||
67 | webapp: { | ||
68 | enabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED | ||
69 | }, | ||
70 | embed: { | ||
71 | enabled: CONFIG.DEFAULTS.P2P.EMBED.ENABLED | ||
72 | } | ||
50 | } | 73 | } |
51 | }, | 74 | }, |
52 | 75 | ||
@@ -247,6 +270,7 @@ class ServerConfigManager { | |||
247 | getRegisteredThemes () { | 270 | getRegisteredThemes () { |
248 | return PluginManager.Instance.getRegisteredThemes() | 271 | return PluginManager.Instance.getRegisteredThemes() |
249 | .map(t => ({ | 272 | .map(t => ({ |
273 | npmName: PluginModel.buildNpmName(t.name, t.type), | ||
250 | name: t.name, | 274 | name: t.name, |
251 | version: t.version, | 275 | version: t.version, |
252 | description: t.description, | 276 | description: t.description, |
@@ -258,6 +282,7 @@ class ServerConfigManager { | |||
258 | getRegisteredPlugins () { | 282 | getRegisteredPlugins () { |
259 | return PluginManager.Instance.getRegisteredPlugins() | 283 | return PluginManager.Instance.getRegisteredPlugins() |
260 | .map(p => ({ | 284 | .map(p => ({ |
285 | npmName: PluginModel.buildNpmName(p.name, p.type), | ||
261 | name: p.name, | 286 | name: p.name, |
262 | version: p.version, | 287 | version: p.version, |
263 | description: p.description, | 288 | description: p.description, |
diff --git a/server/lib/transcoding/video-transcoding-profiles.ts b/server/lib/transcoding/video-transcoding-profiles.ts index 34a364415..dcc8d4c5c 100644 --- a/server/lib/transcoding/video-transcoding-profiles.ts +++ b/server/lib/transcoding/video-transcoding-profiles.ts | |||
@@ -23,10 +23,9 @@ const defaultX264VODOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOpt | |||
23 | 23 | ||
24 | return { | 24 | return { |
25 | outputOptions: [ | 25 | outputOptions: [ |
26 | `-preset veryfast`, | 26 | ...getCommonOutputOptions(targetBitrate), |
27 | `-r ${fps}`, | 27 | |
28 | `-maxrate ${targetBitrate}`, | 28 | `-r ${fps}` |
29 | `-bufsize ${targetBitrate * 2}` | ||
30 | ] | 29 | ] |
31 | } | 30 | } |
32 | } | 31 | } |
@@ -38,11 +37,10 @@ const defaultX264LiveOptionsBuilder: EncoderOptionsBuilder = (options: EncoderOp | |||
38 | 37 | ||
39 | return { | 38 | return { |
40 | outputOptions: [ | 39 | outputOptions: [ |
41 | `-preset veryfast`, | 40 | ...getCommonOutputOptions(targetBitrate), |
41 | |||
42 | `${buildStreamSuffix('-r:v', streamNum)} ${fps}`, | 42 | `${buildStreamSuffix('-r:v', streamNum)} ${fps}`, |
43 | `${buildStreamSuffix('-b:v', streamNum)} ${targetBitrate}`, | 43 | `${buildStreamSuffix('-b:v', streamNum)} ${targetBitrate}` |
44 | `-maxrate ${targetBitrate}`, | ||
45 | `-bufsize ${targetBitrate * 2}` | ||
46 | ] | 44 | ] |
47 | } | 45 | } |
48 | } | 46 | } |
@@ -257,3 +255,16 @@ function capBitrate (inputBitrate: number, targetBitrate: number) { | |||
257 | 255 | ||
258 | return Math.min(targetBitrate, inputBitrateWithMargin) | 256 | return Math.min(targetBitrate, inputBitrateWithMargin) |
259 | } | 257 | } |
258 | |||
259 | function getCommonOutputOptions (targetBitrate: number) { | ||
260 | return [ | ||
261 | `-preset veryfast`, | ||
262 | `-maxrate ${targetBitrate}`, | ||
263 | `-bufsize ${targetBitrate * 2}`, | ||
264 | |||
265 | // NOTE: b-strategy 1 - heuristic algorithm, 16 is optimal B-frames for it | ||
266 | `-b_strategy 1`, | ||
267 | // NOTE: Why 16: https://github.com/Chocobozzz/PeerTube/pull/774. b-strategy 2 -> B-frames<16 | ||
268 | `-bf 16` | ||
269 | ] | ||
270 | } | ||
diff --git a/server/lib/transcoding/video-transcoding.ts b/server/lib/transcoding/video-transcoding.ts index d0db05216..9942a067b 100644 --- a/server/lib/transcoding/video-transcoding.ts +++ b/server/lib/transcoding/video-transcoding.ts | |||
@@ -169,6 +169,7 @@ function mergeAudioVideofile (video: MVideoFullLight, resolution: VideoResolutio | |||
169 | 169 | ||
170 | // Important to do this before getVideoFilename() to take in account the new file extension | 170 | // Important to do this before getVideoFilename() to take in account the new file extension |
171 | inputVideoFile.extname = newExtname | 171 | inputVideoFile.extname = newExtname |
172 | inputVideoFile.resolution = resolution | ||
172 | inputVideoFile.filename = generateWebTorrentVideoFilename(inputVideoFile.resolution, newExtname) | 173 | inputVideoFile.filename = generateWebTorrentVideoFilename(inputVideoFile.resolution, newExtname) |
173 | 174 | ||
174 | const videoOutputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, inputVideoFile) | 175 | const videoOutputPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, inputVideoFile) |
diff --git a/server/lib/uploadx.ts b/server/lib/uploadx.ts new file mode 100644 index 000000000..36f5a556c --- /dev/null +++ b/server/lib/uploadx.ts | |||
@@ -0,0 +1,14 @@ | |||
1 | import express from 'express' | ||
2 | import { getResumableUploadPath } from '@server/helpers/upload' | ||
3 | import { Uploadx } from '@uploadx/core' | ||
4 | |||
5 | const uploadx = new Uploadx({ | ||
6 | directory: getResumableUploadPath(), | ||
7 | // Could be big with thumbnails/previews | ||
8 | maxMetadataSize: '10MB' | ||
9 | }) | ||
10 | uploadx.getUserId = (_, res: express.Response) => res.locals.oauth?.token.user.id | ||
11 | |||
12 | export { | ||
13 | uploadx | ||
14 | } | ||
diff --git a/server/lib/user.ts b/server/lib/user.ts index 936403692..0d292ac90 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Transaction } from 'sequelize/types' | 1 | import { Transaction } from 'sequelize/types' |
2 | import { buildUUID } from '@server/helpers/uuid' | ||
3 | import { UserModel } from '@server/models/user/user' | 2 | import { UserModel } from '@server/models/user/user' |
4 | import { MActorDefault } from '@server/types/models/actor' | 3 | import { MActorDefault } from '@server/types/models/actor' |
4 | import { buildUUID } from '@shared/extra-utils' | ||
5 | import { ActivityPubActorType } from '../../shared/models/activitypub' | 5 | import { ActivityPubActorType } from '../../shared/models/activitypub' |
6 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' | 6 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' |
7 | import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants' | 7 | import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants' |
diff --git a/server/lib/video-path-manager.ts b/server/lib/video-path-manager.ts index 27058005c..c3f55fd95 100644 --- a/server/lib/video-path-manager.ts +++ b/server/lib/video-path-manager.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { remove } from 'fs-extra' | 1 | import { remove } from 'fs-extra' |
2 | import { extname, join } from 'path' | 2 | import { extname, join } from 'path' |
3 | import { buildUUID } from '@server/helpers/uuid' | ||
4 | import { extractVideo } from '@server/helpers/video' | 3 | import { extractVideo } from '@server/helpers/video' |
5 | import { CONFIG } from '@server/initializers/config' | 4 | import { CONFIG } from '@server/initializers/config' |
6 | import { | 5 | import { |
@@ -11,6 +10,7 @@ import { | |||
11 | MVideoFileVideo, | 10 | MVideoFileVideo, |
12 | MVideoUUID | 11 | MVideoUUID |
13 | } from '@server/types/models' | 12 | } from '@server/types/models' |
13 | import { buildUUID } from '@shared/extra-utils' | ||
14 | import { VideoStorage } from '@shared/models' | 14 | import { VideoStorage } from '@shared/models' |
15 | import { makeHLSFileAvailable, makeWebTorrentFileAvailable } from './object-storage' | 15 | import { makeHLSFileAvailable, makeWebTorrentFileAvailable } from './object-storage' |
16 | import { getHLSDirectory, getHLSRedundancyDirectory, getHlsResolutionPlaylistFilename } from './paths' | 16 | import { getHLSDirectory, getHLSRedundancyDirectory, getHlsResolutionPlaylistFilename } from './paths' |
diff --git a/server/lib/video-state.ts b/server/lib/video-state.ts index e420991cd..97ff540ed 100644 --- a/server/lib/video-state.ts +++ b/server/lib/video-state.ts | |||
@@ -4,7 +4,7 @@ import { CONFIG } from '@server/initializers/config' | |||
4 | import { sequelizeTypescript } from '@server/initializers/database' | 4 | import { sequelizeTypescript } from '@server/initializers/database' |
5 | import { VideoModel } from '@server/models/video/video' | 5 | import { VideoModel } from '@server/models/video/video' |
6 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' | 6 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' |
7 | import { MVideoFullLight, MVideoUUID } from '@server/types/models' | 7 | import { MVideo, MVideoFullLight, MVideoUUID } from '@server/types/models' |
8 | import { VideoState } from '@shared/models' | 8 | import { VideoState } from '@shared/models' |
9 | import { federateVideoIfNeeded } from './activitypub/videos' | 9 | import { federateVideoIfNeeded } from './activitypub/videos' |
10 | import { Notifier } from './notifier' | 10 | import { Notifier } from './notifier' |
@@ -79,18 +79,25 @@ async function moveToExternalStorageState (video: MVideoFullLight, isNewVideo: b | |||
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | function moveToFailedTranscodingState (video: MVideoFullLight) { | 82 | function moveToFailedTranscodingState (video: MVideo) { |
83 | if (video.state === VideoState.TRANSCODING_FAILED) return | 83 | if (video.state === VideoState.TRANSCODING_FAILED) return |
84 | 84 | ||
85 | return video.setNewState(VideoState.TRANSCODING_FAILED, false, undefined) | 85 | return video.setNewState(VideoState.TRANSCODING_FAILED, false, undefined) |
86 | } | 86 | } |
87 | 87 | ||
88 | function moveToFailedMoveToObjectStorageState (video: MVideo) { | ||
89 | if (video.state === VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED) return | ||
90 | |||
91 | return video.setNewState(VideoState.TO_MOVE_TO_EXTERNAL_STORAGE_FAILED, false, undefined) | ||
92 | } | ||
93 | |||
88 | // --------------------------------------------------------------------------- | 94 | // --------------------------------------------------------------------------- |
89 | 95 | ||
90 | export { | 96 | export { |
91 | buildNextVideoState, | 97 | buildNextVideoState, |
92 | moveToExternalStorageState, | 98 | moveToExternalStorageState, |
93 | moveToFailedTranscodingState, | 99 | moveToFailedTranscodingState, |
100 | moveToFailedMoveToObjectStorageState, | ||
94 | moveToNextState | 101 | moveToNextState |
95 | } | 102 | } |
96 | 103 | ||
diff --git a/server/lib/video.ts b/server/lib/video.ts index 1cfe4f27c..e5af028ea 100644 --- a/server/lib/video.ts +++ b/server/lib/video.ts | |||
@@ -9,16 +9,17 @@ import { MThumbnail, MUserId, MVideoFile, MVideoTag, MVideoThumbnail, MVideoUUID | |||
9 | import { ThumbnailType, VideoCreate, VideoPrivacy, VideoTranscodingPayload } from '@shared/models' | 9 | import { ThumbnailType, VideoCreate, VideoPrivacy, VideoTranscodingPayload } from '@shared/models' |
10 | import { CreateJobOptions, JobQueue } from './job-queue/job-queue' | 10 | import { CreateJobOptions, JobQueue } from './job-queue/job-queue' |
11 | import { updateVideoMiniatureFromExisting } from './thumbnail' | 11 | import { updateVideoMiniatureFromExisting } from './thumbnail' |
12 | import { CONFIG } from '@server/initializers/config' | ||
12 | 13 | ||
13 | function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): FilteredModelAttributes<VideoModel> { | 14 | function buildLocalVideoFromReq (videoInfo: VideoCreate, channelId: number): FilteredModelAttributes<VideoModel> { |
14 | return { | 15 | return { |
15 | name: videoInfo.name, | 16 | name: videoInfo.name, |
16 | remote: false, | 17 | remote: false, |
17 | category: videoInfo.category, | 18 | category: videoInfo.category, |
18 | licence: videoInfo.licence, | 19 | licence: videoInfo.licence ?? CONFIG.DEFAULTS.PUBLISH.LICENCE, |
19 | language: videoInfo.language, | 20 | language: videoInfo.language, |
20 | commentsEnabled: videoInfo.commentsEnabled !== false, // If the value is not "false", the default is "true" | 21 | commentsEnabled: videoInfo.commentsEnabled ?? CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED, |
21 | downloadEnabled: videoInfo.downloadEnabled !== false, | 22 | downloadEnabled: videoInfo.downloadEnabled ?? CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED, |
22 | waitTranscoding: videoInfo.waitTranscoding || false, | 23 | waitTranscoding: videoInfo.waitTranscoding || false, |
23 | nsfw: videoInfo.nsfw || false, | 24 | nsfw: videoInfo.nsfw || false, |
24 | description: videoInfo.description, | 25 | description: videoInfo.description, |
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 6ef90b275..86d3c1d6c 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import { NextFunction, Request, Response } from 'express' | 1 | import { NextFunction, Request, Response } from 'express' |
2 | import { getAPId } from '@server/helpers/activitypub' | 2 | import { getAPId } from '@server/helpers/activitypub' |
3 | import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' | 3 | import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' |
4 | import { ActivityDelete, ActivityPubSignature } from '../../shared' | 4 | import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@shared/models' |
5 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' | ||
6 | import { logger } from '../helpers/logger' | 5 | import { logger } from '../helpers/logger' |
7 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' | 6 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' |
8 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' | 7 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' |
diff --git a/server/middlewares/async.ts b/server/middlewares/async.ts index 3d6e38809..9d0193536 100644 --- a/server/middlewares/async.ts +++ b/server/middlewares/async.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { eachSeries } from 'async' | 1 | import { eachSeries } from 'async' |
2 | import { NextFunction, Request, RequestHandler, Response } from 'express' | 2 | import { NextFunction, Request, RequestHandler, Response } from 'express' |
3 | import { ValidationChain } from 'express-validator' | 3 | import { ValidationChain } from 'express-validator' |
4 | import { ExpressPromiseHandler } from '@server/types/express' | 4 | import { ExpressPromiseHandler } from '@server/types/express-handler' |
5 | import { retryTransactionWrapper } from '../helpers/database-utils' | 5 | import { retryTransactionWrapper } from '../helpers/database-utils' |
6 | 6 | ||
7 | // Syntactic sugar to avoid try/catch in express controllers | 7 | // Syntactic sugar to avoid try/catch in express controllers |
diff --git a/server/middlewares/cache/cache.ts b/server/middlewares/cache/cache.ts index 48162a0ae..e14160ba8 100644 --- a/server/middlewares/cache/cache.ts +++ b/server/middlewares/cache/cache.ts | |||
@@ -1,10 +1,6 @@ | |||
1 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 1 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' |
2 | import { Redis } from '../../lib/redis' | ||
3 | import { ApiCache, APICacheOptions } from './shared' | 2 | import { ApiCache, APICacheOptions } from './shared' |
4 | 3 | ||
5 | // Ensure Redis is initialized | ||
6 | Redis.Instance.init() | ||
7 | |||
8 | const defaultOptions: APICacheOptions = { | 4 | const defaultOptions: APICacheOptions = { |
9 | excludeStatus: [ | 5 | excludeStatus: [ |
10 | HttpStatusCode.FORBIDDEN_403, | 6 | HttpStatusCode.FORBIDDEN_403, |
diff --git a/server/middlewares/cache/shared/api-cache.ts b/server/middlewares/cache/shared/api-cache.ts index f8846dcfc..86c5095b5 100644 --- a/server/middlewares/cache/shared/api-cache.ts +++ b/server/middlewares/cache/shared/api-cache.ts | |||
@@ -7,6 +7,7 @@ import { isTestInstance, parseDurationToMs } from '@server/helpers/core-utils' | |||
7 | import { logger } from '@server/helpers/logger' | 7 | import { logger } from '@server/helpers/logger' |
8 | import { Redis } from '@server/lib/redis' | 8 | import { Redis } from '@server/lib/redis' |
9 | import { HttpStatusCode } from '@shared/models' | 9 | import { HttpStatusCode } from '@shared/models' |
10 | import { asyncMiddleware } from '@server/middlewares' | ||
10 | 11 | ||
11 | export interface APICacheOptions { | 12 | export interface APICacheOptions { |
12 | headerBlacklist?: string[] | 13 | headerBlacklist?: string[] |
@@ -40,24 +41,25 @@ export class ApiCache { | |||
40 | buildMiddleware (strDuration: string) { | 41 | buildMiddleware (strDuration: string) { |
41 | const duration = parseDurationToMs(strDuration) | 42 | const duration = parseDurationToMs(strDuration) |
42 | 43 | ||
43 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { | 44 | return asyncMiddleware( |
44 | const key = Redis.Instance.getPrefix() + 'api-cache-' + req.originalUrl | 45 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
45 | const redis = Redis.Instance.getClient() | 46 | const key = Redis.Instance.getPrefix() + 'api-cache-' + req.originalUrl |
47 | const redis = Redis.Instance.getClient() | ||
46 | 48 | ||
47 | if (!redis.connected) return this.makeResponseCacheable(res, next, key, duration) | 49 | if (!Redis.Instance.isConnected()) return this.makeResponseCacheable(res, next, key, duration) |
48 | 50 | ||
49 | try { | 51 | try { |
50 | redis.hgetall(key, (err, obj) => { | 52 | const obj = await redis.hGetAll(key) |
51 | if (!err && obj && obj.response) { | 53 | if (obj?.response) { |
52 | return this.sendCachedResponse(req, res, JSON.parse(obj.response), duration) | 54 | return this.sendCachedResponse(req, res, JSON.parse(obj.response), duration) |
53 | } | 55 | } |
54 | 56 | ||
55 | return this.makeResponseCacheable(res, next, key, duration) | 57 | return this.makeResponseCacheable(res, next, key, duration) |
56 | }) | 58 | } catch (err) { |
57 | } catch (err) { | 59 | return this.makeResponseCacheable(res, next, key, duration) |
58 | return this.makeResponseCacheable(res, next, key, duration) | 60 | } |
59 | } | 61 | } |
60 | } | 62 | ) |
61 | } | 63 | } |
62 | 64 | ||
63 | private shouldCacheResponse (response: express.Response) { | 65 | private shouldCacheResponse (response: express.Response) { |
@@ -93,21 +95,22 @@ export class ApiCache { | |||
93 | } as CacheObject | 95 | } as CacheObject |
94 | } | 96 | } |
95 | 97 | ||
96 | private cacheResponse (key: string, value: object, duration: number) { | 98 | private async cacheResponse (key: string, value: object, duration: number) { |
97 | const redis = Redis.Instance.getClient() | 99 | const redis = Redis.Instance.getClient() |
98 | 100 | ||
99 | if (redis.connected) { | 101 | if (Redis.Instance.isConnected()) { |
100 | try { | 102 | await Promise.all([ |
101 | redis.hset(key, 'response', JSON.stringify(value)) | 103 | redis.hSet(key, 'response', JSON.stringify(value)), |
102 | redis.hset(key, 'duration', duration + '') | 104 | redis.hSet(key, 'duration', duration + ''), |
103 | redis.expire(key, duration / 1000) | 105 | redis.expire(key, duration / 1000) |
104 | } catch (err) { | 106 | ]) |
105 | logger.error('Cannot set cache in redis.', { err }) | ||
106 | } | ||
107 | } | 107 | } |
108 | 108 | ||
109 | // add automatic cache clearing from duration, includes max limit on setTimeout | 109 | // add automatic cache clearing from duration, includes max limit on setTimeout |
110 | this.timers[key] = setTimeout(() => this.clear(key), Math.min(duration, 2147483647)) | 110 | this.timers[key] = setTimeout(() => { |
111 | this.clear(key) | ||
112 | .catch(err => logger.error('Cannot clear Redis key %s.', key, { err })) | ||
113 | }, Math.min(duration, 2147483647)) | ||
111 | } | 114 | } |
112 | 115 | ||
113 | private accumulateContent (res: express.Response, content: any) { | 116 | private accumulateContent (res: express.Response, content: any) { |
@@ -184,6 +187,7 @@ export class ApiCache { | |||
184 | encoding | 187 | encoding |
185 | ) | 188 | ) |
186 | self.cacheResponse(key, cacheObject, duration) | 189 | self.cacheResponse(key, cacheObject, duration) |
190 | .catch(err => logger.error('Cannot cache response', { err })) | ||
187 | } | 191 | } |
188 | } | 192 | } |
189 | 193 | ||
@@ -235,7 +239,7 @@ export class ApiCache { | |||
235 | return response.end(data, cacheObject.encoding) | 239 | return response.end(data, cacheObject.encoding) |
236 | } | 240 | } |
237 | 241 | ||
238 | private clear (target: string) { | 242 | private async clear (target: string) { |
239 | const redis = Redis.Instance.getClient() | 243 | const redis = Redis.Instance.getClient() |
240 | 244 | ||
241 | if (target) { | 245 | if (target) { |
@@ -243,7 +247,7 @@ export class ApiCache { | |||
243 | delete this.timers[target] | 247 | delete this.timers[target] |
244 | 248 | ||
245 | try { | 249 | try { |
246 | redis.del(target) | 250 | await redis.del(target) |
247 | } catch (err) { | 251 | } catch (err) { |
248 | logger.error('Cannot delete %s in redis cache.', target, { err }) | 252 | logger.error('Cannot delete %s in redis cache.', target, { err }) |
249 | } | 253 | } |
@@ -255,7 +259,7 @@ export class ApiCache { | |||
255 | delete this.timers[key] | 259 | delete this.timers[key] |
256 | 260 | ||
257 | try { | 261 | try { |
258 | redis.del(key) | 262 | await redis.del(key) |
259 | } catch (err) { | 263 | } catch (err) { |
260 | logger.error('Cannot delete %s in redis cache.', key, { err }) | 264 | logger.error('Cannot delete %s in redis cache.', key, { err }) |
261 | } | 265 | } |
diff --git a/server/middlewares/error.ts b/server/middlewares/error.ts index 6c52ce7bd..34c87a26d 100644 --- a/server/middlewares/error.ts +++ b/server/middlewares/error.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { ProblemDocument, ProblemDocumentExtension } from 'http-problem-details' | 2 | import { ProblemDocument, ProblemDocumentExtension } from 'http-problem-details' |
3 | import { logger } from '@server/helpers/logger' | ||
3 | import { HttpStatusCode } from '@shared/models' | 4 | import { HttpStatusCode } from '@shared/models' |
4 | 5 | ||
5 | function apiFailMiddleware (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | function apiFailMiddleware (req: express.Request, res: express.Response, next: express.NextFunction) { |
@@ -18,7 +19,8 @@ function apiFailMiddleware (req: express.Request, res: express.Response, next: e | |||
18 | 19 | ||
19 | res.status(status) | 20 | res.status(status) |
20 | res.setHeader('Content-Type', 'application/problem+json') | 21 | res.setHeader('Content-Type', 'application/problem+json') |
21 | res.json(new ProblemDocument({ | 22 | |
23 | const json = new ProblemDocument({ | ||
22 | status, | 24 | status, |
23 | title, | 25 | title, |
24 | instance, | 26 | instance, |
@@ -28,7 +30,11 @@ function apiFailMiddleware (req: express.Request, res: express.Response, next: e | |||
28 | type: type | 30 | type: type |
29 | ? `https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/${type}` | 31 | ? `https://docs.joinpeertube.org/api-rest-reference.html#section/Errors/${type}` |
30 | : undefined | 32 | : undefined |
31 | }, extension)) | 33 | }, extension) |
34 | |||
35 | logger.debug('Bad HTTP request.', { json }) | ||
36 | |||
37 | res.json(json) | ||
32 | } | 38 | } |
33 | 39 | ||
34 | if (next) next() | 40 | if (next) next() |
diff --git a/server/middlewares/user-right.ts b/server/middlewares/user-right.ts index ea95b16c2..7d53e8341 100644 --- a/server/middlewares/user-right.ts +++ b/server/middlewares/user-right.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { UserRight } from '../../shared' | 2 | import { HttpStatusCode, UserRight } from '@shared/models' |
3 | import { HttpStatusCode } from '../../shared/models/http/http-error-codes' | ||
4 | import { logger } from '../helpers/logger' | 3 | import { logger } from '../helpers/logger' |
5 | 4 | ||
6 | function ensureUserHasRight (userRight: UserRight) { | 5 | function ensureUserHasRight (userRight: UserRight) { |
diff --git a/server/middlewares/validators/blocklist.ts b/server/middlewares/validators/blocklist.ts index b7749e204..12980ced4 100644 --- a/server/middlewares/validators/blocklist.ts +++ b/server/middlewares/validators/blocklist.ts | |||
@@ -1,8 +1,10 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { areValidActorHandles } from '@server/helpers/custom-validators/activitypub/actor' | ||
4 | import { toArray } from '@server/helpers/custom-validators/misc' | ||
3 | import { getServerActor } from '@server/models/application/application' | 5 | import { getServerActor } from '@server/models/application/application' |
4 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' | 6 | import { HttpStatusCode } from '../../../shared/models/http/http-error-codes' |
5 | import { isHostValid } from '../../helpers/custom-validators/servers' | 7 | import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers' |
6 | import { logger } from '../../helpers/logger' | 8 | import { logger } from '../../helpers/logger' |
7 | import { WEBSERVER } from '../../initializers/constants' | 9 | import { WEBSERVER } from '../../initializers/constants' |
8 | import { AccountBlocklistModel } from '../../models/account/account-blocklist' | 10 | import { AccountBlocklistModel } from '../../models/account/account-blocklist' |
@@ -123,6 +125,26 @@ const unblockServerByServerValidator = [ | |||
123 | } | 125 | } |
124 | ] | 126 | ] |
125 | 127 | ||
128 | const blocklistStatusValidator = [ | ||
129 | query('hosts') | ||
130 | .optional() | ||
131 | .customSanitizer(toArray) | ||
132 | .custom(isEachUniqueHostValid).withMessage('Should have a valid hosts array'), | ||
133 | |||
134 | query('accounts') | ||
135 | .optional() | ||
136 | .customSanitizer(toArray) | ||
137 | .custom(areValidActorHandles).withMessage('Should have a valid accounts array'), | ||
138 | |||
139 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
140 | logger.debug('Checking blocklistStatusValidator parameters', { query: req.query }) | ||
141 | |||
142 | if (areValidationErrors(req, res)) return | ||
143 | |||
144 | return next() | ||
145 | } | ||
146 | ] | ||
147 | |||
126 | // --------------------------------------------------------------------------- | 148 | // --------------------------------------------------------------------------- |
127 | 149 | ||
128 | export { | 150 | export { |
@@ -131,7 +153,8 @@ export { | |||
131 | unblockAccountByAccountValidator, | 153 | unblockAccountByAccountValidator, |
132 | unblockServerByAccountValidator, | 154 | unblockServerByAccountValidator, |
133 | unblockAccountByServerValidator, | 155 | unblockAccountByServerValidator, |
134 | unblockServerByServerValidator | 156 | unblockServerByServerValidator, |
157 | blocklistStatusValidator | ||
135 | } | 158 | } |
136 | 159 | ||
137 | // --------------------------------------------------------------------------- | 160 | // --------------------------------------------------------------------------- |
diff --git a/server/middlewares/validators/plugins.ts b/server/middlewares/validators/plugins.ts index 21171af23..c1e9ebefb 100644 --- a/server/middlewares/validators/plugins.ts +++ b/server/middlewares/validators/plugins.ts | |||
@@ -116,6 +116,9 @@ const installOrUpdatePluginValidator = [ | |||
116 | body('npmName') | 116 | body('npmName') |
117 | .optional() | 117 | .optional() |
118 | .custom(isNpmPluginNameValid).withMessage('Should have a valid npm name'), | 118 | .custom(isNpmPluginNameValid).withMessage('Should have a valid npm name'), |
119 | body('pluginVersion') | ||
120 | .optional() | ||
121 | .custom(isPluginVersionValid).withMessage('Should have a valid plugin version'), | ||
119 | body('path') | 122 | body('path') |
120 | .optional() | 123 | .optional() |
121 | .custom(isSafePath).withMessage('Should have a valid safe path'), | 124 | .custom(isSafePath).withMessage('Should have a valid safe path'), |
@@ -129,6 +132,9 @@ const installOrUpdatePluginValidator = [ | |||
129 | if (!body.path && !body.npmName) { | 132 | if (!body.path && !body.npmName) { |
130 | return res.fail({ message: 'Should have either a npmName or a path' }) | 133 | return res.fail({ message: 'Should have either a npmName or a path' }) |
131 | } | 134 | } |
135 | if (body.pluginVersion && !body.npmName) { | ||
136 | return res.fail({ message: 'Should have a npmName when specifying a pluginVersion' }) | ||
137 | } | ||
132 | 138 | ||
133 | return next() | 139 | return next() |
134 | } | 140 | } |
diff --git a/server/middlewares/validators/shared/video-channels.ts b/server/middlewares/validators/shared/video-channels.ts index 7c0c89267..bed9f5dbe 100644 --- a/server/middlewares/validators/shared/video-channels.ts +++ b/server/middlewares/validators/shared/video-channels.ts | |||
@@ -3,12 +3,6 @@ import { VideoChannelModel } from '@server/models/video/video-channel' | |||
3 | import { MChannelBannerAccountDefault } from '@server/types/models' | 3 | import { MChannelBannerAccountDefault } from '@server/types/models' |
4 | import { HttpStatusCode } from '@shared/models' | 4 | import { HttpStatusCode } from '@shared/models' |
5 | 5 | ||
6 | async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { | ||
7 | const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) | ||
8 | |||
9 | return processVideoChannelExist(videoChannel, res) | ||
10 | } | ||
11 | |||
12 | async function doesVideoChannelIdExist (id: number, res: express.Response) { | 6 | async function doesVideoChannelIdExist (id: number, res: express.Response) { |
13 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) | 7 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) |
14 | 8 | ||
@@ -24,7 +18,6 @@ async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: e | |||
24 | // --------------------------------------------------------------------------- | 18 | // --------------------------------------------------------------------------- |
25 | 19 | ||
26 | export { | 20 | export { |
27 | doesLocalVideoChannelNameExist, | ||
28 | doesVideoChannelIdExist, | 21 | doesVideoChannelIdExist, |
29 | doesVideoChannelNameWithHostExist | 22 | doesVideoChannelNameWithHostExist |
30 | } | 23 | } |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 33b31d54b..bc6007c6d 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -3,7 +3,7 @@ import { body, param, query } from 'express-validator' | |||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import { Hooks } from '@server/lib/plugins/hooks' | 4 | import { Hooks } from '@server/lib/plugins/hooks' |
5 | import { MUserDefault } from '@server/types/models' | 5 | import { MUserDefault } from '@server/types/models' |
6 | import { HttpStatusCode, UserRegister, UserRole } from '@shared/models' | 6 | import { HttpStatusCode, UserRegister, UserRight, UserRole } from '@shared/models' |
7 | import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' | 7 | import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' |
8 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' | 8 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' |
9 | import { | 9 | import { |
@@ -15,6 +15,7 @@ import { | |||
15 | isUserDisplayNameValid, | 15 | isUserDisplayNameValid, |
16 | isUserNoModal, | 16 | isUserNoModal, |
17 | isUserNSFWPolicyValid, | 17 | isUserNSFWPolicyValid, |
18 | isUserP2PEnabledValid, | ||
18 | isUserPasswordValid, | 19 | isUserPasswordValid, |
19 | isUserPasswordValidOrEmpty, | 20 | isUserPasswordValidOrEmpty, |
20 | isUserRoleValid, | 21 | isUserRoleValid, |
@@ -239,6 +240,9 @@ const usersUpdateMeValidator = [ | |||
239 | body('autoPlayVideo') | 240 | body('autoPlayVideo') |
240 | .optional() | 241 | .optional() |
241 | .custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), | 242 | .custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), |
243 | body('p2pEnabled') | ||
244 | .optional() | ||
245 | .custom(isUserP2PEnabledValid).withMessage('Should have a valid p2p enabled boolean'), | ||
242 | body('videoLanguages') | 246 | body('videoLanguages') |
243 | .optional() | 247 | .optional() |
244 | .custom(isUserVideoLanguages).withMessage('Should have a valid video languages attribute'), | 248 | .custom(isUserVideoLanguages).withMessage('Should have a valid video languages attribute'), |
@@ -490,14 +494,17 @@ const ensureAuthUserOwnsAccountValidator = [ | |||
490 | } | 494 | } |
491 | ] | 495 | ] |
492 | 496 | ||
493 | const ensureAuthUserOwnsChannelValidator = [ | 497 | const ensureCanManageChannel = [ |
494 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 498 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
495 | const user = res.locals.oauth.token.User | 499 | const user = res.locals.oauth.token.user |
500 | const isUserOwner = res.locals.videoChannel.Account.userId === user.id | ||
501 | |||
502 | if (!isUserOwner && user.hasRight(UserRight.MANAGE_ANY_VIDEO_CHANNEL) === false) { | ||
503 | const message = `User ${user.username} does not have right to manage channel ${req.params.nameWithHost}.` | ||
496 | 504 | ||
497 | if (res.locals.videoChannel.Account.userId !== user.id) { | ||
498 | return res.fail({ | 505 | return res.fail({ |
499 | status: HttpStatusCode.FORBIDDEN_403, | 506 | status: HttpStatusCode.FORBIDDEN_403, |
500 | message: 'Only owner of this video channel can access this ressource' | 507 | message |
501 | }) | 508 | }) |
502 | } | 509 | } |
503 | 510 | ||
@@ -542,8 +549,8 @@ export { | |||
542 | usersVerifyEmailValidator, | 549 | usersVerifyEmailValidator, |
543 | userAutocompleteValidator, | 550 | userAutocompleteValidator, |
544 | ensureAuthUserOwnsAccountValidator, | 551 | ensureAuthUserOwnsAccountValidator, |
545 | ensureAuthUserOwnsChannelValidator, | 552 | ensureCanManageUser, |
546 | ensureCanManageUser | 553 | ensureCanManageChannel |
547 | } | 554 | } |
548 | 555 | ||
549 | // --------------------------------------------------------------------------- | 556 | // --------------------------------------------------------------------------- |
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts index 4fc4c8ec5..a399871e1 100644 --- a/server/middlewares/validators/videos/video-captions.ts +++ b/server/middlewares/validators/videos/video-captions.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param } from 'express-validator' |
3 | import { HttpStatusCode, UserRight } from '../../../../shared' | 3 | import { HttpStatusCode, UserRight } from '@shared/models' |
4 | import { isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions' | 4 | import { isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions' |
5 | import { cleanUpReqFiles } from '../../../helpers/express-utils' | 5 | import { cleanUpReqFiles } from '../../../helpers/express-utils' |
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts index edce48c7f..3bfdebbb1 100644 --- a/server/middlewares/validators/videos/video-channels.ts +++ b/server/middlewares/validators/videos/video-channels.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param, query } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { MChannelAccountDefault, MUser } from '@server/types/models' | 3 | import { CONFIG } from '@server/initializers/config' |
4 | import { UserRight } from '../../../../shared' | 4 | import { MChannelAccountDefault } from '@server/types/models' |
5 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 5 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' |
6 | import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' | 6 | import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' |
7 | import { | 7 | import { |
@@ -13,8 +13,7 @@ import { | |||
13 | import { logger } from '../../../helpers/logger' | 13 | import { logger } from '../../../helpers/logger' |
14 | import { ActorModel } from '../../../models/actor/actor' | 14 | import { ActorModel } from '../../../models/actor/actor' |
15 | import { VideoChannelModel } from '../../../models/video/video-channel' | 15 | import { VideoChannelModel } from '../../../models/video/video-channel' |
16 | import { areValidationErrors, doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../shared' | 16 | import { areValidationErrors, doesVideoChannelNameWithHostExist } from '../shared' |
17 | import { CONFIG } from '@server/initializers/config' | ||
18 | 17 | ||
19 | const videoChannelsAddValidator = [ | 18 | const videoChannelsAddValidator = [ |
20 | body('name').custom(isVideoChannelUsernameValid).withMessage('Should have a valid channel name'), | 19 | body('name').custom(isVideoChannelUsernameValid).withMessage('Should have a valid channel name'), |
@@ -71,16 +70,10 @@ const videoChannelsUpdateValidator = [ | |||
71 | ] | 70 | ] |
72 | 71 | ||
73 | const videoChannelsRemoveValidator = [ | 72 | const videoChannelsRemoveValidator = [ |
74 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), | ||
75 | |||
76 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 73 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
77 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) | 74 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) |
78 | 75 | ||
79 | if (areValidationErrors(req, res)) return | 76 | if (!await checkVideoChannelIsNotTheLastOne(res.locals.videoChannel, res)) return |
80 | if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return | ||
81 | |||
82 | if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return | ||
83 | if (!await checkVideoChannelIsNotTheLastOne(res)) return | ||
84 | 77 | ||
85 | return next() | 78 | return next() |
86 | } | 79 | } |
@@ -100,14 +93,14 @@ const videoChannelsNameWithHostValidator = [ | |||
100 | } | 93 | } |
101 | ] | 94 | ] |
102 | 95 | ||
103 | const localVideoChannelValidator = [ | 96 | const ensureIsLocalChannel = [ |
104 | param('name').custom(isVideoChannelDisplayNameValid).withMessage('Should have a valid video channel name'), | 97 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
105 | 98 | if (res.locals.videoChannel.Actor.isOwned() === false) { | |
106 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 99 | return res.fail({ |
107 | logger.debug('Checking localVideoChannelValidator parameters', { parameters: req.params }) | 100 | status: HttpStatusCode.FORBIDDEN_403, |
108 | 101 | message: 'This channel is not owned.' | |
109 | if (areValidationErrors(req, res)) return | 102 | }) |
110 | if (!await doesLocalVideoChannelNameExist(req.params.name, res)) return | 103 | } |
111 | 104 | ||
112 | return next() | 105 | return next() |
113 | } | 106 | } |
@@ -144,38 +137,15 @@ export { | |||
144 | videoChannelsUpdateValidator, | 137 | videoChannelsUpdateValidator, |
145 | videoChannelsRemoveValidator, | 138 | videoChannelsRemoveValidator, |
146 | videoChannelsNameWithHostValidator, | 139 | videoChannelsNameWithHostValidator, |
140 | ensureIsLocalChannel, | ||
147 | videoChannelsListValidator, | 141 | videoChannelsListValidator, |
148 | localVideoChannelValidator, | ||
149 | videoChannelStatsValidator | 142 | videoChannelStatsValidator |
150 | } | 143 | } |
151 | 144 | ||
152 | // --------------------------------------------------------------------------- | 145 | // --------------------------------------------------------------------------- |
153 | 146 | ||
154 | function checkUserCanDeleteVideoChannel (user: MUser, videoChannel: MChannelAccountDefault, res: express.Response) { | 147 | async function checkVideoChannelIsNotTheLastOne (videoChannel: MChannelAccountDefault, res: express.Response) { |
155 | if (videoChannel.Actor.isOwned() === false) { | 148 | const count = await VideoChannelModel.countByAccount(videoChannel.Account.id) |
156 | res.fail({ | ||
157 | status: HttpStatusCode.FORBIDDEN_403, | ||
158 | message: 'Cannot remove video channel of another server.' | ||
159 | }) | ||
160 | return false | ||
161 | } | ||
162 | |||
163 | // Check if the user can delete the video channel | ||
164 | // The user can delete it if s/he is an admin | ||
165 | // Or if s/he is the video channel's account | ||
166 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && videoChannel.Account.userId !== user.id) { | ||
167 | res.fail({ | ||
168 | status: HttpStatusCode.FORBIDDEN_403, | ||
169 | message: 'Cannot remove video channel of another user' | ||
170 | }) | ||
171 | return false | ||
172 | } | ||
173 | |||
174 | return true | ||
175 | } | ||
176 | |||
177 | async function checkVideoChannelIsNotTheLastOne (res: express.Response) { | ||
178 | const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id) | ||
179 | 149 | ||
180 | if (count <= 1) { | 150 | if (count <= 1) { |
181 | res.fail({ | 151 | res.fail({ |
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts index 04e7b6973..91ae31ec2 100644 --- a/server/middlewares/validators/videos/video-comments.ts +++ b/server/middlewares/validators/videos/video-comments.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param, query } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { MUserAccountUrl } from '@server/types/models' | 3 | import { MUserAccountUrl } from '@server/types/models' |
4 | import { UserRight } from '../../../../shared' | 4 | import { HttpStatusCode, UserRight } from '@shared/models' |
5 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
6 | import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' | 5 | import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' |
7 | import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' | 6 | import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' |
8 | import { logger } from '../../../helpers/logger' | 7 | import { logger } from '../../../helpers/logger' |
diff --git a/server/middlewares/validators/videos/video-files.ts b/server/middlewares/validators/videos/video-files.ts index c1fa77502..35b0ac757 100644 --- a/server/middlewares/validators/videos/video-files.ts +++ b/server/middlewares/validators/videos/video-files.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { MVideo } from '@server/types/models' | 2 | import { MVideo } from '@server/types/models' |
3 | import { HttpStatusCode } from '../../../../shared' | 3 | import { HttpStatusCode } from '@shared/models' |
4 | import { logger } from '../../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared' | 5 | import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared' |
6 | 6 | ||
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts index 8f5c75fd5..f5fee845e 100644 --- a/server/middlewares/validators/videos/video-playlists.ts +++ b/server/middlewares/validators/videos/video-playlists.ts | |||
@@ -1,11 +1,15 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param, query, ValidationChain } from 'express-validator' | 2 | import { body, param, query, ValidationChain } from 'express-validator' |
3 | import { ExpressPromiseHandler } from '@server/types/express' | 3 | import { ExpressPromiseHandler } from '@server/types/express-handler' |
4 | import { MUserAccountId } from '@server/types/models' | 4 | import { MUserAccountId } from '@server/types/models' |
5 | import { UserRight, VideoPlaylistCreate, VideoPlaylistUpdate } from '../../../../shared' | 5 | import { |
6 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 6 | HttpStatusCode, |
7 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | 7 | UserRight, |
8 | import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model' | 8 | VideoPlaylistCreate, |
9 | VideoPlaylistPrivacy, | ||
10 | VideoPlaylistType, | ||
11 | VideoPlaylistUpdate | ||
12 | } from '@shared/models' | ||
9 | import { | 13 | import { |
10 | isArrayOf, | 14 | isArrayOf, |
11 | isIdOrUUIDValid, | 15 | isIdOrUUIDValid, |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 782f495e8..3a1a905f3 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -5,12 +5,10 @@ import { getResumableUploadPath } from '@server/helpers/upload' | |||
5 | import { Redis } from '@server/lib/redis' | 5 | import { Redis } from '@server/lib/redis' |
6 | import { isAbleToUploadVideo } from '@server/lib/user' | 6 | import { isAbleToUploadVideo } from '@server/lib/user' |
7 | import { getServerActor } from '@server/models/application/application' | 7 | import { getServerActor } from '@server/models/application/application' |
8 | import { ExpressPromiseHandler } from '@server/types/express' | 8 | import { ExpressPromiseHandler } from '@server/types/express-handler' |
9 | import { MUserAccountId, MVideoFullLight } from '@server/types/models' | 9 | import { MUserAccountId, MVideoFullLight } from '@server/types/models' |
10 | import { getAllPrivacies } from '@shared/core-utils' | 10 | import { getAllPrivacies } from '@shared/core-utils' |
11 | import { VideoInclude } from '@shared/models' | 11 | import { HttpStatusCode, ServerErrorCode, UserRight, VideoInclude, VideoPrivacy } from '@shared/models' |
12 | import { ServerErrorCode, UserRight, VideoPrivacy } from '../../../../shared' | ||
13 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | ||
14 | import { | 12 | import { |
15 | exists, | 13 | exists, |
16 | isBooleanValid, | 14 | isBooleanValid, |
diff --git a/server/models/abuse/abuse-message.ts b/server/models/abuse/abuse-message.ts index 2c5987e96..6a441a210 100644 --- a/server/models/abuse/abuse-message.ts +++ b/server/models/abuse/abuse-message.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { isAbuseMessageValid } from '@server/helpers/custom-validators/abuses' | 2 | import { isAbuseMessageValid } from '@server/helpers/custom-validators/abuses' |
3 | import { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models' | 3 | import { MAbuseMessage, MAbuseMessageFormattable } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { AbuseMessage } from '@shared/models' | 5 | import { AbuseMessage } from '@shared/models' |
6 | import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' | 6 | import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' |
7 | import { getSort, throwIfNotValid } from '../utils' | 7 | import { getSort, throwIfNotValid } from '../utils' |
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts index 3518f5c02..4344df006 100644 --- a/server/models/abuse/abuse.ts +++ b/server/models/abuse/abuse.ts | |||
@@ -16,7 +16,7 @@ import { | |||
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' | 18 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' |
19 | import { abusePredefinedReasonsMap, AttributesOnly } from '@shared/core-utils' | 19 | import { abusePredefinedReasonsMap } from '@shared/core-utils' |
20 | import { | 20 | import { |
21 | AbuseFilter, | 21 | AbuseFilter, |
22 | AbuseObject, | 22 | AbuseObject, |
@@ -30,6 +30,7 @@ import { | |||
30 | UserAbuse, | 30 | UserAbuse, |
31 | UserVideoAbuse | 31 | UserVideoAbuse |
32 | } from '@shared/models' | 32 | } from '@shared/models' |
33 | import { AttributesOnly } from '@shared/typescript-utils' | ||
33 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' | 34 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
34 | import { MAbuseAdminFormattable, MAbuseAP, MAbuseFull, MAbuseReporter, MAbuseUserFormattable, MUserAccountId } from '../../types/models' | 35 | import { MAbuseAdminFormattable, MAbuseAP, MAbuseFull, MAbuseReporter, MAbuseUserFormattable, MUserAccountId } from '../../types/models' |
35 | import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account' | 36 | import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account' |
diff --git a/server/models/abuse/video-abuse.ts b/server/models/abuse/video-abuse.ts index 95bff50d0..773a9ebba 100644 --- a/server/models/abuse/video-abuse.ts +++ b/server/models/abuse/video-abuse.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { AttributesOnly } from '@shared/core-utils' | 2 | import { AttributesOnly } from '@shared/typescript-utils' |
3 | import { VideoDetails } from '@shared/models' | 3 | import { VideoDetails } from '@shared/models' |
4 | import { VideoModel } from '../video/video' | 4 | import { VideoModel } from '../video/video' |
5 | import { AbuseModel } from './abuse' | 5 | import { AbuseModel } from './abuse' |
diff --git a/server/models/abuse/video-comment-abuse.ts b/server/models/abuse/video-comment-abuse.ts index 32cb2ca64..337aaaa58 100644 --- a/server/models/abuse/video-comment-abuse.ts +++ b/server/models/abuse/video-comment-abuse.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { AttributesOnly } from '@shared/core-utils' | 2 | import { AttributesOnly } from '@shared/typescript-utils' |
3 | import { VideoCommentModel } from '../video/video-comment' | 3 | import { VideoCommentModel } from '../video/video-comment' |
4 | import { AbuseModel } from './abuse' | 4 | import { AbuseModel } from './abuse' |
5 | 5 | ||
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index b2375b006..1162962bf 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts | |||
@@ -1,11 +1,12 @@ | |||
1 | import { Op } from 'sequelize' | 1 | import { Op, QueryTypes } from 'sequelize' |
2 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { handlesToNameAndHost } from '@server/helpers/actors' | ||
3 | import { MAccountBlocklist, MAccountBlocklistAccounts, MAccountBlocklistFormattable } from '@server/types/models' | 4 | import { MAccountBlocklist, MAccountBlocklistAccounts, MAccountBlocklistFormattable } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 5 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { AccountBlock } from '../../../shared/models' | 6 | import { AccountBlock } from '../../../shared/models' |
6 | import { ActorModel } from '../actor/actor' | 7 | import { ActorModel } from '../actor/actor' |
7 | import { ServerModel } from '../server/server' | 8 | import { ServerModel } from '../server/server' |
8 | import { getSort, searchAttribute } from '../utils' | 9 | import { createSafeIn, getSort, searchAttribute } from '../utils' |
9 | import { AccountModel } from './account' | 10 | import { AccountModel } from './account' |
10 | 11 | ||
11 | enum ScopeNames { | 12 | enum ScopeNames { |
@@ -77,7 +78,7 @@ export class AccountBlocklistModel extends Model<Partial<AttributesOnly<AccountB | |||
77 | }) | 78 | }) |
78 | BlockedAccount: AccountModel | 79 | BlockedAccount: AccountModel |
79 | 80 | ||
80 | static isAccountMutedByMulti (accountIds: number[], targetAccountId: number) { | 81 | static isAccountMutedByAccounts (accountIds: number[], targetAccountId: number) { |
81 | const query = { | 82 | const query = { |
82 | attributes: [ 'accountId', 'id' ], | 83 | attributes: [ 'accountId', 'id' ], |
83 | where: { | 84 | where: { |
@@ -187,6 +188,39 @@ export class AccountBlocklistModel extends Model<Partial<AttributesOnly<AccountB | |||
187 | .then(entries => entries.map(e => `${e.BlockedAccount.Actor.preferredUsername}@${e.BlockedAccount.Actor.Server.host}`)) | 188 | .then(entries => entries.map(e => `${e.BlockedAccount.Actor.preferredUsername}@${e.BlockedAccount.Actor.Server.host}`)) |
188 | } | 189 | } |
189 | 190 | ||
191 | static getBlockStatus (byAccountIds: number[], handles: string[]): Promise<{ name: string, host: string, accountId: number }[]> { | ||
192 | const sanitizedHandles = handlesToNameAndHost(handles) | ||
193 | |||
194 | const localHandles = sanitizedHandles.filter(h => !h.host) | ||
195 | .map(h => h.name) | ||
196 | |||
197 | const remoteHandles = sanitizedHandles.filter(h => !!h.host) | ||
198 | .map(h => ([ h.name, h.host ])) | ||
199 | |||
200 | const handlesWhere: string[] = [] | ||
201 | |||
202 | if (localHandles.length !== 0) { | ||
203 | handlesWhere.push(`("actor"."preferredUsername" IN (:localHandles) AND "server"."id" IS NULL)`) | ||
204 | } | ||
205 | |||
206 | if (remoteHandles.length !== 0) { | ||
207 | handlesWhere.push(`(("actor"."preferredUsername", "server"."host") IN (:remoteHandles))`) | ||
208 | } | ||
209 | |||
210 | const rawQuery = `SELECT "accountBlocklist"."accountId", "actor"."preferredUsername" AS "name", "server"."host" ` + | ||
211 | `FROM "accountBlocklist" ` + | ||
212 | `INNER JOIN "account" ON "account"."id" = "accountBlocklist"."targetAccountId" ` + | ||
213 | `INNER JOIN "actor" ON "actor"."id" = "account"."actorId" ` + | ||
214 | `LEFT JOIN "server" ON "server"."id" = "actor"."serverId" ` + | ||
215 | `WHERE "accountBlocklist"."accountId" IN (${createSafeIn(AccountBlocklistModel.sequelize, byAccountIds)}) ` + | ||
216 | `AND (${handlesWhere.join(' OR ')})` | ||
217 | |||
218 | return AccountBlocklistModel.sequelize.query(rawQuery, { | ||
219 | type: QueryTypes.SELECT as QueryTypes.SELECT, | ||
220 | replacements: { byAccountIds, localHandles, remoteHandles } | ||
221 | }) | ||
222 | } | ||
223 | |||
190 | toFormattedJSON (this: MAccountBlocklistFormattable): AccountBlock { | 224 | toFormattedJSON (this: MAccountBlocklistFormattable): AccountBlock { |
191 | return { | 225 | return { |
192 | byAccount: this.ByAccount.toFormattedJSON(), | 226 | byAccount: this.ByAccount.toFormattedJSON(), |
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index ee6dbc6da..e89d31adf 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts | |||
@@ -6,10 +6,9 @@ import { | |||
6 | MAccountVideoRateAccountUrl, | 6 | MAccountVideoRateAccountUrl, |
7 | MAccountVideoRateAccountVideo, | 7 | MAccountVideoRateAccountVideo, |
8 | MAccountVideoRateFormattable | 8 | MAccountVideoRateFormattable |
9 | } from '@server/types/models/video/video-rate' | 9 | } from '@server/types/models' |
10 | import { AttributesOnly } from '@shared/core-utils' | 10 | import { AccountVideoRate, VideoRateType } from '@shared/models' |
11 | import { AccountVideoRate } from '../../../shared' | 11 | import { AttributesOnly } from '@shared/typescript-utils' |
12 | import { VideoRateType } from '../../../shared/models/videos' | ||
13 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 12 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
14 | import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants' | 13 | import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants' |
15 | import { ActorModel } from '../actor/actor' | 14 | import { ActorModel } from '../actor/actor' |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 71a9b8ccb..619a598dd 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -17,7 +17,7 @@ import { | |||
17 | UpdatedAt | 17 | UpdatedAt |
18 | } from 'sequelize-typescript' | 18 | } from 'sequelize-typescript' |
19 | import { ModelCache } from '@server/models/model-cache' | 19 | import { ModelCache } from '@server/models/model-cache' |
20 | import { AttributesOnly } from '@shared/core-utils' | 20 | import { AttributesOnly } from '@shared/typescript-utils' |
21 | import { Account, AccountSummary } from '../../../shared/models/actors' | 21 | import { Account, AccountSummary } from '../../../shared/models/actors' |
22 | import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts' | 22 | import { isAccountDescriptionValid } from '../../helpers/custom-validators/accounts' |
23 | import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' | 23 | import { CONSTRAINTS_FIELDS, SERVER_ACTOR_NAME, WEBSERVER } from '../../initializers/constants' |
diff --git a/server/models/actor/actor-follow.ts b/server/models/actor/actor-follow.ts index d6a2387a5..006282530 100644 --- a/server/models/actor/actor-follow.ts +++ b/server/models/actor/actor-follow.ts | |||
@@ -30,7 +30,7 @@ import { | |||
30 | MActorFollowFormattable, | 30 | MActorFollowFormattable, |
31 | MActorFollowSubscriptions | 31 | MActorFollowSubscriptions |
32 | } from '@server/types/models' | 32 | } from '@server/types/models' |
33 | import { AttributesOnly } from '@shared/core-utils' | 33 | import { AttributesOnly } from '@shared/typescript-utils' |
34 | import { ActivityPubActorType } from '@shared/models' | 34 | import { ActivityPubActorType } from '@shared/models' |
35 | import { FollowState } from '../../../shared/models/actors' | 35 | import { FollowState } from '../../../shared/models/actors' |
36 | import { ActorFollow } from '../../../shared/models/actors/follow.model' | 36 | import { ActorFollow } from '../../../shared/models/actors/follow.model' |
diff --git a/server/models/actor/actor-image.ts b/server/models/actor/actor-image.ts index 98a7f6fba..8edff5ab4 100644 --- a/server/models/actor/actor-image.ts +++ b/server/models/actor/actor-image.ts | |||
@@ -2,7 +2,7 @@ import { remove } from 'fs-extra' | |||
2 | import { join } from 'path' | 2 | import { join } from 'path' |
3 | import { AfterDestroy, AllowNull, Column, CreatedAt, Default, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 3 | import { AfterDestroy, AllowNull, Column, CreatedAt, Default, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
4 | import { MActorImageFormattable } from '@server/types/models' | 4 | import { MActorImageFormattable } from '@server/types/models' |
5 | import { AttributesOnly } from '@shared/core-utils' | 5 | import { AttributesOnly } from '@shared/typescript-utils' |
6 | import { ActorImageType } from '@shared/models' | 6 | import { ActorImageType } from '@shared/models' |
7 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' | 7 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' |
8 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 8 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts index 8df49951d..c12dcf634 100644 --- a/server/models/actor/actor.ts +++ b/server/models/actor/actor.ts | |||
@@ -16,9 +16,9 @@ import { | |||
16 | Table, | 16 | Table, |
17 | UpdatedAt | 17 | UpdatedAt |
18 | } from 'sequelize-typescript' | 18 | } from 'sequelize-typescript' |
19 | import { getLowercaseExtension } from '@server/helpers/core-utils' | ||
20 | import { ModelCache } from '@server/models/model-cache' | 19 | import { ModelCache } from '@server/models/model-cache' |
21 | import { AttributesOnly } from '@shared/core-utils' | 20 | import { getLowercaseExtension } from '@shared/core-utils' |
21 | import { AttributesOnly } from '@shared/typescript-utils' | ||
22 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' | 22 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' |
23 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' | 23 | import { ActorImage } from '../../../shared/models/actors/actor-image.model' |
24 | import { activityPubContextify } from '../../helpers/activitypub' | 24 | import { activityPubContextify } from '../../helpers/activitypub' |
diff --git a/server/models/application/application.ts b/server/models/application/application.ts index e3939383b..a479de5d2 100644 --- a/server/models/application/application.ts +++ b/server/models/application/application.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import memoizee from 'memoizee' | 1 | import memoizee from 'memoizee' |
2 | import { AllowNull, Column, Default, DefaultScope, HasOne, IsInt, Model, Table } from 'sequelize-typescript' | 2 | import { AllowNull, Column, Default, DefaultScope, HasOne, IsInt, Model, Table } from 'sequelize-typescript' |
3 | import { AttributesOnly } from '@shared/core-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { AccountModel } from '../account/account' | 4 | import { AccountModel } from '../account/account' |
5 | 5 | ||
6 | export const getServerActor = memoizee(async function () { | 6 | export const getServerActor = memoizee(async function () { |
diff --git a/server/models/oauth/oauth-client.ts b/server/models/oauth/oauth-client.ts index 890954bdb..860fa6f53 100644 --- a/server/models/oauth/oauth-client.ts +++ b/server/models/oauth/oauth-client.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { AllowNull, Column, CreatedAt, DataType, HasMany, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, Column, CreatedAt, DataType, HasMany, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { AttributesOnly } from '@shared/core-utils' | 2 | import { AttributesOnly } from '@shared/typescript-utils' |
3 | import { OAuthTokenModel } from './oauth-token' | 3 | import { OAuthTokenModel } from './oauth-token' |
4 | 4 | ||
5 | @Table({ | 5 | @Table({ |
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index af4b0ec42..f72423190 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts | |||
@@ -15,7 +15,7 @@ import { | |||
15 | import { TokensCache } from '@server/lib/auth/tokens-cache' | 15 | import { TokensCache } from '@server/lib/auth/tokens-cache' |
16 | import { MUserAccountId } from '@server/types/models' | 16 | import { MUserAccountId } from '@server/types/models' |
17 | import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' | 17 | import { MOAuthTokenUser } from '@server/types/models/oauth/oauth-token' |
18 | import { AttributesOnly } from '@shared/core-utils' | 18 | import { AttributesOnly } from '@shared/typescript-utils' |
19 | import { logger } from '../../helpers/logger' | 19 | import { logger } from '../../helpers/logger' |
20 | import { AccountModel } from '../account/account' | 20 | import { AccountModel } from '../account/account' |
21 | import { ActorModel } from '../actor/actor' | 21 | import { ActorModel } from '../actor/actor' |
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index e8d79a3ab..6f84747da 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -16,15 +16,17 @@ import { | |||
16 | } from 'sequelize-typescript' | 16 | } from 'sequelize-typescript' |
17 | import { getServerActor } from '@server/models/application/application' | 17 | import { getServerActor } from '@server/models/application/application' |
18 | import { MActor, MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/types/models' | 18 | import { MActor, MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/types/models' |
19 | import { AttributesOnly } from '@shared/core-utils' | ||
20 | import { VideoRedundanciesTarget } from '@shared/models/redundancy/video-redundancies-filters.model' | ||
21 | import { | 19 | import { |
20 | CacheFileObject, | ||
22 | FileRedundancyInformation, | 21 | FileRedundancyInformation, |
23 | StreamingPlaylistRedundancyInformation, | 22 | StreamingPlaylistRedundancyInformation, |
24 | VideoRedundancy | 23 | VideoPrivacy, |
25 | } from '@shared/models/redundancy/video-redundancy.model' | 24 | VideoRedundanciesTarget, |
26 | import { CacheFileObject, VideoPrivacy } from '../../../shared' | 25 | VideoRedundancy, |
27 | import { VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../shared/models/redundancy' | 26 | VideoRedundancyStrategy, |
27 | VideoRedundancyStrategyWithManual | ||
28 | } from '@shared/models' | ||
29 | import { AttributesOnly } from '@shared/typescript-utils' | ||
28 | import { isTestInstance } from '../../helpers/core-utils' | 30 | import { isTestInstance } from '../../helpers/core-utils' |
29 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 31 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
30 | import { logger } from '../../helpers/logger' | 32 | import { logger } from '../../helpers/logger' |
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index a8de64dd4..84f7a14e4 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { FindAndCountOptions, json, QueryTypes } from 'sequelize' | 1 | import { FindAndCountOptions, json, QueryTypes } from 'sequelize' |
2 | import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, Column, CreatedAt, DataType, DefaultScope, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MPlugin, MPluginFormattable } from '@server/types/models' | 3 | import { MPlugin, MPluginFormattable } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { PeerTubePlugin, PluginType, RegisterServerSettingOptions } from '../../../shared/models' | 5 | import { PeerTubePlugin, PluginType, RegisterServerSettingOptions } from '../../../shared/models' |
6 | import { | 6 | import { |
7 | isPluginDescriptionValid, | 7 | isPluginDescriptionValid, |
@@ -197,15 +197,11 @@ export class PluginModel extends Model<Partial<AttributesOnly<PluginModel>>> { | |||
197 | if (!c) return undefined | 197 | if (!c) return undefined |
198 | const value = c.value | 198 | const value = c.value |
199 | 199 | ||
200 | if (typeof value === 'string' && value.startsWith('{')) { | 200 | try { |
201 | try { | 201 | return JSON.parse(value) |
202 | return JSON.parse(value) | 202 | } catch { |
203 | } catch { | 203 | return value |
204 | return value | ||
205 | } | ||
206 | } | 204 | } |
207 | |||
208 | return c.value | ||
209 | }) | 205 | }) |
210 | } | 206 | } |
211 | 207 | ||
diff --git a/server/models/server/server-blocklist.ts b/server/models/server/server-blocklist.ts index b3579d589..9f64eeb7f 100644 --- a/server/models/server/server-blocklist.ts +++ b/server/models/server/server-blocklist.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Op } from 'sequelize' | 1 | import { Op, QueryTypes } from 'sequelize' |
2 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models' | 3 | import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { ServerBlock } from '@shared/models' | 5 | import { ServerBlock } from '@shared/models' |
6 | import { AccountModel } from '../account/account' | 6 | import { AccountModel } from '../account/account' |
7 | import { getSort, searchAttribute } from '../utils' | 7 | import { createSafeIn, getSort, searchAttribute } from '../utils' |
8 | import { ServerModel } from './server' | 8 | import { ServerModel } from './server' |
9 | 9 | ||
10 | enum ScopeNames { | 10 | enum ScopeNames { |
@@ -76,7 +76,7 @@ export class ServerBlocklistModel extends Model<Partial<AttributesOnly<ServerBlo | |||
76 | }) | 76 | }) |
77 | BlockedServer: ServerModel | 77 | BlockedServer: ServerModel |
78 | 78 | ||
79 | static isServerMutedByMulti (accountIds: number[], targetServerId: number) { | 79 | static isServerMutedByAccounts (accountIds: number[], targetServerId: number) { |
80 | const query = { | 80 | const query = { |
81 | attributes: [ 'accountId', 'id' ], | 81 | attributes: [ 'accountId', 'id' ], |
82 | where: { | 82 | where: { |
@@ -141,6 +141,19 @@ export class ServerBlocklistModel extends Model<Partial<AttributesOnly<ServerBlo | |||
141 | .then(entries => entries.map(e => e.BlockedServer.host)) | 141 | .then(entries => entries.map(e => e.BlockedServer.host)) |
142 | } | 142 | } |
143 | 143 | ||
144 | static getBlockStatus (byAccountIds: number[], hosts: string[]): Promise<{ host: string, accountId: number }[]> { | ||
145 | const rawQuery = `SELECT "server"."host", "serverBlocklist"."accountId" ` + | ||
146 | `FROM "serverBlocklist" ` + | ||
147 | `INNER JOIN "server" ON "server"."id" = "serverBlocklist"."targetServerId" ` + | ||
148 | `WHERE "server"."host" IN (:hosts) ` + | ||
149 | `AND "serverBlocklist"."accountId" IN (${createSafeIn(ServerBlocklistModel.sequelize, byAccountIds)})` | ||
150 | |||
151 | return ServerBlocklistModel.sequelize.query(rawQuery, { | ||
152 | type: QueryTypes.SELECT as QueryTypes.SELECT, | ||
153 | replacements: { hosts } | ||
154 | }) | ||
155 | } | ||
156 | |||
144 | static listForApi (parameters: { | 157 | static listForApi (parameters: { |
145 | start: number | 158 | start: number |
146 | count: number | 159 | count: number |
diff --git a/server/models/server/server.ts b/server/models/server/server.ts index edbe92f73..ef42de090 100644 --- a/server/models/server/server.ts +++ b/server/models/server/server.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MServer, MServerFormattable } from '@server/types/models/server' | 3 | import { MServer, MServerFormattable } from '@server/types/models/server' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { isHostValid } from '../../helpers/custom-validators/servers' | 5 | import { isHostValid } from '../../helpers/custom-validators/servers' |
6 | import { ActorModel } from '../actor/actor' | 6 | import { ActorModel } from '../actor/actor' |
7 | import { throwIfNotValid } from '../utils' | 7 | import { throwIfNotValid } from '../utils' |
diff --git a/server/models/server/tracker.ts b/server/models/server/tracker.ts index c09fdd64b..ee087c4a3 100644 --- a/server/models/server/tracker.ts +++ b/server/models/server/tracker.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AllowNull, BelongsToMany, Column, CreatedAt, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsToMany, Column, CreatedAt, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { Transaction } from 'sequelize/types' | 2 | import { Transaction } from 'sequelize/types' |
3 | import { MTracker } from '@server/types/models/server/tracker' | 3 | import { MTracker } from '@server/types/models/server/tracker' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { VideoModel } from '../video/video' | 5 | import { VideoModel } from '../video/video' |
6 | import { VideoTrackerModel } from './video-tracker' | 6 | import { VideoTrackerModel } from './video-tracker' |
7 | 7 | ||
diff --git a/server/models/server/video-tracker.ts b/server/models/server/video-tracker.ts index c49fbd1c6..f14f3bd7d 100644 --- a/server/models/server/video-tracker.ts +++ b/server/models/server/video-tracker.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { AttributesOnly } from '@shared/core-utils' | 2 | import { AttributesOnly } from '@shared/typescript-utils' |
3 | import { VideoModel } from '../video/video' | 3 | import { VideoModel } from '../video/video' |
4 | import { TrackerModel } from './tracker' | 4 | import { TrackerModel } from './tracker' |
5 | 5 | ||
diff --git a/server/models/user/user-notification-setting.ts b/server/models/user/user-notification-setting.ts index bee7d7851..f03b19e41 100644 --- a/server/models/user/user-notification-setting.ts +++ b/server/models/user/user-notification-setting.ts | |||
@@ -14,7 +14,7 @@ import { | |||
14 | } from 'sequelize-typescript' | 14 | } from 'sequelize-typescript' |
15 | import { TokensCache } from '@server/lib/auth/tokens-cache' | 15 | import { TokensCache } from '@server/lib/auth/tokens-cache' |
16 | import { MNotificationSettingFormattable } from '@server/types/models' | 16 | import { MNotificationSettingFormattable } from '@server/types/models' |
17 | import { AttributesOnly } from '@shared/core-utils' | 17 | import { AttributesOnly } from '@shared/typescript-utils' |
18 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' | 18 | import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model' |
19 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' | 19 | import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications' |
20 | import { throwIfNotValid } from '../utils' | 20 | import { throwIfNotValid } from '../utils' |
diff --git a/server/models/user/user-notification.ts b/server/models/user/user-notification.ts index 04c5513a9..edad10a55 100644 --- a/server/models/user/user-notification.ts +++ b/server/models/user/user-notification.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { FindOptions, ModelIndexesOptions, Op, WhereOptions } from 'sequelize' | 1 | import { FindOptions, ModelIndexesOptions, Op, WhereOptions } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { uuidToShort } from '@server/helpers/uuid' | ||
4 | import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user' | 3 | import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/types/models/user' |
5 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { uuidToShort } from '@shared/extra-utils' |
6 | import { UserNotification, UserNotificationType } from '../../../shared' | 5 | import { UserNotification, UserNotificationType } from '@shared/models' |
6 | import { AttributesOnly } from '@shared/typescript-utils' | ||
7 | import { isBooleanValid } from '../../helpers/custom-validators/misc' | 7 | import { isBooleanValid } from '../../helpers/custom-validators/misc' |
8 | import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications' | 8 | import { isUserNotificationTypeValid } from '../../helpers/custom-validators/user-notifications' |
9 | import { AbuseModel } from '../abuse/abuse' | 9 | import { AbuseModel } from '../abuse/abuse' |
diff --git a/server/models/user/user-video-history.ts b/server/models/user/user-video-history.ts index 1aefdf02b..6d9f2e03f 100644 --- a/server/models/user/user-video-history.ts +++ b/server/models/user/user-video-history.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { DestroyOptions, Op, Transaction } from 'sequelize' | 1 | import { DestroyOptions, Op, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MUserAccountId, MUserId } from '@server/types/models' | 3 | import { MUserAccountId, MUserId } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { VideoModel } from '../video/video' | 5 | import { VideoModel } from '../video/video' |
6 | import { UserModel } from './user' | 6 | import { UserModel } from './user' |
7 | import { getServerActor } from '../application/application' | 7 | import { getServerActor } from '../application/application' |
diff --git a/server/models/user/user.ts b/server/models/user/user.ts index b56f37e55..4ad76e5bc 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts | |||
@@ -31,7 +31,7 @@ import { | |||
31 | MUserWithNotificationSetting, | 31 | MUserWithNotificationSetting, |
32 | MVideoWithRights | 32 | MVideoWithRights |
33 | } from '@server/types/models' | 33 | } from '@server/types/models' |
34 | import { AttributesOnly } from '@shared/core-utils' | 34 | import { AttributesOnly } from '@shared/typescript-utils' |
35 | import { hasUserRight, USER_ROLE_LABELS } from '../../../shared/core-utils/users' | 35 | import { hasUserRight, USER_ROLE_LABELS } from '../../../shared/core-utils/users' |
36 | import { AbuseState, MyUser, UserRight, VideoPlaylistType, VideoPrivacy } from '../../../shared/models' | 36 | import { AbuseState, MyUser, UserRight, VideoPlaylistType, VideoPrivacy } from '../../../shared/models' |
37 | import { User, UserRole } from '../../../shared/models/users' | 37 | import { User, UserRole } from '../../../shared/models/users' |
@@ -55,7 +55,7 @@ import { | |||
55 | isUserVideoQuotaDailyValid, | 55 | isUserVideoQuotaDailyValid, |
56 | isUserVideoQuotaValid, | 56 | isUserVideoQuotaValid, |
57 | isUserVideosHistoryEnabledValid, | 57 | isUserVideosHistoryEnabledValid, |
58 | isUserWebTorrentEnabledValid | 58 | isUserP2PEnabledValid |
59 | } from '../../helpers/custom-validators/users' | 59 | } from '../../helpers/custom-validators/users' |
60 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' | 60 | import { comparePassword, cryptPassword } from '../../helpers/peertube-crypto' |
61 | import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' | 61 | import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' |
@@ -267,10 +267,9 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> { | |||
267 | nsfwPolicy: NSFWPolicyType | 267 | nsfwPolicy: NSFWPolicyType |
268 | 268 | ||
269 | @AllowNull(false) | 269 | @AllowNull(false) |
270 | @Default(true) | 270 | @Is('p2pEnabled', value => throwIfNotValid(value, isUserP2PEnabledValid, 'P2P enabled')) |
271 | @Is('UserWebTorrentEnabled', value => throwIfNotValid(value, isUserWebTorrentEnabledValid, 'WebTorrent enabled')) | ||
272 | @Column | 271 | @Column |
273 | webTorrentEnabled: boolean | 272 | p2pEnabled: boolean |
274 | 273 | ||
275 | @AllowNull(false) | 274 | @AllowNull(false) |
276 | @Default(true) | 275 | @Default(true) |
@@ -892,7 +891,11 @@ export class UserModel extends Model<Partial<AttributesOnly<UserModel>>> { | |||
892 | emailVerified: this.emailVerified, | 891 | emailVerified: this.emailVerified, |
893 | 892 | ||
894 | nsfwPolicy: this.nsfwPolicy, | 893 | nsfwPolicy: this.nsfwPolicy, |
895 | webTorrentEnabled: this.webTorrentEnabled, | 894 | |
895 | // FIXME: deprecated in 4.1 | ||
896 | webTorrentEnabled: this.p2pEnabled, | ||
897 | p2pEnabled: this.p2pEnabled, | ||
898 | |||
896 | videosHistoryEnabled: this.videosHistoryEnabled, | 899 | videosHistoryEnabled: this.videosHistoryEnabled, |
897 | autoPlayVideo: this.autoPlayVideo, | 900 | autoPlayVideo: this.autoPlayVideo, |
898 | autoPlayNextVideo: this.autoPlayNextVideo, | 901 | autoPlayNextVideo: this.autoPlayNextVideo, |
diff --git a/server/models/video/formatter/video-format-utils.ts b/server/models/video/formatter/video-format-utils.ts index fd4da68ed..7456f37c5 100644 --- a/server/models/video/formatter/video-format-utils.ts +++ b/server/models/video/formatter/video-format-utils.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { uuidToShort } from '@server/helpers/uuid' | ||
2 | import { generateMagnetUri } from '@server/helpers/webtorrent' | 1 | import { generateMagnetUri } from '@server/helpers/webtorrent' |
3 | import { getLocalVideoFileMetadataUrl } from '@server/lib/video-urls' | 2 | import { getLocalVideoFileMetadataUrl } from '@server/lib/video-urls' |
4 | import { VideoViews } from '@server/lib/video-views' | 3 | import { VideoViews } from '@server/lib/video-views' |
4 | import { uuidToShort } from '@shared/extra-utils' | ||
5 | import { VideoFile, VideosCommonQueryAfterSanitize } from '@shared/models' | 5 | import { VideoFile, VideosCommonQueryAfterSanitize } from '@shared/models' |
6 | import { ActivityTagObject, ActivityUrlObject, VideoObject } from '../../../../shared/models/activitypub/objects' | 6 | import { ActivityTagObject, ActivityUrlObject, VideoObject } from '../../../../shared/models/activitypub/objects' |
7 | import { Video, VideoDetails, VideoInclude } from '../../../../shared/models/videos' | 7 | import { Video, VideoDetails, VideoInclude } from '../../../../shared/models/videos' |
diff --git a/server/models/video/schedule-video-update.ts b/server/models/video/schedule-video-update.ts index d462c20c7..b3cf26966 100644 --- a/server/models/video/schedule-video-update.ts +++ b/server/models/video/schedule-video-update.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Op, Transaction } from 'sequelize' | 1 | import { Op, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MScheduleVideoUpdateFormattable, MScheduleVideoUpdate } from '@server/types/models' | 3 | import { MScheduleVideoUpdateFormattable, MScheduleVideoUpdate } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { VideoPrivacy } from '../../../shared/models/videos' | 5 | import { VideoPrivacy } from '../../../shared/models/videos' |
6 | import { VideoModel } from './video' | 6 | import { VideoModel } from './video' |
7 | 7 | ||
diff --git a/server/models/video/sql/videos-id-list-query-builder.ts b/server/models/video/sql/videos-id-list-query-builder.ts index d825225ab..76aafb883 100644 --- a/server/models/video/sql/videos-id-list-query-builder.ts +++ b/server/models/video/sql/videos-id-list-query-builder.ts | |||
@@ -367,9 +367,10 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery { | |||
367 | ' WHERE "videoShare"."videoId" = "video"."id"' + | 367 | ' WHERE "videoShare"."videoId" = "video"."id"' + |
368 | ' )' + | 368 | ' )' + |
369 | ' OR' + | 369 | ' OR' + |
370 | ' EXISTS (' + // Videos published by accounts we follow | 370 | ' EXISTS (' + // Videos published by channels or accounts we follow |
371 | ' SELECT 1 from "actorFollow" ' + | 371 | ' SELECT 1 from "actorFollow" ' + |
372 | ' WHERE "actorFollow"."targetActorId" = "account"."actorId" AND "actorFollow"."actorId" = :followerActorId ' + | 372 | ' WHERE ("actorFollow"."targetActorId" = "account"."actorId" OR "actorFollow"."targetActorId" = "videoChannel"."actorId") ' + |
373 | ' AND "actorFollow"."actorId" = :followerActorId ' + | ||
373 | ' AND "actorFollow"."state" = \'accepted\'' + | 374 | ' AND "actorFollow"."state" = \'accepted\'' + |
374 | ' )' | 375 | ' )' |
375 | 376 | ||
diff --git a/server/models/video/tag.ts b/server/models/video/tag.ts index 61dfb224d..7900e070d 100644 --- a/server/models/video/tag.ts +++ b/server/models/video/tag.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { col, fn, QueryTypes, Transaction } from 'sequelize' | 1 | import { col, fn, QueryTypes, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MTag } from '@server/types/models' | 3 | import { MTag } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { VideoPrivacy, VideoState } from '../../../shared/models/videos' | 5 | import { VideoPrivacy, VideoState } from '../../../shared/models/videos' |
6 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' | 6 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' |
7 | import { throwIfNotValid } from '../utils' | 7 | import { throwIfNotValid } from '../utils' |
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index 3388478d9..05c58cf19 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts | |||
@@ -17,7 +17,7 @@ import { | |||
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' | 18 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' |
19 | import { MThumbnail, MThumbnailVideo, MVideo } from '@server/types/models' | 19 | import { MThumbnail, MThumbnailVideo, MVideo } from '@server/types/models' |
20 | import { AttributesOnly } from '@shared/core-utils' | 20 | import { AttributesOnly } from '@shared/typescript-utils' |
21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
22 | import { logger } from '../../helpers/logger' | 22 | import { logger } from '../../helpers/logger' |
23 | import { CONFIG } from '../../initializers/config' | 23 | import { CONFIG } from '../../initializers/config' |
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index 98f4ec9c5..1cd8224c0 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { FindOptions } from 'sequelize' | 1 | import { FindOptions } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models' | 3 | import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' | 5 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' |
6 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' | 6 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' |
7 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 7 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index d24be56c3..6b240f116 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -15,9 +15,9 @@ import { | |||
15 | Table, | 15 | Table, |
16 | UpdatedAt | 16 | UpdatedAt |
17 | } from 'sequelize-typescript' | 17 | } from 'sequelize-typescript' |
18 | import { buildUUID } from '@server/helpers/uuid' | ||
19 | import { MVideo, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models' | 18 | import { MVideo, MVideoCaption, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/types/models' |
20 | import { AttributesOnly } from '@shared/core-utils' | 19 | import { buildUUID } from '@shared/extra-utils' |
20 | import { AttributesOnly } from '@shared/typescript-utils' | ||
21 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' | 21 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' |
22 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' | 22 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' |
23 | import { logger } from '../../helpers/logger' | 23 | import { logger } from '../../helpers/logger' |
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index 7d20a954d..1a1b8c88d 100644 --- a/server/models/video/video-change-ownership.ts +++ b/server/models/video/video-change-ownership.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership' | 2 | import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership' |
3 | import { AttributesOnly } from '@shared/core-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' | 4 | import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' |
5 | import { AccountModel } from '../account/account' | 5 | import { AccountModel } from '../account/account' |
6 | import { getSort } from '../utils' | 6 | import { getSort } from '../utils' |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index b652d8531..2c6669bcb 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -17,8 +17,10 @@ import { | |||
17 | Table, | 17 | Table, |
18 | UpdatedAt | 18 | UpdatedAt |
19 | } from 'sequelize-typescript' | 19 | } from 'sequelize-typescript' |
20 | import { CONFIG } from '@server/initializers/config' | ||
20 | import { MAccountActor } from '@server/types/models' | 21 | import { MAccountActor } from '@server/types/models' |
21 | import { AttributesOnly, pick } from '@shared/core-utils' | 22 | import { pick } from '@shared/core-utils' |
23 | import { AttributesOnly } from '@shared/typescript-utils' | ||
22 | import { ActivityPubActor } from '../../../shared/models/activitypub' | 24 | import { ActivityPubActor } from '../../../shared/models/activitypub' |
23 | import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' | 25 | import { VideoChannel, VideoChannelSummary } from '../../../shared/models/videos' |
24 | import { | 26 | import { |
@@ -44,7 +46,6 @@ import { setAsUpdated } from '../shared' | |||
44 | import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' | 46 | import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils' |
45 | import { VideoModel } from './video' | 47 | import { VideoModel } from './video' |
46 | import { VideoPlaylistModel } from './video-playlist' | 48 | import { VideoPlaylistModel } from './video-playlist' |
47 | import { CONFIG } from '@server/initializers/config' | ||
48 | 49 | ||
49 | export enum ScopeNames { | 50 | export enum ScopeNames { |
50 | FOR_API = 'FOR_API', | 51 | FOR_API = 'FOR_API', |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index c89279c65..7f28b86b4 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -16,7 +16,7 @@ import { | |||
16 | } from 'sequelize-typescript' | 16 | } from 'sequelize-typescript' |
17 | import { getServerActor } from '@server/models/application/application' | 17 | import { getServerActor } from '@server/models/application/application' |
18 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' | 18 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' |
19 | import { AttributesOnly } from '@shared/core-utils' | 19 | import { AttributesOnly } from '@shared/typescript-utils' |
20 | import { VideoPrivacy } from '@shared/models' | 20 | import { VideoPrivacy } from '@shared/models' |
21 | import { ActivityTagObject, ActivityTombstoneObject } from '../../../shared/models/activitypub/objects/common-objects' | 21 | import { ActivityTagObject, ActivityTombstoneObject } from '../../../shared/models/activitypub/objects/common-objects' |
22 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' | 22 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' |
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 87311c0ed..6f03fae3a 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts | |||
@@ -26,8 +26,8 @@ import { extractVideo } from '@server/helpers/video' | |||
26 | import { getHLSPublicFileUrl, getWebTorrentPublicFileUrl } from '@server/lib/object-storage' | 26 | import { getHLSPublicFileUrl, getWebTorrentPublicFileUrl } from '@server/lib/object-storage' |
27 | import { getFSTorrentFilePath } from '@server/lib/paths' | 27 | import { getFSTorrentFilePath } from '@server/lib/paths' |
28 | import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoWithHost } from '@server/types/models' | 28 | import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoWithHost } from '@server/types/models' |
29 | import { AttributesOnly } from '@shared/core-utils' | 29 | import { VideoResolution, VideoStorage } from '@shared/models' |
30 | import { VideoStorage } from '@shared/models' | 30 | import { AttributesOnly } from '@shared/typescript-utils' |
31 | import { | 31 | import { |
32 | isVideoFileExtnameValid, | 32 | isVideoFileExtnameValid, |
33 | isVideoFileInfoHashValid, | 33 | isVideoFileInfoHashValid, |
@@ -39,7 +39,6 @@ import { | |||
39 | LAZY_STATIC_PATHS, | 39 | LAZY_STATIC_PATHS, |
40 | MEMOIZE_LENGTH, | 40 | MEMOIZE_LENGTH, |
41 | MEMOIZE_TTL, | 41 | MEMOIZE_TTL, |
42 | MIMETYPES, | ||
43 | STATIC_DOWNLOAD_PATHS, | 42 | STATIC_DOWNLOAD_PATHS, |
44 | STATIC_PATHS, | 43 | STATIC_PATHS, |
45 | WEBSERVER | 44 | WEBSERVER |
@@ -448,7 +447,7 @@ export class VideoFileModel extends Model<Partial<AttributesOnly<VideoFileModel> | |||
448 | } | 447 | } |
449 | 448 | ||
450 | isAudio () { | 449 | isAudio () { |
451 | return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname] | 450 | return this.resolution === VideoResolution.H_NOVIDEO |
452 | } | 451 | } |
453 | 452 | ||
454 | isLive () { | 453 | isLive () { |
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index 5c73fb07c..c5c1a10f4 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -15,8 +15,8 @@ import { | |||
15 | } from 'sequelize-typescript' | 15 | } from 'sequelize-typescript' |
16 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' | 16 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' |
17 | import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import' | 17 | import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import' |
18 | import { AttributesOnly } from '@shared/core-utils' | 18 | import { VideoImport, VideoImportState } from '@shared/models' |
19 | import { VideoImport, VideoImportState } from '../../../shared' | 19 | import { AttributesOnly } from '@shared/typescript-utils' |
20 | import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' | 20 | import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' |
21 | import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' | 21 | import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' |
22 | import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants' | 22 | import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants' |
diff --git a/server/models/video/video-job-info.ts b/server/models/video/video-job-info.ts index 7da5128d7..7497addf1 100644 --- a/server/models/video/video-job-info.ts +++ b/server/models/video/video-job-info.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Op, QueryTypes, Transaction } from 'sequelize' | 1 | import { Op, QueryTypes, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, IsInt, Model, Table, Unique, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, IsInt, Model, Table, Unique, UpdatedAt } from 'sequelize-typescript' |
3 | import { AttributesOnly } from '@shared/core-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { VideoModel } from './video' | 4 | import { VideoModel } from './video' |
5 | 5 | ||
6 | export type VideoJobInfoColumnType = 'pendingMove' | 'pendingTranscode' | 6 | export type VideoJobInfoColumnType = 'pendingMove' | 'pendingTranscode' |
@@ -99,4 +99,19 @@ export class VideoJobInfoModel extends Model<Partial<AttributesOnly<VideoJobInfo | |||
99 | 99 | ||
100 | return pendingMove | 100 | return pendingMove |
101 | } | 101 | } |
102 | |||
103 | static async abortAllTasks (videoUUID: string, column: VideoJobInfoColumnType): Promise<void> { | ||
104 | const options = { type: QueryTypes.UPDATE as QueryTypes.UPDATE, bind: { videoUUID } } | ||
105 | |||
106 | await VideoJobInfoModel.sequelize.query(` | ||
107 | UPDATE | ||
108 | "videoJobInfo" | ||
109 | SET | ||
110 | "${column}" = 0, | ||
111 | "updatedAt" = NOW() | ||
112 | FROM "video" | ||
113 | WHERE | ||
114 | "video"."id" = "videoJobInfo"."videoId" AND "video"."uuid" = $videoUUID | ||
115 | `, options) | ||
116 | } | ||
102 | } | 117 | } |
diff --git a/server/models/video/video-live.ts b/server/models/video/video-live.ts index 0bc8da022..e3fdcc0ba 100644 --- a/server/models/video/video-live.ts +++ b/server/models/video/video-live.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, DefaultScope, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, DefaultScope, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { WEBSERVER } from '@server/initializers/constants' | 2 | import { WEBSERVER } from '@server/initializers/constants' |
3 | import { MVideoLive, MVideoLiveVideo } from '@server/types/models' | 3 | import { MVideoLive, MVideoLiveVideo } from '@server/types/models' |
4 | import { AttributesOnly } from '@shared/core-utils' | 4 | import { AttributesOnly } from '@shared/typescript-utils' |
5 | import { LiveVideo, VideoState } from '@shared/models' | 5 | import { LiveVideo, VideoState } from '@shared/models' |
6 | import { VideoModel } from './video' | 6 | import { VideoModel } from './video' |
7 | import { VideoBlacklistModel } from './video-blacklist' | 7 | import { VideoBlacklistModel } from './video-blacklist' |
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index 82c832188..e20e32f8b 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -32,7 +32,7 @@ import { AccountModel } from '../account/account' | |||
32 | import { getSort, throwIfNotValid } from '../utils' | 32 | import { getSort, throwIfNotValid } from '../utils' |
33 | import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video' | 33 | import { ForAPIOptions, ScopeNames as VideoScopeNames, VideoModel } from './video' |
34 | import { VideoPlaylistModel } from './video-playlist' | 34 | import { VideoPlaylistModel } from './video-playlist' |
35 | import { AttributesOnly } from '@shared/core-utils' | 35 | import { AttributesOnly } from '@shared/typescript-utils' |
36 | 36 | ||
37 | @Table({ | 37 | @Table({ |
38 | tableName: 'videoPlaylistElement', | 38 | tableName: 'videoPlaylistElement', |
@@ -276,7 +276,7 @@ export class VideoPlaylistElementModel extends Model<Partial<AttributesOnly<Vide | |||
276 | } | 276 | } |
277 | 277 | ||
278 | const positionQuery = Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) | 278 | const positionQuery = Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) |
279 | return VideoPlaylistElementModel.update({ position: positionQuery as any }, query) | 279 | return VideoPlaylistElementModel.update({ position: positionQuery }, query) |
280 | } | 280 | } |
281 | 281 | ||
282 | static increasePositionOf ( | 282 | static increasePositionOf ( |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index 630684a88..0d43c795e 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -17,9 +17,10 @@ import { | |||
17 | Table, | 17 | Table, |
18 | UpdatedAt | 18 | UpdatedAt |
19 | } from 'sequelize-typescript' | 19 | } from 'sequelize-typescript' |
20 | import { buildUUID, uuidToShort } from '@server/helpers/uuid' | ||
21 | import { MAccountId, MChannelId } from '@server/types/models' | 20 | import { MAccountId, MChannelId } from '@server/types/models' |
22 | import { AttributesOnly, buildPlaylistEmbedPath, buildPlaylistWatchPath, pick } from '@shared/core-utils' | 21 | import { buildPlaylistEmbedPath, buildPlaylistWatchPath, pick } from '@shared/core-utils' |
22 | import { buildUUID, uuidToShort } from '@shared/extra-utils' | ||
23 | import { AttributesOnly } from '@shared/typescript-utils' | ||
23 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' | 24 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' |
24 | import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' | 25 | import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' |
25 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' | 26 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' |
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts index 505c305e2..f6659b992 100644 --- a/server/models/video/video-share.ts +++ b/server/models/video/video-share.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { literal, Op, QueryTypes, Transaction } from 'sequelize' | 1 | import { literal, Op, QueryTypes, Transaction } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' |
3 | import { AttributesOnly } from '@shared/core-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 4 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 5 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
6 | import { MActorDefault } from '../../types/models' | 6 | import { MActorDefault } from '../../types/models' |
diff --git a/server/models/video/video-streaming-playlist.ts b/server/models/video/video-streaming-playlist.ts index 4643c5452..9957ffee3 100644 --- a/server/models/video/video-streaming-playlist.ts +++ b/server/models/video/video-streaming-playlist.ts | |||
@@ -18,10 +18,10 @@ import { | |||
18 | import { getHLSPublicFileUrl } from '@server/lib/object-storage' | 18 | import { getHLSPublicFileUrl } from '@server/lib/object-storage' |
19 | import { VideoFileModel } from '@server/models/video/video-file' | 19 | import { VideoFileModel } from '@server/models/video/video-file' |
20 | import { MStreamingPlaylist, MVideo } from '@server/types/models' | 20 | import { MStreamingPlaylist, MVideo } from '@server/types/models' |
21 | import { AttributesOnly } from '@shared/core-utils' | 21 | import { sha1 } from '@shared/extra-utils' |
22 | import { VideoStorage } from '@shared/models' | 22 | import { VideoStorage } from '@shared/models' |
23 | import { AttributesOnly } from '@shared/typescript-utils' | ||
23 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 24 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
24 | import { sha1 } from '../../helpers/core-utils' | ||
25 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 25 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
26 | import { isArrayOf } from '../../helpers/custom-validators/misc' | 26 | import { isArrayOf } from '../../helpers/custom-validators/misc' |
27 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 27 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
@@ -198,6 +198,15 @@ export class VideoStreamingPlaylistModel extends Model<Partial<AttributesOnly<Vi | |||
198 | return Object.assign(playlist, { videoId: video.id, Video: video }) | 198 | return Object.assign(playlist, { videoId: video.id, Video: video }) |
199 | } | 199 | } |
200 | 200 | ||
201 | static doesOwnedHLSPlaylistExist (videoUUID: string) { | ||
202 | const query = `SELECT 1 FROM "videoStreamingPlaylist" ` + | ||
203 | `INNER JOIN "video" ON "video"."id" = "videoStreamingPlaylist"."videoId" ` + | ||
204 | `AND "video"."remote" IS FALSE AND "video"."uuid" = $videoUUID ` + | ||
205 | `AND "storage" = ${VideoStorage.FILE_SYSTEM} LIMIT 1` | ||
206 | |||
207 | return doesExist(query, { videoUUID }) | ||
208 | } | ||
209 | |||
201 | assignP2PMediaLoaderInfoHashes (video: MVideo, files: unknown[]) { | 210 | assignP2PMediaLoaderInfoHashes (video: MVideo, files: unknown[]) { |
202 | const masterPlaylistUrl = this.getMasterPlaylistUrl(video) | 211 | const masterPlaylistUrl = this.getMasterPlaylistUrl(video) |
203 | 212 | ||
diff --git a/server/models/video/video-tag.ts b/server/models/video/video-tag.ts index 1285d375b..7e880c968 100644 --- a/server/models/video/video-tag.ts +++ b/server/models/video/video-tag.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { Column, CreatedAt, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { AttributesOnly } from '@shared/core-utils' | 2 | import { AttributesOnly } from '@shared/typescript-utils' |
3 | import { TagModel } from './tag' | 3 | import { TagModel } from './tag' |
4 | import { VideoModel } from './video' | 4 | import { VideoModel } from './video' |
5 | 5 | ||
diff --git a/server/models/video/video-view.ts b/server/models/video/video-view.ts index b51f0f84d..d72df100f 100644 --- a/server/models/video/video-view.ts +++ b/server/models/video/video-view.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { literal, Op } from 'sequelize' | 1 | import { literal, Op } from 'sequelize' |
2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table } from 'sequelize-typescript' | 2 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table } from 'sequelize-typescript' |
3 | import { AttributesOnly } from '@shared/core-utils' | 3 | import { AttributesOnly } from '@shared/typescript-utils' |
4 | import { VideoModel } from './video' | 4 | import { VideoModel } from './video' |
5 | 5 | ||
6 | @Table({ | 6 | @Table({ |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 1050463d2..12b937574 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -25,7 +25,6 @@ import { | |||
25 | UpdatedAt | 25 | UpdatedAt |
26 | } from 'sequelize-typescript' | 26 | } from 'sequelize-typescript' |
27 | import { buildNSFWFilter } from '@server/helpers/express-utils' | 27 | import { buildNSFWFilter } from '@server/helpers/express-utils' |
28 | import { uuidToShort } from '@server/helpers/uuid' | ||
29 | import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' | 28 | import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video' |
30 | import { LiveManager } from '@server/lib/live/live-manager' | 29 | import { LiveManager } from '@server/lib/live/live-manager' |
31 | import { removeHLSObjectStorage, removeWebTorrentObjectStorage } from '@server/lib/object-storage' | 30 | import { removeHLSObjectStorage, removeWebTorrentObjectStorage } from '@server/lib/object-storage' |
@@ -33,13 +32,24 @@ import { getHLSDirectory, getHLSRedundancyDirectory } from '@server/lib/paths' | |||
33 | import { VideoPathManager } from '@server/lib/video-path-manager' | 32 | import { VideoPathManager } from '@server/lib/video-path-manager' |
34 | import { getServerActor } from '@server/models/application/application' | 33 | import { getServerActor } from '@server/models/application/application' |
35 | import { ModelCache } from '@server/models/model-cache' | 34 | import { ModelCache } from '@server/models/model-cache' |
36 | import { AttributesOnly, buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' | 35 | import { buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils' |
37 | import { VideoFile, VideoInclude } from '@shared/models' | 36 | import { ffprobePromise, getAudioStream, uuidToShort } from '@shared/extra-utils' |
38 | import { ResultList, UserRight, VideoPrivacy, VideoState } from '../../../shared' | 37 | import { |
39 | import { VideoObject } from '../../../shared/models/activitypub/objects' | 38 | ResultList, |
40 | import { Video, VideoDetails, VideoRateType, VideoStorage } from '../../../shared/models/videos' | 39 | ThumbnailType, |
41 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 40 | UserRight, |
42 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 41 | Video, |
42 | VideoDetails, | ||
43 | VideoFile, | ||
44 | VideoInclude, | ||
45 | VideoObject, | ||
46 | VideoPrivacy, | ||
47 | VideoRateType, | ||
48 | VideoState, | ||
49 | VideoStorage, | ||
50 | VideoStreamingPlaylistType | ||
51 | } from '@shared/models' | ||
52 | import { AttributesOnly } from '@shared/typescript-utils' | ||
43 | import { peertubeTruncate } from '../../helpers/core-utils' | 53 | import { peertubeTruncate } from '../../helpers/core-utils' |
44 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 54 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
45 | import { exists, isBooleanValid } from '../../helpers/custom-validators/misc' | 55 | import { exists, isBooleanValid } from '../../helpers/custom-validators/misc' |
@@ -1668,12 +1678,20 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> { | |||
1668 | return peertubeTruncate(this.description, { length: maxLength }) | 1678 | return peertubeTruncate(this.description, { length: maxLength }) |
1669 | } | 1679 | } |
1670 | 1680 | ||
1671 | getMaxQualityResolution () { | 1681 | getMaxQualityFileInfo () { |
1672 | const file = this.getMaxQualityFile() | 1682 | const file = this.getMaxQualityFile() |
1673 | const videoOrPlaylist = file.getVideoOrStreamingPlaylist() | 1683 | const videoOrPlaylist = file.getVideoOrStreamingPlaylist() |
1674 | 1684 | ||
1675 | return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), originalFilePath => { | 1685 | return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), async originalFilePath => { |
1676 | return getVideoFileResolution(originalFilePath) | 1686 | const probe = await ffprobePromise(originalFilePath) |
1687 | |||
1688 | const { audioStream } = await getAudioStream(originalFilePath, probe) | ||
1689 | |||
1690 | return { | ||
1691 | audioStream, | ||
1692 | |||
1693 | ...await getVideoFileResolution(originalFilePath, probe) | ||
1694 | } | ||
1677 | }) | 1695 | }) |
1678 | } | 1696 | } |
1679 | 1697 | ||
diff --git a/server/tests/api/activitypub/cleaner.ts b/server/tests/api/activitypub/cleaner.ts index 51cf6e599..d0a151f5c 100644 --- a/server/tests/api/activitypub/cleaner.ts +++ b/server/tests/api/activitypub/cleaner.ts | |||
@@ -2,15 +2,15 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | 7 | cleanupTests, |
7 | createMultipleServers, | 8 | createMultipleServers, |
8 | doubleFollow, | 9 | doubleFollow, |
9 | PeerTubeServer, | 10 | PeerTubeServer, |
10 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
11 | wait, | ||
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
16 | 16 | ||
@@ -270,6 +270,66 @@ describe('Test AP cleaner', function () { | |||
270 | await checkRemote('kyle') | 270 | await checkRemote('kyle') |
271 | }) | 271 | }) |
272 | 272 | ||
273 | it('Should remove unavailable remote resources', async function () { | ||
274 | this.timeout(240000) | ||
275 | |||
276 | async function expectNotDeleted () { | ||
277 | { | ||
278 | const video = await servers[0].videos.get({ id: uuid }) | ||
279 | |||
280 | expect(video.likes).to.equal(3) | ||
281 | expect(video.dislikes).to.equal(0) | ||
282 | } | ||
283 | |||
284 | { | ||
285 | const { total } = await servers[0].comments.listThreads({ videoId: uuid }) | ||
286 | expect(total).to.equal(3) | ||
287 | } | ||
288 | } | ||
289 | |||
290 | async function expectDeleted () { | ||
291 | { | ||
292 | const video = await servers[0].videos.get({ id: uuid }) | ||
293 | |||
294 | expect(video.likes).to.equal(2) | ||
295 | expect(video.dislikes).to.equal(0) | ||
296 | } | ||
297 | |||
298 | { | ||
299 | const { total } = await servers[0].comments.listThreads({ videoId: uuid }) | ||
300 | expect(total).to.equal(2) | ||
301 | } | ||
302 | } | ||
303 | |||
304 | const uuid = (await servers[0].videos.quickUpload({ name: 'server 1 video 2' })).uuid | ||
305 | |||
306 | await waitJobs(servers) | ||
307 | |||
308 | for (const server of servers) { | ||
309 | await server.videos.rate({ id: uuid, rating: 'like' }) | ||
310 | await server.comments.createThread({ videoId: uuid, text: 'comment' }) | ||
311 | } | ||
312 | |||
313 | await waitJobs(servers) | ||
314 | |||
315 | await expectNotDeleted() | ||
316 | |||
317 | await servers[1].kill() | ||
318 | |||
319 | await wait(5000) | ||
320 | await expectNotDeleted() | ||
321 | |||
322 | let continueWhile = true | ||
323 | |||
324 | do { | ||
325 | try { | ||
326 | await expectDeleted() | ||
327 | continueWhile = false | ||
328 | } catch { | ||
329 | } | ||
330 | } while (continueWhile) | ||
331 | }) | ||
332 | |||
273 | after(async function () { | 333 | after(async function () { |
274 | await cleanupTests(servers) | 334 | await cleanupTests(servers) |
275 | }) | 335 | }) |
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts index c3e4b7f74..e69ab3cb9 100644 --- a/server/tests/api/activitypub/client.ts +++ b/server/tests/api/activitypub/client.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | setDefaultVideoChannel | 12 | setDefaultVideoChannel |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | 14 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' |
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts index 422a75d6e..cc71e82ea 100644 --- a/server/tests/api/activitypub/fetch.ts +++ b/server/tests/api/activitypub/fetch.ts | |||
@@ -2,7 +2,14 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { |
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | const expect = chai.expect | 14 | const expect = chai.expect |
8 | 15 | ||
diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts index 57b1cab23..25e1d9823 100644 --- a/server/tests/api/activitypub/helpers.ts +++ b/server/tests/api/activitypub/helpers.ts | |||
@@ -3,7 +3,8 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { cloneDeep } from 'lodash' | 5 | import { cloneDeep } from 'lodash' |
6 | import { buildAbsoluteFixturePath, buildRequestStub } from '@shared/extra-utils' | 6 | import { buildRequestStub } from '@server/tests/shared' |
7 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
7 | import { buildSignedActivity } from '../../../helpers/activitypub' | 8 | import { buildSignedActivity } from '../../../helpers/activitypub' |
8 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' | 9 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' |
9 | 10 | ||
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts index 81fee0044..71e1c40ba 100644 --- a/server/tests/api/activitypub/refresher.ts +++ b/server/tests/api/activitypub/refresher.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { wait } from '@shared/core-utils' | ||
5 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | cleanupTests, | 7 | cleanupTests, |
6 | createMultipleServers, | 8 | createMultipleServers, |
@@ -9,10 +11,8 @@ import { | |||
9 | PeerTubeServer, | 11 | PeerTubeServer, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
12 | wait, | ||
13 | waitJobs | 14 | waitJobs |
14 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | ||
16 | 16 | ||
17 | describe('Test AP refresher', function () { | 17 | describe('Test AP refresher', function () { |
18 | let servers: PeerTubeServer[] = [] | 18 | let servers: PeerTubeServer[] = [] |
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index 94d946563..c4cb5ea0d 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts | |||
@@ -6,9 +6,10 @@ import { activityPubContextify, buildSignedActivity } from '@server/helpers/acti | |||
6 | import { buildDigest } from '@server/helpers/peertube-crypto' | 6 | import { buildDigest } from '@server/helpers/peertube-crypto' |
7 | import { HTTP_SIGNATURE } from '@server/initializers/constants' | 7 | import { HTTP_SIGNATURE } from '@server/initializers/constants' |
8 | import { buildGlobalHeaders } from '@server/lib/job-queue/handlers/utils/activitypub-http-utils' | 8 | import { buildGlobalHeaders } from '@server/lib/job-queue/handlers/utils/activitypub-http-utils' |
9 | import { buildAbsoluteFixturePath, cleanupTests, createMultipleServers, killallServers, PeerTubeServer, wait } from '@shared/extra-utils' | 9 | import { makeFollowRequest, makePOSTAPRequest } from '@server/tests/shared' |
10 | import { makeFollowRequest, makePOSTAPRequest } from '@shared/extra-utils/requests/activitypub' | 10 | import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' |
11 | import { HttpStatusCode } from '@shared/models' | 11 | import { HttpStatusCode } from '@shared/models' |
12 | import { cleanupTests, createMultipleServers, killallServers, PeerTubeServer } from '@shared/server-commands' | ||
12 | 13 | ||
13 | const expect = chai.expect | 14 | const expect = chai.expect |
14 | 15 | ||
diff --git a/server/tests/api/check-params/abuses.ts b/server/tests/api/check-params/abuses.ts index fb9a5fd8b..c4b051723 100644 --- a/server/tests/api/check-params/abuses.ts +++ b/server/tests/api/check-params/abuses.ts | |||
@@ -1,11 +1,10 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { AbuseCreate, AbuseState, HttpStatusCode } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | AbusesCommand, | 7 | AbusesCommand, |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
9 | cleanupTests, | 8 | cleanupTests, |
10 | createSingleServer, | 9 | createSingleServer, |
11 | doubleFollow, | 10 | doubleFollow, |
@@ -14,8 +13,7 @@ import { | |||
14 | PeerTubeServer, | 13 | PeerTubeServer, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
16 | waitJobs | 15 | waitJobs |
17 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
18 | import { AbuseCreate, AbuseState, HttpStatusCode } from '@shared/models' | ||
19 | 17 | ||
20 | describe('Test abuses API validators', function () { | 18 | describe('Test abuses API validators', function () { |
21 | const basePath = '/api/v1/abuses/' | 19 | const basePath = '/api/v1/abuses/' |
diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts index 141d869b7..07f879e0e 100644 --- a/server/tests/api/check-params/accounts.ts +++ b/server/tests/api/check-params/accounts.ts | |||
@@ -1,15 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | ||
9 | createSingleServer, | ||
10 | PeerTubeServer | ||
11 | } from '@shared/extra-utils' | ||
12 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' | ||
13 | 7 | ||
14 | describe('Test accounts API validators', function () { | 8 | describe('Test accounts API validators', function () { |
15 | const path = '/api/v1/accounts/' | 9 | const path = '/api/v1/accounts/' |
diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts index 7d5fae5cf..36526d494 100644 --- a/server/tests/api/check-params/blocklist.ts +++ b/server/tests/api/check-params/blocklist.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { HttpStatusCode } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | 7 | cleanupTests, |
9 | createMultipleServers, | 8 | createMultipleServers, |
10 | doubleFollow, | 9 | doubleFollow, |
@@ -13,8 +12,7 @@ import { | |||
13 | makePostBodyRequest, | 12 | makePostBodyRequest, |
14 | PeerTubeServer, | 13 | PeerTubeServer, |
15 | setAccessTokensToServers | 14 | setAccessTokensToServers |
16 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
17 | import { HttpStatusCode } from '@shared/models' | ||
18 | 16 | ||
19 | describe('Test blocklist API validators', function () { | 17 | describe('Test blocklist API validators', function () { |
20 | let servers: PeerTubeServer[] | 18 | let servers: PeerTubeServer[] |
@@ -481,6 +479,78 @@ describe('Test blocklist API validators', function () { | |||
481 | }) | 479 | }) |
482 | }) | 480 | }) |
483 | 481 | ||
482 | describe('When getting blocklist status', function () { | ||
483 | const path = '/api/v1/blocklist/status' | ||
484 | |||
485 | it('Should fail with a bad token', async function () { | ||
486 | await makeGetRequest({ | ||
487 | url: server.url, | ||
488 | path, | ||
489 | token: 'false', | ||
490 | expectedStatus: HttpStatusCode.UNAUTHORIZED_401 | ||
491 | }) | ||
492 | }) | ||
493 | |||
494 | it('Should fail with a bad accounts field', async function () { | ||
495 | await makeGetRequest({ | ||
496 | url: server.url, | ||
497 | path, | ||
498 | query: { | ||
499 | accounts: 1 | ||
500 | }, | ||
501 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
502 | }) | ||
503 | |||
504 | await makeGetRequest({ | ||
505 | url: server.url, | ||
506 | path, | ||
507 | query: { | ||
508 | accounts: [ 1 ] | ||
509 | }, | ||
510 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
511 | }) | ||
512 | }) | ||
513 | |||
514 | it('Should fail with a bad hosts field', async function () { | ||
515 | await makeGetRequest({ | ||
516 | url: server.url, | ||
517 | path, | ||
518 | query: { | ||
519 | hosts: 1 | ||
520 | }, | ||
521 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
522 | }) | ||
523 | |||
524 | await makeGetRequest({ | ||
525 | url: server.url, | ||
526 | path, | ||
527 | query: { | ||
528 | hosts: [ 1 ] | ||
529 | }, | ||
530 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
531 | }) | ||
532 | }) | ||
533 | |||
534 | it('Should succeed with the correct parameters', async function () { | ||
535 | await makeGetRequest({ | ||
536 | url: server.url, | ||
537 | path, | ||
538 | query: {}, | ||
539 | expectedStatus: HttpStatusCode.OK_200 | ||
540 | }) | ||
541 | |||
542 | await makeGetRequest({ | ||
543 | url: server.url, | ||
544 | path, | ||
545 | query: { | ||
546 | hosts: [ 'example.com' ], | ||
547 | accounts: [ 'john@example.com' ] | ||
548 | }, | ||
549 | expectedStatus: HttpStatusCode.OK_200 | ||
550 | }) | ||
551 | }) | ||
552 | }) | ||
553 | |||
484 | after(async function () { | 554 | after(async function () { |
485 | await cleanupTests(servers) | 555 | await cleanupTests(servers) |
486 | }) | 556 | }) |
diff --git a/server/tests/api/check-params/bulk.ts b/server/tests/api/check-params/bulk.ts index bc9d7784d..9bd0016cf 100644 --- a/server/tests/api/check-params/bulk.ts +++ b/server/tests/api/check-params/bulk.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 4 | import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
5 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | 6 | ||
7 | describe('Test bulk API validators', function () { | 7 | describe('Test bulk API validators', function () { |
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index d0cd7722b..3cccb612a 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | makePutBodyRequest, | 10 | makePutBodyRequest, |
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | setAccessTokensToServers | 12 | setAccessTokensToServers |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { CustomConfig, HttpStatusCode } from '@shared/models' | 14 | import { CustomConfig, HttpStatusCode } from '@shared/models' |
15 | 15 | ||
16 | describe('Test config API validators', function () { | 16 | describe('Test config API validators', function () { |
@@ -54,6 +54,18 @@ describe('Test config API validators', function () { | |||
54 | whitelisted: true | 54 | whitelisted: true |
55 | } | 55 | } |
56 | }, | 56 | }, |
57 | client: { | ||
58 | videos: { | ||
59 | miniature: { | ||
60 | preferAuthorDisplayName: false | ||
61 | } | ||
62 | }, | ||
63 | menu: { | ||
64 | login: { | ||
65 | redirectOnSingleExternalAuth: false | ||
66 | } | ||
67 | } | ||
68 | }, | ||
57 | cache: { | 69 | cache: { |
58 | previews: { | 70 | previews: { |
59 | size: 2 | 71 | size: 2 |
diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts index 9f86fecc6..9db442b0b 100644 --- a/server/tests/api/check-params/contact-form.ts +++ b/server/tests/api/check-params/contact-form.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createSingleServer, killallServers, MockSmtpServer, PeerTubeServer } from '@shared/extra-utils' | 4 | import { MockSmtpServer } from '@server/tests/shared' |
5 | import { ContactFormCommand } from '@shared/extra-utils/server' | ||
6 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | import { cleanupTests, ContactFormCommand, createSingleServer, killallServers, PeerTubeServer } from '@shared/server-commands' | ||
7 | 7 | ||
8 | describe('Test contact form API validators', function () { | 8 | describe('Test contact form API validators', function () { |
9 | let server: PeerTubeServer | 9 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/custom-pages.ts b/server/tests/api/check-params/custom-pages.ts index 9fbbea315..a102ee437 100644 --- a/server/tests/api/check-params/custom-pages.ts +++ b/server/tests/api/check-params/custom-pages.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | makePutBodyRequest, | 8 | makePutBodyRequest, |
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | setAccessTokensToServers | 10 | setAccessTokensToServers |
11 | } from '@shared/extra-utils' | 11 | } from '@shared/server-commands' |
12 | import { HttpStatusCode } from '@shared/models' | 12 | import { HttpStatusCode } from '@shared/models' |
13 | 13 | ||
14 | describe('Test custom pages validators', function () { | 14 | describe('Test custom pages validators', function () { |
diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts index a55786359..cfa44deca 100644 --- a/server/tests/api/check-params/debug.ts +++ b/server/tests/api/check-params/debug.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 4 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
5 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | 6 | ||
7 | describe('Test debug API validators', function () { | 7 | describe('Test debug API validators', function () { |
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts index 2bc9f6b96..d4dae5a75 100644 --- a/server/tests/api/check-params/follows.ts +++ b/server/tests/api/check-params/follows.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { HttpStatusCode } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | 7 | cleanupTests, |
9 | createSingleServer, | 8 | createSingleServer, |
10 | makeDeleteRequest, | 9 | makeDeleteRequest, |
@@ -12,8 +11,7 @@ import { | |||
12 | makePostBodyRequest, | 11 | makePostBodyRequest, |
13 | PeerTubeServer, | 12 | PeerTubeServer, |
14 | setAccessTokensToServers | 13 | setAccessTokensToServers |
15 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
16 | import { HttpStatusCode } from '@shared/models' | ||
17 | 15 | ||
18 | describe('Test server follows API validators', function () { | 16 | describe('Test server follows API validators', function () { |
19 | let server: PeerTubeServer | 17 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts index 23d95d8e4..d85961d62 100644 --- a/server/tests/api/check-params/jobs.ts +++ b/server/tests/api/check-params/jobs.ts | |||
@@ -1,17 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | ||
9 | createSingleServer, | ||
10 | makeGetRequest, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers | ||
13 | } from '@shared/extra-utils' | ||
14 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
15 | 7 | ||
16 | describe('Test jobs API validators', function () { | 8 | describe('Test jobs API validators', function () { |
17 | const path = '/api/v1/jobs/failed' | 9 | const path = '/api/v1/jobs/failed' |
diff --git a/server/tests/api/check-params/live.ts b/server/tests/api/check-params/live.ts index 8e1d655d4..8aee6164c 100644 --- a/server/tests/api/check-params/live.ts +++ b/server/tests/api/check-params/live.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
5 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
6 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | buildAbsoluteFixturePath, | ||
7 | cleanupTests, | 8 | cleanupTests, |
8 | createSingleServer, | 9 | createSingleServer, |
9 | LiveCommand, | 10 | LiveCommand, |
@@ -13,8 +14,7 @@ import { | |||
13 | sendRTMPStream, | 14 | sendRTMPStream, |
14 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
15 | stopFfmpeg | 16 | stopFfmpeg |
16 | } from '@shared/extra-utils' | 17 | } from '@shared/server-commands' |
17 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
18 | 18 | ||
19 | describe('Test video lives API validator', function () { | 19 | describe('Test video lives API validator', function () { |
20 | const path = '/api/v1/videos/live' | 20 | const path = '/api/v1/videos/live' |
diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts index 05372257a..970671c15 100644 --- a/server/tests/api/check-params/logs.ts +++ b/server/tests/api/check-params/logs.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 4 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
5 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | 6 | ||
7 | describe('Test logs API validators', function () { | 7 | describe('Test logs API validators', function () { |
diff --git a/server/tests/api/check-params/my-user.ts b/server/tests/api/check-params/my-user.ts index d35284d60..95f2122ae 100644 --- a/server/tests/api/check-params/my-user.ts +++ b/server/tests/api/check-params/my-user.ts | |||
@@ -1,22 +1,19 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared' | ||
5 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
6 | import { HttpStatusCode, UserRole, VideoCreateResult } from '@shared/models' | ||
4 | import { | 7 | import { |
5 | buildAbsoluteFixturePath, | ||
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
9 | cleanupTests, | 8 | cleanupTests, |
10 | createSingleServer, | 9 | createSingleServer, |
11 | makeGetRequest, | 10 | makeGetRequest, |
12 | makePutBodyRequest, | 11 | makePutBodyRequest, |
13 | makeUploadRequest, | 12 | makeUploadRequest, |
14 | MockSmtpServer, | ||
15 | PeerTubeServer, | 13 | PeerTubeServer, |
16 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
17 | UsersCommand | 15 | UsersCommand |
18 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
19 | import { HttpStatusCode, UserRole, VideoCreateResult } from '@shared/models' | ||
20 | 17 | ||
21 | describe('Test my user API validators', function () { | 18 | describe('Test my user API validators', function () { |
22 | const path = '/api/v1/users/' | 19 | const path = '/api/v1/users/' |
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts index 33f84ecbc..c3f15b86e 100644 --- a/server/tests/api/check-params/plugins.ts +++ b/server/tests/api/check-params/plugins.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { HttpStatusCode, PeerTubePlugin, PluginType } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | 7 | cleanupTests, |
9 | createSingleServer, | 8 | createSingleServer, |
10 | makeGetRequest, | 9 | makeGetRequest, |
@@ -12,8 +11,7 @@ import { | |||
12 | makePutBodyRequest, | 11 | makePutBodyRequest, |
13 | PeerTubeServer, | 12 | PeerTubeServer, |
14 | setAccessTokensToServers | 13 | setAccessTokensToServers |
15 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, PeerTubePlugin, PluginType } from '@shared/models' | ||
17 | 15 | ||
18 | describe('Test server plugins API validators', function () { | 16 | describe('Test server plugins API validators', function () { |
19 | let server: PeerTubeServer | 17 | let server: PeerTubeServer |
@@ -30,7 +28,7 @@ describe('Test server plugins API validators', function () { | |||
30 | // --------------------------------------------------------------- | 28 | // --------------------------------------------------------------- |
31 | 29 | ||
32 | before(async function () { | 30 | before(async function () { |
33 | this.timeout(30000) | 31 | this.timeout(60000) |
34 | 32 | ||
35 | server = await createSingleServer(1) | 33 | server = await createSingleServer(1) |
36 | 34 | ||
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts index d9f905549..04519cf23 100644 --- a/server/tests/api/check-params/redundancy.ts +++ b/server/tests/api/check-params/redundancy.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { HttpStatusCode, VideoCreateResult } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | 7 | cleanupTests, |
9 | createMultipleServers, | 8 | createMultipleServers, |
10 | doubleFollow, | 9 | doubleFollow, |
@@ -15,8 +14,7 @@ import { | |||
15 | PeerTubeServer, | 14 | PeerTubeServer, |
16 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
17 | waitJobs | 16 | waitJobs |
18 | } from '@shared/extra-utils' | 17 | } from '@shared/server-commands' |
19 | import { HttpStatusCode, VideoCreateResult } from '@shared/models' | ||
20 | 18 | ||
21 | describe('Test server redundancy API validators', function () { | 19 | describe('Test server redundancy API validators', function () { |
22 | let servers: PeerTubeServer[] | 20 | let servers: PeerTubeServer[] |
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts index cc15d2593..ca0fbf31d 100644 --- a/server/tests/api/check-params/search.ts +++ b/server/tests/api/check-params/search.ts | |||
@@ -1,17 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | ||
9 | createSingleServer, | ||
10 | makeGetRequest, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers | ||
13 | } from '@shared/extra-utils' | ||
14 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
15 | 7 | ||
16 | function updateSearchIndex (server: PeerTubeServer, enabled: boolean, disableLocalSearch = false) { | 8 | function updateSearchIndex (server: PeerTubeServer, enabled: boolean, disableLocalSearch = false) { |
17 | return server.config.updateCustomSubConfig({ | 9 | return server.config.updateCustomSubConfig({ |
diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts index 8d795fabc..e63f09884 100644 --- a/server/tests/api/check-params/services.ts +++ b/server/tests/api/check-params/services.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | PeerTubeServer, | 8 | PeerTubeServer, |
9 | setAccessTokensToServers, | 9 | setAccessTokensToServers, |
10 | setDefaultVideoChannel | 10 | setDefaultVideoChannel |
11 | } from '@shared/extra-utils' | 11 | } from '@shared/server-commands' |
12 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | 12 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' |
13 | 13 | ||
14 | describe('Test services API validators', function () { | 14 | describe('Test services API validators', function () { |
diff --git a/server/tests/api/check-params/transcoding.ts b/server/tests/api/check-params/transcoding.ts index a8daafe3e..333012940 100644 --- a/server/tests/api/check-params/transcoding.ts +++ b/server/tests/api/check-params/transcoding.ts | |||
@@ -1,8 +1,15 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | ||
5 | import { HttpStatusCode, UserRole } from '@shared/models' | 4 | import { HttpStatusCode, UserRole } from '@shared/models' |
5 | import { | ||
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | describe('Test transcoding API validators', function () { | 14 | describe('Test transcoding API validators', function () { |
8 | let servers: PeerTubeServer[] | 15 | let servers: PeerTubeServer[] |
@@ -16,7 +23,7 @@ describe('Test transcoding API validators', function () { | |||
16 | // --------------------------------------------------------------- | 23 | // --------------------------------------------------------------- |
17 | 24 | ||
18 | before(async function () { | 25 | before(async function () { |
19 | this.timeout(60000) | 26 | this.timeout(120000) |
20 | 27 | ||
21 | servers = await createMultipleServers(2) | 28 | servers = await createMultipleServers(2) |
22 | await setAccessTokensToServers(servers) | 29 | await setAccessTokensToServers(servers) |
diff --git a/server/tests/api/check-params/upload-quota.ts b/server/tests/api/check-params/upload-quota.ts index 322e93d0d..deb4a7aa3 100644 --- a/server/tests/api/check-params/upload-quota.ts +++ b/server/tests/api/check-params/upload-quota.ts | |||
@@ -2,18 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { FIXTURE_URLS } from '@server/tests/shared' | ||
5 | import { randomInt } from '@shared/core-utils' | 6 | import { randomInt } from '@shared/core-utils' |
7 | import { HttpStatusCode, VideoImportState, VideoPrivacy } from '@shared/models' | ||
6 | import { | 8 | import { |
7 | cleanupTests, | 9 | cleanupTests, |
8 | createSingleServer, | 10 | createSingleServer, |
9 | FIXTURE_URLS, | ||
10 | PeerTubeServer, | 11 | PeerTubeServer, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
13 | VideosCommand, | 14 | VideosCommand, |
14 | waitJobs | 15 | waitJobs |
15 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, VideoImportState, VideoPrivacy } from '@shared/models' | ||
17 | 17 | ||
18 | describe('Test upload quota', function () { | 18 | describe('Test upload quota', function () { |
19 | let server: PeerTubeServer | 19 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts index 17edf5aa1..4bc8084a1 100644 --- a/server/tests/api/check-params/user-notifications.ts +++ b/server/tests/api/check-params/user-notifications.ts | |||
@@ -2,20 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { io } from 'socket.io-client' | 4 | import { io } from 'socket.io-client' |
5 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
6 | import { wait } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, UserNotificationSetting, UserNotificationSettingValue } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
9 | cleanupTests, | 9 | cleanupTests, |
10 | createSingleServer, | 10 | createSingleServer, |
11 | makeGetRequest, | 11 | makeGetRequest, |
12 | makePostBodyRequest, | 12 | makePostBodyRequest, |
13 | makePutBodyRequest, | 13 | makePutBodyRequest, |
14 | PeerTubeServer, | 14 | PeerTubeServer, |
15 | setAccessTokensToServers, | 15 | setAccessTokensToServers |
16 | wait | 16 | } from '@shared/server-commands' |
17 | } from '@shared/extra-utils' | ||
18 | import { HttpStatusCode, UserNotificationSetting, UserNotificationSettingValue } from '@shared/models' | ||
19 | 17 | ||
20 | describe('Test user notifications API validators', function () { | 18 | describe('Test user notifications API validators', function () { |
21 | let server: PeerTubeServer | 19 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts index 624069c80..a13ed5aa3 100644 --- a/server/tests/api/check-params/user-subscriptions.ts +++ b/server/tests/api/check-params/user-subscriptions.ts | |||
@@ -2,9 +2,6 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | 5 | cleanupTests, |
9 | createSingleServer, | 6 | createSingleServer, |
10 | makeDeleteRequest, | 7 | makeDeleteRequest, |
@@ -13,8 +10,9 @@ import { | |||
13 | PeerTubeServer, | 10 | PeerTubeServer, |
14 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
15 | waitJobs | 12 | waitJobs |
16 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
17 | import { HttpStatusCode } from '@shared/models' | 14 | import { HttpStatusCode } from '@shared/models' |
15 | import { checkBadStartPagination, checkBadCountPagination, checkBadSortPagination } from '@server/tests/shared' | ||
18 | 16 | ||
19 | describe('Test user subscriptions API validators', function () { | 17 | describe('Test user subscriptions API validators', function () { |
20 | const path = '/api/v1/users/me/subscriptions' | 18 | const path = '/api/v1/users/me/subscriptions' |
diff --git a/server/tests/api/check-params/users-admin.ts b/server/tests/api/check-params/users-admin.ts index f71414a6b..d8353f83b 100644 --- a/server/tests/api/check-params/users-admin.ts +++ b/server/tests/api/check-params/users-admin.ts | |||
@@ -2,21 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
5 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, MockSmtpServer } from '@server/tests/shared' | ||
6 | import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
9 | cleanupTests, | 8 | cleanupTests, |
10 | createSingleServer, | 9 | createSingleServer, |
11 | killallServers, | 10 | killallServers, |
12 | makeGetRequest, | 11 | makeGetRequest, |
13 | makePostBodyRequest, | 12 | makePostBodyRequest, |
14 | makePutBodyRequest, | 13 | makePutBodyRequest, |
15 | MockSmtpServer, | ||
16 | PeerTubeServer, | 14 | PeerTubeServer, |
17 | setAccessTokensToServers | 15 | setAccessTokensToServers |
18 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
19 | import { HttpStatusCode, UserAdminFlag, UserRole } from '@shared/models' | ||
20 | 17 | ||
21 | describe('Test users admin API validators', function () { | 18 | describe('Test users admin API validators', function () { |
22 | const path = '/api/v1/users/' | 19 | const path = '/api/v1/users/' |
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 5f9cbc5eb..84254945c 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -2,15 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
5 | import { | 5 | import { MockSmtpServer } from '@server/tests/shared' |
6 | cleanupTests, | ||
7 | createSingleServer, | ||
8 | makePostBodyRequest, | ||
9 | MockSmtpServer, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers | ||
12 | } from '@shared/extra-utils' | ||
13 | import { HttpStatusCode, UserRole } from '@shared/models' | 6 | import { HttpStatusCode, UserRole } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, makePostBodyRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
14 | 8 | ||
15 | describe('Test users API validators', function () { | 9 | describe('Test users API validators', function () { |
16 | const path = '/api/v1/users/' | 10 | const path = '/api/v1/users/' |
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts index 1f926d227..1aab60826 100644 --- a/server/tests/api/check-params/video-blacklist.ts +++ b/server/tests/api/check-params/video-blacklist.ts | |||
@@ -2,11 +2,10 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
6 | import { HttpStatusCode, VideoBlacklistType } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | BlacklistCommand, | 8 | BlacklistCommand, |
7 | checkBadCountPagination, | ||
8 | checkBadSortPagination, | ||
9 | checkBadStartPagination, | ||
10 | cleanupTests, | 9 | cleanupTests, |
11 | createMultipleServers, | 10 | createMultipleServers, |
12 | doubleFollow, | 11 | doubleFollow, |
@@ -15,8 +14,7 @@ import { | |||
15 | PeerTubeServer, | 14 | PeerTubeServer, |
16 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
17 | waitJobs | 16 | waitJobs |
18 | } from '@shared/extra-utils' | 17 | } from '@shared/server-commands' |
19 | import { HttpStatusCode, VideoBlacklistType } from '@shared/models' | ||
20 | 18 | ||
21 | describe('Test video blacklist API validators', function () { | 19 | describe('Test video blacklist API validators', function () { |
22 | let servers: PeerTubeServer[] | 20 | let servers: PeerTubeServer[] |
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts index 84c6c1355..9881df80c 100644 --- a/server/tests/api/check-params/video-captions.ts +++ b/server/tests/api/check-params/video-captions.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
5 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | buildAbsoluteFixturePath, | ||
6 | cleanupTests, | 7 | cleanupTests, |
7 | createSingleServer, | 8 | createSingleServer, |
8 | makeDeleteRequest, | 9 | makeDeleteRequest, |
@@ -10,8 +11,7 @@ import { | |||
10 | makeUploadRequest, | 11 | makeUploadRequest, |
11 | PeerTubeServer, | 12 | PeerTubeServer, |
12 | setAccessTokensToServers | 13 | setAccessTokensToServers |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
15 | 15 | ||
16 | describe('Test video captions API validator', function () { | 16 | describe('Test video captions API validator', function () { |
17 | const path = '/api/v1/videos/' | 17 | const path = '/api/v1/videos/' |
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index e86c315fa..1e9732fe9 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts | |||
@@ -3,12 +3,11 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
7 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
8 | import { HttpStatusCode, VideoChannelUpdate } from '@shared/models' | ||
6 | import { | 9 | import { |
7 | buildAbsoluteFixturePath, | ||
8 | ChannelsCommand, | 10 | ChannelsCommand, |
9 | checkBadCountPagination, | ||
10 | checkBadSortPagination, | ||
11 | checkBadStartPagination, | ||
12 | cleanupTests, | 11 | cleanupTests, |
13 | createSingleServer, | 12 | createSingleServer, |
14 | makeGetRequest, | 13 | makeGetRequest, |
@@ -17,8 +16,7 @@ import { | |||
17 | makeUploadRequest, | 16 | makeUploadRequest, |
18 | PeerTubeServer, | 17 | PeerTubeServer, |
19 | setAccessTokensToServers | 18 | setAccessTokensToServers |
20 | } from '@shared/extra-utils' | 19 | } from '@shared/server-commands' |
21 | import { HttpStatusCode, VideoChannelUpdate } from '@shared/models' | ||
22 | 20 | ||
23 | const expect = chai.expect | 21 | const expect = chai.expect |
24 | 22 | ||
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts index 8d63fe70c..829f3c8b1 100644 --- a/server/tests/api/check-params/video-comments.ts +++ b/server/tests/api/check-params/video-comments.ts | |||
@@ -2,10 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' | ||
6 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
9 | cleanupTests, | 8 | cleanupTests, |
10 | createSingleServer, | 9 | createSingleServer, |
11 | makeDeleteRequest, | 10 | makeDeleteRequest, |
@@ -13,8 +12,7 @@ import { | |||
13 | makePostBodyRequest, | 12 | makePostBodyRequest, |
14 | PeerTubeServer, | 13 | PeerTubeServer, |
15 | setAccessTokensToServers | 14 | setAccessTokensToServers |
16 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
17 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
18 | 16 | ||
19 | const expect = chai.expect | 17 | const expect = chai.expect |
20 | 18 | ||
diff --git a/server/tests/api/check-params/video-files.ts b/server/tests/api/check-params/video-files.ts index 3ccdf5f49..8c0795092 100644 --- a/server/tests/api/check-params/video-files.ts +++ b/server/tests/api/check-params/video-files.ts | |||
@@ -1,8 +1,15 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | ||
5 | import { HttpStatusCode, UserRole } from '@shared/models' | 4 | import { HttpStatusCode, UserRole } from '@shared/models' |
5 | import { | ||
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | describe('Test videos files', function () { | 14 | describe('Test videos files', function () { |
8 | let servers: PeerTubeServer[] | 15 | let servers: PeerTubeServer[] |
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts index 6c31daa9b..da05793a0 100644 --- a/server/tests/api/check-params/video-imports.ts +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -2,21 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
5 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, FIXTURE_URLS } from '@server/tests/shared' | ||
6 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | buildAbsoluteFixturePath, | ||
7 | checkBadCountPagination, | ||
8 | checkBadSortPagination, | ||
9 | checkBadStartPagination, | ||
10 | cleanupTests, | 9 | cleanupTests, |
11 | createSingleServer, | 10 | createSingleServer, |
12 | FIXTURE_URLS, | ||
13 | makeGetRequest, | 11 | makeGetRequest, |
14 | makePostBodyRequest, | 12 | makePostBodyRequest, |
15 | makeUploadRequest, | 13 | makeUploadRequest, |
16 | PeerTubeServer, | 14 | PeerTubeServer, |
17 | setAccessTokensToServers | 15 | setAccessTokensToServers |
18 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
19 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
20 | 17 | ||
21 | describe('Test video imports API validator', function () { | 18 | describe('Test video imports API validator', function () { |
22 | const path = '/api/v1/videos/imports' | 19 | const path = '/api/v1/videos/imports' |
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts index e4d541b48..4b17ce7db 100644 --- a/server/tests/api/check-params/video-playlists.ts +++ b/server/tests/api/check-params/video-playlists.ts | |||
@@ -1,18 +1,7 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@server/tests/shared' |
5 | checkBadCountPagination, | ||
6 | checkBadSortPagination, | ||
7 | checkBadStartPagination, | ||
8 | cleanupTests, | ||
9 | createSingleServer, | ||
10 | makeGetRequest, | ||
11 | PeerTubeServer, | ||
12 | PlaylistsCommand, | ||
13 | setAccessTokensToServers, | ||
14 | setDefaultVideoChannel | ||
15 | } from '@shared/extra-utils' | ||
16 | import { | 5 | import { |
17 | HttpStatusCode, | 6 | HttpStatusCode, |
18 | VideoPlaylistCreate, | 7 | VideoPlaylistCreate, |
@@ -23,6 +12,15 @@ import { | |||
23 | VideoPlaylistReorder, | 12 | VideoPlaylistReorder, |
24 | VideoPlaylistType | 13 | VideoPlaylistType |
25 | } from '@shared/models' | 14 | } from '@shared/models' |
15 | import { | ||
16 | cleanupTests, | ||
17 | createSingleServer, | ||
18 | makeGetRequest, | ||
19 | PeerTubeServer, | ||
20 | PlaylistsCommand, | ||
21 | setAccessTokensToServers, | ||
22 | setDefaultVideoChannel | ||
23 | } from '@shared/server-commands' | ||
26 | 24 | ||
27 | describe('Test video playlists API validator', function () { | 25 | describe('Test video playlists API validator', function () { |
28 | let server: PeerTubeServer | 26 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/videos-common-filters.ts b/server/tests/api/check-params/videos-common-filters.ts index f2b5bee8e..6b3ec917e 100644 --- a/server/tests/api/check-params/videos-common-filters.ts +++ b/server/tests/api/check-params/videos-common-filters.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | PeerTubeServer, | 8 | PeerTubeServer, |
9 | setAccessTokensToServers, | 9 | setAccessTokensToServers, |
10 | setDefaultVideoChannel | 10 | setDefaultVideoChannel |
11 | } from '@shared/extra-utils' | 11 | } from '@shared/server-commands' |
12 | import { HttpStatusCode, UserRole, VideoInclude, VideoPrivacy } from '@shared/models' | 12 | import { HttpStatusCode, UserRole, VideoInclude, VideoPrivacy } from '@shared/models' |
13 | 13 | ||
14 | describe('Test video filters validators', function () { | 14 | describe('Test video filters validators', function () { |
diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts index c3c309ed2..31a0752c7 100644 --- a/server/tests/api/check-params/videos-history.ts +++ b/server/tests/api/check-params/videos-history.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { checkBadCountPagination, checkBadStartPagination } from '@server/tests/shared' | ||
5 | import { HttpStatusCode } from '@shared/models' | ||
4 | import { | 6 | import { |
5 | checkBadCountPagination, | ||
6 | checkBadStartPagination, | ||
7 | cleanupTests, | 7 | cleanupTests, |
8 | createSingleServer, | 8 | createSingleServer, |
9 | makeGetRequest, | 9 | makeGetRequest, |
@@ -11,8 +11,7 @@ import { | |||
11 | makePutBodyRequest, | 11 | makePutBodyRequest, |
12 | PeerTubeServer, | 12 | PeerTubeServer, |
13 | setAccessTokensToServers | 13 | setAccessTokensToServers |
14 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | import { HttpStatusCode } from '@shared/models' | ||
16 | 15 | ||
17 | describe('Test videos history API validator', function () { | 16 | describe('Test videos history API validator', function () { |
18 | const myHistoryPath = '/api/v1/users/me/history/videos' | 17 | const myHistoryPath = '/api/v1/users/me/history/videos' |
diff --git a/server/tests/api/check-params/videos-overviews.ts b/server/tests/api/check-params/videos-overviews.ts index c2139d74b..1da15dc43 100644 --- a/server/tests/api/check-params/videos-overviews.ts +++ b/server/tests/api/check-params/videos-overviews.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/extra-utils' | 4 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' |
5 | 5 | ||
6 | describe('Test videos overview', function () { | 6 | describe('Test videos overview', function () { |
7 | let server: PeerTubeServer | 7 | let server: PeerTubeServer |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index d02b6e156..4cc70f5cc 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -4,12 +4,10 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { randomInt } from '@shared/core-utils' | 7 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination, checkUploadVideoParam } from '@server/tests/shared' |
8 | import { randomInt, root } from '@shared/core-utils' | ||
9 | import { HttpStatusCode, PeerTubeProblemDocument, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
8 | import { | 10 | import { |
9 | checkBadCountPagination, | ||
10 | checkBadSortPagination, | ||
11 | checkBadStartPagination, | ||
12 | checkUploadVideoParam, | ||
13 | cleanupTests, | 11 | cleanupTests, |
14 | createSingleServer, | 12 | createSingleServer, |
15 | makeDeleteRequest, | 13 | makeDeleteRequest, |
@@ -17,10 +15,8 @@ import { | |||
17 | makePutBodyRequest, | 15 | makePutBodyRequest, |
18 | makeUploadRequest, | 16 | makeUploadRequest, |
19 | PeerTubeServer, | 17 | PeerTubeServer, |
20 | root, | ||
21 | setAccessTokensToServers | 18 | setAccessTokensToServers |
22 | } from '@shared/extra-utils' | 19 | } from '@shared/server-commands' |
23 | import { HttpStatusCode, PeerTubeProblemDocument, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
24 | 20 | ||
25 | const expect = chai.expect | 21 | const expect = chai.expect |
26 | 22 | ||
diff --git a/server/tests/api/live/live-constraints.ts b/server/tests/api/live/live-constraints.ts index 6a6a11796..909399836 100644 --- a/server/tests/api/live/live-constraints.ts +++ b/server/tests/api/live/live-constraints.ts | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
5 | import { VideoPrivacy } from '@shared/models' | 6 | import { VideoPrivacy } from '@shared/models' |
6 | import { | 7 | import { |
7 | checkLiveCleanupAfterSave, | ||
8 | cleanupTests, | 8 | cleanupTests, |
9 | ConfigCommand, | 9 | ConfigCommand, |
10 | createMultipleServers, | 10 | createMultipleServers, |
@@ -12,9 +12,9 @@ import { | |||
12 | PeerTubeServer, | 12 | PeerTubeServer, |
13 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
14 | setDefaultVideoChannel, | 14 | setDefaultVideoChannel, |
15 | wait, | ||
16 | waitJobs | 15 | waitJobs |
17 | } from '../../../../shared/extra-utils' | 16 | } from '@shared/server-commands' |
17 | import { checkLiveCleanupAfterSave } from '../../shared' | ||
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/api/live/live-permanent.ts b/server/tests/api/live/live-permanent.ts index c5f942901..3e6fec453 100644 --- a/server/tests/api/live/live-permanent.ts +++ b/server/tests/api/live/live-permanent.ts | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
5 | import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' | 6 | import { LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' |
6 | import { | 7 | import { |
7 | cleanupTests, | 8 | cleanupTests, |
@@ -12,9 +13,8 @@ import { | |||
12 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
13 | setDefaultVideoChannel, | 14 | setDefaultVideoChannel, |
14 | stopFfmpeg, | 15 | stopFfmpeg, |
15 | wait, | ||
16 | waitJobs | 16 | waitJobs |
17 | } from '../../../../shared/extra-utils' | 17 | } from '@shared/server-commands' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
@@ -140,7 +140,7 @@ describe('Permanent live', function () { | |||
140 | }) | 140 | }) |
141 | 141 | ||
142 | it('Should be able to stream again in the permanent live', async function () { | 142 | it('Should be able to stream again in the permanent live', async function () { |
143 | this.timeout(20000) | 143 | this.timeout(60000) |
144 | 144 | ||
145 | await servers[0].config.updateCustomSubConfig({ | 145 | await servers[0].config.updateCustomSubConfig({ |
146 | newConfig: { | 146 | newConfig: { |
diff --git a/server/tests/api/live/live-rtmps.ts b/server/tests/api/live/live-rtmps.ts index 378e6df3c..935061971 100644 --- a/server/tests/api/live/live-rtmps.ts +++ b/server/tests/api/live/live-rtmps.ts | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { buildAbsoluteFixturePath } from '@shared/core-utils' | ||
5 | import { VideoPrivacy } from '@shared/models' | 6 | import { VideoPrivacy } from '@shared/models' |
6 | import { | 7 | import { |
7 | buildAbsoluteFixturePath, | ||
8 | cleanupTests, | 8 | cleanupTests, |
9 | createSingleServer, | 9 | createSingleServer, |
10 | PeerTubeServer, | 10 | PeerTubeServer, |
@@ -14,7 +14,7 @@ import { | |||
14 | stopFfmpeg, | 14 | stopFfmpeg, |
15 | testFfmpegStreamError, | 15 | testFfmpegStreamError, |
16 | waitUntilLivePublishedOnAllServers | 16 | waitUntilLivePublishedOnAllServers |
17 | } from '../../../../shared/extra-utils' | 17 | } from '@shared/server-commands' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/api/live/live-save-replay.ts b/server/tests/api/live/live-save-replay.ts index 6c4ea90ca..95a342b01 100644 --- a/server/tests/api/live/live-save-replay.ts +++ b/server/tests/api/live/live-save-replay.ts | |||
@@ -3,8 +3,10 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { FfmpegCommand } from 'fluent-ffmpeg' | 5 | import { FfmpegCommand } from 'fluent-ffmpeg' |
6 | import { checkLiveCleanupAfterSave } from '@server/tests/shared' | ||
7 | import { wait } from '@shared/core-utils' | ||
8 | import { HttpStatusCode, LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' | ||
6 | import { | 9 | import { |
7 | checkLiveCleanupAfterSave, | ||
8 | cleanupTests, | 10 | cleanupTests, |
9 | ConfigCommand, | 11 | ConfigCommand, |
10 | createMultipleServers, | 12 | createMultipleServers, |
@@ -14,12 +16,10 @@ import { | |||
14 | setDefaultVideoChannel, | 16 | setDefaultVideoChannel, |
15 | stopFfmpeg, | 17 | stopFfmpeg, |
16 | testFfmpegStreamError, | 18 | testFfmpegStreamError, |
17 | wait, | ||
18 | waitJobs, | 19 | waitJobs, |
19 | waitUntilLivePublishedOnAllServers, | 20 | waitUntilLivePublishedOnAllServers, |
20 | waitUntilLiveSavedOnAllServers | 21 | waitUntilLiveSavedOnAllServers |
21 | } from '@shared/extra-utils' | 22 | } from '@shared/server-commands' |
22 | import { HttpStatusCode, LiveVideoCreate, VideoPrivacy, VideoState } from '@shared/models' | ||
23 | 23 | ||
24 | const expect = chai.expect | 24 | const expect = chai.expect |
25 | 25 | ||
diff --git a/server/tests/api/live/live-socket-messages.ts b/server/tests/api/live/live-socket-messages.ts index 33ee2c051..50b16443e 100644 --- a/server/tests/api/live/live-socket-messages.ts +++ b/server/tests/api/live/live-socket-messages.ts | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
5 | import { VideoPrivacy, VideoState } from '@shared/models' | 6 | import { VideoPrivacy, VideoState } from '@shared/models' |
6 | import { | 7 | import { |
7 | cleanupTests, | 8 | cleanupTests, |
@@ -11,10 +12,9 @@ import { | |||
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
13 | stopFfmpeg, | 14 | stopFfmpeg, |
14 | wait, | ||
15 | waitJobs, | 15 | waitJobs, |
16 | waitUntilLivePublishedOnAllServers | 16 | waitUntilLivePublishedOnAllServers |
17 | } from '../../../../shared/extra-utils' | 17 | } from '@shared/server-commands' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/api/live/live-views.ts b/server/tests/api/live/live-views.ts index 9186af8e7..446d0913c 100644 --- a/server/tests/api/live/live-views.ts +++ b/server/tests/api/live/live-views.ts | |||
@@ -3,6 +3,7 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { FfmpegCommand } from 'fluent-ffmpeg' | 5 | import { FfmpegCommand } from 'fluent-ffmpeg' |
6 | import { wait } from '@shared/core-utils' | ||
6 | import { VideoPrivacy } from '@shared/models' | 7 | import { VideoPrivacy } from '@shared/models' |
7 | import { | 8 | import { |
8 | cleanupTests, | 9 | cleanupTests, |
@@ -12,10 +13,9 @@ import { | |||
12 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
13 | setDefaultVideoChannel, | 14 | setDefaultVideoChannel, |
14 | stopFfmpeg, | 15 | stopFfmpeg, |
15 | wait, | ||
16 | waitJobs, | 16 | waitJobs, |
17 | waitUntilLivePublishedOnAllServers | 17 | waitUntilLivePublishedOnAllServers |
18 | } from '../../../../shared/extra-utils' | 18 | } from '@shared/server-commands' |
19 | 19 | ||
20 | const expect = chai.expect | 20 | const expect = chai.expect |
21 | 21 | ||
diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index b96c03cf8..3f9355d2d 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts | |||
@@ -4,10 +4,18 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { basename, join } from 'path' | 5 | import { basename, join } from 'path' |
6 | import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils' | 6 | import { ffprobePromise, getVideoStreamFromFile } from '@server/helpers/ffprobe-utils' |
7 | import { checkLiveCleanupAfterSave, checkLiveSegmentHash, checkResolutionsInMasterPlaylist, testImage } from '@server/tests/shared' | ||
8 | import { wait } from '@shared/core-utils' | ||
9 | import { | ||
10 | HttpStatusCode, | ||
11 | LiveVideo, | ||
12 | LiveVideoCreate, | ||
13 | VideoDetails, | ||
14 | VideoPrivacy, | ||
15 | VideoState, | ||
16 | VideoStreamingPlaylistType | ||
17 | } from '@shared/models' | ||
7 | import { | 18 | import { |
8 | checkLiveCleanupAfterSave, | ||
9 | checkLiveSegmentHash, | ||
10 | checkResolutionsInMasterPlaylist, | ||
11 | cleanupTests, | 19 | cleanupTests, |
12 | createMultipleServers, | 20 | createMultipleServers, |
13 | doubleFollow, | 21 | doubleFollow, |
@@ -20,20 +28,9 @@ import { | |||
20 | setDefaultVideoChannel, | 28 | setDefaultVideoChannel, |
21 | stopFfmpeg, | 29 | stopFfmpeg, |
22 | testFfmpegStreamError, | 30 | testFfmpegStreamError, |
23 | testImage, | ||
24 | wait, | ||
25 | waitJobs, | 31 | waitJobs, |
26 | waitUntilLivePublishedOnAllServers | 32 | waitUntilLivePublishedOnAllServers |
27 | } from '@shared/extra-utils' | 33 | } from '@shared/server-commands' |
28 | import { | ||
29 | HttpStatusCode, | ||
30 | LiveVideo, | ||
31 | LiveVideoCreate, | ||
32 | VideoDetails, | ||
33 | VideoPrivacy, | ||
34 | VideoState, | ||
35 | VideoStreamingPlaylistType | ||
36 | } from '@shared/models' | ||
37 | 34 | ||
38 | const expect = chai.expect | 35 | const expect = chai.expect |
39 | 36 | ||
diff --git a/server/tests/api/moderation/abuses.ts b/server/tests/api/moderation/abuses.ts index c258414ce..0c3bed3e7 100644 --- a/server/tests/api/moderation/abuses.ts +++ b/server/tests/api/moderation/abuses.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { AbuseMessage, AbusePredefinedReasonsString, AbuseState, AdminAbuse, UserAbuse } from '@shared/models' | 14 | import { AbuseMessage, AbusePredefinedReasonsString, AbuseState, AdminAbuse, UserAbuse } from '@shared/models' |
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
@@ -468,7 +468,7 @@ describe('Test abuses', function () { | |||
468 | }) | 468 | }) |
469 | 469 | ||
470 | it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { | 470 | it('Should have 2 comment abuses on server 1 and 1 on server 2', async function () { |
471 | const commentServer2 = await getComment(servers[0], servers[1].store.videoCreated.id) | 471 | const commentServer2 = await getComment(servers[0], servers[1].store.videoCreated.shortUUID) |
472 | 472 | ||
473 | { | 473 | { |
474 | const body = await commands[0].getAdminList({ filter: 'comment' }) | 474 | const body = await commands[0].getAdminList({ filter: 'comment' }) |
diff --git a/server/tests/api/moderation/blocklist-notification.ts b/server/tests/api/moderation/blocklist-notification.ts index 75b15c298..87d147998 100644 --- a/server/tests/api/moderation/blocklist-notification.ts +++ b/server/tests/api/moderation/blocklist-notification.ts | |||
@@ -2,8 +2,15 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | ||
6 | import { UserNotificationType } from '@shared/models' | 5 | import { UserNotificationType } from '@shared/models' |
6 | import { | ||
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | waitJobs | ||
13 | } from '@shared/server-commands' | ||
7 | 14 | ||
8 | const expect = chai.expect | 15 | const expect = chai.expect |
9 | 16 | ||
diff --git a/server/tests/api/moderation/blocklist.ts b/server/tests/api/moderation/blocklist.ts index 089af8b15..b45460bb4 100644 --- a/server/tests/api/moderation/blocklist.ts +++ b/server/tests/api/moderation/blocklist.ts | |||
@@ -11,7 +11,7 @@ import { | |||
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | waitJobs | 13 | waitJobs |
14 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | import { UserNotificationType } from '@shared/models' | 15 | import { UserNotificationType } from '@shared/models' |
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
@@ -254,6 +254,45 @@ describe('Test blocklist', function () { | |||
254 | } | 254 | } |
255 | }) | 255 | }) |
256 | 256 | ||
257 | it('Should get blocked status', async function () { | ||
258 | const remoteHandle = 'user2@' + servers[1].host | ||
259 | const localHandle = 'user1@' + servers[0].host | ||
260 | const unknownHandle = 'user5@' + servers[0].host | ||
261 | |||
262 | { | ||
263 | const status = await command.getStatus({ accounts: [ remoteHandle ] }) | ||
264 | expect(Object.keys(status.accounts)).to.have.lengthOf(1) | ||
265 | expect(status.accounts[remoteHandle].blockedByUser).to.be.false | ||
266 | expect(status.accounts[remoteHandle].blockedByServer).to.be.false | ||
267 | |||
268 | expect(Object.keys(status.hosts)).to.have.lengthOf(0) | ||
269 | } | ||
270 | |||
271 | { | ||
272 | const status = await command.getStatus({ token: servers[0].accessToken, accounts: [ remoteHandle ] }) | ||
273 | expect(Object.keys(status.accounts)).to.have.lengthOf(1) | ||
274 | expect(status.accounts[remoteHandle].blockedByUser).to.be.true | ||
275 | expect(status.accounts[remoteHandle].blockedByServer).to.be.false | ||
276 | |||
277 | expect(Object.keys(status.hosts)).to.have.lengthOf(0) | ||
278 | } | ||
279 | |||
280 | { | ||
281 | const status = await command.getStatus({ token: servers[0].accessToken, accounts: [ localHandle, remoteHandle, unknownHandle ] }) | ||
282 | expect(Object.keys(status.accounts)).to.have.lengthOf(3) | ||
283 | |||
284 | for (const handle of [ localHandle, remoteHandle ]) { | ||
285 | expect(status.accounts[handle].blockedByUser).to.be.true | ||
286 | expect(status.accounts[handle].blockedByServer).to.be.false | ||
287 | } | ||
288 | |||
289 | expect(status.accounts[unknownHandle].blockedByUser).to.be.false | ||
290 | expect(status.accounts[unknownHandle].blockedByServer).to.be.false | ||
291 | |||
292 | expect(Object.keys(status.hosts)).to.have.lengthOf(0) | ||
293 | } | ||
294 | }) | ||
295 | |||
257 | it('Should not allow a remote blocked user to comment my videos', async function () { | 296 | it('Should not allow a remote blocked user to comment my videos', async function () { |
258 | this.timeout(60000) | 297 | this.timeout(60000) |
259 | 298 | ||
@@ -434,6 +473,35 @@ describe('Test blocklist', function () { | |||
434 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 473 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
435 | }) | 474 | }) |
436 | 475 | ||
476 | it('Should get blocklist status', async function () { | ||
477 | const blockedServer = servers[1].host | ||
478 | const notBlockedServer = 'example.com' | ||
479 | |||
480 | { | ||
481 | const status = await command.getStatus({ hosts: [ blockedServer, notBlockedServer ] }) | ||
482 | expect(Object.keys(status.accounts)).to.have.lengthOf(0) | ||
483 | |||
484 | expect(Object.keys(status.hosts)).to.have.lengthOf(2) | ||
485 | expect(status.hosts[blockedServer].blockedByUser).to.be.false | ||
486 | expect(status.hosts[blockedServer].blockedByServer).to.be.false | ||
487 | |||
488 | expect(status.hosts[notBlockedServer].blockedByUser).to.be.false | ||
489 | expect(status.hosts[notBlockedServer].blockedByServer).to.be.false | ||
490 | } | ||
491 | |||
492 | { | ||
493 | const status = await command.getStatus({ token: servers[0].accessToken, hosts: [ blockedServer, notBlockedServer ] }) | ||
494 | expect(Object.keys(status.accounts)).to.have.lengthOf(0) | ||
495 | |||
496 | expect(Object.keys(status.hosts)).to.have.lengthOf(2) | ||
497 | expect(status.hosts[blockedServer].blockedByUser).to.be.true | ||
498 | expect(status.hosts[blockedServer].blockedByServer).to.be.false | ||
499 | |||
500 | expect(status.hosts[notBlockedServer].blockedByUser).to.be.false | ||
501 | expect(status.hosts[notBlockedServer].blockedByServer).to.be.false | ||
502 | } | ||
503 | }) | ||
504 | |||
437 | it('Should unblock the remote server', async function () { | 505 | it('Should unblock the remote server', async function () { |
438 | await command.removeFromMyBlocklist({ server: 'localhost:' + servers[1].port }) | 506 | await command.removeFromMyBlocklist({ server: 'localhost:' + servers[1].port }) |
439 | }) | 507 | }) |
@@ -575,6 +643,27 @@ describe('Test blocklist', function () { | |||
575 | } | 643 | } |
576 | }) | 644 | }) |
577 | 645 | ||
646 | it('Should get blocked status', async function () { | ||
647 | const remoteHandle = 'user2@' + servers[1].host | ||
648 | const localHandle = 'user1@' + servers[0].host | ||
649 | const unknownHandle = 'user5@' + servers[0].host | ||
650 | |||
651 | for (const token of [ undefined, servers[0].accessToken ]) { | ||
652 | const status = await command.getStatus({ token, accounts: [ localHandle, remoteHandle, unknownHandle ] }) | ||
653 | expect(Object.keys(status.accounts)).to.have.lengthOf(3) | ||
654 | |||
655 | for (const handle of [ localHandle, remoteHandle ]) { | ||
656 | expect(status.accounts[handle].blockedByUser).to.be.false | ||
657 | expect(status.accounts[handle].blockedByServer).to.be.true | ||
658 | } | ||
659 | |||
660 | expect(status.accounts[unknownHandle].blockedByUser).to.be.false | ||
661 | expect(status.accounts[unknownHandle].blockedByServer).to.be.false | ||
662 | |||
663 | expect(Object.keys(status.hosts)).to.have.lengthOf(0) | ||
664 | } | ||
665 | }) | ||
666 | |||
578 | it('Should unblock the remote account', async function () { | 667 | it('Should unblock the remote account', async function () { |
579 | await command.removeFromServerBlocklist({ account: 'user2@localhost:' + servers[1].port }) | 668 | await command.removeFromServerBlocklist({ account: 'user2@localhost:' + servers[1].port }) |
580 | }) | 669 | }) |
@@ -620,6 +709,7 @@ describe('Test blocklist', function () { | |||
620 | }) | 709 | }) |
621 | 710 | ||
622 | describe('When managing server blocklist', function () { | 711 | describe('When managing server blocklist', function () { |
712 | |||
623 | it('Should list all videos', async function () { | 713 | it('Should list all videos', async function () { |
624 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { | 714 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
625 | await checkAllVideos(servers[0], token) | 715 | await checkAllVideos(servers[0], token) |
@@ -713,6 +803,23 @@ describe('Test blocklist', function () { | |||
713 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 803 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
714 | }) | 804 | }) |
715 | 805 | ||
806 | it('Should get blocklist status', async function () { | ||
807 | const blockedServer = servers[1].host | ||
808 | const notBlockedServer = 'example.com' | ||
809 | |||
810 | for (const token of [ undefined, servers[0].accessToken ]) { | ||
811 | const status = await command.getStatus({ token, hosts: [ blockedServer, notBlockedServer ] }) | ||
812 | expect(Object.keys(status.accounts)).to.have.lengthOf(0) | ||
813 | |||
814 | expect(Object.keys(status.hosts)).to.have.lengthOf(2) | ||
815 | expect(status.hosts[blockedServer].blockedByUser).to.be.false | ||
816 | expect(status.hosts[blockedServer].blockedByServer).to.be.true | ||
817 | |||
818 | expect(status.hosts[notBlockedServer].blockedByUser).to.be.false | ||
819 | expect(status.hosts[notBlockedServer].blockedByServer).to.be.false | ||
820 | } | ||
821 | }) | ||
822 | |||
716 | it('Should unblock the remote server', async function () { | 823 | it('Should unblock the remote server', async function () { |
717 | await command.removeFromServerBlocklist({ server: 'localhost:' + servers[1].port }) | 824 | await command.removeFromServerBlocklist({ server: 'localhost:' + servers[1].port }) |
718 | }) | 825 | }) |
diff --git a/server/tests/api/moderation/video-blacklist.ts b/server/tests/api/moderation/video-blacklist.ts index d5838191a..322e93815 100644 --- a/server/tests/api/moderation/video-blacklist.ts +++ b/server/tests/api/moderation/video-blacklist.ts | |||
@@ -3,18 +3,18 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { orderBy } from 'lodash' | 5 | import { orderBy } from 'lodash' |
6 | import { FIXTURE_URLS } from '@server/tests/shared' | ||
7 | import { UserAdminFlag, UserRole, VideoBlacklist, VideoBlacklistType } from '@shared/models' | ||
6 | import { | 8 | import { |
7 | BlacklistCommand, | 9 | BlacklistCommand, |
8 | cleanupTests, | 10 | cleanupTests, |
9 | createMultipleServers, | 11 | createMultipleServers, |
10 | doubleFollow, | 12 | doubleFollow, |
11 | FIXTURE_URLS, | ||
12 | killallServers, | 13 | killallServers, |
13 | PeerTubeServer, | 14 | PeerTubeServer, |
14 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
15 | waitJobs | 16 | waitJobs |
16 | } from '@shared/extra-utils' | 17 | } from '@shared/server-commands' |
17 | import { UserAdminFlag, UserRole, VideoBlacklist, VideoBlacklistType } from '@shared/models' | ||
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/api/notifications/admin-notifications.ts b/server/tests/api/notifications/admin-notifications.ts index c00d4e257..f037e7aae 100644 --- a/server/tests/api/notifications/admin-notifications.ts +++ b/server/tests/api/notifications/admin-notifications.ts | |||
@@ -6,14 +6,13 @@ import { | |||
6 | CheckerBaseParams, | 6 | CheckerBaseParams, |
7 | checkNewPeerTubeVersion, | 7 | checkNewPeerTubeVersion, |
8 | checkNewPluginVersion, | 8 | checkNewPluginVersion, |
9 | cleanupTests, | ||
10 | MockJoinPeerTubeVersions, | 9 | MockJoinPeerTubeVersions, |
11 | MockSmtpServer, | 10 | MockSmtpServer, |
12 | PeerTubeServer, | 11 | prepareNotificationsTest |
13 | prepareNotificationsTest, | 12 | } from '@server/tests/shared' |
14 | wait | 13 | import { wait } from '@shared/core-utils' |
15 | } from '@shared/extra-utils' | ||
16 | import { PluginType, UserNotification, UserNotificationType } from '@shared/models' | 14 | import { PluginType, UserNotification, UserNotificationType } from '@shared/models' |
15 | import { cleanupTests, PeerTubeServer } from '@shared/server-commands' | ||
17 | 16 | ||
18 | describe('Test admin notifications', function () { | 17 | describe('Test admin notifications', function () { |
19 | let server: PeerTubeServer | 18 | let server: PeerTubeServer |
diff --git a/server/tests/api/notifications/comments-notifications.ts b/server/tests/api/notifications/comments-notifications.ts index 7cbb21397..b82f1712a 100644 --- a/server/tests/api/notifications/comments-notifications.ts +++ b/server/tests/api/notifications/comments-notifications.ts | |||
@@ -6,13 +6,11 @@ import { | |||
6 | checkCommentMention, | 6 | checkCommentMention, |
7 | CheckerBaseParams, | 7 | CheckerBaseParams, |
8 | checkNewCommentOnMyVideo, | 8 | checkNewCommentOnMyVideo, |
9 | cleanupTests, | ||
10 | MockSmtpServer, | 9 | MockSmtpServer, |
11 | PeerTubeServer, | 10 | prepareNotificationsTest |
12 | prepareNotificationsTest, | 11 | } from '@server/tests/shared' |
13 | waitJobs | ||
14 | } from '@shared/extra-utils' | ||
15 | import { UserNotification } from '@shared/models' | 12 | import { UserNotification } from '@shared/models' |
13 | import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' | ||
16 | 14 | ||
17 | const expect = chai.expect | 15 | const expect = chai.expect |
18 | 16 | ||
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts index f806fed31..9e330bd61 100644 --- a/server/tests/api/notifications/moderation-notifications.ts +++ b/server/tests/api/notifications/moderation-notifications.ts | |||
@@ -1,7 +1,6 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { buildUUID } from '@server/helpers/uuid' | ||
5 | import { | 4 | import { |
6 | checkAbuseStateChange, | 5 | checkAbuseStateChange, |
7 | checkAutoInstanceFollowing, | 6 | checkAutoInstanceFollowing, |
@@ -16,19 +15,20 @@ import { | |||
16 | checkUserRegistered, | 15 | checkUserRegistered, |
17 | checkVideoAutoBlacklistForModerators, | 16 | checkVideoAutoBlacklistForModerators, |
18 | checkVideoIsPublished, | 17 | checkVideoIsPublished, |
19 | cleanupTests, | ||
20 | MockInstancesIndex, | 18 | MockInstancesIndex, |
21 | MockSmtpServer, | 19 | MockSmtpServer, |
22 | PeerTubeServer, | 20 | prepareNotificationsTest |
23 | prepareNotificationsTest, | 21 | } from '@server/tests/shared' |
24 | wait, | 22 | import { wait } from '@shared/core-utils' |
25 | waitJobs | 23 | import { buildUUID } from '@shared/extra-utils' |
26 | } from '@shared/extra-utils' | 24 | import { AbuseState, CustomConfig, UserNotification, UserRole, VideoPrivacy } from '@shared/models' |
27 | import { AbuseState, CustomConfig, UserNotification, VideoPrivacy } from '@shared/models' | 25 | import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' |
28 | 26 | ||
29 | describe('Test moderation notifications', function () { | 27 | describe('Test moderation notifications', function () { |
30 | let servers: PeerTubeServer[] = [] | 28 | let servers: PeerTubeServer[] = [] |
31 | let userAccessToken: string | 29 | let userToken1: string |
30 | let userToken2: string | ||
31 | |||
32 | let userNotifications: UserNotification[] = [] | 32 | let userNotifications: UserNotification[] = [] |
33 | let adminNotifications: UserNotification[] = [] | 33 | let adminNotifications: UserNotification[] = [] |
34 | let adminNotificationsServer2: UserNotification[] = [] | 34 | let adminNotificationsServer2: UserNotification[] = [] |
@@ -39,11 +39,13 @@ describe('Test moderation notifications', function () { | |||
39 | 39 | ||
40 | const res = await prepareNotificationsTest(3) | 40 | const res = await prepareNotificationsTest(3) |
41 | emails = res.emails | 41 | emails = res.emails |
42 | userAccessToken = res.userAccessToken | 42 | userToken1 = res.userAccessToken |
43 | servers = res.servers | 43 | servers = res.servers |
44 | userNotifications = res.userNotifications | 44 | userNotifications = res.userNotifications |
45 | adminNotifications = res.adminNotifications | 45 | adminNotifications = res.adminNotifications |
46 | adminNotificationsServer2 = res.adminNotificationsServer2 | 46 | adminNotificationsServer2 = res.adminNotificationsServer2 |
47 | |||
48 | userToken2 = await servers[1].users.generateUserAndToken('user2', UserRole.USER) | ||
47 | }) | 49 | }) |
48 | 50 | ||
49 | describe('Abuse for moderators notification', function () { | 51 | describe('Abuse for moderators notification', function () { |
@@ -58,15 +60,27 @@ describe('Test moderation notifications', function () { | |||
58 | } | 60 | } |
59 | }) | 61 | }) |
60 | 62 | ||
61 | it('Should send a notification to moderators on local video abuse', async function () { | 63 | it('Should not send a notification to moderators on local abuse reported by an admin', async function () { |
62 | this.timeout(20000) | 64 | this.timeout(20000) |
63 | 65 | ||
64 | const name = 'video for abuse ' + buildUUID() | 66 | const name = 'video for abuse ' + buildUUID() |
65 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 67 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
66 | 68 | ||
67 | await servers[0].abuses.report({ videoId: video.id, reason: 'super reason' }) | 69 | await servers[0].abuses.report({ videoId: video.id, reason: 'super reason' }) |
68 | 70 | ||
69 | await waitJobs(servers) | 71 | await waitJobs(servers) |
72 | await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'absence' }) | ||
73 | }) | ||
74 | |||
75 | it('Should send a notification to moderators on local video abuse', async function () { | ||
76 | this.timeout(20000) | ||
77 | |||
78 | const name = 'video for abuse ' + buildUUID() | ||
79 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | ||
80 | |||
81 | await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) | ||
82 | |||
83 | await waitJobs(servers) | ||
70 | await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) | 84 | await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) |
71 | }) | 85 | }) |
72 | 86 | ||
@@ -74,12 +88,12 @@ describe('Test moderation notifications', function () { | |||
74 | this.timeout(20000) | 88 | this.timeout(20000) |
75 | 89 | ||
76 | const name = 'video for abuse ' + buildUUID() | 90 | const name = 'video for abuse ' + buildUUID() |
77 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 91 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
78 | 92 | ||
79 | await waitJobs(servers) | 93 | await waitJobs(servers) |
80 | 94 | ||
81 | const videoId = await servers[1].videos.getId({ uuid: video.uuid }) | 95 | const videoId = await servers[1].videos.getId({ uuid: video.uuid }) |
82 | await servers[1].abuses.report({ videoId, reason: 'super reason' }) | 96 | await servers[1].abuses.report({ token: userToken2, videoId, reason: 'super reason' }) |
83 | 97 | ||
84 | await waitJobs(servers) | 98 | await waitJobs(servers) |
85 | await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) | 99 | await checkNewVideoAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) |
@@ -89,16 +103,16 @@ describe('Test moderation notifications', function () { | |||
89 | this.timeout(20000) | 103 | this.timeout(20000) |
90 | 104 | ||
91 | const name = 'video for abuse ' + buildUUID() | 105 | const name = 'video for abuse ' + buildUUID() |
92 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 106 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
93 | const comment = await servers[0].comments.createThread({ | 107 | const comment = await servers[0].comments.createThread({ |
94 | token: userAccessToken, | 108 | token: userToken1, |
95 | videoId: video.id, | 109 | videoId: video.id, |
96 | text: 'comment abuse ' + buildUUID() | 110 | text: 'comment abuse ' + buildUUID() |
97 | }) | 111 | }) |
98 | 112 | ||
99 | await waitJobs(servers) | 113 | await waitJobs(servers) |
100 | 114 | ||
101 | await servers[0].abuses.report({ commentId: comment.id, reason: 'super reason' }) | 115 | await servers[0].abuses.report({ token: userToken1, commentId: comment.id, reason: 'super reason' }) |
102 | 116 | ||
103 | await waitJobs(servers) | 117 | await waitJobs(servers) |
104 | await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) | 118 | await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) |
@@ -108,10 +122,10 @@ describe('Test moderation notifications', function () { | |||
108 | this.timeout(20000) | 122 | this.timeout(20000) |
109 | 123 | ||
110 | const name = 'video for abuse ' + buildUUID() | 124 | const name = 'video for abuse ' + buildUUID() |
111 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 125 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
112 | 126 | ||
113 | await servers[0].comments.createThread({ | 127 | await servers[0].comments.createThread({ |
114 | token: userAccessToken, | 128 | token: userToken1, |
115 | videoId: video.id, | 129 | videoId: video.id, |
116 | text: 'comment abuse ' + buildUUID() | 130 | text: 'comment abuse ' + buildUUID() |
117 | }) | 131 | }) |
@@ -120,7 +134,7 @@ describe('Test moderation notifications', function () { | |||
120 | 134 | ||
121 | const { data } = await servers[1].comments.listThreads({ videoId: video.uuid }) | 135 | const { data } = await servers[1].comments.listThreads({ videoId: video.uuid }) |
122 | const commentId = data[0].id | 136 | const commentId = data[0].id |
123 | await servers[1].abuses.report({ commentId, reason: 'super reason' }) | 137 | await servers[1].abuses.report({ token: userToken2, commentId, reason: 'super reason' }) |
124 | 138 | ||
125 | await waitJobs(servers) | 139 | await waitJobs(servers) |
126 | await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) | 140 | await checkNewCommentAbuseForModerators({ ...baseParams, shortUUID: video.shortUUID, videoName: name, checkType: 'presence' }) |
@@ -133,7 +147,7 @@ describe('Test moderation notifications', function () { | |||
133 | const { account } = await servers[0].users.create({ username, password: 'donald' }) | 147 | const { account } = await servers[0].users.create({ username, password: 'donald' }) |
134 | const accountId = account.id | 148 | const accountId = account.id |
135 | 149 | ||
136 | await servers[0].abuses.report({ accountId, reason: 'super reason' }) | 150 | await servers[0].abuses.report({ token: userToken1, accountId, reason: 'super reason' }) |
137 | 151 | ||
138 | await waitJobs(servers) | 152 | await waitJobs(servers) |
139 | await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) | 153 | await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) |
@@ -149,7 +163,7 @@ describe('Test moderation notifications', function () { | |||
149 | await waitJobs(servers) | 163 | await waitJobs(servers) |
150 | 164 | ||
151 | const account = await servers[1].accounts.get({ accountName: username + '@' + servers[0].host }) | 165 | const account = await servers[1].accounts.get({ accountName: username + '@' + servers[0].host }) |
152 | await servers[1].abuses.report({ accountId: account.id, reason: 'super reason' }) | 166 | await servers[1].abuses.report({ token: userToken2, accountId: account.id, reason: 'super reason' }) |
153 | 167 | ||
154 | await waitJobs(servers) | 168 | await waitJobs(servers) |
155 | await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) | 169 | await checkNewAccountAbuseForModerators({ ...baseParams, displayName: username, checkType: 'presence' }) |
@@ -165,13 +179,13 @@ describe('Test moderation notifications', function () { | |||
165 | server: servers[0], | 179 | server: servers[0], |
166 | emails, | 180 | emails, |
167 | socketNotifications: userNotifications, | 181 | socketNotifications: userNotifications, |
168 | token: userAccessToken | 182 | token: userToken1 |
169 | } | 183 | } |
170 | 184 | ||
171 | const name = 'abuse ' + buildUUID() | 185 | const name = 'abuse ' + buildUUID() |
172 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 186 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
173 | 187 | ||
174 | const body = await servers[0].abuses.report({ token: userAccessToken, videoId: video.id, reason: 'super reason' }) | 188 | const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) |
175 | abuseId = body.abuse.id | 189 | abuseId = body.abuse.id |
176 | }) | 190 | }) |
177 | 191 | ||
@@ -205,7 +219,7 @@ describe('Test moderation notifications', function () { | |||
205 | server: servers[0], | 219 | server: servers[0], |
206 | emails, | 220 | emails, |
207 | socketNotifications: userNotifications, | 221 | socketNotifications: userNotifications, |
208 | token: userAccessToken | 222 | token: userToken1 |
209 | } | 223 | } |
210 | 224 | ||
211 | baseParamsAdmin = { | 225 | baseParamsAdmin = { |
@@ -216,15 +230,15 @@ describe('Test moderation notifications', function () { | |||
216 | } | 230 | } |
217 | 231 | ||
218 | const name = 'abuse ' + buildUUID() | 232 | const name = 'abuse ' + buildUUID() |
219 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 233 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
220 | 234 | ||
221 | { | 235 | { |
222 | const body = await servers[0].abuses.report({ token: userAccessToken, videoId: video.id, reason: 'super reason' }) | 236 | const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason' }) |
223 | abuseId = body.abuse.id | 237 | abuseId = body.abuse.id |
224 | } | 238 | } |
225 | 239 | ||
226 | { | 240 | { |
227 | const body = await servers[0].abuses.report({ token: userAccessToken, videoId: video.id, reason: 'super reason 2' }) | 241 | const body = await servers[0].abuses.report({ token: userToken1, videoId: video.id, reason: 'super reason 2' }) |
228 | abuseId2 = body.abuse.id | 242 | abuseId2 = body.abuse.id |
229 | } | 243 | } |
230 | }) | 244 | }) |
@@ -254,7 +268,7 @@ describe('Test moderation notifications', function () { | |||
254 | this.timeout(10000) | 268 | this.timeout(10000) |
255 | 269 | ||
256 | const message = 'my super message to moderators' | 270 | const message = 'my super message to moderators' |
257 | await servers[0].abuses.addMessage({ token: userAccessToken, abuseId: abuseId2, message }) | 271 | await servers[0].abuses.addMessage({ token: userToken1, abuseId: abuseId2, message }) |
258 | await waitJobs(servers) | 272 | await waitJobs(servers) |
259 | 273 | ||
260 | const toEmail = 'admin' + servers[0].internalServerNumber + '@example.com' | 274 | const toEmail = 'admin' + servers[0].internalServerNumber + '@example.com' |
@@ -265,7 +279,7 @@ describe('Test moderation notifications', function () { | |||
265 | this.timeout(10000) | 279 | this.timeout(10000) |
266 | 280 | ||
267 | const message = 'my super message that should not be sent to reporter' | 281 | const message = 'my super message that should not be sent to reporter' |
268 | await servers[0].abuses.addMessage({ token: userAccessToken, abuseId: abuseId2, message }) | 282 | await servers[0].abuses.addMessage({ token: userToken1, abuseId: abuseId2, message }) |
269 | await waitJobs(servers) | 283 | await waitJobs(servers) |
270 | 284 | ||
271 | const toEmail = 'user_1@example.com' | 285 | const toEmail = 'user_1@example.com' |
@@ -281,7 +295,7 @@ describe('Test moderation notifications', function () { | |||
281 | server: servers[0], | 295 | server: servers[0], |
282 | emails, | 296 | emails, |
283 | socketNotifications: userNotifications, | 297 | socketNotifications: userNotifications, |
284 | token: userAccessToken | 298 | token: userToken1 |
285 | } | 299 | } |
286 | }) | 300 | }) |
287 | 301 | ||
@@ -289,7 +303,7 @@ describe('Test moderation notifications', function () { | |||
289 | this.timeout(10000) | 303 | this.timeout(10000) |
290 | 304 | ||
291 | const name = 'video for abuse ' + buildUUID() | 305 | const name = 'video for abuse ' + buildUUID() |
292 | const { uuid, shortUUID } = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 306 | const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
293 | 307 | ||
294 | await servers[0].blacklist.add({ videoId: uuid }) | 308 | await servers[0].blacklist.add({ videoId: uuid }) |
295 | 309 | ||
@@ -301,7 +315,7 @@ describe('Test moderation notifications', function () { | |||
301 | this.timeout(10000) | 315 | this.timeout(10000) |
302 | 316 | ||
303 | const name = 'video for abuse ' + buildUUID() | 317 | const name = 'video for abuse ' + buildUUID() |
304 | const { uuid, shortUUID } = await servers[0].videos.upload({ token: userAccessToken, attributes: { name } }) | 318 | const { uuid, shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
305 | 319 | ||
306 | await servers[0].blacklist.add({ videoId: uuid }) | 320 | await servers[0].blacklist.add({ videoId: uuid }) |
307 | 321 | ||
@@ -335,7 +349,7 @@ describe('Test moderation notifications', function () { | |||
335 | 349 | ||
336 | await checkUserRegistered({ ...baseParams, username: 'user_45', checkType: 'presence' }) | 350 | await checkUserRegistered({ ...baseParams, username: 'user_45', checkType: 'presence' }) |
337 | 351 | ||
338 | const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } | 352 | const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } |
339 | await checkUserRegistered({ ...baseParams, ...userOverride, username: 'user_45', checkType: 'absence' }) | 353 | await checkUserRegistered({ ...baseParams, ...userOverride, username: 'user_45', checkType: 'absence' }) |
340 | }) | 354 | }) |
341 | }) | 355 | }) |
@@ -377,7 +391,7 @@ describe('Test moderation notifications', function () { | |||
377 | 391 | ||
378 | await checkNewInstanceFollower({ ...baseParams, followerHost: 'localhost:' + servers[2].port, checkType: 'presence' }) | 392 | await checkNewInstanceFollower({ ...baseParams, followerHost: 'localhost:' + servers[2].port, checkType: 'presence' }) |
379 | 393 | ||
380 | const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } | 394 | const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } |
381 | await checkNewInstanceFollower({ ...baseParams, ...userOverride, followerHost: 'localhost:' + servers[2].port, checkType: 'absence' }) | 395 | await checkNewInstanceFollower({ ...baseParams, ...userOverride, followerHost: 'localhost:' + servers[2].port, checkType: 'absence' }) |
382 | }) | 396 | }) |
383 | 397 | ||
@@ -404,7 +418,7 @@ describe('Test moderation notifications', function () { | |||
404 | const followingHost = servers[2].host | 418 | const followingHost = servers[2].host |
405 | await checkAutoInstanceFollowing({ ...baseParams, followerHost, followingHost, checkType: 'presence' }) | 419 | await checkAutoInstanceFollowing({ ...baseParams, followerHost, followingHost, checkType: 'presence' }) |
406 | 420 | ||
407 | const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } } | 421 | const userOverride = { socketNotifications: userNotifications, token: userToken1, check: { web: true, mail: false } } |
408 | await checkAutoInstanceFollowing({ ...baseParams, ...userOverride, followerHost, followingHost, checkType: 'absence' }) | 422 | await checkAutoInstanceFollowing({ ...baseParams, ...userOverride, followerHost, followingHost, checkType: 'absence' }) |
409 | 423 | ||
410 | config.followings.instance.autoFollowBack.enabled = false | 424 | config.followings.instance.autoFollowBack.enabled = false |
@@ -461,7 +475,7 @@ describe('Test moderation notifications', function () { | |||
461 | server: servers[0], | 475 | server: servers[0], |
462 | emails, | 476 | emails, |
463 | socketNotifications: userNotifications, | 477 | socketNotifications: userNotifications, |
464 | token: userAccessToken | 478 | token: userToken1 |
465 | } | 479 | } |
466 | 480 | ||
467 | currentCustomConfig = await servers[0].config.getCustomConfig() | 481 | currentCustomConfig = await servers[0].config.getCustomConfig() |
@@ -490,7 +504,7 @@ describe('Test moderation notifications', function () { | |||
490 | this.timeout(120000) | 504 | this.timeout(120000) |
491 | 505 | ||
492 | videoName = 'video with auto-blacklist ' + buildUUID() | 506 | videoName = 'video with auto-blacklist ' + buildUUID() |
493 | const video = await servers[0].videos.upload({ token: userAccessToken, attributes: { name: videoName } }) | 507 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name: videoName } }) |
494 | shortUUID = video.shortUUID | 508 | shortUUID = video.shortUUID |
495 | uuid = video.uuid | 509 | uuid = video.uuid |
496 | 510 | ||
@@ -547,7 +561,7 @@ describe('Test moderation notifications', function () { | |||
547 | } | 561 | } |
548 | } | 562 | } |
549 | 563 | ||
550 | const { shortUUID, uuid } = await servers[0].videos.upload({ token: userAccessToken, attributes }) | 564 | const { shortUUID, uuid } = await servers[0].videos.upload({ token: userToken1, attributes }) |
551 | 565 | ||
552 | await servers[0].blacklist.remove({ videoId: uuid }) | 566 | await servers[0].blacklist.remove({ videoId: uuid }) |
553 | 567 | ||
@@ -579,7 +593,7 @@ describe('Test moderation notifications', function () { | |||
579 | } | 593 | } |
580 | } | 594 | } |
581 | 595 | ||
582 | const { shortUUID } = await servers[0].videos.upload({ token: userAccessToken, attributes }) | 596 | const { shortUUID } = await servers[0].videos.upload({ token: userToken1, attributes }) |
583 | 597 | ||
584 | await wait(6000) | 598 | await wait(6000) |
585 | await checkVideoIsPublished({ ...userBaseParams, videoName: name, shortUUID, checkType: 'absence' }) | 599 | await checkVideoIsPublished({ ...userBaseParams, videoName: name, shortUUID, checkType: 'absence' }) |
diff --git a/server/tests/api/notifications/notifications-api.ts b/server/tests/api/notifications/notifications-api.ts index a529a9bf7..ac08449f8 100644 --- a/server/tests/api/notifications/notifications-api.ts +++ b/server/tests/api/notifications/notifications-api.ts | |||
@@ -5,14 +5,12 @@ import * as chai from 'chai' | |||
5 | import { | 5 | import { |
6 | CheckerBaseParams, | 6 | CheckerBaseParams, |
7 | checkNewVideoFromSubscription, | 7 | checkNewVideoFromSubscription, |
8 | cleanupTests, | ||
9 | getAllNotificationsSettings, | 8 | getAllNotificationsSettings, |
10 | MockSmtpServer, | 9 | MockSmtpServer, |
11 | PeerTubeServer, | 10 | prepareNotificationsTest |
12 | prepareNotificationsTest, | 11 | } from '@server/tests/shared' |
13 | waitJobs | ||
14 | } from '@shared/extra-utils' | ||
15 | import { UserNotification, UserNotificationSettingValue } from '@shared/models' | 12 | import { UserNotification, UserNotificationSettingValue } from '@shared/models' |
13 | import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' | ||
16 | 14 | ||
17 | const expect = chai.expect | 15 | const expect = chai.expect |
18 | 16 | ||
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts index 468efdf35..f9f3e0e0e 100644 --- a/server/tests/api/notifications/user-notifications.ts +++ b/server/tests/api/notifications/user-notifications.ts | |||
@@ -2,23 +2,21 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { buildUUID } from '@server/helpers/uuid' | ||
6 | import { | 5 | import { |
7 | CheckerBaseParams, | 6 | CheckerBaseParams, |
8 | checkMyVideoImportIsFinished, | 7 | checkMyVideoImportIsFinished, |
9 | checkNewActorFollow, | 8 | checkNewActorFollow, |
10 | checkNewVideoFromSubscription, | 9 | checkNewVideoFromSubscription, |
11 | checkVideoIsPublished, | 10 | checkVideoIsPublished, |
12 | cleanupTests, | ||
13 | FIXTURE_URLS, | 11 | FIXTURE_URLS, |
14 | MockSmtpServer, | 12 | MockSmtpServer, |
15 | PeerTubeServer, | ||
16 | prepareNotificationsTest, | 13 | prepareNotificationsTest, |
17 | uploadRandomVideoOnServers, | 14 | uploadRandomVideoOnServers |
18 | wait, | 15 | } from '@server/tests/shared' |
19 | waitJobs | 16 | import { wait } from '@shared/core-utils' |
20 | } from '@shared/extra-utils' | 17 | import { buildUUID } from '@shared/extra-utils' |
21 | import { UserNotification, UserNotificationType, VideoPrivacy } from '@shared/models' | 18 | import { UserNotification, UserNotificationType, VideoPrivacy } from '@shared/models' |
19 | import { cleanupTests, PeerTubeServer, waitJobs } from '@shared/server-commands' | ||
22 | 20 | ||
23 | const expect = chai.expect | 21 | const expect = chai.expect |
24 | 22 | ||
@@ -128,7 +126,7 @@ describe('Test user notifications', function () { | |||
128 | }) | 126 | }) |
129 | 127 | ||
130 | it('Should not send a notification before the video is published', async function () { | 128 | it('Should not send a notification before the video is published', async function () { |
131 | this.timeout(50000) | 129 | this.timeout(150000) |
132 | 130 | ||
133 | const updateAt = new Date(new Date().getTime() + 1000000) | 131 | const updateAt = new Date(new Date().getTime() + 1000000) |
134 | 132 | ||
@@ -267,7 +265,7 @@ describe('Test user notifications', function () { | |||
267 | }) | 265 | }) |
268 | 266 | ||
269 | it('Should send a notification when an imported video is transcoded', async function () { | 267 | it('Should send a notification when an imported video is transcoded', async function () { |
270 | this.timeout(50000) | 268 | this.timeout(120000) |
271 | 269 | ||
272 | const name = 'video import ' + buildUUID() | 270 | const name = 'video import ' + buildUUID() |
273 | 271 | ||
diff --git a/server/tests/api/object-storage/live.ts b/server/tests/api/object-storage/live.ts index 3726a717b..0cb0a6e34 100644 --- a/server/tests/api/object-storage/live.ts +++ b/server/tests/api/object-storage/live.ts | |||
@@ -3,11 +3,12 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { FfmpegCommand } from 'fluent-ffmpeg' | 5 | import { FfmpegCommand } from 'fluent-ffmpeg' |
6 | import { expectStartWith } from '@server/tests/shared' | ||
7 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
8 | import { HttpStatusCode, LiveVideoCreate, VideoFile, VideoPrivacy } from '@shared/models' | ||
6 | import { | 9 | import { |
7 | areObjectStorageTestsDisabled, | ||
8 | createMultipleServers, | 10 | createMultipleServers, |
9 | doubleFollow, | 11 | doubleFollow, |
10 | expectStartWith, | ||
11 | killallServers, | 12 | killallServers, |
12 | makeRawRequest, | 13 | makeRawRequest, |
13 | ObjectStorageCommand, | 14 | ObjectStorageCommand, |
@@ -18,8 +19,7 @@ import { | |||
18 | waitJobs, | 19 | waitJobs, |
19 | waitUntilLivePublishedOnAllServers, | 20 | waitUntilLivePublishedOnAllServers, |
20 | waitUntilLiveSavedOnAllServers | 21 | waitUntilLiveSavedOnAllServers |
21 | } from '@shared/extra-utils' | 22 | } from '@shared/server-commands' |
22 | import { HttpStatusCode, LiveVideoCreate, VideoFile, VideoPrivacy } from '@shared/models' | ||
23 | 23 | ||
24 | const expect = chai.expect | 24 | const expect = chai.expect |
25 | 25 | ||
diff --git a/server/tests/api/object-storage/video-imports.ts b/server/tests/api/object-storage/video-imports.ts index 363fe3b5b..fb81832af 100644 --- a/server/tests/api/object-storage/video-imports.ts +++ b/server/tests/api/object-storage/video-imports.ts | |||
@@ -2,11 +2,11 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { expectStartWith, FIXTURE_URLS } from '@server/tests/shared' | ||
6 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | areObjectStorageTestsDisabled, | ||
7 | createSingleServer, | 9 | createSingleServer, |
8 | expectStartWith, | ||
9 | FIXTURE_URLS, | ||
10 | killallServers, | 10 | killallServers, |
11 | makeRawRequest, | 11 | makeRawRequest, |
12 | ObjectStorageCommand, | 12 | ObjectStorageCommand, |
@@ -14,8 +14,7 @@ import { | |||
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | setDefaultVideoChannel, | 15 | setDefaultVideoChannel, |
16 | waitJobs | 16 | waitJobs |
17 | } from '@shared/extra-utils' | 17 | } from '@shared/server-commands' |
18 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
19 | 18 | ||
20 | const expect = chai.expect | 19 | const expect = chai.expect |
21 | 20 | ||
diff --git a/server/tests/api/object-storage/videos.ts b/server/tests/api/object-storage/videos.ts index 35a5f19ed..498efcb17 100644 --- a/server/tests/api/object-storage/videos.ts +++ b/server/tests/api/object-storage/videos.ts | |||
@@ -3,25 +3,22 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { merge } from 'lodash' | 5 | import { merge } from 'lodash' |
6 | import { checkTmpIsEmpty, expectLogDoesNotContain, expectStartWith, MockObjectStorage } from '@server/tests/shared' | ||
7 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
8 | import { HttpStatusCode, VideoDetails } from '@shared/models' | ||
6 | import { | 9 | import { |
7 | areObjectStorageTestsDisabled, | ||
8 | checkTmpIsEmpty, | ||
9 | cleanupTests, | 10 | cleanupTests, |
10 | createMultipleServers, | 11 | createMultipleServers, |
11 | createSingleServer, | 12 | createSingleServer, |
12 | doubleFollow, | 13 | doubleFollow, |
13 | expectLogDoesNotContain, | ||
14 | expectStartWith, | ||
15 | killallServers, | 14 | killallServers, |
16 | makeRawRequest, | 15 | makeRawRequest, |
17 | MockObjectStorage, | ||
18 | ObjectStorageCommand, | 16 | ObjectStorageCommand, |
19 | PeerTubeServer, | 17 | PeerTubeServer, |
20 | setAccessTokensToServers, | 18 | setAccessTokensToServers, |
21 | waitJobs, | 19 | waitJobs, |
22 | webtorrentAdd | 20 | webtorrentAdd |
23 | } from '@shared/extra-utils' | 21 | } from '@shared/server-commands' |
24 | import { HttpStatusCode, VideoDetails } from '@shared/models' | ||
25 | 22 | ||
26 | const expect = chai.expect | 23 | const expect = chai.expect |
27 | 24 | ||
diff --git a/server/tests/api/redundancy/manage-redundancy.ts b/server/tests/api/redundancy/manage-redundancy.ts index 5fd464ded..cbf3106bd 100644 --- a/server/tests/api/redundancy/manage-redundancy.ts +++ b/server/tests/api/redundancy/manage-redundancy.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | RedundancyCommand, | 10 | RedundancyCommand, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { VideoPrivacy, VideoRedundanciesTarget } from '@shared/models' | 14 | import { VideoPrivacy, VideoRedundanciesTarget } from '@shared/models' |
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
diff --git a/server/tests/api/redundancy/redundancy-constraints.ts b/server/tests/api/redundancy/redundancy-constraints.ts index 933a2c776..17c6b25a5 100644 --- a/server/tests/api/redundancy/redundancy-constraints.ts +++ b/server/tests/api/redundancy/redundancy-constraints.ts | |||
@@ -2,8 +2,15 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | ||
6 | import { VideoPrivacy } from '@shared/models' | 5 | import { VideoPrivacy } from '@shared/models' |
6 | import { | ||
7 | cleanupTests, | ||
8 | createSingleServer, | ||
9 | killallServers, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | waitJobs | ||
13 | } from '@shared/server-commands' | ||
7 | 14 | ||
8 | describe('Test redundancy constraints', function () { | 15 | describe('Test redundancy constraints', function () { |
9 | let remoteServer: PeerTubeServer | 16 | let remoteServer: PeerTubeServer |
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index 86b40cfe6..3f2286278 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts | |||
@@ -5,29 +5,26 @@ import * as chai from 'chai' | |||
5 | import { readdir } from 'fs-extra' | 5 | import { readdir } from 'fs-extra' |
6 | import magnetUtil from 'magnet-uri' | 6 | import magnetUtil from 'magnet-uri' |
7 | import { basename, join } from 'path' | 7 | import { basename, join } from 'path' |
8 | import { checkSegmentHash, checkVideoFilesWereRemoved, saveVideoInServers } from '@server/tests/shared' | ||
9 | import { root, wait } from '@shared/core-utils' | ||
10 | import { | ||
11 | HttpStatusCode, | ||
12 | VideoDetails, | ||
13 | VideoFile, | ||
14 | VideoPrivacy, | ||
15 | VideoRedundancyStrategy, | ||
16 | VideoRedundancyStrategyWithManual | ||
17 | } from '@shared/models' | ||
8 | import { | 18 | import { |
9 | checkSegmentHash, | ||
10 | checkVideoFilesWereRemoved, | ||
11 | cleanupTests, | 19 | cleanupTests, |
12 | createMultipleServers, | 20 | createMultipleServers, |
13 | doubleFollow, | 21 | doubleFollow, |
14 | killallServers, | 22 | killallServers, |
15 | makeRawRequest, | 23 | makeRawRequest, |
16 | PeerTubeServer, | 24 | PeerTubeServer, |
17 | root, | ||
18 | saveVideoInServers, | ||
19 | setAccessTokensToServers, | 25 | setAccessTokensToServers, |
20 | wait, | ||
21 | waitJobs | 26 | waitJobs |
22 | } from '@shared/extra-utils' | 27 | } from '@shared/server-commands' |
23 | import { | ||
24 | HttpStatusCode, | ||
25 | VideoDetails, | ||
26 | VideoFile, | ||
27 | VideoPrivacy, | ||
28 | VideoRedundancyStrategy, | ||
29 | VideoRedundancyStrategyWithManual | ||
30 | } from '@shared/models' | ||
31 | 28 | ||
32 | const expect = chai.expect | 29 | const expect = chai.expect |
33 | 30 | ||
@@ -307,7 +304,7 @@ describe('Test videos redundancy', function () { | |||
307 | const strategy = 'most-views' | 304 | const strategy = 'most-views' |
308 | 305 | ||
309 | before(function () { | 306 | before(function () { |
310 | this.timeout(120000) | 307 | this.timeout(240000) |
311 | 308 | ||
312 | return createServers(strategy) | 309 | return createServers(strategy) |
313 | }) | 310 | }) |
@@ -357,7 +354,7 @@ describe('Test videos redundancy', function () { | |||
357 | const strategy = 'trending' | 354 | const strategy = 'trending' |
358 | 355 | ||
359 | before(function () { | 356 | before(function () { |
360 | this.timeout(120000) | 357 | this.timeout(240000) |
361 | 358 | ||
362 | return createServers(strategy) | 359 | return createServers(strategy) |
363 | }) | 360 | }) |
@@ -420,7 +417,7 @@ describe('Test videos redundancy', function () { | |||
420 | const strategy = 'recently-added' | 417 | const strategy = 'recently-added' |
421 | 418 | ||
422 | before(function () { | 419 | before(function () { |
423 | this.timeout(120000) | 420 | this.timeout(240000) |
424 | 421 | ||
425 | return createServers(strategy, { min_views: 3 }) | 422 | return createServers(strategy, { min_views: 3 }) |
426 | }) | 423 | }) |
@@ -491,7 +488,7 @@ describe('Test videos redundancy', function () { | |||
491 | const strategy = 'recently-added' | 488 | const strategy = 'recently-added' |
492 | 489 | ||
493 | before(async function () { | 490 | before(async function () { |
494 | this.timeout(120000) | 491 | this.timeout(240000) |
495 | 492 | ||
496 | await createServers(strategy, { min_views: 3 }, false) | 493 | await createServers(strategy, { min_views: 3 }, false) |
497 | }) | 494 | }) |
@@ -553,7 +550,7 @@ describe('Test videos redundancy', function () { | |||
553 | 550 | ||
554 | describe('With manual strategy', function () { | 551 | describe('With manual strategy', function () { |
555 | before(function () { | 552 | before(function () { |
556 | this.timeout(120000) | 553 | this.timeout(240000) |
557 | 554 | ||
558 | return createServers(null) | 555 | return createServers(null) |
559 | }) | 556 | }) |
@@ -632,7 +629,7 @@ describe('Test videos redundancy', function () { | |||
632 | } | 629 | } |
633 | 630 | ||
634 | before(async function () { | 631 | before(async function () { |
635 | this.timeout(120000) | 632 | this.timeout(240000) |
636 | 633 | ||
637 | await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) | 634 | await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) |
638 | 635 | ||
@@ -674,7 +671,7 @@ describe('Test videos redundancy', function () { | |||
674 | const strategy = 'recently-added' | 671 | const strategy = 'recently-added' |
675 | 672 | ||
676 | before(async function () { | 673 | before(async function () { |
677 | this.timeout(120000) | 674 | this.timeout(240000) |
678 | 675 | ||
679 | await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) | 676 | await createServers(strategy, { min_lifetime: '7 seconds', min_views: 0 }) |
680 | 677 | ||
@@ -698,7 +695,7 @@ describe('Test videos redundancy', function () { | |||
698 | }) | 695 | }) |
699 | 696 | ||
700 | it('Should cache video 2 webseeds on the first video', async function () { | 697 | it('Should cache video 2 webseeds on the first video', async function () { |
701 | this.timeout(120000) | 698 | this.timeout(240000) |
702 | 699 | ||
703 | await waitJobs(servers) | 700 | await waitJobs(servers) |
704 | 701 | ||
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts index efcdb33dc..2e0abc6ba 100644 --- a/server/tests/api/search/search-activitypub-video-channels.ts +++ b/server/tests/api/search/search-activitypub-video-channels.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { VideoChannel } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | PeerTubeServer, | 10 | PeerTubeServer, |
9 | SearchCommand, | 11 | SearchCommand, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | wait, | ||
12 | waitJobs | 13 | waitJobs |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { VideoChannel } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/api/search/search-activitypub-video-playlists.ts b/server/tests/api/search/search-activitypub-video-playlists.ts index 34b318268..d9243ac53 100644 --- a/server/tests/api/search/search-activitypub-video-playlists.ts +++ b/server/tests/api/search/search-activitypub-video-playlists.ts | |||
@@ -2,6 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { VideoPlaylistPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
@@ -9,10 +11,8 @@ import { | |||
9 | SearchCommand, | 11 | SearchCommand, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
12 | wait, | ||
13 | waitJobs | 14 | waitJobs |
14 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { VideoPlaylistPrivacy } from '@shared/models' | ||
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
18 | 18 | ||
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts index a2e6e70fe..60b95ae4c 100644 --- a/server/tests/api/search/search-activitypub-videos.ts +++ b/server/tests/api/search/search-activitypub-videos.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { VideoPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | PeerTubeServer, | 10 | PeerTubeServer, |
9 | SearchCommand, | 11 | SearchCommand, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | wait, | ||
12 | waitJobs | 13 | waitJobs |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { VideoPrivacy } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/api/search/search-channels.ts b/server/tests/api/search/search-channels.ts index 67612537c..8a92def61 100644 --- a/server/tests/api/search/search-channels.ts +++ b/server/tests/api/search/search-channels.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | SearchCommand, | 10 | SearchCommand, |
11 | setAccessTokensToServers | 11 | setAccessTokensToServers |
12 | } from '@shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | import { VideoChannel } from '@shared/models' | 13 | import { VideoChannel } from '@shared/models' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
diff --git a/server/tests/api/search/search-index.ts b/server/tests/api/search/search-index.ts index 1845c2069..f84d03345 100644 --- a/server/tests/api/search/search-index.ts +++ b/server/tests/api/search/search-index.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, SearchCommand, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, PeerTubeServer, SearchCommand, setAccessTokensToServers } from '@shared/server-commands' |
6 | import { | 6 | import { |
7 | BooleanBothQuery, | 7 | BooleanBothQuery, |
8 | VideoChannelsSearchQuery, | 8 | VideoChannelsSearchQuery, |
diff --git a/server/tests/api/search/search-playlists.ts b/server/tests/api/search/search-playlists.ts index 15aac029a..1e9c8d4bb 100644 --- a/server/tests/api/search/search-playlists.ts +++ b/server/tests/api/search/search-playlists.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | SearchCommand, | 10 | SearchCommand, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | setDefaultVideoChannel | 12 | setDefaultVideoChannel |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { VideoPlaylistPrivacy } from '@shared/models' | 14 | import { VideoPlaylistPrivacy } from '@shared/models' |
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts index ad2a2fddc..c544705d3 100644 --- a/server/tests/api/search/search-videos.ts +++ b/server/tests/api/search/search-videos.ts | |||
@@ -10,10 +10,10 @@ import { | |||
10 | SearchCommand, | 10 | SearchCommand, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | setDefaultVideoChannel, | 12 | setDefaultVideoChannel, |
13 | stopFfmpeg, | 13 | stopFfmpeg |
14 | wait | 14 | } from '@shared/server-commands' |
15 | } from '@shared/extra-utils' | ||
16 | import { VideoPrivacy } from '@shared/models' | 15 | import { VideoPrivacy } from '@shared/models' |
16 | import { wait } from '@shared/core-utils' | ||
17 | 17 | ||
18 | const expect = chai.expect | 18 | const expect = chai.expect |
19 | 19 | ||
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts index 90a668edb..6d2333a6b 100644 --- a/server/tests/api/server/auto-follows.ts +++ b/server/tests/api/server/auto-follows.ts | |||
@@ -2,15 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { | 5 | import { MockInstancesIndex } from '@server/tests/shared' |
6 | cleanupTests, | 6 | import { wait } from '@shared/core-utils' |
7 | createMultipleServers, | 7 | import { cleanupTests, createMultipleServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' |
8 | MockInstancesIndex, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | wait, | ||
12 | waitJobs | ||
13 | } from '@shared/extra-utils' | ||
14 | 8 | ||
15 | const expect = chai.expect | 9 | const expect = chai.expect |
16 | 10 | ||
diff --git a/server/tests/api/server/bulk.ts b/server/tests/api/server/bulk.ts index 16cbcd5c3..1b81a6954 100644 --- a/server/tests/api/server/bulk.ts +++ b/server/tests/api/server/bulk.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
16 | 16 | ||
diff --git a/server/tests/api/server/config-defaults.ts b/server/tests/api/server/config-defaults.ts new file mode 100644 index 000000000..3ff09bf7e --- /dev/null +++ b/server/tests/api/server/config-defaults.ts | |||
@@ -0,0 +1,213 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import * as chai from 'chai' | ||
5 | import { FIXTURE_URLS } from '@server/tests/shared' | ||
6 | import { VideoDetails, VideoPrivacy } from '@shared/models' | ||
7 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' | ||
8 | |||
9 | const expect = chai.expect | ||
10 | |||
11 | describe('Test config defaults', function () { | ||
12 | let server: PeerTubeServer | ||
13 | let channelId: number | ||
14 | |||
15 | before(async function () { | ||
16 | this.timeout(30000) | ||
17 | |||
18 | server = await createSingleServer(1) | ||
19 | await setAccessTokensToServers([ server ]) | ||
20 | await setDefaultVideoChannel([ server ]) | ||
21 | |||
22 | channelId = server.store.channel.id | ||
23 | }) | ||
24 | |||
25 | describe('Default publish values', function () { | ||
26 | |||
27 | before(async function () { | ||
28 | const overrideConfig = { | ||
29 | defaults: { | ||
30 | publish: { | ||
31 | comments_enabled: false, | ||
32 | download_enabled: false, | ||
33 | privacy: VideoPrivacy.INTERNAL, | ||
34 | licence: 4 | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | await server.kill() | ||
40 | await server.run(overrideConfig) | ||
41 | }) | ||
42 | |||
43 | const attributes = { | ||
44 | name: 'video', | ||
45 | downloadEnabled: undefined, | ||
46 | commentsEnabled: undefined, | ||
47 | licence: undefined, | ||
48 | privacy: VideoPrivacy.PUBLIC // Privacy is mandatory for server | ||
49 | } | ||
50 | |||
51 | function checkVideo (video: VideoDetails) { | ||
52 | expect(video.downloadEnabled).to.be.false | ||
53 | expect(video.commentsEnabled).to.be.false | ||
54 | expect(video.licence.id).to.equal(4) | ||
55 | } | ||
56 | |||
57 | before(async function () { | ||
58 | await server.config.disableTranscoding() | ||
59 | await server.config.enableImports() | ||
60 | await server.config.enableLive({ allowReplay: false, transcoding: false }) | ||
61 | }) | ||
62 | |||
63 | it('Should have the correct server configuration', async function () { | ||
64 | const config = await server.config.getConfig() | ||
65 | |||
66 | expect(config.defaults.publish.commentsEnabled).to.be.false | ||
67 | expect(config.defaults.publish.downloadEnabled).to.be.false | ||
68 | expect(config.defaults.publish.licence).to.equal(4) | ||
69 | expect(config.defaults.publish.privacy).to.equal(VideoPrivacy.INTERNAL) | ||
70 | }) | ||
71 | |||
72 | it('Should respect default values when uploading a video', async function () { | ||
73 | for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) { | ||
74 | const { id } = await server.videos.upload({ attributes, mode }) | ||
75 | |||
76 | const video = await server.videos.get({ id }) | ||
77 | checkVideo(video) | ||
78 | } | ||
79 | }) | ||
80 | |||
81 | it('Should respect default values when importing a video using URL', async function () { | ||
82 | const { video: { id } } = await server.imports.importVideo({ | ||
83 | attributes: { | ||
84 | ...attributes, | ||
85 | channelId, | ||
86 | targetUrl: FIXTURE_URLS.goodVideo | ||
87 | } | ||
88 | }) | ||
89 | |||
90 | const video = await server.videos.get({ id }) | ||
91 | checkVideo(video) | ||
92 | }) | ||
93 | |||
94 | it('Should respect default values when importing a video using magnet URI', async function () { | ||
95 | const { video: { id } } = await server.imports.importVideo({ | ||
96 | attributes: { | ||
97 | ...attributes, | ||
98 | channelId, | ||
99 | magnetUri: FIXTURE_URLS.magnet | ||
100 | } | ||
101 | }) | ||
102 | |||
103 | const video = await server.videos.get({ id }) | ||
104 | checkVideo(video) | ||
105 | }) | ||
106 | |||
107 | it('Should respect default values when creating a live', async function () { | ||
108 | const { id } = await server.live.create({ | ||
109 | fields: { | ||
110 | ...attributes, | ||
111 | channelId | ||
112 | } | ||
113 | }) | ||
114 | |||
115 | const video = await server.videos.get({ id }) | ||
116 | checkVideo(video) | ||
117 | }) | ||
118 | }) | ||
119 | |||
120 | describe('Default P2P values', function () { | ||
121 | |||
122 | describe('Webapp default value', function () { | ||
123 | |||
124 | before(async function () { | ||
125 | const overrideConfig = { | ||
126 | defaults: { | ||
127 | p2p: { | ||
128 | webapp: { | ||
129 | enabled: false | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | await server.kill() | ||
136 | await server.run(overrideConfig) | ||
137 | }) | ||
138 | |||
139 | it('Should have appropriate P2P config', async function () { | ||
140 | const config = await server.config.getConfig() | ||
141 | |||
142 | expect(config.defaults.p2p.webapp.enabled).to.be.false | ||
143 | expect(config.defaults.p2p.embed.enabled).to.be.true | ||
144 | }) | ||
145 | |||
146 | it('Should create a user with this default setting', async function () { | ||
147 | await server.users.create({ username: 'user_p2p_1' }) | ||
148 | const userToken = await server.login.getAccessToken('user_p2p_1') | ||
149 | |||
150 | const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
151 | expect(p2pEnabled).to.be.false | ||
152 | }) | ||
153 | |||
154 | it('Should register a user with this default setting', async function () { | ||
155 | await server.users.register({ username: 'user_p2p_2' }) | ||
156 | |||
157 | const userToken = await server.login.getAccessToken('user_p2p_2') | ||
158 | |||
159 | const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
160 | expect(p2pEnabled).to.be.false | ||
161 | }) | ||
162 | }) | ||
163 | |||
164 | describe('Embed default value', function () { | ||
165 | |||
166 | before(async function () { | ||
167 | const overrideConfig = { | ||
168 | defaults: { | ||
169 | p2p: { | ||
170 | embed: { | ||
171 | enabled: false | ||
172 | } | ||
173 | } | ||
174 | }, | ||
175 | signup: { | ||
176 | limit: 15 | ||
177 | } | ||
178 | } | ||
179 | |||
180 | await server.kill() | ||
181 | await server.run(overrideConfig) | ||
182 | }) | ||
183 | |||
184 | it('Should have appropriate P2P config', async function () { | ||
185 | const config = await server.config.getConfig() | ||
186 | |||
187 | expect(config.defaults.p2p.webapp.enabled).to.be.true | ||
188 | expect(config.defaults.p2p.embed.enabled).to.be.false | ||
189 | }) | ||
190 | |||
191 | it('Should create a user with this default setting', async function () { | ||
192 | await server.users.create({ username: 'user_p2p_3' }) | ||
193 | const userToken = await server.login.getAccessToken('user_p2p_3') | ||
194 | |||
195 | const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
196 | expect(p2pEnabled).to.be.true | ||
197 | }) | ||
198 | |||
199 | it('Should register a user with this default setting', async function () { | ||
200 | await server.users.register({ username: 'user_p2p_4' }) | ||
201 | |||
202 | const userToken = await server.login.getAccessToken('user_p2p_4') | ||
203 | |||
204 | const { p2pEnabled } = await server.users.getMyInfo({ token: userToken }) | ||
205 | expect(p2pEnabled).to.be.true | ||
206 | }) | ||
207 | }) | ||
208 | }) | ||
209 | |||
210 | after(async function () { | ||
211 | await cleanupTests([ server ]) | ||
212 | }) | ||
213 | }) | ||
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index ea524723c..2356f701c 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { parallelTests } from '@shared/core-utils' | ||
6 | import { CustomConfig, HttpStatusCode } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createSingleServer, | 9 | createSingleServer, |
8 | killallServers, | 10 | killallServers, |
9 | makeGetRequest, | 11 | makeGetRequest, |
10 | parallelTests, | ||
11 | PeerTubeServer, | 12 | PeerTubeServer, |
12 | setAccessTokensToServers | 13 | setAccessTokensToServers |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { CustomConfig, HttpStatusCode } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
@@ -43,6 +43,9 @@ function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) { | |||
43 | expect(data.services.twitter.username).to.equal('@Chocobozzz') | 43 | expect(data.services.twitter.username).to.equal('@Chocobozzz') |
44 | expect(data.services.twitter.whitelisted).to.be.false | 44 | expect(data.services.twitter.whitelisted).to.be.false |
45 | 45 | ||
46 | expect(data.client.videos.miniature.preferAuthorDisplayName).to.be.false | ||
47 | expect(data.client.menu.login.redirectOnSingleExternalAuth).to.be.false | ||
48 | |||
46 | expect(data.cache.previews.size).to.equal(1) | 49 | expect(data.cache.previews.size).to.equal(1) |
47 | expect(data.cache.captions.size).to.equal(1) | 50 | expect(data.cache.captions.size).to.equal(1) |
48 | expect(data.cache.torrents.size).to.equal(1) | 51 | expect(data.cache.torrents.size).to.equal(1) |
@@ -138,6 +141,9 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
138 | expect(data.services.twitter.username).to.equal('@Kuja') | 141 | expect(data.services.twitter.username).to.equal('@Kuja') |
139 | expect(data.services.twitter.whitelisted).to.be.true | 142 | expect(data.services.twitter.whitelisted).to.be.true |
140 | 143 | ||
144 | expect(data.client.videos.miniature.preferAuthorDisplayName).to.be.true | ||
145 | expect(data.client.menu.login.redirectOnSingleExternalAuth).to.be.true | ||
146 | |||
141 | expect(data.cache.previews.size).to.equal(2) | 147 | expect(data.cache.previews.size).to.equal(2) |
142 | expect(data.cache.captions.size).to.equal(3) | 148 | expect(data.cache.captions.size).to.equal(3) |
143 | expect(data.cache.torrents.size).to.equal(4) | 149 | expect(data.cache.torrents.size).to.equal(4) |
@@ -246,6 +252,18 @@ const newCustomConfig: CustomConfig = { | |||
246 | whitelisted: true | 252 | whitelisted: true |
247 | } | 253 | } |
248 | }, | 254 | }, |
255 | client: { | ||
256 | videos: { | ||
257 | miniature: { | ||
258 | preferAuthorDisplayName: true | ||
259 | } | ||
260 | }, | ||
261 | menu: { | ||
262 | login: { | ||
263 | redirectOnSingleExternalAuth: true | ||
264 | } | ||
265 | } | ||
266 | }, | ||
249 | cache: { | 267 | cache: { |
250 | previews: { | 268 | previews: { |
251 | size: 2 | 269 | size: 2 |
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index c555661ad..f3facb04a 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts | |||
@@ -2,17 +2,17 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { MockSmtpServer } from '@server/tests/shared' | ||
6 | import { wait } from '@shared/core-utils' | ||
7 | import { HttpStatusCode } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | cleanupTests, | 9 | cleanupTests, |
7 | ContactFormCommand, | 10 | ContactFormCommand, |
8 | createSingleServer, | 11 | createSingleServer, |
9 | MockSmtpServer, | ||
10 | PeerTubeServer, | 12 | PeerTubeServer, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
12 | wait, | ||
13 | waitJobs | 14 | waitJobs |
14 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { HttpStatusCode } from '@shared/models' | ||
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
18 | 18 | ||
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index 5f97edbc2..20b5e378c 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, MockSmtpServer, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { MockSmtpServer } from '@server/tests/shared' |
6 | import { HttpStatusCode } from '@shared/models' | 6 | import { HttpStatusCode } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' | ||
7 | 8 | ||
8 | const expect = chai.expect | 9 | const expect = chai.expect |
9 | 10 | ||
@@ -185,7 +186,7 @@ describe('Test emails', function () { | |||
185 | this.timeout(10000) | 186 | this.timeout(10000) |
186 | 187 | ||
187 | const reason = 'my super bad reason' | 188 | const reason = 'my super bad reason' |
188 | await server.abuses.report({ videoId, reason }) | 189 | await server.abuses.report({ token: userAccessToken, videoId, reason }) |
189 | 190 | ||
190 | await waitJobs(server) | 191 | await waitJobs(server) |
191 | expect(emails).to.have.lengthOf(3) | 192 | expect(emails).to.have.lengthOf(3) |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 471f5d8d0..455fbc762 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
6 | import { HttpStatusCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' | 6 | import { HttpStatusCode, PeerTubeProblemDocument, ServerErrorCode } from '@shared/models' |
7 | 7 | ||
8 | const expect = chai.expect | 8 | const expect = chai.expect |
@@ -14,7 +14,7 @@ describe('Test follow constraints', function () { | |||
14 | let userToken: string | 14 | let userToken: string |
15 | 15 | ||
16 | before(async function () { | 16 | before(async function () { |
17 | this.timeout(90000) | 17 | this.timeout(240000) |
18 | 18 | ||
19 | servers = await createMultipleServers(2) | 19 | servers = await createMultipleServers(2) |
20 | 20 | ||
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts index 921f51043..120bd7f88 100644 --- a/server/tests/api/server/follows-moderation.ts +++ b/server/tests/api/server/follows-moderation.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
11 | waitJobs | 11 | waitJobs |
12 | } from '@shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | 13 | ||
14 | const expect = chai.expect | 14 | const expect = chai.expect |
15 | 15 | ||
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts index 832ba561a..c588cf664 100644 --- a/server/tests/api/server/follows.ts +++ b/server/tests/api/server/follows.ts | |||
@@ -2,19 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { | 5 | import { completeVideoCheck, dateIsValid, expectAccountFollows, expectChannelsFollows, testCaptionFile } from '@server/tests/shared' |
6 | cleanupTests, | ||
7 | completeVideoCheck, | ||
8 | createMultipleServers, | ||
9 | dateIsValid, | ||
10 | expectAccountFollows, | ||
11 | expectChannelsFollows, | ||
12 | PeerTubeServer, | ||
13 | setAccessTokensToServers, | ||
14 | testCaptionFile, | ||
15 | waitJobs | ||
16 | } from '@shared/extra-utils' | ||
17 | import { VideoCreateResult, VideoPrivacy } from '@shared/models' | 6 | import { VideoCreateResult, VideoPrivacy } from '@shared/models' |
7 | import { cleanupTests, createMultipleServers, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' | ||
18 | 8 | ||
19 | const expect = chai.expect | 9 | const expect = chai.expect |
20 | 10 | ||
@@ -22,7 +12,7 @@ describe('Test follows', function () { | |||
22 | let servers: PeerTubeServer[] = [] | 12 | let servers: PeerTubeServer[] = [] |
23 | 13 | ||
24 | before(async function () { | 14 | before(async function () { |
25 | this.timeout(30000) | 15 | this.timeout(120000) |
26 | 16 | ||
27 | servers = await createMultipleServers(3) | 17 | servers = await createMultipleServers(3) |
28 | 18 | ||
@@ -292,7 +282,7 @@ describe('Test follows', function () { | |||
292 | }) | 282 | }) |
293 | 283 | ||
294 | it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { | 284 | it('Should upload a video on server 2 and 3 and propagate only the video of server 2', async function () { |
295 | this.timeout(60000) | 285 | this.timeout(120000) |
296 | 286 | ||
297 | await servers[1].videos.upload({ attributes: { name: 'server2' } }) | 287 | await servers[1].videos.upload({ attributes: { name: 'server2' } }) |
298 | await servers[2].videos.upload({ attributes: { name: 'server3' } }) | 288 | await servers[2].videos.upload({ attributes: { name: 'server3' } }) |
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index fa1da8fe0..3dcd076f5 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts | |||
@@ -2,18 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { completeVideoCheck } from '@server/tests/shared' | ||
6 | import { wait } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, JobState, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | cleanupTests, | 9 | cleanupTests, |
7 | CommentsCommand, | 10 | CommentsCommand, |
8 | completeVideoCheck, | ||
9 | createMultipleServers, | 11 | createMultipleServers, |
10 | killallServers, | 12 | killallServers, |
11 | PeerTubeServer, | 13 | PeerTubeServer, |
12 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
13 | wait, | ||
14 | waitJobs | 15 | waitJobs |
15 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, JobState, VideoCreateResult, VideoPrivacy } from '@shared/models' | ||
17 | 17 | ||
18 | const expect = chai.expect | 18 | const expect = chai.expect |
19 | 19 | ||
@@ -50,7 +50,7 @@ describe('Test handle downs', function () { | |||
50 | let commentCommands: CommentsCommand[] | 50 | let commentCommands: CommentsCommand[] |
51 | 51 | ||
52 | before(async function () { | 52 | before(async function () { |
53 | this.timeout(30000) | 53 | this.timeout(120000) |
54 | 54 | ||
55 | servers = await createMultipleServers(3) | 55 | servers = await createMultipleServers(3) |
56 | commentCommands = servers.map(s => s.comments) | 56 | commentCommands = servers.map(s => s.comments) |
diff --git a/server/tests/api/server/homepage.ts b/server/tests/api/server/homepage.ts index cb3ba5677..552ee98cf 100644 --- a/server/tests/api/server/homepage.ts +++ b/server/tests/api/server/homepage.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | killallServers, | 10 | killallServers, |
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | setAccessTokensToServers | 12 | setAccessTokensToServers |
13 | } from '../../../../shared/extra-utils/index' | 13 | } from '../../../../shared/server-commands/index' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
16 | 16 | ||
diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts index 8136fc3c6..45be107ce 100644 --- a/server/tests/api/server/index.ts +++ b/server/tests/api/server/index.ts | |||
@@ -1,4 +1,6 @@ | |||
1 | import './auto-follows' | 1 | import './auto-follows' |
2 | import './bulk' | ||
3 | import './config-defaults' | ||
2 | import './config' | 4 | import './config' |
3 | import './contact-form' | 5 | import './contact-form' |
4 | import './email' | 6 | import './email' |
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts index 5d946f5e8..4294e1fd5 100644 --- a/server/tests/api/server/jobs.ts +++ b/server/tests/api/server/jobs.ts | |||
@@ -2,15 +2,15 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { dateIsValid } from '@server/tests/shared' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | 7 | cleanupTests, |
7 | createMultipleServers, | 8 | createMultipleServers, |
8 | dateIsValid, | ||
9 | doubleFollow, | 9 | doubleFollow, |
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
16 | 16 | ||
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts index 4fa13886e..697f10337 100644 --- a/server/tests/api/server/logs.ts +++ b/server/tests/api/server/logs.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
12 | waitJobs | 12 | waitJobs |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
16 | 16 | ||
diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts index 1e0c95a3b..913907788 100644 --- a/server/tests/api/server/no-client.ts +++ b/server/tests/api/server/no-client.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import 'mocha' | 1 | import 'mocha' |
2 | import request from 'supertest' | 2 | import request from 'supertest' |
3 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/extra-utils' | 3 | import { cleanupTests, createSingleServer, PeerTubeServer } from '@shared/server-commands' |
4 | import { HttpStatusCode } from '@shared/models' | 4 | import { HttpStatusCode } from '@shared/models' |
5 | 5 | ||
6 | describe('Start and stop server without web client routes', function () { | 6 | describe('Start and stop server without web client routes', function () { |
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts index 5f9f4ffdd..76d3e2481 100644 --- a/server/tests/api/server/plugins.ts +++ b/server/tests/api/server/plugins.ts | |||
@@ -2,17 +2,17 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { testHelloWorldRegisteredSettings } from '@server/tests/shared' | ||
6 | import { wait } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, PluginType } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | cleanupTests, | 9 | cleanupTests, |
7 | createSingleServer, | 10 | createSingleServer, |
8 | killallServers, | 11 | killallServers, |
9 | PeerTubeServer, | 12 | PeerTubeServer, |
10 | PluginsCommand, | 13 | PluginsCommand, |
11 | setAccessTokensToServers, | 14 | setAccessTokensToServers |
12 | testHelloWorldRegisteredSettings, | 15 | } from '@shared/server-commands' |
13 | wait | ||
14 | } from '@shared/extra-utils' | ||
15 | import { HttpStatusCode, PluginType } from '@shared/models' | ||
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
18 | 18 | ||
@@ -99,9 +99,11 @@ describe('Test plugins', function () { | |||
99 | 99 | ||
100 | const theme = config.theme.registered.find(r => r.name === 'background-red') | 100 | const theme = config.theme.registered.find(r => r.name === 'background-red') |
101 | expect(theme).to.not.be.undefined | 101 | expect(theme).to.not.be.undefined |
102 | expect(theme.npmName).to.equal('peertube-theme-background-red') | ||
102 | 103 | ||
103 | const plugin = config.plugin.registered.find(r => r.name === 'hello-world') | 104 | const plugin = config.plugin.registered.find(r => r.name === 'hello-world') |
104 | expect(plugin).to.not.be.undefined | 105 | expect(plugin).to.not.be.undefined |
106 | expect(plugin.npmName).to.equal('peertube-plugin-hello-world') | ||
105 | }) | 107 | }) |
106 | 108 | ||
107 | it('Should update the default theme in the configuration', async function () { | 109 | it('Should update the default theme in the configuration', async function () { |
diff --git a/server/tests/api/server/proxy.ts b/server/tests/api/server/proxy.ts index 29f3e10d8..2a8ff56d2 100644 --- a/server/tests/api/server/proxy.ts +++ b/server/tests/api/server/proxy.ts | |||
@@ -2,18 +2,17 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { FIXTURE_URLS, MockProxy } from '@server/tests/shared' | ||
6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | doubleFollow, | 10 | doubleFollow, |
9 | FIXTURE_URLS, | ||
10 | PeerTubeServer, | 11 | PeerTubeServer, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
13 | waitJobs | 14 | waitJobs |
14 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { MockProxy } from '@shared/extra-utils/mock-servers/mock-proxy' | ||
16 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | ||
17 | 16 | ||
18 | const expect = chai.expect | 17 | const expect = chai.expect |
19 | 18 | ||
@@ -97,7 +96,7 @@ describe('Test proxy', function () { | |||
97 | } | 96 | } |
98 | 97 | ||
99 | it('Should succeed import with the appropriate proxy config', async function () { | 98 | it('Should succeed import with the appropriate proxy config', async function () { |
100 | this.timeout(40000) | 99 | this.timeout(120000) |
101 | 100 | ||
102 | await servers[0].kill() | 101 | await servers[0].kill() |
103 | await servers[0].run({}, { env: goodEnv }) | 102 | await servers[0].run({}, { env: goodEnv }) |
@@ -112,7 +111,7 @@ describe('Test proxy', function () { | |||
112 | }) | 111 | }) |
113 | 112 | ||
114 | it('Should fail import with a wrong proxy config', async function () { | 113 | it('Should fail import with a wrong proxy config', async function () { |
115 | this.timeout(40000) | 114 | this.timeout(120000) |
116 | 115 | ||
117 | await servers[0].kill() | 116 | await servers[0].kill() |
118 | await servers[0].run({}, { env: badEnv }) | 117 | await servers[0].run({}, { env: badEnv }) |
diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts index 484f88d67..968d98e96 100644 --- a/server/tests/api/server/reverse-proxy.ts +++ b/server/tests/api/server/reverse-proxy.ts | |||
@@ -1,8 +1,9 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { expect } from 'chai' | 3 | import { expect } from 'chai' |
4 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, wait } from '@shared/extra-utils' | 4 | import { wait } from '@shared/core-utils' |
5 | import { HttpStatusCode } from '@shared/models' | 5 | import { HttpStatusCode } from '@shared/models' |
6 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
6 | 7 | ||
7 | describe('Test application behind a reverse proxy', function () { | 8 | describe('Test application behind a reverse proxy', function () { |
8 | let server: PeerTubeServer | 9 | let server: PeerTubeServer |
diff --git a/server/tests/api/server/services.ts b/server/tests/api/server/services.ts index 823630ae4..5fd2abda4 100644 --- a/server/tests/api/server/services.ts +++ b/server/tests/api/server/services.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' |
6 | import { Video, VideoPlaylistPrivacy } from '@shared/models' | 6 | import { Video, VideoPlaylistPrivacy } from '@shared/models' |
7 | 7 | ||
8 | const expect = chai.expect | 8 | const expect = chai.expect |
diff --git a/server/tests/api/server/slow-follows.ts b/server/tests/api/server/slow-follows.ts index 2bef0c9f2..666a7c2e6 100644 --- a/server/tests/api/server/slow-follows.ts +++ b/server/tests/api/server/slow-follows.ts | |||
@@ -2,8 +2,15 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | ||
6 | import { Job } from '@shared/models' | 5 | import { Job } from '@shared/models' |
6 | import { | ||
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | waitJobs | ||
13 | } from '@shared/server-commands' | ||
7 | 14 | ||
8 | const expect = chai.expect | 15 | const expect = chai.expect |
9 | 16 | ||
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts index efc80463c..f0334532b 100644 --- a/server/tests/api/server/stats.ts +++ b/server/tests/api/server/stats.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { ActivityType, VideoPlaylistPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | doubleFollow, | 10 | doubleFollow, |
9 | PeerTubeServer, | 11 | PeerTubeServer, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | wait, | ||
12 | waitJobs | 13 | waitJobs |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { ActivityType, VideoPlaylistPrivacy } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/api/server/tracker.ts b/server/tests/api/server/tracker.ts index 30a9618b3..712bb485f 100644 --- a/server/tests/api/server/tracker.ts +++ b/server/tests/api/server/tracker.ts | |||
@@ -3,7 +3,7 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import magnetUtil from 'magnet-uri' | 4 | import magnetUtil from 'magnet-uri' |
5 | import WebTorrent from 'webtorrent' | 5 | import WebTorrent from 'webtorrent' |
6 | import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 6 | import { cleanupTests, createSingleServer, killallServers, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
7 | 7 | ||
8 | describe('Test tracker', function () { | 8 | describe('Test tracker', function () { |
9 | let server: PeerTubeServer | 9 | let server: PeerTubeServer |
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts index d1d192238..57cca6ad4 100644 --- a/server/tests/api/users/user-subscriptions.ts +++ b/server/tests/api/users/user-subscriptions.ts | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { VideoPrivacy } from '@shared/models' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | 7 | cleanupTests, |
7 | createMultipleServers, | 8 | createMultipleServers, |
@@ -10,7 +11,7 @@ import { | |||
10 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
11 | SubscriptionsCommand, | 12 | SubscriptionsCommand, |
12 | waitJobs | 13 | waitJobs |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | 15 | ||
15 | const expect = chai.expect | 16 | const expect = chai.expect |
16 | 17 | ||
@@ -32,20 +33,18 @@ describe('Test users subscriptions', function () { | |||
32 | // Server 1 and server 2 follow each other | 33 | // Server 1 and server 2 follow each other |
33 | await doubleFollow(servers[0], servers[1]) | 34 | await doubleFollow(servers[0], servers[1]) |
34 | 35 | ||
35 | { | 36 | for (const server of servers) { |
36 | for (const server of servers) { | 37 | const user = { username: 'user' + server.serverNumber, password: 'password' } |
37 | const user = { username: 'user' + server.serverNumber, password: 'password' } | 38 | await server.users.create({ username: user.username, password: user.password }) |
38 | await server.users.create({ username: user.username, password: user.password }) | ||
39 | 39 | ||
40 | const accessToken = await server.login.getAccessToken(user) | 40 | const accessToken = await server.login.getAccessToken(user) |
41 | users.push({ accessToken }) | 41 | users.push({ accessToken }) |
42 | 42 | ||
43 | const videoName1 = 'video 1-' + server.serverNumber | 43 | const videoName1 = 'video 1-' + server.serverNumber |
44 | await server.videos.upload({ token: accessToken, attributes: { name: videoName1 } }) | 44 | await server.videos.upload({ token: accessToken, attributes: { name: videoName1 } }) |
45 | 45 | ||
46 | const videoName2 = 'video 2-' + server.serverNumber | 46 | const videoName2 = 'video 2-' + server.serverNumber |
47 | await server.videos.upload({ token: accessToken, attributes: { name: videoName2 } }) | 47 | await server.videos.upload({ token: accessToken, attributes: { name: videoName2 } }) |
48 | } | ||
49 | } | 48 | } |
50 | 49 | ||
51 | await waitJobs(servers) | 50 | await waitJobs(servers) |
@@ -540,6 +539,40 @@ describe('Test users subscriptions', function () { | |||
540 | } | 539 | } |
541 | }) | 540 | }) |
542 | 541 | ||
542 | it('Should update video as internal and not see from remote server', async function () { | ||
543 | this.timeout(30000) | ||
544 | |||
545 | await servers[2].videos.update({ id: video3UUID, attributes: { name: 'internal', privacy: VideoPrivacy.INTERNAL } }) | ||
546 | await waitJobs(servers) | ||
547 | |||
548 | { | ||
549 | const { data } = await command.listVideos({ token: users[0].accessToken }) | ||
550 | expect(data.find(v => v.name === 'internal')).to.not.exist | ||
551 | } | ||
552 | }) | ||
553 | |||
554 | it('Should see internal from local user', async function () { | ||
555 | const { data } = await servers[2].subscriptions.listVideos({ token: servers[2].accessToken }) | ||
556 | expect(data.find(v => v.name === 'internal')).to.exist | ||
557 | }) | ||
558 | |||
559 | it('Should update video as private and not see from anyone server', async function () { | ||
560 | this.timeout(30000) | ||
561 | |||
562 | await servers[2].videos.update({ id: video3UUID, attributes: { name: 'private', privacy: VideoPrivacy.PRIVATE } }) | ||
563 | await waitJobs(servers) | ||
564 | |||
565 | { | ||
566 | const { data } = await command.listVideos({ token: users[0].accessToken }) | ||
567 | expect(data.find(v => v.name === 'private')).to.not.exist | ||
568 | } | ||
569 | |||
570 | { | ||
571 | const { data } = await servers[2].subscriptions.listVideos({ token: servers[2].accessToken }) | ||
572 | expect(data.find(v => v.name === 'private')).to.not.exist | ||
573 | } | ||
574 | }) | ||
575 | |||
543 | after(async function () { | 576 | after(async function () { |
544 | await cleanupTests(servers) | 577 | await cleanupTests(servers) |
545 | }) | 578 | }) |
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index d0ca82b07..5b2bbc520 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -6,16 +6,18 @@ import { | |||
6 | checkActorFilesWereRemoved, | 6 | checkActorFilesWereRemoved, |
7 | checkTmpIsEmpty, | 7 | checkTmpIsEmpty, |
8 | checkVideoFilesWereRemoved, | 8 | checkVideoFilesWereRemoved, |
9 | saveVideoInServers, | ||
10 | testImage | ||
11 | } from '@server/tests/shared' | ||
12 | import { MyUser } from '@shared/models' | ||
13 | import { | ||
9 | cleanupTests, | 14 | cleanupTests, |
10 | createMultipleServers, | 15 | createMultipleServers, |
11 | doubleFollow, | 16 | doubleFollow, |
12 | PeerTubeServer, | 17 | PeerTubeServer, |
13 | saveVideoInServers, | ||
14 | setAccessTokensToServers, | 18 | setAccessTokensToServers, |
15 | testImage, | ||
16 | waitJobs | 19 | waitJobs |
17 | } from '@shared/extra-utils' | 20 | } from '@shared/server-commands' |
18 | import { MyUser } from '@shared/models' | ||
19 | 21 | ||
20 | const expect = chai.expect | 22 | const expect = chai.expect |
21 | 23 | ||
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts index f54463359..0f3cc401a 100644 --- a/server/tests/api/users/users-verification.ts +++ b/server/tests/api/users/users-verification.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, MockSmtpServer, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { MockSmtpServer } from '@server/tests/shared' |
6 | import { HttpStatusCode } from '@shared/models' | 6 | import { HttpStatusCode } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' | ||
7 | 8 | ||
8 | const expect = chai.expect | 9 | const expect = chai.expect |
9 | 10 | ||
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 6c41e7d56..7023b3f08 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -2,6 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { testImage } from '@server/tests/shared' | ||
6 | import { AbuseState, HttpStatusCode, OAuth2ErrorCode, UserAdminFlag, UserRole, Video, VideoPlaylistType } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createSingleServer, | 9 | createSingleServer, |
@@ -9,10 +11,8 @@ import { | |||
9 | makePutBodyRequest, | 11 | makePutBodyRequest, |
10 | PeerTubeServer, | 12 | PeerTubeServer, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
12 | testImage, | ||
13 | waitJobs | 14 | waitJobs |
14 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { AbuseState, HttpStatusCode, OAuth2ErrorCode, UserAdminFlag, UserRole, Video, VideoPlaylistType } from '@shared/models' | ||
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
18 | 18 | ||
@@ -230,7 +230,7 @@ describe('Test users', function () { | |||
230 | }) | 230 | }) |
231 | 231 | ||
232 | it('Should have an expired access token', async function () { | 232 | it('Should have an expired access token', async function () { |
233 | this.timeout(15000) | 233 | this.timeout(60000) |
234 | 234 | ||
235 | await server.sql.setTokenField(server.accessToken, 'accessTokenExpiresAt', new Date().toISOString()) | 235 | await server.sql.setTokenField(server.accessToken, 'accessTokenExpiresAt', new Date().toISOString()) |
236 | await server.sql.setTokenField(server.accessToken, 'refreshTokenExpiresAt', new Date().toISOString()) | 236 | await server.sql.setTokenField(server.accessToken, 'refreshTokenExpiresAt', new Date().toISOString()) |
@@ -559,6 +559,28 @@ describe('Test users', function () { | |||
559 | expect(user.autoPlayNextVideo).to.be.true | 559 | expect(user.autoPlayNextVideo).to.be.true |
560 | }) | 560 | }) |
561 | 561 | ||
562 | it('Should be able to change the p2p attribute', async function () { | ||
563 | { | ||
564 | await server.users.updateMe({ | ||
565 | token: userToken, | ||
566 | webTorrentEnabled: false | ||
567 | }) | ||
568 | |||
569 | const user = await server.users.getMyInfo({ token: userToken }) | ||
570 | expect(user.p2pEnabled).to.be.false | ||
571 | } | ||
572 | |||
573 | { | ||
574 | await server.users.updateMe({ | ||
575 | token: userToken, | ||
576 | p2pEnabled: true | ||
577 | }) | ||
578 | |||
579 | const user = await server.users.getMyInfo({ token: userToken }) | ||
580 | expect(user.p2pEnabled).to.be.true | ||
581 | } | ||
582 | }) | ||
583 | |||
562 | it('Should be able to change the email attribute', async function () { | 584 | it('Should be able to change the email attribute', async function () { |
563 | await server.users.updateMe({ | 585 | await server.users.updateMe({ |
564 | token: userToken, | 586 | token: userToken, |
diff --git a/server/tests/api/videos/audio-only.ts b/server/tests/api/videos/audio-only.ts index f4b635bd5..e58360ffe 100644 --- a/server/tests/api/videos/audio-only.ts +++ b/server/tests/api/videos/audio-only.ts | |||
@@ -3,7 +3,14 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { getAudioStream, getVideoStreamSize } from '@server/helpers/ffprobe-utils' | 5 | import { getAudioStream, getVideoStreamSize } from '@server/helpers/ffprobe-utils' |
6 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 6 | import { |
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | waitJobs | ||
13 | } from '@shared/server-commands' | ||
7 | 14 | ||
8 | const expect = chai.expect | 15 | const expect = chai.expect |
9 | 16 | ||
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index c6c279064..ecdd36613 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -4,23 +4,24 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import request from 'supertest' | 5 | import request from 'supertest' |
6 | import { | 6 | import { |
7 | buildAbsoluteFixturePath, | ||
8 | checkTmpIsEmpty, | 7 | checkTmpIsEmpty, |
9 | checkVideoFilesWereRemoved, | 8 | checkVideoFilesWereRemoved, |
10 | cleanupTests, | ||
11 | completeVideoCheck, | 9 | completeVideoCheck, |
12 | createMultipleServers, | ||
13 | dateIsValid, | 10 | dateIsValid, |
11 | saveVideoInServers, | ||
12 | testImage | ||
13 | } from '@server/tests/shared' | ||
14 | import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' | ||
15 | import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models' | ||
16 | import { | ||
17 | cleanupTests, | ||
18 | createMultipleServers, | ||
14 | doubleFollow, | 19 | doubleFollow, |
15 | PeerTubeServer, | 20 | PeerTubeServer, |
16 | saveVideoInServers, | ||
17 | setAccessTokensToServers, | 21 | setAccessTokensToServers, |
18 | testImage, | ||
19 | wait, | ||
20 | waitJobs, | 22 | waitJobs, |
21 | webtorrentAdd | 23 | webtorrentAdd |
22 | } from '@shared/extra-utils' | 24 | } from '@shared/server-commands' |
23 | import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@shared/models' | ||
24 | 25 | ||
25 | const expect = chai.expect | 26 | const expect = chai.expect |
26 | 27 | ||
@@ -379,7 +380,7 @@ describe('Test multiple servers', function () { | |||
379 | 380 | ||
380 | describe('Should seed the uploaded video', function () { | 381 | describe('Should seed the uploaded video', function () { |
381 | it('Should add the file 1 by asking server 3', async function () { | 382 | it('Should add the file 1 by asking server 3', async function () { |
382 | this.timeout(10000) | 383 | this.timeout(30000) |
383 | 384 | ||
384 | const { data } = await servers[2].videos.list() | 385 | const { data } = await servers[2].videos.list() |
385 | 386 | ||
@@ -395,7 +396,7 @@ describe('Test multiple servers', function () { | |||
395 | }) | 396 | }) |
396 | 397 | ||
397 | it('Should add the file 2 by asking server 1', async function () { | 398 | it('Should add the file 2 by asking server 1', async function () { |
398 | this.timeout(10000) | 399 | this.timeout(30000) |
399 | 400 | ||
400 | const { data } = await servers[0].videos.list() | 401 | const { data } = await servers[0].videos.list() |
401 | 402 | ||
@@ -409,7 +410,7 @@ describe('Test multiple servers', function () { | |||
409 | }) | 410 | }) |
410 | 411 | ||
411 | it('Should add the file 3 by asking server 2', async function () { | 412 | it('Should add the file 3 by asking server 2', async function () { |
412 | this.timeout(10000) | 413 | this.timeout(30000) |
413 | 414 | ||
414 | const { data } = await servers[1].videos.list() | 415 | const { data } = await servers[1].videos.list() |
415 | 416 | ||
@@ -423,7 +424,7 @@ describe('Test multiple servers', function () { | |||
423 | }) | 424 | }) |
424 | 425 | ||
425 | it('Should add the file 3-2 by asking server 1', async function () { | 426 | it('Should add the file 3-2 by asking server 1', async function () { |
426 | this.timeout(10000) | 427 | this.timeout(30000) |
427 | 428 | ||
428 | const { data } = await servers[0].videos.list() | 429 | const { data } = await servers[0].videos.list() |
429 | 430 | ||
@@ -437,7 +438,7 @@ describe('Test multiple servers', function () { | |||
437 | }) | 438 | }) |
438 | 439 | ||
439 | it('Should add the file 2 in 360p by asking server 1', async function () { | 440 | it('Should add the file 2 in 360p by asking server 1', async function () { |
440 | this.timeout(10000) | 441 | this.timeout(30000) |
441 | 442 | ||
442 | const { data } = await servers[0].videos.list() | 443 | const { data } = await servers[0].videos.list() |
443 | 444 | ||
@@ -594,7 +595,7 @@ describe('Test multiple servers', function () { | |||
594 | let updatedAtMin: Date | 595 | let updatedAtMin: Date |
595 | 596 | ||
596 | it('Should update video 3', async function () { | 597 | it('Should update video 3', async function () { |
597 | this.timeout(10000) | 598 | this.timeout(30000) |
598 | 599 | ||
599 | const attributes = { | 600 | const attributes = { |
600 | name: 'my super video updated', | 601 | name: 'my super video updated', |
@@ -617,7 +618,7 @@ describe('Test multiple servers', function () { | |||
617 | }) | 618 | }) |
618 | 619 | ||
619 | it('Should have the video 3 updated on each server', async function () { | 620 | it('Should have the video 3 updated on each server', async function () { |
620 | this.timeout(10000) | 621 | this.timeout(30000) |
621 | 622 | ||
622 | for (const server of servers) { | 623 | for (const server of servers) { |
623 | const { data } = await server.videos.list() | 624 | const { data } = await server.videos.list() |
@@ -668,7 +669,7 @@ describe('Test multiple servers', function () { | |||
668 | }) | 669 | }) |
669 | 670 | ||
670 | it('Should only update thumbnail and update updatedAt attribute', async function () { | 671 | it('Should only update thumbnail and update updatedAt attribute', async function () { |
671 | this.timeout(10000) | 672 | this.timeout(30000) |
672 | 673 | ||
673 | const attributes = { | 674 | const attributes = { |
674 | thumbnailfile: 'thumbnail.jpg' | 675 | thumbnailfile: 'thumbnail.jpg' |
@@ -860,7 +861,7 @@ describe('Test multiple servers', function () { | |||
860 | }) | 861 | }) |
861 | 862 | ||
862 | it('Should delete a reply', async function () { | 863 | it('Should delete a reply', async function () { |
863 | this.timeout(10000) | 864 | this.timeout(30000) |
864 | 865 | ||
865 | await servers[2].comments.delete({ videoId: videoUUID, commentId: childOfFirstChild.comment.id }) | 866 | await servers[2].comments.delete({ videoId: videoUUID, commentId: childOfFirstChild.comment.id }) |
866 | 867 | ||
@@ -891,7 +892,7 @@ describe('Test multiple servers', function () { | |||
891 | }) | 892 | }) |
892 | 893 | ||
893 | it('Should delete the thread comments', async function () { | 894 | it('Should delete the thread comments', async function () { |
894 | this.timeout(10000) | 895 | this.timeout(30000) |
895 | 896 | ||
896 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) | 897 | const { data } = await servers[0].comments.listThreads({ videoId: videoUUID }) |
897 | const commentId = data.find(c => c.text === 'my super first comment').id | 898 | const commentId = data.find(c => c.text === 'my super first comment').id |
diff --git a/server/tests/api/videos/resumable-upload.ts b/server/tests/api/videos/resumable-upload.ts index 1ba7cdbcc..d6f4da630 100644 --- a/server/tests/api/videos/resumable-upload.ts +++ b/server/tests/api/videos/resumable-upload.ts | |||
@@ -4,15 +4,9 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { pathExists, readdir, stat } from 'fs-extra' | 5 | import { pathExists, readdir, stat } from 'fs-extra' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { | 7 | import { buildAbsoluteFixturePath } from '@shared/core-utils' |
8 | buildAbsoluteFixturePath, | ||
9 | cleanupTests, | ||
10 | createSingleServer, | ||
11 | PeerTubeServer, | ||
12 | setAccessTokensToServers, | ||
13 | setDefaultVideoChannel | ||
14 | } from '@shared/extra-utils' | ||
15 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 8 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
9 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, setDefaultVideoChannel } from '@shared/server-commands' | ||
16 | 10 | ||
17 | const expect = chai.expect | 11 | const expect = chai.expect |
18 | 12 | ||
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts index a0e4a156c..28bf018c5 100644 --- a/server/tests/api/videos/single-server.ts +++ b/server/tests/api/videos/single-server.ts | |||
@@ -2,17 +2,10 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { | 5 | import { checkVideoFilesWereRemoved, completeVideoCheck, testImage } from '@server/tests/shared' |
6 | checkVideoFilesWereRemoved, | 6 | import { wait } from '@shared/core-utils' |
7 | cleanupTests, | ||
8 | completeVideoCheck, | ||
9 | createSingleServer, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | testImage, | ||
13 | wait | ||
14 | } from '@shared/extra-utils' | ||
15 | import { Video, VideoPrivacy } from '@shared/models' | 7 | import { Video, VideoPrivacy } from '@shared/models' |
8 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
16 | 9 | ||
17 | const expect = chai.expect | 10 | const expect = chai.expect |
18 | 11 | ||
diff --git a/server/tests/api/videos/video-captions.ts b/server/tests/api/videos/video-captions.ts index 3bb0d131c..b7f26c35f 100644 --- a/server/tests/api/videos/video-captions.ts +++ b/server/tests/api/videos/video-captions.ts | |||
@@ -2,17 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { checkVideoFilesWereRemoved, testCaptionFile } from '@server/tests/shared' | ||
6 | import { wait } from '@shared/core-utils' | ||
5 | import { | 7 | import { |
6 | checkVideoFilesWereRemoved, | ||
7 | cleanupTests, | 8 | cleanupTests, |
8 | createMultipleServers, | 9 | createMultipleServers, |
9 | doubleFollow, | 10 | doubleFollow, |
10 | PeerTubeServer, | 11 | PeerTubeServer, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | testCaptionFile, | ||
13 | wait, | ||
14 | waitJobs | 13 | waitJobs |
15 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
16 | 15 | ||
17 | const expect = chai.expect | 16 | const expect = chai.expect |
18 | 17 | ||
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index d6665fe4e..6c229c6cf 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
14 | waitJobs | 14 | waitJobs |
15 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 16 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
17 | 17 | ||
18 | const expect = chai.expect | 18 | const expect = chai.expect |
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index c25754eb6..d435f3682 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -4,6 +4,9 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { basename } from 'path' | 5 | import { basename } from 'path' |
6 | import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants' | 6 | import { ACTOR_IMAGES_SIZE } from '@server/initializers/constants' |
7 | import { testFileExistsOrNot, testImage } from '@server/tests/shared' | ||
8 | import { wait } from '@shared/core-utils' | ||
9 | import { User, VideoChannel } from '@shared/models' | ||
7 | import { | 10 | import { |
8 | cleanupTests, | 11 | cleanupTests, |
9 | createMultipleServers, | 12 | createMultipleServers, |
@@ -11,12 +14,8 @@ import { | |||
11 | PeerTubeServer, | 14 | PeerTubeServer, |
12 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
13 | setDefaultVideoChannel, | 16 | setDefaultVideoChannel, |
14 | testFileExistsOrNot, | ||
15 | testImage, | ||
16 | wait, | ||
17 | waitJobs | 17 | waitJobs |
18 | } from '@shared/extra-utils' | 18 | } from '@shared/server-commands' |
19 | import { User, VideoChannel } from '@shared/models' | ||
20 | 19 | ||
21 | const expect = chai.expect | 20 | const expect = chai.expect |
22 | 21 | ||
@@ -33,6 +32,7 @@ describe('Test video channels', function () { | |||
33 | let totoChannel: number | 32 | let totoChannel: number |
34 | let videoUUID: string | 33 | let videoUUID: string |
35 | let accountName: string | 34 | let accountName: string |
35 | let secondUserChannelName: string | ||
36 | 36 | ||
37 | const avatarPaths: { [ port: number ]: string } = {} | 37 | const avatarPaths: { [ port: number ]: string } = {} |
38 | const bannerPaths: { [ port: number ]: string } = {} | 38 | const bannerPaths: { [ port: number ]: string } = {} |
@@ -219,6 +219,35 @@ describe('Test video channels', function () { | |||
219 | } | 219 | } |
220 | }) | 220 | }) |
221 | 221 | ||
222 | it('Should update another accounts video channel', async function () { | ||
223 | this.timeout(15000) | ||
224 | |||
225 | const result = await servers[0].users.generate('second_user') | ||
226 | secondUserChannelName = result.userChannelName | ||
227 | |||
228 | await servers[0].videos.quickUpload({ name: 'video', token: result.token }) | ||
229 | |||
230 | const videoChannelAttributes = { | ||
231 | displayName: 'video channel updated', | ||
232 | description: 'video channel description updated', | ||
233 | support: 'support updated' | ||
234 | } | ||
235 | |||
236 | await servers[0].channels.update({ channelName: secondUserChannelName, attributes: videoChannelAttributes }) | ||
237 | |||
238 | await waitJobs(servers) | ||
239 | }) | ||
240 | |||
241 | it('Should have another accounts video channel updated', async function () { | ||
242 | for (const server of servers) { | ||
243 | const body = await server.channels.get({ channelName: `${secondUserChannelName}@${servers[0].host}` }) | ||
244 | |||
245 | expect(body.displayName).to.equal('video channel updated') | ||
246 | expect(body.description).to.equal('video channel description updated') | ||
247 | expect(body.support).to.equal('support updated') | ||
248 | } | ||
249 | }) | ||
250 | |||
222 | it('Should update the channel support field and update videos too', async function () { | 251 | it('Should update the channel support field and update videos too', async function () { |
223 | this.timeout(35000) | 252 | this.timeout(35000) |
224 | 253 | ||
@@ -368,12 +397,13 @@ describe('Test video channels', function () { | |||
368 | }) | 397 | }) |
369 | 398 | ||
370 | it('Should have video channel deleted', async function () { | 399 | it('Should have video channel deleted', async function () { |
371 | const body = await servers[0].channels.list({ start: 0, count: 10 }) | 400 | const body = await servers[0].channels.list({ start: 0, count: 10, sort: 'createdAt' }) |
372 | 401 | ||
373 | expect(body.total).to.equal(1) | 402 | expect(body.total).to.equal(2) |
374 | expect(body.data).to.be.an('array') | 403 | expect(body.data).to.be.an('array') |
375 | expect(body.data).to.have.lengthOf(1) | 404 | expect(body.data).to.have.lengthOf(2) |
376 | expect(body.data[0].displayName).to.equal('Main root channel') | 405 | expect(body.data[0].displayName).to.equal('Main root channel') |
406 | expect(body.data[1].displayName).to.equal('video channel updated') | ||
377 | }) | 407 | }) |
378 | 408 | ||
379 | it('Should create the main channel with an uuid if there is a conflict', async function () { | 409 | it('Should create the main channel with an uuid if there is a conflict', async function () { |
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts index 61ee54540..2ae523970 100644 --- a/server/tests/api/videos/video-comments.ts +++ b/server/tests/api/videos/video-comments.ts | |||
@@ -2,15 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { | 5 | import { dateIsValid, testImage } from '@server/tests/shared' |
6 | cleanupTests, | 6 | import { cleanupTests, CommentsCommand, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
7 | CommentsCommand, | ||
8 | createSingleServer, | ||
9 | dateIsValid, | ||
10 | PeerTubeServer, | ||
11 | setAccessTokensToServers, | ||
12 | testImage | ||
13 | } from '@shared/extra-utils' | ||
14 | 7 | ||
15 | const expect = chai.expect | 8 | const expect = chai.expect |
16 | 9 | ||
diff --git a/server/tests/api/videos/video-create-transcoding.ts b/server/tests/api/videos/video-create-transcoding.ts index c4627e0c1..62a6bab0d 100644 --- a/server/tests/api/videos/video-create-transcoding.ts +++ b/server/tests/api/videos/video-create-transcoding.ts | |||
@@ -2,20 +2,20 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { expectStartWith } from '@server/tests/shared' | ||
6 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
7 | import { HttpStatusCode, VideoDetails } from '@shared/models' | ||
5 | import { | 8 | import { |
6 | areObjectStorageTestsDisabled, | ||
7 | cleanupTests, | 9 | cleanupTests, |
8 | createMultipleServers, | 10 | createMultipleServers, |
9 | doubleFollow, | 11 | doubleFollow, |
10 | expectNoFailedTranscodingJob, | 12 | expectNoFailedTranscodingJob, |
11 | expectStartWith, | ||
12 | makeRawRequest, | 13 | makeRawRequest, |
13 | ObjectStorageCommand, | 14 | ObjectStorageCommand, |
14 | PeerTubeServer, | 15 | PeerTubeServer, |
15 | setAccessTokensToServers, | 16 | setAccessTokensToServers, |
16 | waitJobs | 17 | waitJobs |
17 | } from '@shared/extra-utils' | 18 | } from '@shared/server-commands' |
18 | import { HttpStatusCode, VideoDetails } from '@shared/models' | ||
19 | 19 | ||
20 | const expect = chai.expect | 20 | const expect = chai.expect |
21 | 21 | ||
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts index d22b4ed96..20b20488f 100644 --- a/server/tests/api/videos/video-description.ts +++ b/server/tests/api/videos/video-description.ts | |||
@@ -2,7 +2,14 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { |
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | const expect = chai.expect | 14 | const expect = chai.expect |
8 | 15 | ||
diff --git a/server/tests/api/videos/video-files.ts b/server/tests/api/videos/video-files.ts index fcb2ca2e4..b0ef4a2e9 100644 --- a/server/tests/api/videos/video-files.ts +++ b/server/tests/api/videos/video-files.ts | |||
@@ -2,7 +2,14 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { |
6 | cleanupTests, | ||
7 | createMultipleServers, | ||
8 | doubleFollow, | ||
9 | PeerTubeServer, | ||
10 | setAccessTokensToServers, | ||
11 | waitJobs | ||
12 | } from '@shared/server-commands' | ||
6 | 13 | ||
7 | describe('Test videos files', function () { | 14 | describe('Test videos files', function () { |
8 | let servers: PeerTubeServer[] | 15 | let servers: PeerTubeServer[] |
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index a18c3d672..218ec08ae 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts | |||
@@ -3,26 +3,27 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { basename, join } from 'path' | 5 | import { basename, join } from 'path' |
6 | import { removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' | ||
7 | import { | 6 | import { |
8 | areObjectStorageTestsDisabled, | ||
9 | checkDirectoryIsEmpty, | 7 | checkDirectoryIsEmpty, |
10 | checkResolutionsInMasterPlaylist, | 8 | checkResolutionsInMasterPlaylist, |
11 | checkSegmentHash, | 9 | checkSegmentHash, |
12 | checkTmpIsEmpty, | 10 | checkTmpIsEmpty, |
11 | expectStartWith, | ||
12 | hlsInfohashExist | ||
13 | } from '@server/tests/shared' | ||
14 | import { areObjectStorageTestsDisabled, removeFragmentedMP4Ext, uuidRegex } from '@shared/core-utils' | ||
15 | import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models' | ||
16 | import { | ||
13 | cleanupTests, | 17 | cleanupTests, |
14 | createMultipleServers, | 18 | createMultipleServers, |
15 | doubleFollow, | 19 | doubleFollow, |
16 | expectStartWith, | ||
17 | hlsInfohashExist, | ||
18 | makeRawRequest, | 20 | makeRawRequest, |
19 | ObjectStorageCommand, | 21 | ObjectStorageCommand, |
20 | PeerTubeServer, | 22 | PeerTubeServer, |
21 | setAccessTokensToServers, | 23 | setAccessTokensToServers, |
22 | waitJobs, | 24 | waitJobs, |
23 | webtorrentAdd | 25 | webtorrentAdd |
24 | } from '@shared/extra-utils' | 26 | } from '@shared/server-commands' |
25 | import { HttpStatusCode, VideoStreamingPlaylistType } from '@shared/models' | ||
26 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | 27 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' |
27 | 28 | ||
28 | const expect = chai.expect | 29 | const expect = chai.expect |
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts index b6168b54e..e8e0f01f1 100644 --- a/server/tests/api/videos/video-imports.ts +++ b/server/tests/api/videos/video-imports.ts | |||
@@ -4,21 +4,19 @@ import 'mocha' | |||
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { pathExists, readdir, remove } from 'fs-extra' | 5 | import { pathExists, readdir, remove } from 'fs-extra' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { FIXTURE_URLS, testCaptionFile, testImage } from '@server/tests/shared' | ||
8 | import { areHttpImportTestsDisabled } from '@shared/core-utils' | ||
9 | import { VideoPrivacy, VideoResolution } from '@shared/models' | ||
7 | import { | 10 | import { |
8 | areHttpImportTestsDisabled, | ||
9 | cleanupTests, | 11 | cleanupTests, |
10 | createMultipleServers, | 12 | createMultipleServers, |
11 | createSingleServer, | 13 | createSingleServer, |
12 | doubleFollow, | 14 | doubleFollow, |
13 | FIXTURE_URLS, | ||
14 | PeerTubeServer, | 15 | PeerTubeServer, |
15 | setAccessTokensToServers, | 16 | setAccessTokensToServers, |
16 | setDefaultVideoChannel, | 17 | setDefaultVideoChannel, |
17 | testCaptionFile, | ||
18 | testImage, | ||
19 | waitJobs | 18 | waitJobs |
20 | } from '@shared/extra-utils' | 19 | } from '@shared/server-commands' |
21 | import { VideoPrivacy, VideoResolution } from '@shared/models' | ||
22 | 20 | ||
23 | async function checkVideosServer1 (server: PeerTubeServer, idHttp: string, idMagnet: string, idTorrent: string) { | 21 | async function checkVideosServer1 (server: PeerTubeServer, idHttp: string, idMagnet: string, idTorrent: string) { |
24 | const videoHttp = await server.videos.get({ id: idHttp }) | 22 | const videoHttp = await server.videos.get({ id: idHttp }) |
diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts index b5d183d62..99ea67a0f 100644 --- a/server/tests/api/videos/video-nsfw.ts +++ b/server/tests/api/videos/video-nsfw.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
6 | import { BooleanBothQuery, CustomConfig, ResultList, Video, VideosOverview } from '@shared/models' | 6 | import { BooleanBothQuery, CustomConfig, ResultList, Video, VideosOverview } from '@shared/models' |
7 | 7 | ||
8 | const expect = chai.expect | 8 | const expect = chai.expect |
diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts index f0b2ca169..5fdb0fc03 100644 --- a/server/tests/api/videos/video-playlist-thumbnails.ts +++ b/server/tests/api/videos/video-playlist-thumbnails.ts | |||
@@ -2,6 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { testImage } from '@server/tests/shared' | ||
6 | import { VideoPlaylistPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
@@ -9,10 +11,8 @@ import { | |||
9 | PeerTubeServer, | 11 | PeerTubeServer, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
12 | testImage, | ||
13 | waitJobs | 14 | waitJobs |
14 | } from '../../../../shared/extra-utils' | 15 | } from '@shared/server-commands' |
15 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | ||
16 | 16 | ||
17 | const expect = chai.expect | 17 | const expect = chai.expect |
18 | 18 | ||
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index f42aee2ff..34327334f 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts | |||
@@ -2,19 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { | 5 | import { checkPlaylistFilesWereRemoved, testImage } from '@server/tests/shared' |
6 | checkPlaylistFilesWereRemoved, | 6 | import { wait } from '@shared/core-utils' |
7 | cleanupTests, | ||
8 | createMultipleServers, | ||
9 | doubleFollow, | ||
10 | PeerTubeServer, | ||
11 | PlaylistsCommand, | ||
12 | setAccessTokensToServers, | ||
13 | setDefaultVideoChannel, | ||
14 | testImage, | ||
15 | wait, | ||
16 | waitJobs | ||
17 | } from '@shared/extra-utils' | ||
18 | import { | 7 | import { |
19 | HttpStatusCode, | 8 | HttpStatusCode, |
20 | VideoPlaylist, | 9 | VideoPlaylist, |
@@ -24,6 +13,16 @@ import { | |||
24 | VideoPlaylistType, | 13 | VideoPlaylistType, |
25 | VideoPrivacy | 14 | VideoPrivacy |
26 | } from '@shared/models' | 15 | } from '@shared/models' |
16 | import { | ||
17 | cleanupTests, | ||
18 | createMultipleServers, | ||
19 | doubleFollow, | ||
20 | PeerTubeServer, | ||
21 | PlaylistsCommand, | ||
22 | setAccessTokensToServers, | ||
23 | setDefaultVideoChannel, | ||
24 | waitJobs | ||
25 | } from '@shared/server-commands' | ||
27 | 26 | ||
28 | const expect = chai.expect | 27 | const expect = chai.expect |
29 | 28 | ||
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index b51b3bcdd..3051a443d 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' | 5 | import { wait } from '@shared/core-utils' |
6 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/server-commands' | ||
7 | 8 | ||
8 | const expect = chai.expect | 9 | const expect = chai.expect |
9 | 10 | ||
@@ -209,7 +210,7 @@ describe('Test video privacy', function () { | |||
209 | describe('Privacy update', function () { | 210 | describe('Privacy update', function () { |
210 | 211 | ||
211 | it('Should update the private and internal videos to public on server 1', async function () { | 212 | it('Should update the private and internal videos to public on server 1', async function () { |
212 | this.timeout(10000) | 213 | this.timeout(100000) |
213 | 214 | ||
214 | now = Date.now() | 215 | now = Date.now() |
215 | 216 | ||
@@ -230,6 +231,7 @@ describe('Test video privacy', function () { | |||
230 | await servers[0].videos.update({ id: internalVideoId, attributes }) | 231 | await servers[0].videos.update({ id: internalVideoId, attributes }) |
231 | } | 232 | } |
232 | 233 | ||
234 | await wait(10000) | ||
233 | await waitJobs(servers) | 235 | await waitJobs(servers) |
234 | }) | 236 | }) |
235 | 237 | ||
diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts index 3f7738784..00b4f6cbc 100644 --- a/server/tests/api/videos/video-schedule-update.ts +++ b/server/tests/api/videos/video-schedule-update.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { VideoPrivacy } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | doubleFollow, | 10 | doubleFollow, |
9 | PeerTubeServer, | 11 | PeerTubeServer, |
10 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
11 | wait, | ||
12 | waitJobs | 13 | waitJobs |
13 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
14 | import { VideoPrivacy } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts index 7ed55b8e8..d24a8f4e1 100644 --- a/server/tests/api/videos/video-transcoder.ts +++ b/server/tests/api/videos/video-transcoder.ts | |||
@@ -3,29 +3,21 @@ | |||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { omit } from 'lodash' | 5 | import { omit } from 'lodash' |
6 | import { getMaxBitrate, getMinLimitBitrate } from '@shared/core-utils' | 6 | import { canDoQuickTranscode } from '@server/helpers/ffprobe-utils' |
7 | import { generateHighBitrateVideo, generateVideoWithFramerate } from '@server/tests/shared' | ||
8 | import { buildAbsoluteFixturePath, getMaxBitrate, getMinLimitBitrate } from '@shared/core-utils' | ||
9 | import { getAudioStream, getMetadataFromFile, getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '@shared/extra-utils' | ||
10 | import { HttpStatusCode, VideoState } from '@shared/models' | ||
7 | import { | 11 | import { |
8 | buildAbsoluteFixturePath, | ||
9 | cleanupTests, | 12 | cleanupTests, |
10 | createMultipleServers, | 13 | createMultipleServers, |
11 | doubleFollow, | 14 | doubleFollow, |
12 | generateHighBitrateVideo, | ||
13 | generateVideoWithFramerate, | ||
14 | makeGetRequest, | 15 | makeGetRequest, |
15 | PeerTubeServer, | 16 | PeerTubeServer, |
16 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
17 | waitJobs, | 18 | waitJobs, |
18 | webtorrentAdd | 19 | webtorrentAdd |
19 | } from '@shared/extra-utils' | 20 | } from '@shared/server-commands' |
20 | import { HttpStatusCode, VideoState } from '@shared/models' | ||
21 | import { | ||
22 | canDoQuickTranscode, | ||
23 | getAudioStream, | ||
24 | getMetadataFromFile, | ||
25 | getVideoFileBitrate, | ||
26 | getVideoFileFPS, | ||
27 | getVideoFileResolution | ||
28 | } from '../../../helpers/ffprobe-utils' | ||
29 | 21 | ||
30 | const expect = chai.expect | 22 | const expect = chai.expect |
31 | 23 | ||
diff --git a/server/tests/api/videos/videos-common-filters.ts b/server/tests/api/videos/videos-common-filters.ts index ca5f42173..0254662c5 100644 --- a/server/tests/api/videos/videos-common-filters.ts +++ b/server/tests/api/videos/videos-common-filters.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | setDefaultVideoChannel, | 13 | setDefaultVideoChannel, |
14 | waitJobs | 14 | waitJobs |
15 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models' | 16 | import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models' |
17 | 17 | ||
18 | describe('Test videos filter', function () { | 18 | describe('Test videos filter', function () { |
diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts index e4bc0bb3a..4e5ba13aa 100644 --- a/server/tests/api/videos/videos-history.ts +++ b/server/tests/api/videos/videos-history.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { HttpStatusCode, Video } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createSingleServer, | 9 | createSingleServer, |
8 | HistoryCommand, | 10 | HistoryCommand, |
9 | killallServers, | 11 | killallServers, |
10 | PeerTubeServer, | 12 | PeerTubeServer, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers |
12 | wait | 14 | } from '@shared/server-commands' |
13 | } from '@shared/extra-utils' | ||
14 | import { HttpStatusCode, Video } from '@shared/models' | ||
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts index 70aa66549..61fc0cb20 100644 --- a/server/tests/api/videos/videos-overview.ts +++ b/server/tests/api/videos/videos-overview.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers, wait } from '@shared/extra-utils' | 5 | import { wait } from '@shared/core-utils' |
6 | import { VideosOverview } from '@shared/models' | 6 | import { VideosOverview } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
7 | 8 | ||
8 | const expect = chai.expect | 9 | const expect = chai.expect |
9 | 10 | ||
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts index 82268b1be..e6815a4a8 100644 --- a/server/tests/api/videos/videos-views-cleaner.ts +++ b/server/tests/api/videos/videos-views-cleaner.ts | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | 7 | cleanupTests, |
7 | createMultipleServers, | 8 | createMultipleServers, |
@@ -9,9 +10,8 @@ import { | |||
9 | killallServers, | 10 | killallServers, |
10 | PeerTubeServer, | 11 | PeerTubeServer, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | wait, | ||
13 | waitJobs | 13 | waitJobs |
14 | } from '../../../../shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | 15 | ||
16 | const expect = chai.expect | 16 | const expect = chai.expect |
17 | 17 | ||
diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts index c06b9550c..8ef0545d0 100644 --- a/server/tests/cli/create-import-video-file-job.ts +++ b/server/tests/cli/create-import-video-file-job.ts | |||
@@ -2,19 +2,19 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
6 | import { HttpStatusCode, VideoDetails, VideoFile, VideoInclude } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | areObjectStorageTestsDisabled, | ||
7 | cleanupTests, | 8 | cleanupTests, |
8 | createMultipleServers, | 9 | createMultipleServers, |
9 | doubleFollow, | 10 | doubleFollow, |
10 | expectStartWith, | ||
11 | makeRawRequest, | 11 | makeRawRequest, |
12 | ObjectStorageCommand, | 12 | ObjectStorageCommand, |
13 | PeerTubeServer, | 13 | PeerTubeServer, |
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | waitJobs | 15 | waitJobs |
16 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
17 | import { HttpStatusCode, VideoDetails, VideoFile, VideoInclude } from '@shared/models' | 17 | import { expectStartWith } from '../shared' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/cli/create-move-video-storage-job.ts b/server/tests/cli/create-move-video-storage-job.ts index b598c8359..c674d28d2 100644 --- a/server/tests/cli/create-move-video-storage-job.ts +++ b/server/tests/cli/create-move-video-storage-job.ts | |||
@@ -1,20 +1,19 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | |
5 | import { HttpStatusCode, VideoDetails } from '@shared/models' | ||
5 | import { | 6 | import { |
6 | areObjectStorageTestsDisabled, | ||
7 | cleanupTests, | 7 | cleanupTests, |
8 | createMultipleServers, | 8 | createMultipleServers, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | expectStartWith, | ||
11 | makeRawRequest, | 10 | makeRawRequest, |
12 | ObjectStorageCommand, | 11 | ObjectStorageCommand, |
13 | PeerTubeServer, | 12 | PeerTubeServer, |
14 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
15 | waitJobs | 14 | waitJobs |
16 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
17 | import { HttpStatusCode, VideoDetails } from '@shared/models' | 16 | import { expectStartWith } from '../shared' |
18 | 17 | ||
19 | async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObjectStorage: boolean) { | 18 | async function checkFiles (origin: PeerTubeServer, video: VideoDetails, inObjectStorage: boolean) { |
20 | for (const file of video.files) { | 19 | for (const file of video.files) { |
diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts index fb9c2584f..c85130fef 100644 --- a/server/tests/cli/create-transcoding-job.ts +++ b/server/tests/cli/create-transcoding-job.ts | |||
@@ -2,19 +2,19 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { areObjectStorageTestsDisabled } from '@shared/core-utils' | ||
5 | import { HttpStatusCode, VideoFile } from '@shared/models' | 6 | import { HttpStatusCode, VideoFile } from '@shared/models' |
6 | import { | 7 | import { |
7 | areObjectStorageTestsDisabled, | ||
8 | cleanupTests, | 8 | cleanupTests, |
9 | createMultipleServers, | 9 | createMultipleServers, |
10 | doubleFollow, | 10 | doubleFollow, |
11 | expectStartWith, | ||
12 | makeRawRequest, | 11 | makeRawRequest, |
13 | ObjectStorageCommand, | 12 | ObjectStorageCommand, |
14 | PeerTubeServer, | 13 | PeerTubeServer, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
16 | waitJobs | 15 | waitJobs |
17 | } from '../../../shared/extra-utils' | 16 | } from '@shared/server-commands' |
17 | import { expectStartWith } from '../shared' | ||
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index f2a984962..034d216e3 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -2,19 +2,17 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { areHttpImportTestsDisabled, buildAbsoluteFixturePath } from '@shared/core-utils' | ||
5 | import { | 6 | import { |
6 | areHttpImportTestsDisabled, | ||
7 | buildAbsoluteFixturePath, | ||
8 | cleanupTests, | 7 | cleanupTests, |
9 | CLICommand, | 8 | CLICommand, |
10 | createSingleServer, | 9 | createSingleServer, |
11 | doubleFollow, | 10 | doubleFollow, |
12 | FIXTURE_URLS, | ||
13 | PeerTubeServer, | 11 | PeerTubeServer, |
14 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
15 | testHelloWorldRegisteredSettings, | ||
16 | waitJobs | 13 | waitJobs |
17 | } from '../../../shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | import { FIXTURE_URLS, testHelloWorldRegisteredSettings } from '../shared' | ||
18 | 16 | ||
19 | describe('Test CLI wrapper', function () { | 17 | describe('Test CLI wrapper', function () { |
20 | let server: PeerTubeServer | 18 | let server: PeerTubeServer |
@@ -207,6 +205,25 @@ describe('Test CLI wrapper', function () { | |||
207 | 205 | ||
208 | expect(res).to.not.contain('peertube-plugin-hello-world') | 206 | expect(res).to.not.contain('peertube-plugin-hello-world') |
209 | }) | 207 | }) |
208 | |||
209 | it('Should install a plugin in requested version', async function () { | ||
210 | this.timeout(60000) | ||
211 | |||
212 | await cliCommand.execWithEnv(`${cmd} plugins install --npm-name peertube-plugin-hello-world --plugin-version 0.0.17`) | ||
213 | }) | ||
214 | |||
215 | it('Should list installed plugins, in correct version', async function () { | ||
216 | const res = await cliCommand.execWithEnv(`${cmd} plugins list`) | ||
217 | |||
218 | expect(res).to.contain('peertube-plugin-hello-world') | ||
219 | expect(res).to.contain('0.0.17') | ||
220 | }) | ||
221 | |||
222 | it('Should uninstall the plugin again', async function () { | ||
223 | const res = await cliCommand.execWithEnv(`${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`) | ||
224 | |||
225 | expect(res).to.not.contain('peertube-plugin-hello-world') | ||
226 | }) | ||
210 | }) | 227 | }) |
211 | 228 | ||
212 | describe('Manage video redundancies', function () { | 229 | describe('Manage video redundancies', function () { |
diff --git a/server/tests/cli/plugins.ts b/server/tests/cli/plugins.ts index 07c78cc89..cd9f4e1c3 100644 --- a/server/tests/cli/plugins.ts +++ b/server/tests/cli/plugins.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | PluginsCommand, | 10 | PluginsCommand, |
11 | setAccessTokensToServers | 11 | setAccessTokensToServers |
12 | } from '../../../shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | 13 | ||
14 | describe('Test plugin scripts', function () { | 14 | describe('Test plugin scripts', function () { |
15 | let server: PeerTubeServer | 15 | let server: PeerTubeServer |
diff --git a/server/tests/cli/print-transcode-command.ts b/server/tests/cli/print-transcode-command.ts index 0b8629251..27896f031 100644 --- a/server/tests/cli/print-transcode-command.ts +++ b/server/tests/cli/print-transcode-command.ts | |||
@@ -2,7 +2,8 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { buildAbsoluteFixturePath, CLICommand } from '@shared/extra-utils' | 5 | import { buildAbsoluteFixturePath } from '@shared/core-utils' |
6 | import { CLICommand } from '@shared/server-commands' | ||
6 | import { VideoResolution } from '../../../shared/models/videos' | 7 | import { VideoResolution } from '../../../shared/models/videos' |
7 | 8 | ||
8 | const expect = chai.expect | 9 | const expect = chai.expect |
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts index 2d4c02da7..a723ed8b4 100644 --- a/server/tests/cli/prune-storage.ts +++ b/server/tests/cli/prune-storage.ts | |||
@@ -4,7 +4,9 @@ import 'mocha' | |||
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { createFile, readdir } from 'fs-extra' | 5 | import { createFile, readdir } from 'fs-extra' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { buildUUID } from '@server/helpers/uuid' | 7 | import { wait } from '@shared/core-utils' |
8 | import { buildUUID } from '@shared/extra-utils' | ||
9 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | ||
8 | import { | 10 | import { |
9 | cleanupTests, | 11 | cleanupTests, |
10 | CLICommand, | 12 | CLICommand, |
@@ -15,10 +17,8 @@ import { | |||
15 | PeerTubeServer, | 17 | PeerTubeServer, |
16 | setAccessTokensToServers, | 18 | setAccessTokensToServers, |
17 | setDefaultVideoChannel, | 19 | setDefaultVideoChannel, |
18 | wait, | ||
19 | waitJobs | 20 | waitJobs |
20 | } from '@shared/extra-utils' | 21 | } from '@shared/server-commands' |
21 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | ||
22 | 22 | ||
23 | const expect = chai.expect | 23 | const expect = chai.expect |
24 | 24 | ||
@@ -36,7 +36,7 @@ async function assertNotExists (server: PeerTubeServer, directory: string, subst | |||
36 | } | 36 | } |
37 | } | 37 | } |
38 | 38 | ||
39 | async function assertCountAreOkay (servers: PeerTubeServer[], videoServer2UUID: string) { | 39 | async function assertCountAreOkay (servers: PeerTubeServer[]) { |
40 | for (const server of servers) { | 40 | for (const server of servers) { |
41 | const videosCount = await countFiles(server, 'videos') | 41 | const videosCount = await countFiles(server, 'videos') |
42 | expect(videosCount).to.equal(8) | 42 | expect(videosCount).to.equal(8) |
@@ -52,22 +52,16 @@ async function assertCountAreOkay (servers: PeerTubeServer[], videoServer2UUID: | |||
52 | 52 | ||
53 | const avatarsCount = await countFiles(server, 'avatars') | 53 | const avatarsCount = await countFiles(server, 'avatars') |
54 | expect(avatarsCount).to.equal(2) | 54 | expect(avatarsCount).to.equal(2) |
55 | } | ||
56 | |||
57 | // When we'll prune HLS directories too | ||
58 | // const hlsRootCount = await countFiles(servers[1], 'streaming-playlists/hls/') | ||
59 | // expect(hlsRootCount).to.equal(2) | ||
60 | 55 | ||
61 | // const hlsCount = await countFiles(servers[1], 'streaming-playlists/hls/' + videoServer2UUID) | 56 | const hlsRootCount = await countFiles(server, 'streaming-playlists/hls') |
62 | // expect(hlsCount).to.equal(10) | 57 | expect(hlsRootCount).to.equal(2) |
58 | } | ||
63 | } | 59 | } |
64 | 60 | ||
65 | describe('Test prune storage scripts', function () { | 61 | describe('Test prune storage scripts', function () { |
66 | let servers: PeerTubeServer[] | 62 | let servers: PeerTubeServer[] |
67 | const badNames: { [directory: string]: string[] } = {} | 63 | const badNames: { [directory: string]: string[] } = {} |
68 | 64 | ||
69 | let videoServer2UUID: string | ||
70 | |||
71 | before(async function () { | 65 | before(async function () { |
72 | this.timeout(120000) | 66 | this.timeout(120000) |
73 | 67 | ||
@@ -77,9 +71,7 @@ describe('Test prune storage scripts', function () { | |||
77 | 71 | ||
78 | for (const server of servers) { | 72 | for (const server of servers) { |
79 | await server.videos.upload({ attributes: { name: 'video 1' } }) | 73 | await server.videos.upload({ attributes: { name: 'video 1' } }) |
80 | 74 | await server.videos.upload({ attributes: { name: 'video 2' } }) | |
81 | const { uuid } = await server.videos.upload({ attributes: { name: 'video 2' } }) | ||
82 | if (server.serverNumber === 2) videoServer2UUID = uuid | ||
83 | 75 | ||
84 | await server.users.updateMyAvatar({ fixture: 'avatar.png' }) | 76 | await server.users.updateMyAvatar({ fixture: 'avatar.png' }) |
85 | 77 | ||
@@ -123,7 +115,7 @@ describe('Test prune storage scripts', function () { | |||
123 | }) | 115 | }) |
124 | 116 | ||
125 | it('Should have the files on the disk', async function () { | 117 | it('Should have the files on the disk', async function () { |
126 | await assertCountAreOkay(servers, videoServer2UUID) | 118 | await assertCountAreOkay(servers) |
127 | }) | 119 | }) |
128 | 120 | ||
129 | it('Should create some dirty files', async function () { | 121 | it('Should create some dirty files', async function () { |
@@ -188,27 +180,14 @@ describe('Test prune storage scripts', function () { | |||
188 | badNames['avatars'] = [ n1, n2 ] | 180 | badNames['avatars'] = [ n1, n2 ] |
189 | } | 181 | } |
190 | 182 | ||
191 | // When we'll prune HLS directories too | 183 | { |
192 | // { | 184 | const directory = join('streaming-playlists', 'hls') |
193 | // const directory = join('streaming-playlists', 'hls') | 185 | const base = servers[0].servers.buildDirectory(directory) |
194 | // const base = servers[1].servers.buildDirectory(directory) | ||
195 | |||
196 | // const n1 = buildUUID() | ||
197 | // await createFile(join(base, n1)) | ||
198 | // badNames[directory] = [ n1 ] | ||
199 | // } | ||
200 | |||
201 | // { | ||
202 | // const directory = join('streaming-playlists', 'hls', videoServer2UUID) | ||
203 | // const base = servers[1].servers.buildDirectory(directory) | ||
204 | // const n1 = buildUUID() + '-240-fragmented-.mp4' | ||
205 | // const n2 = buildUUID() + '-master.m3u8' | ||
206 | |||
207 | // await createFile(join(base, n1)) | ||
208 | // await createFile(join(base, n2)) | ||
209 | 186 | ||
210 | // badNames[directory] = [ n1, n2 ] | 187 | const n1 = buildUUID() |
211 | // } | 188 | await createFile(join(base, n1)) |
189 | badNames[directory] = [ n1 ] | ||
190 | } | ||
212 | } | 191 | } |
213 | }) | 192 | }) |
214 | 193 | ||
@@ -220,7 +199,7 @@ describe('Test prune storage scripts', function () { | |||
220 | }) | 199 | }) |
221 | 200 | ||
222 | it('Should have removed files', async function () { | 201 | it('Should have removed files', async function () { |
223 | await assertCountAreOkay(servers, videoServer2UUID) | 202 | await assertCountAreOkay(servers) |
224 | 203 | ||
225 | for (const directory of Object.keys(badNames)) { | 204 | for (const directory of Object.keys(badNames)) { |
226 | for (const name of badNames[directory]) { | 205 | for (const name of badNames[directory]) { |
diff --git a/server/tests/cli/regenerate-thumbnails.ts b/server/tests/cli/regenerate-thumbnails.ts index 780c9b4bd..98d15272a 100644 --- a/server/tests/cli/regenerate-thumbnails.ts +++ b/server/tests/cli/regenerate-thumbnails.ts | |||
@@ -11,7 +11,7 @@ import { | |||
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | waitJobs | 13 | waitJobs |
14 | } from '../../../shared/extra-utils' | 14 | } from '../../../shared/server-commands' |
15 | 15 | ||
16 | async function testThumbnail (server: PeerTubeServer, videoId: number | string) { | 16 | async function testThumbnail (server: PeerTubeServer, videoId: number | string) { |
17 | const video = await server.videos.get({ id: videoId }) | 17 | const video = await server.videos.get({ id: videoId }) |
diff --git a/server/tests/cli/reset-password.ts b/server/tests/cli/reset-password.ts index 4a02db35d..018e9d788 100644 --- a/server/tests/cli/reset-password.ts +++ b/server/tests/cli/reset-password.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import 'mocha' | 1 | import 'mocha' |
2 | import { cleanupTests, CLICommand, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '../../../shared/extra-utils' | 2 | import { cleanupTests, CLICommand, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
3 | 3 | ||
4 | describe('Test reset password scripts', function () { | 4 | describe('Test reset password scripts', function () { |
5 | let server: PeerTubeServer | 5 | let server: PeerTubeServer |
diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts index 43fbaec30..da89ff153 100644 --- a/server/tests/cli/update-host.ts +++ b/server/tests/cli/update-host.ts | |||
@@ -11,7 +11,7 @@ import { | |||
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
13 | waitJobs | 13 | waitJobs |
14 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | 15 | ||
16 | describe('Test update host scripts', function () { | 16 | describe('Test update host scripts', function () { |
17 | let server: PeerTubeServer | 17 | let server: PeerTubeServer |
diff --git a/server/tests/client.ts b/server/tests/client.ts index a91bec906..fe048d7ff 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -14,7 +14,7 @@ import { | |||
14 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
15 | setDefaultVideoChannel, | 15 | setDefaultVideoChannel, |
16 | waitJobs | 16 | waitJobs |
17 | } from '../../shared/extra-utils' | 17 | } from '../../shared/server-commands' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
diff --git a/server/tests/external-plugins/auth-ldap.ts b/server/tests/external-plugins/auth-ldap.ts index acec69df5..326453a5f 100644 --- a/server/tests/external-plugins/auth-ldap.ts +++ b/server/tests/external-plugins/auth-ldap.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
6 | import { HttpStatusCode } from '@shared/models' | 6 | import { HttpStatusCode } from '@shared/models' |
7 | 7 | ||
8 | describe('Official plugin auth-ldap', function () { | 8 | describe('Official plugin auth-ldap', function () { |
diff --git a/server/tests/external-plugins/auto-block-videos.ts b/server/tests/external-plugins/auto-block-videos.ts index 0eb4bda9a..bc5c93621 100644 --- a/server/tests/external-plugins/auto-block-videos.ts +++ b/server/tests/external-plugins/auto-block-videos.ts | |||
@@ -2,17 +2,17 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { Video } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | doubleFollow, | 10 | doubleFollow, |
9 | killallServers, | 11 | killallServers, |
10 | MockBlocklist, | ||
11 | PeerTubeServer, | 12 | PeerTubeServer, |
12 | setAccessTokensToServers, | 13 | setAccessTokensToServers |
13 | wait | 14 | } from '@shared/server-commands' |
14 | } from '@shared/extra-utils' | 15 | import { MockBlocklist } from '../shared' |
15 | import { Video } from '@shared/models' | ||
16 | 16 | ||
17 | async function check (server: PeerTubeServer, videoUUID: string, exists = true) { | 17 | async function check (server: PeerTubeServer, videoUUID: string, exists = true) { |
18 | const { data } = await server.videos.list() | 18 | const { data } = await server.videos.list() |
diff --git a/server/tests/external-plugins/auto-mute.ts b/server/tests/external-plugins/auto-mute.ts index 271779dd4..375ccf91a 100644 --- a/server/tests/external-plugins/auto-mute.ts +++ b/server/tests/external-plugins/auto-mute.ts | |||
@@ -2,18 +2,18 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { HttpStatusCode } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createMultipleServers, | 9 | createMultipleServers, |
8 | doubleFollow, | 10 | doubleFollow, |
9 | killallServers, | 11 | killallServers, |
10 | makeGetRequest, | 12 | makeGetRequest, |
11 | MockBlocklist, | ||
12 | PeerTubeServer, | 13 | PeerTubeServer, |
13 | setAccessTokensToServers, | 14 | setAccessTokensToServers |
14 | wait | 15 | } from '@shared/server-commands' |
15 | } from '@shared/extra-utils' | 16 | import { MockBlocklist } from '../shared' |
16 | import { HttpStatusCode } from '@shared/models' | ||
17 | 17 | ||
18 | describe('Official plugin auto-mute', function () { | 18 | describe('Official plugin auto-mute', function () { |
19 | const autoMuteListPath = '/plugins/auto-mute/router/api/v1/mute-list' | 19 | const autoMuteListPath = '/plugins/auto-mute/router/api/v1/mute-list' |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index a1c976fd3..24a518342 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { parse, validate } from 'fast-xml-parser' | 5 | import { XMLParser, XMLValidator } from 'fast-xml-parser' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | createMultipleServers, | 8 | createMultipleServers, |
@@ -12,7 +12,7 @@ import { | |||
12 | PeerTubeServer, | 12 | PeerTubeServer, |
13 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
14 | waitJobs | 14 | waitJobs |
15 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
16 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 16 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
17 | 17 | ||
18 | chai.use(require('chai-xml')) | 18 | chai.use(require('chai-xml')) |
@@ -149,9 +149,10 @@ describe('Test syndication feeds', () => { | |||
149 | it('Should contain a valid enclosure (covers RSS 2.0 endpoint)', async function () { | 149 | it('Should contain a valid enclosure (covers RSS 2.0 endpoint)', async function () { |
150 | for (const server of servers) { | 150 | for (const server of servers) { |
151 | const rss = await server.feed.getXML({ feed: 'videos' }) | 151 | const rss = await server.feed.getXML({ feed: 'videos' }) |
152 | expect(validate(rss)).to.be.true | 152 | expect(XMLValidator.validate(rss)).to.be.true |
153 | 153 | ||
154 | const xmlDoc = parse(rss, { parseAttributeValue: true, ignoreAttributes: false }) | 154 | const parser = new XMLParser({ parseAttributeValue: true, ignoreAttributes: false }) |
155 | const xmlDoc = parser.parse(rss) | ||
155 | 156 | ||
156 | const enclosure = xmlDoc.rss.channel.item[0].enclosure | 157 | const enclosure = xmlDoc.rss.channel.item[0].enclosure |
157 | expect(enclosure).to.exist | 158 | expect(enclosure).to.exist |
diff --git a/server/tests/fixtures/peertube-plugin-test-four/main.js b/server/tests/fixtures/peertube-plugin-test-four/main.js index b9b207b81..bff42ff40 100644 --- a/server/tests/fixtures/peertube-plugin-test-four/main.js +++ b/server/tests/fixtures/peertube-plugin-test-four/main.js | |||
@@ -104,6 +104,20 @@ async function register ({ | |||
104 | isUser | 104 | isUser |
105 | }) | 105 | }) |
106 | }) | 106 | }) |
107 | |||
108 | router.get('/video-files/:id', async (req, res) => { | ||
109 | const details = await peertubeHelpers.videos.getFiles(req.params.id) | ||
110 | if (!details) return res.sendStatus(404) | ||
111 | |||
112 | return res.json(details) | ||
113 | }) | ||
114 | |||
115 | router.get('/ffprobe', async (req, res) => { | ||
116 | const result = await peertubeHelpers.videos.ffprobe(req.query.path) | ||
117 | if (!result) return res.sendStatus(404) | ||
118 | |||
119 | return res.json(result) | ||
120 | }) | ||
107 | } | 121 | } |
108 | 122 | ||
109 | } | 123 | } |
diff --git a/server/tests/fixtures/peertube-plugin-test-six/main.js b/server/tests/fixtures/peertube-plugin-test-six/main.js index 858bdb2df..243b041e7 100644 --- a/server/tests/fixtures/peertube-plugin-test-six/main.js +++ b/server/tests/fixtures/peertube-plugin-test-six/main.js | |||
@@ -11,9 +11,14 @@ async function register ({ | |||
11 | { | 11 | { |
12 | await storageManager.storeData('superkey', { value: 'toto' }) | 12 | await storageManager.storeData('superkey', { value: 'toto' }) |
13 | await storageManager.storeData('anotherkey', { value: 'toto2' }) | 13 | await storageManager.storeData('anotherkey', { value: 'toto2' }) |
14 | await storageManager.storeData('storedArrayKey', ['toto', 'toto2']) | ||
14 | 15 | ||
15 | const result = await storageManager.getData('superkey') | 16 | const result = await storageManager.getData('superkey') |
16 | logger.info('superkey stored value is %s', result.value) | 17 | logger.info('superkey stored value is %s', result.value) |
18 | |||
19 | const storedArrayValue = await storageManager.getData('storedArrayKey') | ||
20 | logger.info('storedArrayKey isArray is %s', Array.isArray(storedArrayValue) ? 'true' : 'false') | ||
21 | logger.info('storedArrayKey stored value is %s', storedArrayValue.join(', ')) | ||
17 | } | 22 | } |
18 | 23 | ||
19 | { | 24 | { |
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index db405ff31..90951d611 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js | |||
@@ -13,6 +13,9 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
13 | 'action:api.video-comment-reply.created', | 13 | 'action:api.video-comment-reply.created', |
14 | 'action:api.video-comment.deleted', | 14 | 'action:api.video-comment.deleted', |
15 | 15 | ||
16 | 'action:api.video-caption.created', | ||
17 | 'action:api.video-caption.deleted', | ||
18 | |||
16 | 'action:api.user.blocked', | 19 | 'action:api.user.blocked', |
17 | 'action:api.user.unblocked', | 20 | 'action:api.user.unblocked', |
18 | 'action:api.user.registered', | 21 | 'action:api.user.registered', |
@@ -233,6 +236,28 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
233 | } | 236 | } |
234 | }) | 237 | }) |
235 | 238 | ||
239 | registerHook({ | ||
240 | target: 'filter:api.server.stats.get.result', | ||
241 | handler: (result) => { | ||
242 | return { ...result, customStats: 14 } | ||
243 | } | ||
244 | }) | ||
245 | |||
246 | // Upload/import/live attributes | ||
247 | for (const target of [ | ||
248 | 'filter:api.video.upload.video-attribute.result', | ||
249 | 'filter:api.video.import-url.video-attribute.result', | ||
250 | 'filter:api.video.import-torrent.video-attribute.result', | ||
251 | 'filter:api.video.live.video-attribute.result' | ||
252 | ]) { | ||
253 | registerHook({ | ||
254 | target, | ||
255 | handler: (result) => { | ||
256 | return { ...result, description: result.description + ' - ' + target } | ||
257 | } | ||
258 | }) | ||
259 | } | ||
260 | |||
236 | { | 261 | { |
237 | const filterHooks = [ | 262 | const filterHooks = [ |
238 | 'filter:api.search.videos.local.list.params', | 263 | 'filter:api.search.videos.local.list.params', |
diff --git a/server/tests/helpers/image.ts b/server/tests/helpers/image.ts index 9fe9aa4cb..64bd373cc 100644 --- a/server/tests/helpers/image.ts +++ b/server/tests/helpers/image.ts | |||
@@ -4,8 +4,8 @@ import 'mocha' | |||
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { readFile, remove } from 'fs-extra' | 5 | import { readFile, remove } from 'fs-extra' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { buildAbsoluteFixturePath, root } from '@shared/core-utils' | ||
7 | import { processImage } from '../../../server/helpers/image-utils' | 8 | import { processImage } from '../../../server/helpers/image-utils' |
8 | import { buildAbsoluteFixturePath, root } from '../../../shared/extra-utils' | ||
9 | 9 | ||
10 | async function checkBuffers (path1: string, path2: string, equals: boolean) { | 10 | async function checkBuffers (path1: string, path2: string, equals: boolean) { |
11 | const [ buf1, buf2 ] = await Promise.all([ | 11 | const [ buf1, buf2 ] = await Promise.all([ |
diff --git a/server/tests/helpers/request.ts b/server/tests/helpers/request.ts index 6edbf2a76..de507ba35 100644 --- a/server/tests/helpers/request.ts +++ b/server/tests/helpers/request.ts | |||
@@ -4,9 +4,9 @@ import 'mocha' | |||
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { pathExists, remove } from 'fs-extra' | 5 | import { pathExists, remove } from 'fs-extra' |
6 | import { join } from 'path' | 6 | import { join } from 'path' |
7 | import { Mock429 } from '@shared/extra-utils/mock-servers/mock-429' | 7 | import { root, wait } from '@shared/core-utils' |
8 | import { FIXTURE_URLS, root, wait } from '../../../shared/extra-utils' | ||
9 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 8 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
9 | import { FIXTURE_URLS, Mock429 } from '../shared' | ||
10 | 10 | ||
11 | describe('Request helpers', function () { | 11 | describe('Request helpers', function () { |
12 | const destPath1 = join(root(), 'test-output-1.txt') | 12 | const destPath1 = join(root(), 'test-output-1.txt') |
diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts index 4968eef08..876546d89 100644 --- a/server/tests/misc-endpoints.ts +++ b/server/tests/misc-endpoints.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' |
6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' | 6 | import { HttpStatusCode, VideoPrivacy } from '@shared/models' |
7 | 7 | ||
8 | const expect = chai.expect | 8 | const expect = chai.expect |
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index 4c1bc7d06..8788a9644 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PluginsCommand, | 9 | PluginsCommand, |
10 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
11 | setDefaultVideoChannel | 11 | setDefaultVideoChannel |
12 | } from '@shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | import { ServerHookName, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | 13 | import { ServerHookName, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' |
14 | 14 | ||
15 | describe('Test plugin action hooks', function () { | 15 | describe('Test plugin action hooks', function () { |
@@ -103,6 +103,20 @@ describe('Test plugin action hooks', function () { | |||
103 | }) | 103 | }) |
104 | }) | 104 | }) |
105 | 105 | ||
106 | describe('Captions hooks', function () { | ||
107 | it('Should run action:api.video-caption.created', async function () { | ||
108 | await servers[0].captions.add({ videoId: videoUUID, language: 'en', fixture: 'subtitle-good.srt' }) | ||
109 | |||
110 | await checkHook('action:api.video-caption.created') | ||
111 | }) | ||
112 | |||
113 | it('Should run action:api.video-caption.deleted', async function () { | ||
114 | await servers[0].captions.delete({ videoId: videoUUID, language: 'en' }) | ||
115 | |||
116 | await checkHook('action:api.video-caption.deleted') | ||
117 | }) | ||
118 | }) | ||
119 | |||
106 | describe('Users hooks', function () { | 120 | describe('Users hooks', function () { |
107 | let userId: number | 121 | let userId: number |
108 | 122 | ||
diff --git a/server/tests/plugins/external-auth.ts b/server/tests/plugins/external-auth.ts index f3e018d43..583100671 100644 --- a/server/tests/plugins/external-auth.ts +++ b/server/tests/plugins/external-auth.ts | |||
@@ -2,16 +2,16 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { wait } from '@shared/core-utils' | ||
6 | import { HttpStatusCode, UserRole } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | cleanupTests, | 8 | cleanupTests, |
7 | createSingleServer, | 9 | createSingleServer, |
8 | decodeQueryString, | 10 | decodeQueryString, |
9 | PeerTubeServer, | 11 | PeerTubeServer, |
10 | PluginsCommand, | 12 | PluginsCommand, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers |
12 | wait | 14 | } from '@shared/server-commands' |
13 | } from '@shared/extra-utils' | ||
14 | import { HttpStatusCode, UserRole } from '@shared/models' | ||
15 | 15 | ||
16 | async function loginExternal (options: { | 16 | async function loginExternal (options: { |
17 | server: PeerTubeServer | 17 | server: PeerTubeServer |
@@ -125,7 +125,7 @@ describe('Test external auth plugins', function () { | |||
125 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | 125 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 |
126 | }) | 126 | }) |
127 | 127 | ||
128 | await server.servers.waitUntilLog('expired external auth token', 2) | 128 | await server.servers.waitUntilLog('expired external auth token', 4) |
129 | }) | 129 | }) |
130 | 130 | ||
131 | it('Should auto login Cyan, create the user and use the token', async function () { | 131 | it('Should auto login Cyan, create the user and use the token', async function () { |
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 02915f08c..52ba396e5 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts | |||
@@ -2,19 +2,19 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { HttpStatusCode, VideoDetails, VideoImportState, VideoPlaylist, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | 7 | cleanupTests, |
7 | createMultipleServers, | 8 | createMultipleServers, |
8 | doubleFollow, | 9 | doubleFollow, |
9 | FIXTURE_URLS, | ||
10 | makeRawRequest, | 10 | makeRawRequest, |
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | PluginsCommand, | 12 | PluginsCommand, |
13 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
14 | setDefaultVideoChannel, | 14 | setDefaultVideoChannel, |
15 | waitJobs | 15 | waitJobs |
16 | } from '@shared/extra-utils' | 16 | } from '@shared/server-commands' |
17 | import { HttpStatusCode, VideoDetails, VideoImportState, VideoPlaylist, VideoPlaylistPrivacy, VideoPrivacy } from '@shared/models' | 17 | import { FIXTURE_URLS } from '../shared' |
18 | 18 | ||
19 | const expect = chai.expect | 19 | const expect = chai.expect |
20 | 20 | ||
@@ -537,6 +537,75 @@ describe('Test plugin filter hooks', function () { | |||
537 | }) | 537 | }) |
538 | }) | 538 | }) |
539 | 539 | ||
540 | describe('Upload/import/live attributes filters', function () { | ||
541 | |||
542 | before(async function () { | ||
543 | await servers[0].config.enableLive({ transcoding: false, allowReplay: false }) | ||
544 | await servers[0].config.enableImports() | ||
545 | await servers[0].config.disableTranscoding() | ||
546 | }) | ||
547 | |||
548 | it('Should run filter:api.video.upload.video-attribute.result', async function () { | ||
549 | for (const mode of [ 'legacy' as 'legacy', 'resumable' as 'resumable' ]) { | ||
550 | const { id } = await servers[0].videos.upload({ attributes: { name: 'video', description: 'upload' }, mode }) | ||
551 | |||
552 | const video = await servers[0].videos.get({ id }) | ||
553 | expect(video.description).to.equal('upload - filter:api.video.upload.video-attribute.result') | ||
554 | } | ||
555 | }) | ||
556 | |||
557 | it('Should run filter:api.video.import-url.video-attribute.result', async function () { | ||
558 | const attributes = { | ||
559 | name: 'video', | ||
560 | description: 'import url', | ||
561 | channelId: servers[0].store.channel.id, | ||
562 | targetUrl: FIXTURE_URLS.goodVideo, | ||
563 | privacy: VideoPrivacy.PUBLIC | ||
564 | } | ||
565 | const { video: { id } } = await servers[0].imports.importVideo({ attributes }) | ||
566 | |||
567 | const video = await servers[0].videos.get({ id }) | ||
568 | expect(video.description).to.equal('import url - filter:api.video.import-url.video-attribute.result') | ||
569 | }) | ||
570 | |||
571 | it('Should run filter:api.video.import-torrent.video-attribute.result', async function () { | ||
572 | const attributes = { | ||
573 | name: 'video', | ||
574 | description: 'import torrent', | ||
575 | channelId: servers[0].store.channel.id, | ||
576 | magnetUri: FIXTURE_URLS.magnet, | ||
577 | privacy: VideoPrivacy.PUBLIC | ||
578 | } | ||
579 | const { video: { id } } = await servers[0].imports.importVideo({ attributes }) | ||
580 | |||
581 | const video = await servers[0].videos.get({ id }) | ||
582 | expect(video.description).to.equal('import torrent - filter:api.video.import-torrent.video-attribute.result') | ||
583 | }) | ||
584 | |||
585 | it('Should run filter:api.video.live.video-attribute.result', async function () { | ||
586 | const fields = { | ||
587 | name: 'live', | ||
588 | description: 'live', | ||
589 | channelId: servers[0].store.channel.id, | ||
590 | privacy: VideoPrivacy.PUBLIC | ||
591 | } | ||
592 | const { id } = await servers[0].live.create({ fields }) | ||
593 | |||
594 | const video = await servers[0].videos.get({ id }) | ||
595 | expect(video.description).to.equal('live - filter:api.video.live.video-attribute.result') | ||
596 | }) | ||
597 | }) | ||
598 | |||
599 | describe('Stats filters', function () { | ||
600 | |||
601 | it('Should run filter:api.server.stats.get.result', async function () { | ||
602 | const data = await servers[0].stats.get() | ||
603 | |||
604 | expect((data as any).customStats).to.equal(14) | ||
605 | }) | ||
606 | |||
607 | }) | ||
608 | |||
540 | after(async function () { | 609 | after(async function () { |
541 | await cleanupTests(servers) | 610 | await cleanupTests(servers) |
542 | }) | 611 | }) |
diff --git a/server/tests/plugins/html-injection.ts b/server/tests/plugins/html-injection.ts index 95c0cd687..0a3a9c25f 100644 --- a/server/tests/plugins/html-injection.ts +++ b/server/tests/plugins/html-injection.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | PluginsCommand, | 10 | PluginsCommand, |
11 | setAccessTokensToServers | 11 | setAccessTokensToServers |
12 | } from '../../../shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | 13 | ||
14 | const expect = chai.expect | 14 | const expect = chai.expect |
15 | 15 | ||
diff --git a/server/tests/plugins/id-and-pass-auth.ts b/server/tests/plugins/id-and-pass-auth.ts index fde0166f9..e72046ce2 100644 --- a/server/tests/plugins/id-and-pass-auth.ts +++ b/server/tests/plugins/id-and-pass-auth.ts | |||
@@ -2,8 +2,9 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers, wait } from '@shared/extra-utils' | 5 | import { wait } from '@shared/core-utils' |
6 | import { HttpStatusCode, UserRole } from '@shared/models' | 6 | import { HttpStatusCode, UserRole } from '@shared/models' |
7 | import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' | ||
7 | 8 | ||
8 | describe('Test id and pass auth plugins', function () { | 9 | describe('Test id and pass auth plugins', function () { |
9 | let server: PeerTubeServer | 10 | let server: PeerTubeServer |
diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts index 5d16b28a4..167429ef4 100644 --- a/server/tests/plugins/plugin-helpers.ts +++ b/server/tests/plugins/plugin-helpers.ts | |||
@@ -2,19 +2,21 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
5 | import { pathExists } from 'fs-extra' | ||
6 | import { HttpStatusCode, ThumbnailType } from '@shared/models' | ||
5 | import { | 7 | import { |
6 | checkVideoFilesWereRemoved, | ||
7 | cleanupTests, | 8 | cleanupTests, |
8 | createMultipleServers, | 9 | createMultipleServers, |
9 | doubleFollow, | 10 | doubleFollow, |
10 | makeGetRequest, | 11 | makeGetRequest, |
11 | makePostBodyRequest, | 12 | makePostBodyRequest, |
13 | makeRawRequest, | ||
12 | PeerTubeServer, | 14 | PeerTubeServer, |
13 | PluginsCommand, | 15 | PluginsCommand, |
14 | setAccessTokensToServers, | 16 | setAccessTokensToServers, |
15 | waitJobs | 17 | waitJobs |
16 | } from '@shared/extra-utils' | 18 | } from '@shared/server-commands' |
17 | import { HttpStatusCode } from '@shared/models' | 19 | import { checkVideoFilesWereRemoved } from '../shared' |
18 | 20 | ||
19 | function postCommand (server: PeerTubeServer, command: string, bodyArg?: object) { | 21 | function postCommand (server: PeerTubeServer, command: string, bodyArg?: object) { |
20 | const body = { command } | 22 | const body = { command } |
@@ -222,10 +224,75 @@ describe('Test plugin helpers', function () { | |||
222 | 224 | ||
223 | describe('Videos', function () { | 225 | describe('Videos', function () { |
224 | let videoUUID: string | 226 | let videoUUID: string |
227 | let videoPath: string | ||
225 | 228 | ||
226 | before(async () => { | 229 | before(async () => { |
230 | this.timeout(240000) | ||
231 | |||
232 | await servers[0].config.enableTranscoding() | ||
233 | |||
227 | const res = await servers[0].videos.quickUpload({ name: 'video1' }) | 234 | const res = await servers[0].videos.quickUpload({ name: 'video1' }) |
228 | videoUUID = res.uuid | 235 | videoUUID = res.uuid |
236 | |||
237 | await waitJobs(servers) | ||
238 | }) | ||
239 | |||
240 | it('Should get video files', async function () { | ||
241 | const { body } = await makeGetRequest({ | ||
242 | url: servers[0].url, | ||
243 | path: '/plugins/test-four/router/video-files/' + videoUUID, | ||
244 | expectedStatus: HttpStatusCode.OK_200 | ||
245 | }) | ||
246 | |||
247 | // Video files check | ||
248 | { | ||
249 | expect(body.webtorrent.videoFiles).to.be.an('array') | ||
250 | expect(body.hls.videoFiles).to.be.an('array') | ||
251 | |||
252 | for (const resolution of [ 144, 240, 360, 480, 720 ]) { | ||
253 | for (const files of [ body.webtorrent.videoFiles, body.hls.videoFiles ]) { | ||
254 | const file = files.find(f => f.resolution === resolution) | ||
255 | expect(file).to.exist | ||
256 | |||
257 | expect(file.size).to.be.a('number') | ||
258 | expect(file.fps).to.equal(25) | ||
259 | |||
260 | expect(await pathExists(file.path)).to.be.true | ||
261 | await makeRawRequest(file.url, HttpStatusCode.OK_200) | ||
262 | } | ||
263 | } | ||
264 | |||
265 | videoPath = body.webtorrent.videoFiles[0].path | ||
266 | } | ||
267 | |||
268 | // Thumbnails check | ||
269 | { | ||
270 | expect(body.thumbnails).to.be.an('array') | ||
271 | |||
272 | const miniature = body.thumbnails.find(t => t.type === ThumbnailType.MINIATURE) | ||
273 | expect(miniature).to.exist | ||
274 | expect(await pathExists(miniature.path)).to.be.true | ||
275 | await makeRawRequest(miniature.url, HttpStatusCode.OK_200) | ||
276 | |||
277 | const preview = body.thumbnails.find(t => t.type === ThumbnailType.PREVIEW) | ||
278 | expect(preview).to.exist | ||
279 | expect(await pathExists(preview.path)).to.be.true | ||
280 | await makeRawRequest(preview.url, HttpStatusCode.OK_200) | ||
281 | } | ||
282 | }) | ||
283 | |||
284 | it('Should probe a file', async function () { | ||
285 | const { body } = await makeGetRequest({ | ||
286 | url: servers[0].url, | ||
287 | path: '/plugins/test-four/router/ffprobe', | ||
288 | query: { | ||
289 | path: videoPath | ||
290 | }, | ||
291 | expectedStatus: HttpStatusCode.OK_200 | ||
292 | }) | ||
293 | |||
294 | expect(body.streams).to.be.an('array') | ||
295 | expect(body.streams).to.have.lengthOf(2) | ||
229 | }) | 296 | }) |
230 | 297 | ||
231 | it('Should remove a video after a view', async function () { | 298 | it('Should remove a video after a view', async function () { |
diff --git a/server/tests/plugins/plugin-router.ts b/server/tests/plugins/plugin-router.ts index b1ac9e2fe..58629adc7 100644 --- a/server/tests/plugins/plugin-router.ts +++ b/server/tests/plugins/plugin-router.ts | |||
@@ -10,7 +10,7 @@ import { | |||
10 | PeerTubeServer, | 10 | PeerTubeServer, |
11 | PluginsCommand, | 11 | PluginsCommand, |
12 | setAccessTokensToServers | 12 | setAccessTokensToServers |
13 | } from '@shared/extra-utils' | 13 | } from '@shared/server-commands' |
14 | import { HttpStatusCode } from '@shared/models' | 14 | import { HttpStatusCode } from '@shared/models' |
15 | 15 | ||
16 | describe('Test plugin helpers', function () { | 16 | describe('Test plugin helpers', function () { |
diff --git a/server/tests/plugins/plugin-storage.ts b/server/tests/plugins/plugin-storage.ts index e20c36dba..0bfc4fe28 100644 --- a/server/tests/plugins/plugin-storage.ts +++ b/server/tests/plugins/plugin-storage.ts | |||
@@ -11,7 +11,7 @@ import { | |||
11 | PeerTubeServer, | 11 | PeerTubeServer, |
12 | PluginsCommand, | 12 | PluginsCommand, |
13 | setAccessTokensToServers | 13 | setAccessTokensToServers |
14 | } from '@shared/extra-utils' | 14 | } from '@shared/server-commands' |
15 | import { HttpStatusCode } from '@shared/models' | 15 | import { HttpStatusCode } from '@shared/models' |
16 | 16 | ||
17 | describe('Test plugin storage', function () { | 17 | describe('Test plugin storage', function () { |
@@ -27,10 +27,14 @@ describe('Test plugin storage', function () { | |||
27 | }) | 27 | }) |
28 | 28 | ||
29 | describe('DB storage', function () { | 29 | describe('DB storage', function () { |
30 | |||
31 | it('Should correctly store a subkey', async function () { | 30 | it('Should correctly store a subkey', async function () { |
32 | await server.servers.waitUntilLog('superkey stored value is toto') | 31 | await server.servers.waitUntilLog('superkey stored value is toto') |
33 | }) | 32 | }) |
33 | |||
34 | it('Should correctly retrieve an array as array from the storage.', async function () { | ||
35 | await server.servers.waitUntilLog('storedArrayKey isArray is true') | ||
36 | await server.servers.waitUntilLog('storedArrayKey stored value is toto, toto2') | ||
37 | }) | ||
34 | }) | 38 | }) |
35 | 39 | ||
36 | describe('Disk storage', function () { | 40 | describe('Disk storage', function () { |
diff --git a/server/tests/plugins/plugin-transcoding.ts b/server/tests/plugins/plugin-transcoding.ts index 93637e3ce..5ab686472 100644 --- a/server/tests/plugins/plugin-transcoding.ts +++ b/server/tests/plugins/plugin-transcoding.ts | |||
@@ -12,7 +12,7 @@ import { | |||
12 | setDefaultVideoChannel, | 12 | setDefaultVideoChannel, |
13 | testFfmpegStreamError, | 13 | testFfmpegStreamError, |
14 | waitJobs | 14 | waitJobs |
15 | } from '@shared/extra-utils' | 15 | } from '@shared/server-commands' |
16 | import { VideoPrivacy } from '@shared/models' | 16 | import { VideoPrivacy } from '@shared/models' |
17 | 17 | ||
18 | async function createLiveWrapper (server: PeerTubeServer) { | 18 | async function createLiveWrapper (server: PeerTubeServer) { |
diff --git a/server/tests/plugins/plugin-unloading.ts b/server/tests/plugins/plugin-unloading.ts index 6bf2fda9b..a94b83695 100644 --- a/server/tests/plugins/plugin-unloading.ts +++ b/server/tests/plugins/plugin-unloading.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | PluginsCommand, | 10 | PluginsCommand, |
11 | setAccessTokensToServers | 11 | setAccessTokensToServers |
12 | } from '@shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | import { HttpStatusCode } from '@shared/models' | 13 | import { HttpStatusCode } from '@shared/models' |
14 | 14 | ||
15 | describe('Test plugins module unloading', function () { | 15 | describe('Test plugins module unloading', function () { |
diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts index 8b25c6b75..0b6e5793d 100644 --- a/server/tests/plugins/translations.ts +++ b/server/tests/plugins/translations.ts | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
5 | import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/extra-utils' | 5 | import { cleanupTests, createSingleServer, PeerTubeServer, PluginsCommand, setAccessTokensToServers } from '@shared/server-commands' |
6 | 6 | ||
7 | const expect = chai.expect | 7 | const expect = chai.expect |
8 | 8 | ||
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts index 19cba6c2c..6dce6922f 100644 --- a/server/tests/plugins/video-constants.ts +++ b/server/tests/plugins/video-constants.ts | |||
@@ -9,7 +9,7 @@ import { | |||
9 | PeerTubeServer, | 9 | PeerTubeServer, |
10 | PluginsCommand, | 10 | PluginsCommand, |
11 | setAccessTokensToServers | 11 | setAccessTokensToServers |
12 | } from '@shared/extra-utils' | 12 | } from '@shared/server-commands' |
13 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' | 13 | import { HttpStatusCode, VideoPlaylistPrivacy } from '@shared/models' |
14 | 14 | ||
15 | const expect = chai.expect | 15 | const expect = chai.expect |
diff --git a/server/tests/register.ts b/server/tests/register.ts deleted file mode 100644 index af6c8c644..000000000 --- a/server/tests/register.ts +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
2 | |||
3 | registerTSPaths() | ||
diff --git a/server/tests/shared/actors.ts b/server/tests/shared/actors.ts new file mode 100644 index 000000000..f8f4a5137 --- /dev/null +++ b/server/tests/shared/actors.ts | |||
@@ -0,0 +1,73 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readdir } from 'fs-extra' | ||
5 | import { join } from 'path' | ||
6 | import { root } from '@shared/core-utils' | ||
7 | import { Account, VideoChannel } from '@shared/models' | ||
8 | import { PeerTubeServer } from '@shared/server-commands' | ||
9 | |||
10 | async function expectChannelsFollows (options: { | ||
11 | server: PeerTubeServer | ||
12 | handle: string | ||
13 | followers: number | ||
14 | following: number | ||
15 | }) { | ||
16 | const { server } = options | ||
17 | const { data } = await server.channels.list() | ||
18 | |||
19 | return expectActorFollow({ ...options, data }) | ||
20 | } | ||
21 | |||
22 | async function expectAccountFollows (options: { | ||
23 | server: PeerTubeServer | ||
24 | handle: string | ||
25 | followers: number | ||
26 | following: number | ||
27 | }) { | ||
28 | const { server } = options | ||
29 | const { data } = await server.accounts.list() | ||
30 | |||
31 | return expectActorFollow({ ...options, data }) | ||
32 | } | ||
33 | |||
34 | async function checkActorFilesWereRemoved (filename: string, serverNumber: number) { | ||
35 | const testDirectory = 'test' + serverNumber | ||
36 | |||
37 | for (const directory of [ 'avatars' ]) { | ||
38 | const directoryPath = join(root(), testDirectory, directory) | ||
39 | |||
40 | const directoryExists = await pathExists(directoryPath) | ||
41 | expect(directoryExists).to.be.true | ||
42 | |||
43 | const files = await readdir(directoryPath) | ||
44 | for (const file of files) { | ||
45 | expect(file).to.not.contain(filename) | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | export { | ||
51 | expectAccountFollows, | ||
52 | expectChannelsFollows, | ||
53 | checkActorFilesWereRemoved | ||
54 | } | ||
55 | |||
56 | // --------------------------------------------------------------------------- | ||
57 | |||
58 | function expectActorFollow (options: { | ||
59 | server: PeerTubeServer | ||
60 | data: (Account | VideoChannel)[] | ||
61 | handle: string | ||
62 | followers: number | ||
63 | following: number | ||
64 | }) { | ||
65 | const { server, data, handle, followers, following } = options | ||
66 | |||
67 | const actor = data.find(a => a.name + '@' + a.host === handle) | ||
68 | const message = `${handle} on ${server.url}` | ||
69 | |||
70 | expect(actor, message).to.exist | ||
71 | expect(actor.followersCount).to.equal(followers, message) | ||
72 | expect(actor.followingCount).to.equal(following, message) | ||
73 | } | ||
diff --git a/server/tests/shared/captions.ts b/server/tests/shared/captions.ts new file mode 100644 index 000000000..35e722408 --- /dev/null +++ b/server/tests/shared/captions.ts | |||
@@ -0,0 +1,21 @@ | |||
1 | import { expect } from 'chai' | ||
2 | import request from 'supertest' | ||
3 | import { HttpStatusCode } from '@shared/models' | ||
4 | |||
5 | async function testCaptionFile (url: string, captionPath: string, toTest: RegExp | string) { | ||
6 | const res = await request(url) | ||
7 | .get(captionPath) | ||
8 | .expect(HttpStatusCode.OK_200) | ||
9 | |||
10 | if (toTest instanceof RegExp) { | ||
11 | expect(res.text).to.match(toTest) | ||
12 | } else { | ||
13 | expect(res.text).to.contain(toTest) | ||
14 | } | ||
15 | } | ||
16 | |||
17 | // --------------------------------------------------------------------------- | ||
18 | |||
19 | export { | ||
20 | testCaptionFile | ||
21 | } | ||
diff --git a/server/tests/shared/checks.ts b/server/tests/shared/checks.ts new file mode 100644 index 000000000..9ecc84b5d --- /dev/null +++ b/server/tests/shared/checks.ts | |||
@@ -0,0 +1,98 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readFile } from 'fs-extra' | ||
5 | import { join } from 'path' | ||
6 | import { root } from '@shared/core-utils' | ||
7 | import { HttpStatusCode } from '@shared/models' | ||
8 | import { makeGetRequest, PeerTubeServer } from '@shared/server-commands' | ||
9 | |||
10 | // Default interval -> 5 minutes | ||
11 | function dateIsValid (dateString: string, interval = 300000) { | ||
12 | const dateToCheck = new Date(dateString) | ||
13 | const now = new Date() | ||
14 | |||
15 | return Math.abs(now.getTime() - dateToCheck.getTime()) <= interval | ||
16 | } | ||
17 | |||
18 | function expectStartWith (str: string, start: string) { | ||
19 | expect(str.startsWith(start), `${str} does not start with ${start}`).to.be.true | ||
20 | } | ||
21 | |||
22 | async function expectLogDoesNotContain (server: PeerTubeServer, str: string) { | ||
23 | const content = await server.servers.getLogContent() | ||
24 | |||
25 | expect(content.toString()).to.not.contain(str) | ||
26 | } | ||
27 | |||
28 | async function testImage (url: string, imageName: string, imagePath: string, extension = '.jpg') { | ||
29 | const res = await makeGetRequest({ | ||
30 | url, | ||
31 | path: imagePath, | ||
32 | expectedStatus: HttpStatusCode.OK_200 | ||
33 | }) | ||
34 | |||
35 | const body = res.body | ||
36 | |||
37 | const data = await readFile(join(root(), 'server', 'tests', 'fixtures', imageName + extension)) | ||
38 | const minLength = body.length - ((30 * body.length) / 100) | ||
39 | const maxLength = body.length + ((30 * body.length) / 100) | ||
40 | |||
41 | expect(data.length).to.be.above(minLength, 'the generated image is way smaller than the recorded fixture') | ||
42 | expect(data.length).to.be.below(maxLength, 'the generated image is way larger than the recorded fixture') | ||
43 | } | ||
44 | |||
45 | async function testFileExistsOrNot (server: PeerTubeServer, directory: string, filePath: string, exist: boolean) { | ||
46 | const base = server.servers.buildDirectory(directory) | ||
47 | |||
48 | expect(await pathExists(join(base, filePath))).to.equal(exist) | ||
49 | } | ||
50 | |||
51 | function checkBadStartPagination (url: string, path: string, token?: string, query = {}) { | ||
52 | return makeGetRequest({ | ||
53 | url, | ||
54 | path, | ||
55 | token, | ||
56 | query: { ...query, start: 'hello' }, | ||
57 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
58 | }) | ||
59 | } | ||
60 | |||
61 | async function checkBadCountPagination (url: string, path: string, token?: string, query = {}) { | ||
62 | await makeGetRequest({ | ||
63 | url, | ||
64 | path, | ||
65 | token, | ||
66 | query: { ...query, count: 'hello' }, | ||
67 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
68 | }) | ||
69 | |||
70 | await makeGetRequest({ | ||
71 | url, | ||
72 | path, | ||
73 | token, | ||
74 | query: { ...query, count: 2000 }, | ||
75 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | function checkBadSortPagination (url: string, path: string, token?: string, query = {}) { | ||
80 | return makeGetRequest({ | ||
81 | url, | ||
82 | path, | ||
83 | token, | ||
84 | query: { ...query, sort: 'hello' }, | ||
85 | expectedStatus: HttpStatusCode.BAD_REQUEST_400 | ||
86 | }) | ||
87 | } | ||
88 | |||
89 | export { | ||
90 | dateIsValid, | ||
91 | testImage, | ||
92 | expectLogDoesNotContain, | ||
93 | testFileExistsOrNot, | ||
94 | expectStartWith, | ||
95 | checkBadStartPagination, | ||
96 | checkBadCountPagination, | ||
97 | checkBadSortPagination | ||
98 | } | ||
diff --git a/server/tests/shared/directories.ts b/server/tests/shared/directories.ts new file mode 100644 index 000000000..c7065a767 --- /dev/null +++ b/server/tests/shared/directories.ts | |||
@@ -0,0 +1,34 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readdir } from 'fs-extra' | ||
5 | import { join } from 'path' | ||
6 | import { root } from '@shared/core-utils' | ||
7 | import { PeerTubeServer } from '@shared/server-commands' | ||
8 | |||
9 | async function checkTmpIsEmpty (server: PeerTubeServer) { | ||
10 | await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ]) | ||
11 | |||
12 | if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) { | ||
13 | await checkDirectoryIsEmpty(server, 'tmp/hls') | ||
14 | } | ||
15 | } | ||
16 | |||
17 | async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) { | ||
18 | const testDirectory = 'test' + server.internalServerNumber | ||
19 | |||
20 | const directoryPath = join(root(), testDirectory, directory) | ||
21 | |||
22 | const directoryExists = await pathExists(directoryPath) | ||
23 | expect(directoryExists).to.be.true | ||
24 | |||
25 | const files = await readdir(directoryPath) | ||
26 | const filtered = files.filter(f => exceptions.includes(f) === false) | ||
27 | |||
28 | expect(filtered).to.have.lengthOf(0) | ||
29 | } | ||
30 | |||
31 | export { | ||
32 | checkTmpIsEmpty, | ||
33 | checkDirectoryIsEmpty | ||
34 | } | ||
diff --git a/server/tests/shared/generate.ts b/server/tests/shared/generate.ts new file mode 100644 index 000000000..f806df2f5 --- /dev/null +++ b/server/tests/shared/generate.ts | |||
@@ -0,0 +1,74 @@ | |||
1 | import { expect } from 'chai' | ||
2 | import ffmpeg from 'fluent-ffmpeg' | ||
3 | import { ensureDir, pathExists } from 'fs-extra' | ||
4 | import { dirname } from 'path' | ||
5 | import { buildAbsoluteFixturePath, getMaxBitrate } from '@shared/core-utils' | ||
6 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution } from '@shared/extra-utils' | ||
7 | |||
8 | async function ensureHasTooBigBitrate (fixturePath: string) { | ||
9 | const bitrate = await getVideoFileBitrate(fixturePath) | ||
10 | const dataResolution = await getVideoFileResolution(fixturePath) | ||
11 | const fps = await getVideoFileFPS(fixturePath) | ||
12 | |||
13 | const maxBitrate = getMaxBitrate({ ...dataResolution, fps }) | ||
14 | expect(bitrate).to.be.above(maxBitrate) | ||
15 | } | ||
16 | |||
17 | async function generateHighBitrateVideo () { | ||
18 | const tempFixturePath = buildAbsoluteFixturePath('video_high_bitrate_1080p.mp4', true) | ||
19 | |||
20 | await ensureDir(dirname(tempFixturePath)) | ||
21 | |||
22 | const exists = await pathExists(tempFixturePath) | ||
23 | if (!exists) { | ||
24 | console.log('Generating high bitrate video.') | ||
25 | |||
26 | // Generate a random, high bitrate video on the fly, so we don't have to include | ||
27 | // a large file in the repo. The video needs to have a certain minimum length so | ||
28 | // that FFmpeg properly applies bitrate limits. | ||
29 | // https://stackoverflow.com/a/15795112 | ||
30 | return new Promise<string>((res, rej) => { | ||
31 | ffmpeg() | ||
32 | .outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ]) | ||
33 | .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) | ||
34 | .outputOptions([ '-maxrate 10M', '-bufsize 10M' ]) | ||
35 | .output(tempFixturePath) | ||
36 | .on('error', rej) | ||
37 | .on('end', () => res(tempFixturePath)) | ||
38 | .run() | ||
39 | }) | ||
40 | } | ||
41 | |||
42 | await ensureHasTooBigBitrate(tempFixturePath) | ||
43 | |||
44 | return tempFixturePath | ||
45 | } | ||
46 | |||
47 | async function generateVideoWithFramerate (fps = 60) { | ||
48 | const tempFixturePath = buildAbsoluteFixturePath(`video_${fps}fps.mp4`, true) | ||
49 | |||
50 | await ensureDir(dirname(tempFixturePath)) | ||
51 | |||
52 | const exists = await pathExists(tempFixturePath) | ||
53 | if (!exists) { | ||
54 | console.log('Generating video with framerate %d.', fps) | ||
55 | |||
56 | return new Promise<string>((res, rej) => { | ||
57 | ffmpeg() | ||
58 | .outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ]) | ||
59 | .outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ]) | ||
60 | .outputOptions([ `-r ${fps}` ]) | ||
61 | .output(tempFixturePath) | ||
62 | .on('error', rej) | ||
63 | .on('end', () => res(tempFixturePath)) | ||
64 | .run() | ||
65 | }) | ||
66 | } | ||
67 | |||
68 | return tempFixturePath | ||
69 | } | ||
70 | |||
71 | export { | ||
72 | generateHighBitrateVideo, | ||
73 | generateVideoWithFramerate | ||
74 | } | ||
diff --git a/server/tests/shared/index.ts b/server/tests/shared/index.ts new file mode 100644 index 000000000..47019d6a8 --- /dev/null +++ b/server/tests/shared/index.ts | |||
@@ -0,0 +1,15 @@ | |||
1 | export * from './mock-servers' | ||
2 | export * from './actors' | ||
3 | export * from './captions' | ||
4 | export * from './checks' | ||
5 | export * from './directories' | ||
6 | export * from './generate' | ||
7 | export * from './live' | ||
8 | export * from './notifications' | ||
9 | export * from './playlists' | ||
10 | export * from './plugins' | ||
11 | export * from './requests' | ||
12 | export * from './streaming-playlists' | ||
13 | export * from './tests' | ||
14 | export * from './tracker' | ||
15 | export * from './videos' | ||
diff --git a/server/tests/shared/live.ts b/server/tests/shared/live.ts new file mode 100644 index 000000000..72e3e27f6 --- /dev/null +++ b/server/tests/shared/live.ts | |||
@@ -0,0 +1,41 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readdir } from 'fs-extra' | ||
5 | import { join } from 'path' | ||
6 | import { PeerTubeServer } from '@shared/server-commands' | ||
7 | |||
8 | async function checkLiveCleanupAfterSave (server: PeerTubeServer, videoUUID: string, resolutions: number[] = []) { | ||
9 | const basePath = server.servers.buildDirectory('streaming-playlists') | ||
10 | const hlsPath = join(basePath, 'hls', videoUUID) | ||
11 | |||
12 | if (resolutions.length === 0) { | ||
13 | const result = await pathExists(hlsPath) | ||
14 | expect(result).to.be.false | ||
15 | |||
16 | return | ||
17 | } | ||
18 | |||
19 | const files = await readdir(hlsPath) | ||
20 | |||
21 | // fragmented file and playlist per resolution + master playlist + segments sha256 json file | ||
22 | expect(files).to.have.lengthOf(resolutions.length * 2 + 2) | ||
23 | |||
24 | for (const resolution of resolutions) { | ||
25 | const fragmentedFile = files.find(f => f.endsWith(`-${resolution}-fragmented.mp4`)) | ||
26 | expect(fragmentedFile).to.exist | ||
27 | |||
28 | const playlistFile = files.find(f => f.endsWith(`${resolution}.m3u8`)) | ||
29 | expect(playlistFile).to.exist | ||
30 | } | ||
31 | |||
32 | const masterPlaylistFile = files.find(f => f.endsWith('-master.m3u8')) | ||
33 | expect(masterPlaylistFile).to.exist | ||
34 | |||
35 | const shaFile = files.find(f => f.endsWith('-segments-sha256.json')) | ||
36 | expect(shaFile).to.exist | ||
37 | } | ||
38 | |||
39 | export { | ||
40 | checkLiveCleanupAfterSave | ||
41 | } | ||
diff --git a/server/tests/shared/mock-servers/index.ts b/server/tests/shared/mock-servers/index.ts new file mode 100644 index 000000000..abf4a8203 --- /dev/null +++ b/server/tests/shared/mock-servers/index.ts | |||
@@ -0,0 +1,7 @@ | |||
1 | export * from './mock-429' | ||
2 | export * from './mock-email' | ||
3 | export * from './mock-instances-index' | ||
4 | export * from './mock-joinpeertube-versions' | ||
5 | export * from './mock-object-storage' | ||
6 | export * from './mock-plugin-blocklist' | ||
7 | export * from './mock-proxy' | ||
diff --git a/server/tests/shared/mock-servers/mock-429.ts b/server/tests/shared/mock-servers/mock-429.ts new file mode 100644 index 000000000..1fc20b079 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-429.ts | |||
@@ -0,0 +1,33 @@ | |||
1 | import express from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { getPort, randomListen, terminateServer } from './shared' | ||
4 | |||
5 | export class Mock429 { | ||
6 | private server: Server | ||
7 | private responseSent = false | ||
8 | |||
9 | async initialize () { | ||
10 | const app = express() | ||
11 | |||
12 | app.get('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
13 | |||
14 | if (!this.responseSent) { | ||
15 | this.responseSent = true | ||
16 | |||
17 | // Retry after 5 seconds | ||
18 | res.header('retry-after', '2') | ||
19 | return res.sendStatus(429) | ||
20 | } | ||
21 | |||
22 | return res.sendStatus(200) | ||
23 | }) | ||
24 | |||
25 | this.server = await randomListen(app) | ||
26 | |||
27 | return getPort(this.server) | ||
28 | } | ||
29 | |||
30 | terminate () { | ||
31 | return terminateServer(this.server) | ||
32 | } | ||
33 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-email.ts b/server/tests/shared/mock-servers/mock-email.ts new file mode 100644 index 000000000..c518679c9 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-email.ts | |||
@@ -0,0 +1,62 @@ | |||
1 | import { ChildProcess } from 'child_process' | ||
2 | import MailDev from '@peertube/maildev' | ||
3 | import { parallelTests, randomInt } from '@shared/core-utils' | ||
4 | |||
5 | class MockSmtpServer { | ||
6 | |||
7 | private static instance: MockSmtpServer | ||
8 | private started = false | ||
9 | private emailChildProcess: ChildProcess | ||
10 | private emails: object[] | ||
11 | |||
12 | private constructor () { } | ||
13 | |||
14 | collectEmails (emailsCollection: object[]) { | ||
15 | return new Promise<number>((res, rej) => { | ||
16 | const port = parallelTests() ? randomInt(1000, 2000) : 1025 | ||
17 | this.emails = emailsCollection | ||
18 | |||
19 | if (this.started) { | ||
20 | return res(undefined) | ||
21 | } | ||
22 | |||
23 | const maildev = new MailDev({ | ||
24 | ip: '127.0.0.1', | ||
25 | smtp: port, | ||
26 | disableWeb: true, | ||
27 | silent: true | ||
28 | }) | ||
29 | |||
30 | maildev.on('new', email => { | ||
31 | this.emails.push(email) | ||
32 | }) | ||
33 | |||
34 | maildev.listen(err => { | ||
35 | if (err) return rej(err) | ||
36 | |||
37 | this.started = true | ||
38 | |||
39 | return res(port) | ||
40 | }) | ||
41 | }) | ||
42 | } | ||
43 | |||
44 | kill () { | ||
45 | if (!this.emailChildProcess) return | ||
46 | |||
47 | process.kill(this.emailChildProcess.pid) | ||
48 | |||
49 | this.emailChildProcess = null | ||
50 | MockSmtpServer.instance = null | ||
51 | } | ||
52 | |||
53 | static get Instance () { | ||
54 | return this.instance || (this.instance = new this()) | ||
55 | } | ||
56 | } | ||
57 | |||
58 | // --------------------------------------------------------------------------- | ||
59 | |||
60 | export { | ||
61 | MockSmtpServer | ||
62 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-instances-index.ts b/server/tests/shared/mock-servers/mock-instances-index.ts new file mode 100644 index 000000000..598b007f1 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-instances-index.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import express from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { getPort, randomListen, terminateServer } from './shared' | ||
4 | |||
5 | export class MockInstancesIndex { | ||
6 | private server: Server | ||
7 | |||
8 | private readonly indexInstances: { host: string, createdAt: string }[] = [] | ||
9 | |||
10 | async initialize () { | ||
11 | const app = express() | ||
12 | |||
13 | app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
14 | if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) | ||
15 | |||
16 | return next() | ||
17 | }) | ||
18 | |||
19 | app.get('/api/v1/instances/hosts', (req: express.Request, res: express.Response) => { | ||
20 | const since = req.query.since | ||
21 | |||
22 | const filtered = this.indexInstances.filter(i => { | ||
23 | if (!since) return true | ||
24 | |||
25 | return i.createdAt > since | ||
26 | }) | ||
27 | |||
28 | return res.json({ | ||
29 | total: filtered.length, | ||
30 | data: filtered | ||
31 | }) | ||
32 | }) | ||
33 | |||
34 | this.server = await randomListen(app) | ||
35 | |||
36 | return getPort(this.server) | ||
37 | } | ||
38 | |||
39 | addInstance (host: string) { | ||
40 | this.indexInstances.push({ host, createdAt: new Date().toISOString() }) | ||
41 | } | ||
42 | |||
43 | terminate () { | ||
44 | return terminateServer(this.server) | ||
45 | } | ||
46 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts b/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts new file mode 100644 index 000000000..502f4e2f5 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-joinpeertube-versions.ts | |||
@@ -0,0 +1,34 @@ | |||
1 | import express from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { getPort, randomListen } from './shared' | ||
4 | |||
5 | export class MockJoinPeerTubeVersions { | ||
6 | private server: Server | ||
7 | private latestVersion: string | ||
8 | |||
9 | async initialize () { | ||
10 | const app = express() | ||
11 | |||
12 | app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
13 | if (process.env.DEBUG) console.log('Receiving request on mocked server %s.', req.url) | ||
14 | |||
15 | return next() | ||
16 | }) | ||
17 | |||
18 | app.get('/versions.json', (req: express.Request, res: express.Response) => { | ||
19 | return res.json({ | ||
20 | peertube: { | ||
21 | latestVersion: this.latestVersion | ||
22 | } | ||
23 | }) | ||
24 | }) | ||
25 | |||
26 | this.server = await randomListen(app) | ||
27 | |||
28 | return getPort(this.server) | ||
29 | } | ||
30 | |||
31 | setLatestVersion (latestVersion: string) { | ||
32 | this.latestVersion = latestVersion | ||
33 | } | ||
34 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-object-storage.ts b/server/tests/shared/mock-servers/mock-object-storage.ts new file mode 100644 index 000000000..99d68e014 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-object-storage.ts | |||
@@ -0,0 +1,41 @@ | |||
1 | import express from 'express' | ||
2 | import got, { RequestError } from 'got' | ||
3 | import { Server } from 'http' | ||
4 | import { pipeline } from 'stream' | ||
5 | import { ObjectStorageCommand } from '@shared/server-commands' | ||
6 | import { getPort, randomListen, terminateServer } from './shared' | ||
7 | |||
8 | export class MockObjectStorage { | ||
9 | private server: Server | ||
10 | |||
11 | async initialize () { | ||
12 | const app = express() | ||
13 | |||
14 | app.get('/:bucketName/:path(*)', (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
15 | const url = `http://${req.params.bucketName}.${ObjectStorageCommand.getEndpointHost()}/${req.params.path}` | ||
16 | |||
17 | if (process.env.DEBUG) { | ||
18 | console.log('Receiving request on mocked server %s.', req.url) | ||
19 | console.log('Proxifying request to %s', url) | ||
20 | } | ||
21 | |||
22 | return pipeline( | ||
23 | got.stream(url, { throwHttpErrors: false }), | ||
24 | res, | ||
25 | (err: RequestError) => { | ||
26 | if (!err) return | ||
27 | |||
28 | console.error('Pipeline failed.', err) | ||
29 | } | ||
30 | ) | ||
31 | }) | ||
32 | |||
33 | this.server = await randomListen(app) | ||
34 | |||
35 | return getPort(this.server) | ||
36 | } | ||
37 | |||
38 | terminate () { | ||
39 | return terminateServer(this.server) | ||
40 | } | ||
41 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-plugin-blocklist.ts b/server/tests/shared/mock-servers/mock-plugin-blocklist.ts new file mode 100644 index 000000000..5d6e01816 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-plugin-blocklist.ts | |||
@@ -0,0 +1,36 @@ | |||
1 | import express, { Request, Response } from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { getPort, randomListen, terminateServer } from './shared' | ||
4 | |||
5 | type BlocklistResponse = { | ||
6 | data: { | ||
7 | value: string | ||
8 | action?: 'add' | 'remove' | ||
9 | updatedAt?: string | ||
10 | }[] | ||
11 | } | ||
12 | |||
13 | export class MockBlocklist { | ||
14 | private body: BlocklistResponse | ||
15 | private server: Server | ||
16 | |||
17 | async initialize () { | ||
18 | const app = express() | ||
19 | |||
20 | app.get('/blocklist', (req: Request, res: Response) => { | ||
21 | return res.json(this.body) | ||
22 | }) | ||
23 | |||
24 | this.server = await randomListen(app) | ||
25 | |||
26 | return getPort(this.server) | ||
27 | } | ||
28 | |||
29 | replace (body: BlocklistResponse) { | ||
30 | this.body = body | ||
31 | } | ||
32 | |||
33 | terminate () { | ||
34 | return terminateServer(this.server) | ||
35 | } | ||
36 | } | ||
diff --git a/server/tests/shared/mock-servers/mock-proxy.ts b/server/tests/shared/mock-servers/mock-proxy.ts new file mode 100644 index 000000000..cbc7c4466 --- /dev/null +++ b/server/tests/shared/mock-servers/mock-proxy.ts | |||
@@ -0,0 +1,24 @@ | |||
1 | import { createServer, Server } from 'http' | ||
2 | import proxy from 'proxy' | ||
3 | import { getPort, terminateServer } from './shared' | ||
4 | |||
5 | class MockProxy { | ||
6 | private server: Server | ||
7 | |||
8 | initialize () { | ||
9 | return new Promise<number>(res => { | ||
10 | this.server = proxy(createServer()) | ||
11 | this.server.listen(0, () => res(getPort(this.server))) | ||
12 | }) | ||
13 | } | ||
14 | |||
15 | terminate () { | ||
16 | return terminateServer(this.server) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | // --------------------------------------------------------------------------- | ||
21 | |||
22 | export { | ||
23 | MockProxy | ||
24 | } | ||
diff --git a/server/tests/shared/mock-servers/shared.ts b/server/tests/shared/mock-servers/shared.ts new file mode 100644 index 000000000..235642439 --- /dev/null +++ b/server/tests/shared/mock-servers/shared.ts | |||
@@ -0,0 +1,33 @@ | |||
1 | import { Express } from 'express' | ||
2 | import { Server } from 'http' | ||
3 | import { AddressInfo } from 'net' | ||
4 | |||
5 | function randomListen (app: Express) { | ||
6 | return new Promise<Server>(res => { | ||
7 | const server = app.listen(0, () => res(server)) | ||
8 | }) | ||
9 | } | ||
10 | |||
11 | function getPort (server: Server) { | ||
12 | const address = server.address() as AddressInfo | ||
13 | |||
14 | return address.port | ||
15 | } | ||
16 | |||
17 | function terminateServer (server: Server) { | ||
18 | if (!server) return Promise.resolve() | ||
19 | |||
20 | return new Promise<void>((res, rej) => { | ||
21 | server.close(err => { | ||
22 | if (err) return rej(err) | ||
23 | |||
24 | return res() | ||
25 | }) | ||
26 | }) | ||
27 | } | ||
28 | |||
29 | export { | ||
30 | randomListen, | ||
31 | getPort, | ||
32 | terminateServer | ||
33 | } | ||
diff --git a/server/tests/shared/notifications.ts b/server/tests/shared/notifications.ts new file mode 100644 index 000000000..cdc21fdc8 --- /dev/null +++ b/server/tests/shared/notifications.ts | |||
@@ -0,0 +1,798 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { inspect } from 'util' | ||
5 | import { | ||
6 | AbuseState, | ||
7 | PluginType, | ||
8 | UserNotification, | ||
9 | UserNotificationSetting, | ||
10 | UserNotificationSettingValue, | ||
11 | UserNotificationType | ||
12 | } from '@shared/models' | ||
13 | import { createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands' | ||
14 | import { MockSmtpServer } from './mock-servers' | ||
15 | |||
16 | type CheckerBaseParams = { | ||
17 | server: PeerTubeServer | ||
18 | emails: any[] | ||
19 | socketNotifications: UserNotification[] | ||
20 | token: string | ||
21 | check?: { web: boolean, mail: boolean } | ||
22 | } | ||
23 | |||
24 | type CheckerType = 'presence' | 'absence' | ||
25 | |||
26 | function getAllNotificationsSettings (): UserNotificationSetting { | ||
27 | return { | ||
28 | newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
29 | newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
30 | abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
31 | videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
32 | blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
33 | myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
34 | myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
35 | commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
36 | newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
37 | newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
38 | newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
39 | abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
40 | abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
41 | autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
42 | newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL, | ||
43 | newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL | ||
44 | } | ||
45 | } | ||
46 | |||
47 | async function checkNewVideoFromSubscription (options: CheckerBaseParams & { | ||
48 | videoName: string | ||
49 | shortUUID: string | ||
50 | checkType: CheckerType | ||
51 | }) { | ||
52 | const { videoName, shortUUID } = options | ||
53 | const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION | ||
54 | |||
55 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
56 | if (checkType === 'presence') { | ||
57 | expect(notification).to.not.be.undefined | ||
58 | expect(notification.type).to.equal(notificationType) | ||
59 | |||
60 | checkVideo(notification.video, videoName, shortUUID) | ||
61 | checkActor(notification.video.channel) | ||
62 | } else { | ||
63 | expect(notification).to.satisfy((n: UserNotification) => { | ||
64 | return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName | ||
65 | }) | ||
66 | } | ||
67 | } | ||
68 | |||
69 | function emailNotificationFinder (email: object) { | ||
70 | const text = email['text'] | ||
71 | return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1 | ||
72 | } | ||
73 | |||
74 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
75 | } | ||
76 | |||
77 | async function checkVideoIsPublished (options: CheckerBaseParams & { | ||
78 | videoName: string | ||
79 | shortUUID: string | ||
80 | checkType: CheckerType | ||
81 | }) { | ||
82 | const { videoName, shortUUID } = options | ||
83 | const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED | ||
84 | |||
85 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
86 | if (checkType === 'presence') { | ||
87 | expect(notification).to.not.be.undefined | ||
88 | expect(notification.type).to.equal(notificationType) | ||
89 | |||
90 | checkVideo(notification.video, videoName, shortUUID) | ||
91 | checkActor(notification.video.channel) | ||
92 | } else { | ||
93 | expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName) | ||
94 | } | ||
95 | } | ||
96 | |||
97 | function emailNotificationFinder (email: object) { | ||
98 | const text: string = email['text'] | ||
99 | return text.includes(shortUUID) && text.includes('Your video') | ||
100 | } | ||
101 | |||
102 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
103 | } | ||
104 | |||
105 | async function checkMyVideoImportIsFinished (options: CheckerBaseParams & { | ||
106 | videoName: string | ||
107 | shortUUID: string | ||
108 | url: string | ||
109 | success: boolean | ||
110 | checkType: CheckerType | ||
111 | }) { | ||
112 | const { videoName, shortUUID, url, success } = options | ||
113 | |||
114 | const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR | ||
115 | |||
116 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
117 | if (checkType === 'presence') { | ||
118 | expect(notification).to.not.be.undefined | ||
119 | expect(notification.type).to.equal(notificationType) | ||
120 | |||
121 | expect(notification.videoImport.targetUrl).to.equal(url) | ||
122 | |||
123 | if (success) checkVideo(notification.videoImport.video, videoName, shortUUID) | ||
124 | } else { | ||
125 | expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | function emailNotificationFinder (email: object) { | ||
130 | const text: string = email['text'] | ||
131 | const toFind = success ? ' finished' : ' error' | ||
132 | |||
133 | return text.includes(url) && text.includes(toFind) | ||
134 | } | ||
135 | |||
136 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
137 | } | ||
138 | |||
139 | async function checkUserRegistered (options: CheckerBaseParams & { | ||
140 | username: string | ||
141 | checkType: CheckerType | ||
142 | }) { | ||
143 | const { username } = options | ||
144 | const notificationType = UserNotificationType.NEW_USER_REGISTRATION | ||
145 | |||
146 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
147 | if (checkType === 'presence') { | ||
148 | expect(notification).to.not.be.undefined | ||
149 | expect(notification.type).to.equal(notificationType) | ||
150 | |||
151 | checkActor(notification.account) | ||
152 | expect(notification.account.name).to.equal(username) | ||
153 | } else { | ||
154 | expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username) | ||
155 | } | ||
156 | } | ||
157 | |||
158 | function emailNotificationFinder (email: object) { | ||
159 | const text: string = email['text'] | ||
160 | |||
161 | return text.includes(' registered.') && text.includes(username) | ||
162 | } | ||
163 | |||
164 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
165 | } | ||
166 | |||
167 | async function checkNewActorFollow (options: CheckerBaseParams & { | ||
168 | followType: 'channel' | 'account' | ||
169 | followerName: string | ||
170 | followerDisplayName: string | ||
171 | followingDisplayName: string | ||
172 | checkType: CheckerType | ||
173 | }) { | ||
174 | const { followType, followerName, followerDisplayName, followingDisplayName } = options | ||
175 | const notificationType = UserNotificationType.NEW_FOLLOW | ||
176 | |||
177 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
178 | if (checkType === 'presence') { | ||
179 | expect(notification).to.not.be.undefined | ||
180 | expect(notification.type).to.equal(notificationType) | ||
181 | |||
182 | checkActor(notification.actorFollow.follower) | ||
183 | expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName) | ||
184 | expect(notification.actorFollow.follower.name).to.equal(followerName) | ||
185 | expect(notification.actorFollow.follower.host).to.not.be.undefined | ||
186 | |||
187 | const following = notification.actorFollow.following | ||
188 | expect(following.displayName).to.equal(followingDisplayName) | ||
189 | expect(following.type).to.equal(followType) | ||
190 | } else { | ||
191 | expect(notification).to.satisfy(n => { | ||
192 | return n.type !== notificationType || | ||
193 | (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName) | ||
194 | }) | ||
195 | } | ||
196 | } | ||
197 | |||
198 | function emailNotificationFinder (email: object) { | ||
199 | const text: string = email['text'] | ||
200 | |||
201 | return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName) | ||
202 | } | ||
203 | |||
204 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
205 | } | ||
206 | |||
207 | async function checkNewInstanceFollower (options: CheckerBaseParams & { | ||
208 | followerHost: string | ||
209 | checkType: CheckerType | ||
210 | }) { | ||
211 | const { followerHost } = options | ||
212 | const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER | ||
213 | |||
214 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
215 | if (checkType === 'presence') { | ||
216 | expect(notification).to.not.be.undefined | ||
217 | expect(notification.type).to.equal(notificationType) | ||
218 | |||
219 | checkActor(notification.actorFollow.follower) | ||
220 | expect(notification.actorFollow.follower.name).to.equal('peertube') | ||
221 | expect(notification.actorFollow.follower.host).to.equal(followerHost) | ||
222 | |||
223 | expect(notification.actorFollow.following.name).to.equal('peertube') | ||
224 | } else { | ||
225 | expect(notification).to.satisfy(n => { | ||
226 | return n.type !== notificationType || n.actorFollow.follower.host !== followerHost | ||
227 | }) | ||
228 | } | ||
229 | } | ||
230 | |||
231 | function emailNotificationFinder (email: object) { | ||
232 | const text: string = email['text'] | ||
233 | |||
234 | return text.includes('instance has a new follower') && text.includes(followerHost) | ||
235 | } | ||
236 | |||
237 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
238 | } | ||
239 | |||
240 | async function checkAutoInstanceFollowing (options: CheckerBaseParams & { | ||
241 | followerHost: string | ||
242 | followingHost: string | ||
243 | checkType: CheckerType | ||
244 | }) { | ||
245 | const { followerHost, followingHost } = options | ||
246 | const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING | ||
247 | |||
248 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
249 | if (checkType === 'presence') { | ||
250 | expect(notification).to.not.be.undefined | ||
251 | expect(notification.type).to.equal(notificationType) | ||
252 | |||
253 | const following = notification.actorFollow.following | ||
254 | checkActor(following) | ||
255 | expect(following.name).to.equal('peertube') | ||
256 | expect(following.host).to.equal(followingHost) | ||
257 | |||
258 | expect(notification.actorFollow.follower.name).to.equal('peertube') | ||
259 | expect(notification.actorFollow.follower.host).to.equal(followerHost) | ||
260 | } else { | ||
261 | expect(notification).to.satisfy(n => { | ||
262 | return n.type !== notificationType || n.actorFollow.following.host !== followingHost | ||
263 | }) | ||
264 | } | ||
265 | } | ||
266 | |||
267 | function emailNotificationFinder (email: object) { | ||
268 | const text: string = email['text'] | ||
269 | |||
270 | return text.includes(' automatically followed a new instance') && text.includes(followingHost) | ||
271 | } | ||
272 | |||
273 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
274 | } | ||
275 | |||
276 | async function checkCommentMention (options: CheckerBaseParams & { | ||
277 | shortUUID: string | ||
278 | commentId: number | ||
279 | threadId: number | ||
280 | byAccountDisplayName: string | ||
281 | checkType: CheckerType | ||
282 | }) { | ||
283 | const { shortUUID, commentId, threadId, byAccountDisplayName } = options | ||
284 | const notificationType = UserNotificationType.COMMENT_MENTION | ||
285 | |||
286 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
287 | if (checkType === 'presence') { | ||
288 | expect(notification).to.not.be.undefined | ||
289 | expect(notification.type).to.equal(notificationType) | ||
290 | |||
291 | checkComment(notification.comment, commentId, threadId) | ||
292 | checkActor(notification.comment.account) | ||
293 | expect(notification.comment.account.displayName).to.equal(byAccountDisplayName) | ||
294 | |||
295 | checkVideo(notification.comment.video, undefined, shortUUID) | ||
296 | } else { | ||
297 | expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId) | ||
298 | } | ||
299 | } | ||
300 | |||
301 | function emailNotificationFinder (email: object) { | ||
302 | const text: string = email['text'] | ||
303 | |||
304 | return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName) | ||
305 | } | ||
306 | |||
307 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
308 | } | ||
309 | |||
310 | let lastEmailCount = 0 | ||
311 | |||
312 | async function checkNewCommentOnMyVideo (options: CheckerBaseParams & { | ||
313 | shortUUID: string | ||
314 | commentId: number | ||
315 | threadId: number | ||
316 | checkType: CheckerType | ||
317 | }) { | ||
318 | const { server, shortUUID, commentId, threadId, checkType, emails } = options | ||
319 | const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO | ||
320 | |||
321 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
322 | if (checkType === 'presence') { | ||
323 | expect(notification).to.not.be.undefined | ||
324 | expect(notification.type).to.equal(notificationType) | ||
325 | |||
326 | checkComment(notification.comment, commentId, threadId) | ||
327 | checkActor(notification.comment.account) | ||
328 | checkVideo(notification.comment.video, undefined, shortUUID) | ||
329 | } else { | ||
330 | expect(notification).to.satisfy((n: UserNotification) => { | ||
331 | return n === undefined || n.comment === undefined || n.comment.id !== commentId | ||
332 | }) | ||
333 | } | ||
334 | } | ||
335 | |||
336 | const commentUrl = `http://localhost:${server.port}/w/${shortUUID};threadId=${threadId}` | ||
337 | |||
338 | function emailNotificationFinder (email: object) { | ||
339 | return email['text'].indexOf(commentUrl) !== -1 | ||
340 | } | ||
341 | |||
342 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
343 | |||
344 | if (checkType === 'presence') { | ||
345 | // We cannot detect email duplicates, so check we received another email | ||
346 | expect(emails).to.have.length.above(lastEmailCount) | ||
347 | lastEmailCount = emails.length | ||
348 | } | ||
349 | } | ||
350 | |||
351 | async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & { | ||
352 | shortUUID: string | ||
353 | videoName: string | ||
354 | checkType: CheckerType | ||
355 | }) { | ||
356 | const { shortUUID, videoName } = options | ||
357 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | ||
358 | |||
359 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
360 | if (checkType === 'presence') { | ||
361 | expect(notification).to.not.be.undefined | ||
362 | expect(notification.type).to.equal(notificationType) | ||
363 | |||
364 | expect(notification.abuse.id).to.be.a('number') | ||
365 | checkVideo(notification.abuse.video, videoName, shortUUID) | ||
366 | } else { | ||
367 | expect(notification).to.satisfy((n: UserNotification) => { | ||
368 | return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID | ||
369 | }) | ||
370 | } | ||
371 | } | ||
372 | |||
373 | function emailNotificationFinder (email: object) { | ||
374 | const text = email['text'] | ||
375 | return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 | ||
376 | } | ||
377 | |||
378 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
379 | } | ||
380 | |||
381 | async function checkNewAbuseMessage (options: CheckerBaseParams & { | ||
382 | abuseId: number | ||
383 | message: string | ||
384 | toEmail: string | ||
385 | checkType: CheckerType | ||
386 | }) { | ||
387 | const { abuseId, message, toEmail } = options | ||
388 | const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE | ||
389 | |||
390 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
391 | if (checkType === 'presence') { | ||
392 | expect(notification).to.not.be.undefined | ||
393 | expect(notification.type).to.equal(notificationType) | ||
394 | |||
395 | expect(notification.abuse.id).to.equal(abuseId) | ||
396 | } else { | ||
397 | expect(notification).to.satisfy((n: UserNotification) => { | ||
398 | return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId | ||
399 | }) | ||
400 | } | ||
401 | } | ||
402 | |||
403 | function emailNotificationFinder (email: object) { | ||
404 | const text = email['text'] | ||
405 | const to = email['to'].filter(t => t.address === toEmail) | ||
406 | |||
407 | return text.indexOf(message) !== -1 && to.length !== 0 | ||
408 | } | ||
409 | |||
410 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
411 | } | ||
412 | |||
413 | async function checkAbuseStateChange (options: CheckerBaseParams & { | ||
414 | abuseId: number | ||
415 | state: AbuseState | ||
416 | checkType: CheckerType | ||
417 | }) { | ||
418 | const { abuseId, state } = options | ||
419 | const notificationType = UserNotificationType.ABUSE_STATE_CHANGE | ||
420 | |||
421 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
422 | if (checkType === 'presence') { | ||
423 | expect(notification).to.not.be.undefined | ||
424 | expect(notification.type).to.equal(notificationType) | ||
425 | |||
426 | expect(notification.abuse.id).to.equal(abuseId) | ||
427 | expect(notification.abuse.state).to.equal(state) | ||
428 | } else { | ||
429 | expect(notification).to.satisfy((n: UserNotification) => { | ||
430 | return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId | ||
431 | }) | ||
432 | } | ||
433 | } | ||
434 | |||
435 | function emailNotificationFinder (email: object) { | ||
436 | const text = email['text'] | ||
437 | |||
438 | const contains = state === AbuseState.ACCEPTED | ||
439 | ? ' accepted' | ||
440 | : ' rejected' | ||
441 | |||
442 | return text.indexOf(contains) !== -1 | ||
443 | } | ||
444 | |||
445 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
446 | } | ||
447 | |||
448 | async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & { | ||
449 | shortUUID: string | ||
450 | videoName: string | ||
451 | checkType: CheckerType | ||
452 | }) { | ||
453 | const { shortUUID, videoName } = options | ||
454 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | ||
455 | |||
456 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
457 | if (checkType === 'presence') { | ||
458 | expect(notification).to.not.be.undefined | ||
459 | expect(notification.type).to.equal(notificationType) | ||
460 | |||
461 | expect(notification.abuse.id).to.be.a('number') | ||
462 | checkVideo(notification.abuse.comment.video, videoName, shortUUID) | ||
463 | } else { | ||
464 | expect(notification).to.satisfy((n: UserNotification) => { | ||
465 | return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID | ||
466 | }) | ||
467 | } | ||
468 | } | ||
469 | |||
470 | function emailNotificationFinder (email: object) { | ||
471 | const text = email['text'] | ||
472 | return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1 | ||
473 | } | ||
474 | |||
475 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
476 | } | ||
477 | |||
478 | async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & { | ||
479 | displayName: string | ||
480 | checkType: CheckerType | ||
481 | }) { | ||
482 | const { displayName } = options | ||
483 | const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS | ||
484 | |||
485 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
486 | if (checkType === 'presence') { | ||
487 | expect(notification).to.not.be.undefined | ||
488 | expect(notification.type).to.equal(notificationType) | ||
489 | |||
490 | expect(notification.abuse.id).to.be.a('number') | ||
491 | expect(notification.abuse.account.displayName).to.equal(displayName) | ||
492 | } else { | ||
493 | expect(notification).to.satisfy((n: UserNotification) => { | ||
494 | return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName | ||
495 | }) | ||
496 | } | ||
497 | } | ||
498 | |||
499 | function emailNotificationFinder (email: object) { | ||
500 | const text = email['text'] | ||
501 | return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1 | ||
502 | } | ||
503 | |||
504 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
505 | } | ||
506 | |||
507 | async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & { | ||
508 | shortUUID: string | ||
509 | videoName: string | ||
510 | checkType: CheckerType | ||
511 | }) { | ||
512 | const { shortUUID, videoName } = options | ||
513 | const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS | ||
514 | |||
515 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
516 | if (checkType === 'presence') { | ||
517 | expect(notification).to.not.be.undefined | ||
518 | expect(notification.type).to.equal(notificationType) | ||
519 | |||
520 | expect(notification.videoBlacklist.video.id).to.be.a('number') | ||
521 | checkVideo(notification.videoBlacklist.video, videoName, shortUUID) | ||
522 | } else { | ||
523 | expect(notification).to.satisfy((n: UserNotification) => { | ||
524 | return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID | ||
525 | }) | ||
526 | } | ||
527 | } | ||
528 | |||
529 | function emailNotificationFinder (email: object) { | ||
530 | const text = email['text'] | ||
531 | return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1 | ||
532 | } | ||
533 | |||
534 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
535 | } | ||
536 | |||
537 | async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & { | ||
538 | shortUUID: string | ||
539 | videoName: string | ||
540 | blacklistType: 'blacklist' | 'unblacklist' | ||
541 | }) { | ||
542 | const { videoName, shortUUID, blacklistType } = options | ||
543 | const notificationType = blacklistType === 'blacklist' | ||
544 | ? UserNotificationType.BLACKLIST_ON_MY_VIDEO | ||
545 | : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO | ||
546 | |||
547 | function notificationChecker (notification: UserNotification) { | ||
548 | expect(notification).to.not.be.undefined | ||
549 | expect(notification.type).to.equal(notificationType) | ||
550 | |||
551 | const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video | ||
552 | |||
553 | checkVideo(video, videoName, shortUUID) | ||
554 | } | ||
555 | |||
556 | function emailNotificationFinder (email: object) { | ||
557 | const text = email['text'] | ||
558 | const blacklistText = blacklistType === 'blacklist' | ||
559 | ? 'blacklisted' | ||
560 | : 'unblacklisted' | ||
561 | |||
562 | return text.includes(shortUUID) && text.includes(blacklistText) | ||
563 | } | ||
564 | |||
565 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' }) | ||
566 | } | ||
567 | |||
568 | async function checkNewPeerTubeVersion (options: CheckerBaseParams & { | ||
569 | latestVersion: string | ||
570 | checkType: CheckerType | ||
571 | }) { | ||
572 | const { latestVersion } = options | ||
573 | const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION | ||
574 | |||
575 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
576 | if (checkType === 'presence') { | ||
577 | expect(notification).to.not.be.undefined | ||
578 | expect(notification.type).to.equal(notificationType) | ||
579 | |||
580 | expect(notification.peertube).to.exist | ||
581 | expect(notification.peertube.latestVersion).to.equal(latestVersion) | ||
582 | } else { | ||
583 | expect(notification).to.satisfy((n: UserNotification) => { | ||
584 | return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion | ||
585 | }) | ||
586 | } | ||
587 | } | ||
588 | |||
589 | function emailNotificationFinder (email: object) { | ||
590 | const text = email['text'] | ||
591 | |||
592 | return text.includes(latestVersion) | ||
593 | } | ||
594 | |||
595 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
596 | } | ||
597 | |||
598 | async function checkNewPluginVersion (options: CheckerBaseParams & { | ||
599 | pluginType: PluginType | ||
600 | pluginName: string | ||
601 | checkType: CheckerType | ||
602 | }) { | ||
603 | const { pluginName, pluginType } = options | ||
604 | const notificationType = UserNotificationType.NEW_PLUGIN_VERSION | ||
605 | |||
606 | function notificationChecker (notification: UserNotification, checkType: CheckerType) { | ||
607 | if (checkType === 'presence') { | ||
608 | expect(notification).to.not.be.undefined | ||
609 | expect(notification.type).to.equal(notificationType) | ||
610 | |||
611 | expect(notification.plugin.name).to.equal(pluginName) | ||
612 | expect(notification.plugin.type).to.equal(pluginType) | ||
613 | } else { | ||
614 | expect(notification).to.satisfy((n: UserNotification) => { | ||
615 | return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName | ||
616 | }) | ||
617 | } | ||
618 | } | ||
619 | |||
620 | function emailNotificationFinder (email: object) { | ||
621 | const text = email['text'] | ||
622 | |||
623 | return text.includes(pluginName) | ||
624 | } | ||
625 | |||
626 | await checkNotification({ ...options, notificationChecker, emailNotificationFinder }) | ||
627 | } | ||
628 | |||
629 | async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) { | ||
630 | const userNotifications: UserNotification[] = [] | ||
631 | const adminNotifications: UserNotification[] = [] | ||
632 | const adminNotificationsServer2: UserNotification[] = [] | ||
633 | const emails: object[] = [] | ||
634 | |||
635 | const port = await MockSmtpServer.Instance.collectEmails(emails) | ||
636 | |||
637 | const overrideConfig = { | ||
638 | smtp: { | ||
639 | hostname: 'localhost', | ||
640 | port | ||
641 | }, | ||
642 | signup: { | ||
643 | limit: 20 | ||
644 | } | ||
645 | } | ||
646 | const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg)) | ||
647 | |||
648 | await setAccessTokensToServers(servers) | ||
649 | |||
650 | if (serversCount > 1) { | ||
651 | await doubleFollow(servers[0], servers[1]) | ||
652 | } | ||
653 | |||
654 | const user = { username: 'user_1', password: 'super password' } | ||
655 | await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 }) | ||
656 | const userAccessToken = await servers[0].login.getAccessToken(user) | ||
657 | |||
658 | await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() }) | ||
659 | await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) | ||
660 | |||
661 | if (serversCount > 1) { | ||
662 | await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() }) | ||
663 | } | ||
664 | |||
665 | { | ||
666 | const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken }) | ||
667 | socket.on('new-notification', n => userNotifications.push(n)) | ||
668 | } | ||
669 | { | ||
670 | const socket = servers[0].socketIO.getUserNotificationSocket() | ||
671 | socket.on('new-notification', n => adminNotifications.push(n)) | ||
672 | } | ||
673 | |||
674 | if (serversCount > 1) { | ||
675 | const socket = servers[1].socketIO.getUserNotificationSocket() | ||
676 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) | ||
677 | } | ||
678 | |||
679 | const { videoChannels } = await servers[0].users.getMyInfo() | ||
680 | const channelId = videoChannels[0].id | ||
681 | |||
682 | return { | ||
683 | userNotifications, | ||
684 | adminNotifications, | ||
685 | adminNotificationsServer2, | ||
686 | userAccessToken, | ||
687 | emails, | ||
688 | servers, | ||
689 | channelId | ||
690 | } | ||
691 | } | ||
692 | |||
693 | // --------------------------------------------------------------------------- | ||
694 | |||
695 | export { | ||
696 | getAllNotificationsSettings, | ||
697 | |||
698 | CheckerBaseParams, | ||
699 | CheckerType, | ||
700 | checkMyVideoImportIsFinished, | ||
701 | checkUserRegistered, | ||
702 | checkAutoInstanceFollowing, | ||
703 | checkVideoIsPublished, | ||
704 | checkNewVideoFromSubscription, | ||
705 | checkNewActorFollow, | ||
706 | checkNewCommentOnMyVideo, | ||
707 | checkNewBlacklistOnMyVideo, | ||
708 | checkCommentMention, | ||
709 | checkNewVideoAbuseForModerators, | ||
710 | checkVideoAutoBlacklistForModerators, | ||
711 | checkNewAbuseMessage, | ||
712 | checkAbuseStateChange, | ||
713 | checkNewInstanceFollower, | ||
714 | prepareNotificationsTest, | ||
715 | checkNewCommentAbuseForModerators, | ||
716 | checkNewAccountAbuseForModerators, | ||
717 | checkNewPeerTubeVersion, | ||
718 | checkNewPluginVersion | ||
719 | } | ||
720 | |||
721 | // --------------------------------------------------------------------------- | ||
722 | |||
723 | async function checkNotification (options: CheckerBaseParams & { | ||
724 | notificationChecker: (notification: UserNotification, checkType: CheckerType) => void | ||
725 | emailNotificationFinder: (email: object) => boolean | ||
726 | checkType: CheckerType | ||
727 | }) { | ||
728 | const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options | ||
729 | |||
730 | const check = options.check || { web: true, mail: true } | ||
731 | |||
732 | if (check.web) { | ||
733 | const notification = await server.notifications.getLatest({ token: token }) | ||
734 | |||
735 | if (notification || checkType !== 'absence') { | ||
736 | notificationChecker(notification, checkType) | ||
737 | } | ||
738 | |||
739 | const socketNotification = socketNotifications.find(n => { | ||
740 | try { | ||
741 | notificationChecker(n, 'presence') | ||
742 | return true | ||
743 | } catch { | ||
744 | return false | ||
745 | } | ||
746 | }) | ||
747 | |||
748 | if (checkType === 'presence') { | ||
749 | const obj = inspect(socketNotifications, { depth: 5 }) | ||
750 | expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined | ||
751 | } else { | ||
752 | const obj = inspect(socketNotification, { depth: 5 }) | ||
753 | expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined | ||
754 | } | ||
755 | } | ||
756 | |||
757 | if (check.mail) { | ||
758 | // Last email | ||
759 | const email = emails | ||
760 | .slice() | ||
761 | .reverse() | ||
762 | .find(e => emailNotificationFinder(e)) | ||
763 | |||
764 | if (checkType === 'presence') { | ||
765 | const texts = emails.map(e => e.text) | ||
766 | expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined | ||
767 | } else { | ||
768 | expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined | ||
769 | } | ||
770 | } | ||
771 | } | ||
772 | |||
773 | function checkVideo (video: any, videoName?: string, shortUUID?: string) { | ||
774 | if (videoName) { | ||
775 | expect(video.name).to.be.a('string') | ||
776 | expect(video.name).to.not.be.empty | ||
777 | expect(video.name).to.equal(videoName) | ||
778 | } | ||
779 | |||
780 | if (shortUUID) { | ||
781 | expect(video.shortUUID).to.be.a('string') | ||
782 | expect(video.shortUUID).to.not.be.empty | ||
783 | expect(video.shortUUID).to.equal(shortUUID) | ||
784 | } | ||
785 | |||
786 | expect(video.id).to.be.a('number') | ||
787 | } | ||
788 | |||
789 | function checkActor (actor: any) { | ||
790 | expect(actor.displayName).to.be.a('string') | ||
791 | expect(actor.displayName).to.not.be.empty | ||
792 | expect(actor.host).to.not.be.undefined | ||
793 | } | ||
794 | |||
795 | function checkComment (comment: any, commentId: number, threadId: number) { | ||
796 | expect(comment.id).to.equal(commentId) | ||
797 | expect(comment.threadId).to.equal(threadId) | ||
798 | } | ||
diff --git a/server/tests/shared/playlists.ts b/server/tests/shared/playlists.ts new file mode 100644 index 000000000..fdd541d20 --- /dev/null +++ b/server/tests/shared/playlists.ts | |||
@@ -0,0 +1,25 @@ | |||
1 | import { expect } from 'chai' | ||
2 | import { readdir } from 'fs-extra' | ||
3 | import { join } from 'path' | ||
4 | import { root } from '@shared/core-utils' | ||
5 | |||
6 | async function checkPlaylistFilesWereRemoved ( | ||
7 | playlistUUID: string, | ||
8 | internalServerNumber: number, | ||
9 | directories = [ 'thumbnails' ] | ||
10 | ) { | ||
11 | const testDirectory = 'test' + internalServerNumber | ||
12 | |||
13 | for (const directory of directories) { | ||
14 | const directoryPath = join(root(), testDirectory, directory) | ||
15 | |||
16 | const files = await readdir(directoryPath) | ||
17 | for (const file of files) { | ||
18 | expect(file).to.not.contain(playlistUUID) | ||
19 | } | ||
20 | } | ||
21 | } | ||
22 | |||
23 | export { | ||
24 | checkPlaylistFilesWereRemoved | ||
25 | } | ||
diff --git a/server/tests/shared/plugins.ts b/server/tests/shared/plugins.ts new file mode 100644 index 000000000..036fce2ff --- /dev/null +++ b/server/tests/shared/plugins.ts | |||
@@ -0,0 +1,18 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { PeerTubeServer } from '@shared/server-commands' | ||
5 | |||
6 | async function testHelloWorldRegisteredSettings (server: PeerTubeServer) { | ||
7 | const body = await server.plugins.getRegisteredSettings({ npmName: 'peertube-plugin-hello-world' }) | ||
8 | |||
9 | const registeredSettings = body.registeredSettings | ||
10 | expect(registeredSettings).to.have.length.at.least(1) | ||
11 | |||
12 | const adminNameSettings = registeredSettings.find(s => s.name === 'admin-name') | ||
13 | expect(adminNameSettings).to.not.be.undefined | ||
14 | } | ||
15 | |||
16 | export { | ||
17 | testHelloWorldRegisteredSettings | ||
18 | } | ||
diff --git a/server/tests/shared/requests.ts b/server/tests/shared/requests.ts new file mode 100644 index 000000000..7f1acc0e1 --- /dev/null +++ b/server/tests/shared/requests.ts | |||
@@ -0,0 +1,41 @@ | |||
1 | import { activityPubContextify } from '@server/helpers/activitypub' | ||
2 | import { buildDigest } from '@server/helpers/peertube-crypto' | ||
3 | import { doRequest } from '@server/helpers/requests' | ||
4 | import { ACTIVITY_PUB, HTTP_SIGNATURE } from '@server/initializers/constants' | ||
5 | |||
6 | export function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) { | ||
7 | const options = { | ||
8 | method: 'POST' as 'POST', | ||
9 | json: body, | ||
10 | httpSignature, | ||
11 | headers | ||
12 | } | ||
13 | |||
14 | return doRequest(url, options) | ||
15 | } | ||
16 | |||
17 | export async function makeFollowRequest (to: { url: string }, by: { url: string, privateKey }) { | ||
18 | const follow = { | ||
19 | type: 'Follow', | ||
20 | id: by.url + '/' + new Date().getTime(), | ||
21 | actor: by.url, | ||
22 | object: to.url | ||
23 | } | ||
24 | |||
25 | const body = activityPubContextify(follow) | ||
26 | |||
27 | const httpSignature = { | ||
28 | algorithm: HTTP_SIGNATURE.ALGORITHM, | ||
29 | authorizationHeaderName: HTTP_SIGNATURE.HEADER_NAME, | ||
30 | keyId: by.url, | ||
31 | key: by.privateKey, | ||
32 | headers: HTTP_SIGNATURE.HEADERS_TO_SIGN | ||
33 | } | ||
34 | const headers = { | ||
35 | 'digest': buildDigest(body), | ||
36 | 'content-type': 'application/activity+json', | ||
37 | 'accept': ACTIVITY_PUB.ACCEPT_HEADER | ||
38 | } | ||
39 | |||
40 | return makePOSTAPRequest(to.url + '/inbox', body, httpSignature, headers) | ||
41 | } | ||
diff --git a/server/tests/shared/streaming-playlists.ts b/server/tests/shared/streaming-playlists.ts new file mode 100644 index 000000000..7ca707f2e --- /dev/null +++ b/server/tests/shared/streaming-playlists.ts | |||
@@ -0,0 +1,77 @@ | |||
1 | import { expect } from 'chai' | ||
2 | import { basename } from 'path' | ||
3 | import { removeFragmentedMP4Ext } from '@shared/core-utils' | ||
4 | import { sha256 } from '@shared/extra-utils' | ||
5 | import { HttpStatusCode, VideoStreamingPlaylist } from '@shared/models' | ||
6 | import { PeerTubeServer } from '@shared/server-commands' | ||
7 | |||
8 | async function checkSegmentHash (options: { | ||
9 | server: PeerTubeServer | ||
10 | baseUrlPlaylist: string | ||
11 | baseUrlSegment: string | ||
12 | resolution: number | ||
13 | hlsPlaylist: VideoStreamingPlaylist | ||
14 | }) { | ||
15 | const { server, baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist } = options | ||
16 | const command = server.streamingPlaylists | ||
17 | |||
18 | const file = hlsPlaylist.files.find(f => f.resolution.id === resolution) | ||
19 | const videoName = basename(file.fileUrl) | ||
20 | |||
21 | const playlist = await command.get({ url: `${baseUrlPlaylist}/${removeFragmentedMP4Ext(videoName)}.m3u8` }) | ||
22 | |||
23 | const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) | ||
24 | |||
25 | const length = parseInt(matches[1], 10) | ||
26 | const offset = parseInt(matches[2], 10) | ||
27 | const range = `${offset}-${offset + length - 1}` | ||
28 | |||
29 | const segmentBody = await command.getSegment({ | ||
30 | url: `${baseUrlSegment}/${videoName}`, | ||
31 | expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206, | ||
32 | range: `bytes=${range}` | ||
33 | }) | ||
34 | |||
35 | const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) | ||
36 | expect(sha256(segmentBody)).to.equal(shaBody[videoName][range]) | ||
37 | } | ||
38 | |||
39 | async function checkLiveSegmentHash (options: { | ||
40 | server: PeerTubeServer | ||
41 | baseUrlSegment: string | ||
42 | videoUUID: string | ||
43 | segmentName: string | ||
44 | hlsPlaylist: VideoStreamingPlaylist | ||
45 | }) { | ||
46 | const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options | ||
47 | const command = server.streamingPlaylists | ||
48 | |||
49 | const segmentBody = await command.getSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` }) | ||
50 | const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url }) | ||
51 | |||
52 | expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) | ||
53 | } | ||
54 | |||
55 | async function checkResolutionsInMasterPlaylist (options: { | ||
56 | server: PeerTubeServer | ||
57 | playlistUrl: string | ||
58 | resolutions: number[] | ||
59 | }) { | ||
60 | const { server, playlistUrl, resolutions } = options | ||
61 | |||
62 | const masterPlaylist = await server.streamingPlaylists.get({ url: playlistUrl }) | ||
63 | |||
64 | for (const resolution of resolutions) { | ||
65 | const reg = new RegExp( | ||
66 | '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"' | ||
67 | ) | ||
68 | |||
69 | expect(masterPlaylist).to.match(reg) | ||
70 | } | ||
71 | } | ||
72 | |||
73 | export { | ||
74 | checkSegmentHash, | ||
75 | checkLiveSegmentHash, | ||
76 | checkResolutionsInMasterPlaylist | ||
77 | } | ||
diff --git a/server/tests/shared/tests.ts b/server/tests/shared/tests.ts new file mode 100644 index 000000000..3abaf833d --- /dev/null +++ b/server/tests/shared/tests.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | const FIXTURE_URLS = { | ||
2 | peertube_long: 'https://peertube2.cpy.re/videos/watch/122d093a-1ede-43bd-bd34-59d2931ffc5e', | ||
3 | peertube_short: 'https://peertube2.cpy.re/w/3fbif9S3WmtTP8gGsC5HBd', | ||
4 | |||
5 | youtube: 'https://www.youtube.com/watch?v=msX3jv1XdvM', | ||
6 | |||
7 | /** | ||
8 | * The video is used to check format-selection correctness wrt. HDR, | ||
9 | * which brings its own set of oddities outside of a MediaSource. | ||
10 | * | ||
11 | * The video needs to have the following format_ids: | ||
12 | * (which you can check by using `youtube-dl <url> -F`): | ||
13 | * - (webm vp9) | ||
14 | * - (mp4 avc1) | ||
15 | * - (webm vp9.2 HDR) | ||
16 | */ | ||
17 | youtubeHDR: 'https://www.youtube.com/watch?v=RQgnBB9z_N4', | ||
18 | |||
19 | // eslint-disable-next-line max-len | ||
20 | magnet: 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4', | ||
21 | |||
22 | badVideo: 'https://download.cpy.re/peertube/bad_video.mp4', | ||
23 | goodVideo: 'https://download.cpy.re/peertube/good_video.mp4', | ||
24 | goodVideo720: 'https://download.cpy.re/peertube/good_video_720.mp4', | ||
25 | |||
26 | file4K: 'https://download.cpy.re/peertube/4k_file.txt' | ||
27 | } | ||
28 | |||
29 | function buildRequestStub (): any { | ||
30 | return { } | ||
31 | } | ||
32 | |||
33 | export { | ||
34 | FIXTURE_URLS, | ||
35 | |||
36 | buildRequestStub | ||
37 | } | ||
diff --git a/server/tests/shared/tracker.ts b/server/tests/shared/tracker.ts new file mode 100644 index 000000000..9c1f0246a --- /dev/null +++ b/server/tests/shared/tracker.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { expect } from 'chai' | ||
2 | import { sha1 } from '@shared/extra-utils' | ||
3 | import { makeGetRequest } from '@shared/server-commands' | ||
4 | |||
5 | async function hlsInfohashExist (serverUrl: string, masterPlaylistUrl: string, fileNumber: number) { | ||
6 | const path = '/tracker/announce' | ||
7 | |||
8 | const infohash = sha1(`2${masterPlaylistUrl}+V${fileNumber}`) | ||
9 | |||
10 | // From bittorrent-tracker | ||
11 | const infohashBinary = escape(Buffer.from(infohash, 'hex').toString('binary')).replace(/[@*/+]/g, function (char) { | ||
12 | return '%' + char.charCodeAt(0).toString(16).toUpperCase() | ||
13 | }) | ||
14 | |||
15 | const res = await makeGetRequest({ | ||
16 | url: serverUrl, | ||
17 | path, | ||
18 | rawQuery: `peer_id=-WW0105-NkvYO/egUAr4&info_hash=${infohashBinary}&port=42100`, | ||
19 | expectedStatus: 200 | ||
20 | }) | ||
21 | |||
22 | expect(res.text).to.not.contain('failure') | ||
23 | } | ||
24 | |||
25 | export { | ||
26 | hlsInfohashExist | ||
27 | } | ||
diff --git a/server/tests/shared/videos.ts b/server/tests/shared/videos.ts new file mode 100644 index 000000000..6be094f2b --- /dev/null +++ b/server/tests/shared/videos.ts | |||
@@ -0,0 +1,251 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ | ||
2 | |||
3 | import { expect } from 'chai' | ||
4 | import { pathExists, readdir } from 'fs-extra' | ||
5 | import { basename, join } from 'path' | ||
6 | import { loadLanguages, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES } from '@server/initializers/constants' | ||
7 | import { getLowercaseExtension, uuidRegex } from '@shared/core-utils' | ||
8 | import { HttpStatusCode, VideoCaption, VideoDetails } from '@shared/models' | ||
9 | import { makeRawRequest, PeerTubeServer, VideoEdit, waitJobs, webtorrentAdd } from '@shared/server-commands' | ||
10 | import { dateIsValid, testImage } from './checks' | ||
11 | |||
12 | loadLanguages() | ||
13 | |||
14 | async function completeVideoCheck ( | ||
15 | server: PeerTubeServer, | ||
16 | video: any, | ||
17 | attributes: { | ||
18 | name: string | ||
19 | category: number | ||
20 | licence: number | ||
21 | language: string | ||
22 | nsfw: boolean | ||
23 | commentsEnabled: boolean | ||
24 | downloadEnabled: boolean | ||
25 | description: string | ||
26 | publishedAt?: string | ||
27 | support: string | ||
28 | originallyPublishedAt?: string | ||
29 | account: { | ||
30 | name: string | ||
31 | host: string | ||
32 | } | ||
33 | isLocal: boolean | ||
34 | tags: string[] | ||
35 | privacy: number | ||
36 | likes?: number | ||
37 | dislikes?: number | ||
38 | duration: number | ||
39 | channel: { | ||
40 | displayName: string | ||
41 | name: string | ||
42 | description: string | ||
43 | isLocal: boolean | ||
44 | } | ||
45 | fixture: string | ||
46 | files: { | ||
47 | resolution: number | ||
48 | size: number | ||
49 | }[] | ||
50 | thumbnailfile?: string | ||
51 | previewfile?: string | ||
52 | } | ||
53 | ) { | ||
54 | if (!attributes.likes) attributes.likes = 0 | ||
55 | if (!attributes.dislikes) attributes.dislikes = 0 | ||
56 | |||
57 | const host = new URL(server.url).host | ||
58 | const originHost = attributes.account.host | ||
59 | |||
60 | expect(video.name).to.equal(attributes.name) | ||
61 | expect(video.category.id).to.equal(attributes.category) | ||
62 | expect(video.category.label).to.equal(attributes.category !== null ? VIDEO_CATEGORIES[attributes.category] : 'Misc') | ||
63 | expect(video.licence.id).to.equal(attributes.licence) | ||
64 | expect(video.licence.label).to.equal(attributes.licence !== null ? VIDEO_LICENCES[attributes.licence] : 'Unknown') | ||
65 | expect(video.language.id).to.equal(attributes.language) | ||
66 | expect(video.language.label).to.equal(attributes.language !== null ? VIDEO_LANGUAGES[attributes.language] : 'Unknown') | ||
67 | expect(video.privacy.id).to.deep.equal(attributes.privacy) | ||
68 | expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy]) | ||
69 | expect(video.nsfw).to.equal(attributes.nsfw) | ||
70 | expect(video.description).to.equal(attributes.description) | ||
71 | expect(video.account.id).to.be.a('number') | ||
72 | expect(video.account.host).to.equal(attributes.account.host) | ||
73 | expect(video.account.name).to.equal(attributes.account.name) | ||
74 | expect(video.channel.displayName).to.equal(attributes.channel.displayName) | ||
75 | expect(video.channel.name).to.equal(attributes.channel.name) | ||
76 | expect(video.likes).to.equal(attributes.likes) | ||
77 | expect(video.dislikes).to.equal(attributes.dislikes) | ||
78 | expect(video.isLocal).to.equal(attributes.isLocal) | ||
79 | expect(video.duration).to.equal(attributes.duration) | ||
80 | expect(video.url).to.contain(originHost) | ||
81 | expect(dateIsValid(video.createdAt)).to.be.true | ||
82 | expect(dateIsValid(video.publishedAt)).to.be.true | ||
83 | expect(dateIsValid(video.updatedAt)).to.be.true | ||
84 | |||
85 | if (attributes.publishedAt) { | ||
86 | expect(video.publishedAt).to.equal(attributes.publishedAt) | ||
87 | } | ||
88 | |||
89 | if (attributes.originallyPublishedAt) { | ||
90 | expect(video.originallyPublishedAt).to.equal(attributes.originallyPublishedAt) | ||
91 | } else { | ||
92 | expect(video.originallyPublishedAt).to.be.null | ||
93 | } | ||
94 | |||
95 | const videoDetails = await server.videos.get({ id: video.uuid }) | ||
96 | |||
97 | expect(videoDetails.files).to.have.lengthOf(attributes.files.length) | ||
98 | expect(videoDetails.tags).to.deep.equal(attributes.tags) | ||
99 | expect(videoDetails.account.name).to.equal(attributes.account.name) | ||
100 | expect(videoDetails.account.host).to.equal(attributes.account.host) | ||
101 | expect(video.channel.displayName).to.equal(attributes.channel.displayName) | ||
102 | expect(video.channel.name).to.equal(attributes.channel.name) | ||
103 | expect(videoDetails.channel.host).to.equal(attributes.account.host) | ||
104 | expect(videoDetails.channel.isLocal).to.equal(attributes.channel.isLocal) | ||
105 | expect(dateIsValid(videoDetails.channel.createdAt.toString())).to.be.true | ||
106 | expect(dateIsValid(videoDetails.channel.updatedAt.toString())).to.be.true | ||
107 | expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled) | ||
108 | expect(videoDetails.downloadEnabled).to.equal(attributes.downloadEnabled) | ||
109 | |||
110 | for (const attributeFile of attributes.files) { | ||
111 | const file = videoDetails.files.find(f => f.resolution.id === attributeFile.resolution) | ||
112 | expect(file).not.to.be.undefined | ||
113 | |||
114 | let extension = getLowercaseExtension(attributes.fixture) | ||
115 | // Transcoding enabled: extension will always be .mp4 | ||
116 | if (attributes.files.length > 1) extension = '.mp4' | ||
117 | |||
118 | expect(file.magnetUri).to.have.lengthOf.above(2) | ||
119 | |||
120 | expect(file.torrentDownloadUrl).to.match(new RegExp(`http://${host}/download/torrents/${uuidRegex}-${file.resolution.id}.torrent`)) | ||
121 | expect(file.torrentUrl).to.match(new RegExp(`http://${host}/lazy-static/torrents/${uuidRegex}-${file.resolution.id}.torrent`)) | ||
122 | |||
123 | expect(file.fileUrl).to.match(new RegExp(`http://${originHost}/static/webseed/${uuidRegex}-${file.resolution.id}${extension}`)) | ||
124 | expect(file.fileDownloadUrl).to.match(new RegExp(`http://${originHost}/download/videos/${uuidRegex}-${file.resolution.id}${extension}`)) | ||
125 | |||
126 | await Promise.all([ | ||
127 | makeRawRequest(file.torrentUrl, 200), | ||
128 | makeRawRequest(file.torrentDownloadUrl, 200), | ||
129 | makeRawRequest(file.metadataUrl, 200) | ||
130 | ]) | ||
131 | |||
132 | expect(file.resolution.id).to.equal(attributeFile.resolution) | ||
133 | expect(file.resolution.label).to.equal(attributeFile.resolution + 'p') | ||
134 | |||
135 | const minSize = attributeFile.size - ((10 * attributeFile.size) / 100) | ||
136 | const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100) | ||
137 | expect( | ||
138 | file.size, | ||
139 | 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')' | ||
140 | ).to.be.above(minSize).and.below(maxSize) | ||
141 | |||
142 | const torrent = await webtorrentAdd(file.magnetUri, true) | ||
143 | expect(torrent.files).to.be.an('array') | ||
144 | expect(torrent.files.length).to.equal(1) | ||
145 | expect(torrent.files[0].path).to.exist.and.to.not.equal('') | ||
146 | } | ||
147 | |||
148 | expect(videoDetails.thumbnailPath).to.exist | ||
149 | await testImage(server.url, attributes.thumbnailfile || attributes.fixture, videoDetails.thumbnailPath) | ||
150 | |||
151 | if (attributes.previewfile) { | ||
152 | expect(videoDetails.previewPath).to.exist | ||
153 | await testImage(server.url, attributes.previewfile, videoDetails.previewPath) | ||
154 | } | ||
155 | } | ||
156 | |||
157 | async function checkVideoFilesWereRemoved (options: { | ||
158 | server: PeerTubeServer | ||
159 | video: VideoDetails | ||
160 | captions?: VideoCaption[] | ||
161 | onlyVideoFiles?: boolean // default false | ||
162 | }) { | ||
163 | const { video, server, captions = [], onlyVideoFiles = false } = options | ||
164 | |||
165 | const webtorrentFiles = video.files || [] | ||
166 | const hlsFiles = video.streamingPlaylists[0]?.files || [] | ||
167 | |||
168 | const thumbnailName = basename(video.thumbnailPath) | ||
169 | const previewName = basename(video.previewPath) | ||
170 | |||
171 | const torrentNames = webtorrentFiles.concat(hlsFiles).map(f => basename(f.torrentUrl)) | ||
172 | |||
173 | const captionNames = captions.map(c => basename(c.captionPath)) | ||
174 | |||
175 | const webtorrentFilenames = webtorrentFiles.map(f => basename(f.fileUrl)) | ||
176 | const hlsFilenames = hlsFiles.map(f => basename(f.fileUrl)) | ||
177 | |||
178 | let directories: { [ directory: string ]: string[] } = { | ||
179 | videos: webtorrentFilenames, | ||
180 | redundancy: webtorrentFilenames, | ||
181 | [join('playlists', 'hls')]: hlsFilenames, | ||
182 | [join('redundancy', 'hls')]: hlsFilenames | ||
183 | } | ||
184 | |||
185 | if (onlyVideoFiles !== true) { | ||
186 | directories = { | ||
187 | ...directories, | ||
188 | |||
189 | thumbnails: [ thumbnailName ], | ||
190 | previews: [ previewName ], | ||
191 | torrents: torrentNames, | ||
192 | captions: captionNames | ||
193 | } | ||
194 | } | ||
195 | |||
196 | for (const directory of Object.keys(directories)) { | ||
197 | const directoryPath = server.servers.buildDirectory(directory) | ||
198 | |||
199 | const directoryExists = await pathExists(directoryPath) | ||
200 | if (directoryExists === false) continue | ||
201 | |||
202 | const existingFiles = await readdir(directoryPath) | ||
203 | for (const existingFile of existingFiles) { | ||
204 | for (const shouldNotExist of directories[directory]) { | ||
205 | expect(existingFile, `File ${existingFile} should not exist in ${directoryPath}`).to.not.contain(shouldNotExist) | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | async function saveVideoInServers (servers: PeerTubeServer[], uuid: string) { | ||
212 | for (const server of servers) { | ||
213 | server.store.videoDetails = await server.videos.get({ id: uuid }) | ||
214 | } | ||
215 | } | ||
216 | |||
217 | function checkUploadVideoParam ( | ||
218 | server: PeerTubeServer, | ||
219 | token: string, | ||
220 | attributes: Partial<VideoEdit>, | ||
221 | expectedStatus = HttpStatusCode.OK_200, | ||
222 | mode: 'legacy' | 'resumable' = 'legacy' | ||
223 | ) { | ||
224 | return mode === 'legacy' | ||
225 | ? server.videos.buildLegacyUpload({ token, attributes, expectedStatus }) | ||
226 | : server.videos.buildResumeUpload({ token, attributes, expectedStatus }) | ||
227 | } | ||
228 | |||
229 | // serverNumber starts from 1 | ||
230 | async function uploadRandomVideoOnServers ( | ||
231 | servers: PeerTubeServer[], | ||
232 | serverNumber: number, | ||
233 | additionalParams?: VideoEdit & { prefixName?: string } | ||
234 | ) { | ||
235 | const server = servers.find(s => s.serverNumber === serverNumber) | ||
236 | const res = await server.videos.randomUpload({ wait: false, additionalParams }) | ||
237 | |||
238 | await waitJobs(servers) | ||
239 | |||
240 | return res | ||
241 | } | ||
242 | |||
243 | // --------------------------------------------------------------------------- | ||
244 | |||
245 | export { | ||
246 | completeVideoCheck, | ||
247 | checkUploadVideoParam, | ||
248 | uploadRandomVideoOnServers, | ||
249 | checkVideoFilesWereRemoved, | ||
250 | saveVideoInServers | ||
251 | } | ||
diff --git a/server/tools/cli.ts b/server/tools/cli.ts index 52e6ea593..a844b9dcf 100644 --- a/server/tools/cli.ts +++ b/server/tools/cli.ts | |||
@@ -2,17 +2,19 @@ import { Command } from 'commander' | |||
2 | import { Netrc } from 'netrc-parser' | 2 | import { Netrc } from 'netrc-parser' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { createLogger, format, transports } from 'winston' | 4 | import { createLogger, format, transports } from 'winston' |
5 | import { PeerTubeServer } from '@shared/extra-utils' | 5 | import { loadLanguages } from '@server/initializers/constants' |
6 | import { root } from '@shared/core-utils' | ||
6 | import { UserRole } from '@shared/models' | 7 | import { UserRole } from '@shared/models' |
8 | import { PeerTubeServer } from '@shared/server-commands' | ||
7 | import { VideoPrivacy } from '../../shared/models/videos' | 9 | import { VideoPrivacy } from '../../shared/models/videos' |
8 | import { getAppNumber, isTestInstance, root } from '../helpers/core-utils' | 10 | import { getAppNumber, isTestInstance } from '../helpers/core-utils' |
9 | 11 | ||
10 | let configName = 'PeerTube/CLI' | 12 | let configName = 'PeerTube/CLI' |
11 | if (isTestInstance()) configName += `-${getAppNumber()}` | 13 | if (isTestInstance()) configName += `-${getAppNumber()}` |
12 | 14 | ||
13 | const config = require('application-config')(configName) | 15 | const config = require('application-config')(configName) |
14 | 16 | ||
15 | const version = require('../../../package.json').version | 17 | const version = require(join(root(), 'package.json')).version |
16 | 18 | ||
17 | async function getAdminTokenOrDie (server: PeerTubeServer, username: string, password: string) { | 19 | async function getAdminTokenOrDie (server: PeerTubeServer, username: string, password: string) { |
18 | const token = await server.login.getAccessToken(username, password) | 20 | const token = await server.login.getAccessToken(username, password) |
@@ -180,6 +182,7 @@ function getServerCredentials (program: Command) { | |||
180 | } | 182 | } |
181 | 183 | ||
182 | function buildServer (url: string) { | 184 | function buildServer (url: string) { |
185 | loadLanguages() | ||
183 | return new PeerTubeServer({ url }) | 186 | return new PeerTubeServer({ url }) |
184 | } | 187 | } |
185 | 188 | ||
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts index afa19ee08..f8ac8b2ab 100644 --- a/server/tools/peertube-auth.ts +++ b/server/tools/peertube-auth.ts | |||
@@ -1,12 +1,7 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | 1 | import CliTable3 from 'cli-table3' |
2 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
4 | registerTSPaths() | ||
5 | |||
6 | import { OptionValues, program } from 'commander' | 2 | import { OptionValues, program } from 'commander' |
7 | import { assignToken, buildServer, getNetrc, getSettings, writeSettings } from './cli' | ||
8 | import { isUserUsernameValid } from '../helpers/custom-validators/users' | 3 | import { isUserUsernameValid } from '../helpers/custom-validators/users' |
9 | import CliTable3 from 'cli-table3' | 4 | import { assignToken, buildServer, getNetrc, getSettings, writeSettings } from './cli' |
10 | 5 | ||
11 | import prompt = require('prompt') | 6 | import prompt = require('prompt') |
12 | 7 | ||
diff --git a/server/tools/peertube-get-access-token.ts b/server/tools/peertube-get-access-token.ts index a67de9180..d59a3632e 100644 --- a/server/tools/peertube-get-access-token.ts +++ b/server/tools/peertube-get-access-token.ts | |||
@@ -1,6 +1,3 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
2 | registerTSPaths() | ||
3 | |||
4 | import { program } from 'commander' | 1 | import { program } from 'commander' |
5 | import { assignToken, buildServer } from './cli' | 2 | import { assignToken, buildServer } from './cli' |
6 | 3 | ||
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts index a758beef9..661a4cf35 100644 --- a/server/tools/peertube-import-videos.ts +++ b/server/tools/peertube-import-videos.ts | |||
@@ -1,11 +1,10 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
2 | registerTSPaths() | ||
3 | |||
4 | import { program } from 'commander' | 1 | import { program } from 'commander' |
5 | import { accessSync, constants } from 'fs' | 2 | import { accessSync, constants } from 'fs' |
6 | import { remove } from 'fs-extra' | 3 | import { remove } from 'fs-extra' |
7 | import { join } from 'path' | 4 | import { join } from 'path' |
8 | import { sha256 } from '../helpers/core-utils' | 5 | import { YoutubeDLCLI, YoutubeDLInfo, YoutubeDLInfoBuilder } from '@server/helpers/youtube-dl' |
6 | import { wait } from '@shared/core-utils' | ||
7 | import { sha256 } from '@shared/extra-utils' | ||
9 | import { doRequestAndSaveToFile } from '../helpers/requests' | 8 | import { doRequestAndSaveToFile } from '../helpers/requests' |
10 | import { | 9 | import { |
11 | assignToken, | 10 | assignToken, |
@@ -15,8 +14,7 @@ import { | |||
15 | getLogger, | 14 | getLogger, |
16 | getServerCredentials | 15 | getServerCredentials |
17 | } from './cli' | 16 | } from './cli' |
18 | import { wait } from '@shared/extra-utils' | 17 | |
19 | import { YoutubeDLCLI, YoutubeDLInfo, YoutubeDLInfoBuilder } from '@server/helpers/youtube-dl' | ||
20 | import prompt = require('prompt') | 18 | import prompt = require('prompt') |
21 | 19 | ||
22 | const processOptions = { | 20 | const processOptions = { |
diff --git a/server/tools/peertube-plugins.ts b/server/tools/peertube-plugins.ts index ae625114d..47090b3a5 100644 --- a/server/tools/peertube-plugins.ts +++ b/server/tools/peertube-plugins.ts | |||
@@ -1,13 +1,8 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
4 | registerTSPaths() | ||
5 | |||
6 | import { program, Command, OptionValues } from 'commander' | ||
7 | import { assignToken, buildServer, getServerCredentials } from './cli' | ||
8 | import { PluginType } from '../../shared/models' | ||
9 | import { isAbsolute } from 'path' | ||
10 | import CliTable3 from 'cli-table3' | 1 | import CliTable3 from 'cli-table3' |
2 | import { Command, OptionValues, program } from 'commander' | ||
3 | import { isAbsolute } from 'path' | ||
4 | import { PluginType } from '../../shared/models' | ||
5 | import { assignToken, buildServer, getServerCredentials } from './cli' | ||
11 | 6 | ||
12 | program | 7 | program |
13 | .name('plugins') | 8 | .name('plugins') |
@@ -31,6 +26,7 @@ program | |||
31 | .option('-p, --password <token>', 'Password') | 26 | .option('-p, --password <token>', 'Password') |
32 | .option('-P --path <path>', 'Install from a path') | 27 | .option('-P --path <path>', 'Install from a path') |
33 | .option('-n, --npm-name <npmName>', 'Install from npm') | 28 | .option('-n, --npm-name <npmName>', 'Install from npm') |
29 | .option('--plugin-version <pluginVersion>', 'Specify the plugin version to install (only available when installing from npm)') | ||
34 | .action((options, command) => installPluginCLI(command, options)) | 30 | .action((options, command) => installPluginCLI(command, options)) |
35 | 31 | ||
36 | program | 32 | program |
@@ -109,7 +105,7 @@ async function installPluginCLI (command: Command, options: OptionValues) { | |||
109 | await assignToken(server, username, password) | 105 | await assignToken(server, username, password) |
110 | 106 | ||
111 | try { | 107 | try { |
112 | await server.plugins.install({ npmName: options.npmName, path: options.path }) | 108 | await server.plugins.install({ npmName: options.npmName, path: options.path, pluginVersion: options.pluginVersion }) |
113 | } catch (err) { | 109 | } catch (err) { |
114 | console.error('Cannot install plugin.', err) | 110 | console.error('Cannot install plugin.', err) |
115 | process.exit(-1) | 111 | process.exit(-1) |
diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts index 7e27ca49e..2c62a3c19 100644 --- a/server/tools/peertube-redundancy.ts +++ b/server/tools/peertube-redundancy.ts | |||
@@ -1,6 +1,3 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
2 | registerTSPaths() | ||
3 | |||
4 | import CliTable3 from 'cli-table3' | 1 | import CliTable3 from 'cli-table3' |
5 | import { Command, program } from 'commander' | 2 | import { Command, program } from 'commander' |
6 | import { uniq } from 'lodash' | 3 | import { uniq } from 'lodash' |
@@ -12,7 +9,7 @@ import { assignToken, buildServer, getServerCredentials } from './cli' | |||
12 | import bytes = require('bytes') | 9 | import bytes = require('bytes') |
13 | 10 | ||
14 | program | 11 | program |
15 | .name('plugins') | 12 | .name('redundancy') |
16 | .usage('[command] [options]') | 13 | .usage('[command] [options]') |
17 | 14 | ||
18 | program | 15 | program |
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts index 01fb1fe8d..08bd5f2bb 100644 --- a/server/tools/peertube-upload.ts +++ b/server/tools/peertube-upload.ts | |||
@@ -1,6 +1,3 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
2 | registerTSPaths() | ||
3 | |||
4 | import { program } from 'commander' | 1 | import { program } from 'commander' |
5 | import { access, constants } from 'fs-extra' | 2 | import { access, constants } from 'fs-extra' |
6 | import { isAbsolute } from 'path' | 3 | import { isAbsolute } from 'path' |
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts index 9e07640f0..1d3158044 100644 --- a/server/tools/peertube.ts +++ b/server/tools/peertube.ts | |||
@@ -1,8 +1,5 @@ | |||
1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
2 | 2 | ||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
4 | registerTSPaths() | ||
5 | |||
6 | import { CommandOptions, program } from 'commander' | 3 | import { CommandOptions, program } from 'commander' |
7 | import { getSettings, version } from './cli' | 4 | import { getSettings, version } from './cli' |
8 | 5 | ||
diff --git a/server/tools/tsconfig.json b/server/tools/tsconfig.json index 156a8ed22..8264f5b35 100644 --- a/server/tools/tsconfig.json +++ b/server/tools/tsconfig.json | |||
@@ -1,5 +1,17 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../tsconfig.json", |
3 | "compilerOptions": { | ||
4 | "baseUrl": "./", | ||
5 | "outDir": "../../dist/server/tools", | ||
6 | "paths": { // FIXME: https://github.com/benyap/resolve-tspaths/issues/10 | ||
7 | "@server/*": [ "../../server/*" ], | ||
8 | "@shared/*": [ "../../shared/*" ] | ||
9 | } | ||
10 | }, | ||
3 | "include": [ ".", "../typings" ], | 11 | "include": [ ".", "../typings" ], |
12 | "references": [ | ||
13 | { "path": "../" } | ||
14 | ], | ||
15 | "files": [], | ||
4 | "exclude": [ ] // Overwrite exclude property | 16 | "exclude": [ ] // Overwrite exclude property |
5 | } | 17 | } |
diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 000000000..4be7ae2f4 --- /dev/null +++ b/server/tsconfig.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "extends": "../tsconfig.base.json", | ||
3 | "compilerOptions": { | ||
4 | "outDir": "../dist/server" | ||
5 | }, | ||
6 | "references": [ | ||
7 | { "path": "../shared" } | ||
8 | ], | ||
9 | "exclude": [ | ||
10 | "tools/" | ||
11 | ] | ||
12 | } | ||
diff --git a/server/tsconfig.types.json b/server/tsconfig.types.json new file mode 100644 index 000000000..da6b572ea --- /dev/null +++ b/server/tsconfig.types.json | |||
@@ -0,0 +1,16 @@ | |||
1 | { | ||
2 | "extends": "./tsconfig.json", | ||
3 | "compilerOptions": { | ||
4 | "outDir": "../packages/types/dist/server", | ||
5 | "stripInternal": true, | ||
6 | "removeComments": false, | ||
7 | "emitDeclarationOnly": true | ||
8 | }, | ||
9 | "references": [ | ||
10 | { "path": "../shared/tsconfig.types.json" } | ||
11 | ], | ||
12 | "exclude": [ | ||
13 | "tools/", | ||
14 | "tests/" | ||
15 | ] | ||
16 | } | ||
diff --git a/server/types/express.ts b/server/types/express-handler.ts index e72be36e4..e72be36e4 100644 --- a/server/types/express.ts +++ b/server/types/express-handler.ts | |||
diff --git a/server/typings/express/index.d.ts b/server/types/express.d.ts index 1a99b598a..1a99b598a 100644 --- a/server/typings/express/index.d.ts +++ b/server/types/express.d.ts | |||
diff --git a/server/types/models/abuse/abuse-message.ts b/server/types/models/abuse/abuse-message.ts index 565eca706..2d7d09316 100644 --- a/server/types/models/abuse/abuse-message.ts +++ b/server/types/models/abuse/abuse-message.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { AbuseMessageModel } from '@server/models/abuse/abuse-message' | 1 | import { AbuseMessageModel } from '@server/models/abuse/abuse-message' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { AbuseModel } from '../../../models/abuse/abuse' | 3 | import { AbuseModel } from '../../../models/abuse/abuse' |
4 | import { MAccountFormattable } from '../account' | 4 | import { MAccountFormattable } from '../account' |
5 | 5 | ||
diff --git a/server/types/models/abuse/abuse.ts b/server/types/models/abuse/abuse.ts index 6fd83684c..1b45b3879 100644 --- a/server/types/models/abuse/abuse.ts +++ b/server/types/models/abuse/abuse.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoAbuseModel } from '@server/models/abuse/video-abuse' | 1 | import { VideoAbuseModel } from '@server/models/abuse/video-abuse' |
2 | import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse' | 2 | import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse' |
3 | import { VideoCommentModel } from '@server/models/video/video-comment' | 3 | import { VideoCommentModel } from '@server/models/video/video-comment' |
4 | import { PickWith } from '@shared/core-utils' | 4 | import { PickWith } from '@shared/typescript-utils' |
5 | import { AbuseModel } from '../../../models/abuse/abuse' | 5 | import { AbuseModel } from '../../../models/abuse/abuse' |
6 | import { MAccountDefault, MAccountFormattable, MAccountLight, MAccountUrl } from '../account' | 6 | import { MAccountDefault, MAccountFormattable, MAccountLight, MAccountUrl } from '../account' |
7 | import { MComment, MCommentOwner, MCommentUrl, MCommentVideo, MVideoUrl } from '../video' | 7 | import { MComment, MCommentOwner, MCommentUrl, MCommentVideo, MVideoUrl } from '../video' |
diff --git a/server/types/models/account/account-blocklist.ts b/server/types/models/account/account-blocklist.ts index 3126fd0ab..9dae10915 100644 --- a/server/types/models/account/account-blocklist.ts +++ b/server/types/models/account/account-blocklist.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { AccountBlocklistModel } from '../../../models/account/account-blocklist' | 1 | import { AccountBlocklistModel } from '../../../models/account/account-blocklist' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MAccountDefault, MAccountFormattable } from './account' | 3 | import { MAccountDefault, MAccountFormattable } from './account' |
4 | 4 | ||
5 | type Use<K extends keyof AccountBlocklistModel, M> = PickWith<AccountBlocklistModel, K, M> | 5 | type Use<K extends keyof AccountBlocklistModel, M> = PickWith<AccountBlocklistModel, K, M> |
diff --git a/server/types/models/account/account.ts b/server/types/models/account/account.ts index 71f6c79aa..282a2971b 100644 --- a/server/types/models/account/account.ts +++ b/server/types/models/account/account.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FunctionProperties, PickWith } from '@shared/core-utils' | 1 | import { FunctionProperties, PickWith } from '@shared/typescript-utils' |
2 | import { AccountModel } from '../../../models/account/account' | 2 | import { AccountModel } from '../../../models/account/account' |
3 | import { | 3 | import { |
4 | MActor, | 4 | MActor, |
diff --git a/server/types/models/account/actor-custom-page.ts b/server/types/models/account/actor-custom-page.ts index 2cb8aa7e4..fcd8069be 100644 --- a/server/types/models/account/actor-custom-page.ts +++ b/server/types/models/account/actor-custom-page.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | import { ActorCustomPageModel } from '../../../models/account/actor-custom-page' | 1 | import { ActorCustomPageModel } from '../../../models/account/actor-custom-page' |
3 | 2 | ||
4 | export type MActorCustomPage = Omit<ActorCustomPageModel, 'Actor'> | 3 | export type MActorCustomPage = Omit<ActorCustomPageModel, 'Actor'> |
diff --git a/server/types/models/actor/actor-follow.ts b/server/types/models/actor/actor-follow.ts index 98a6ca8a5..338158561 100644 --- a/server/types/models/actor/actor-follow.ts +++ b/server/types/models/actor/actor-follow.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith } from '@shared/core-utils' | 1 | import { PickWith } from '@shared/typescript-utils' |
2 | import { ActorFollowModel } from '../../../models/actor/actor-follow' | 2 | import { ActorFollowModel } from '../../../models/actor/actor-follow' |
3 | import { | 3 | import { |
4 | MActor, | 4 | MActor, |
diff --git a/server/types/models/actor/actor-image.ts b/server/types/models/actor/actor-image.ts index 89adb01ae..521b4cc59 100644 --- a/server/types/models/actor/actor-image.ts +++ b/server/types/models/actor/actor-image.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FunctionProperties } from '@shared/core-utils' | 1 | import { FunctionProperties } from '@shared/typescript-utils' |
2 | import { ActorImageModel } from '../../../models/actor/actor-image' | 2 | import { ActorImageModel } from '../../../models/actor/actor-image' |
3 | 3 | ||
4 | export type MActorImage = ActorImageModel | 4 | export type MActorImage = ActorImageModel |
diff --git a/server/types/models/actor/actor.ts b/server/types/models/actor/actor.ts index b3a70cbce..9ce97094f 100644 --- a/server/types/models/actor/actor.ts +++ b/server/types/models/actor/actor.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/core-utils' | 1 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/typescript-utils' |
2 | import { ActorModel } from '../../../models/actor/actor' | 2 | import { ActorModel } from '../../../models/actor/actor' |
3 | import { MAccount, MAccountDefault, MAccountId, MAccountIdActor } from '../account' | 3 | import { MAccount, MAccountDefault, MAccountId, MAccountIdActor } from '../account' |
4 | import { MServer, MServerHost, MServerHostBlocks, MServerRedundancyAllowed } from '../server' | 4 | import { MServer, MServerHost, MServerHostBlocks, MServerRedundancyAllowed } from '../server' |
diff --git a/server/types/models/oauth/oauth-token.ts b/server/types/models/oauth/oauth-token.ts index 8399af8f1..6af087e3c 100644 --- a/server/types/models/oauth/oauth-token.ts +++ b/server/types/models/oauth/oauth-token.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' | 1 | import { OAuthTokenModel } from '@server/models/oauth/oauth-token' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MUserAccountUrl } from '../user/user' | 3 | import { MUserAccountUrl } from '../user/user' |
4 | 4 | ||
5 | type Use<K extends keyof OAuthTokenModel, M> = PickWith<OAuthTokenModel, K, M> | 5 | type Use<K extends keyof OAuthTokenModel, M> = PickWith<OAuthTokenModel, K, M> |
diff --git a/server/types/models/server/server-blocklist.ts b/server/types/models/server/server-blocklist.ts index 801f179fd..71a4ea963 100644 --- a/server/types/models/server/server-blocklist.ts +++ b/server/types/models/server/server-blocklist.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' | 1 | import { ServerBlocklistModel } from '@server/models/server/server-blocklist' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MAccountDefault, MAccountFormattable } from '../account/account' | 3 | import { MAccountDefault, MAccountFormattable } from '../account/account' |
4 | import { MServer, MServerFormattable } from './server' | 4 | import { MServer, MServerFormattable } from './server' |
5 | 5 | ||
diff --git a/server/types/models/server/server.ts b/server/types/models/server/server.ts index 876186fc0..0b16186cd 100644 --- a/server/types/models/server/server.ts +++ b/server/types/models/server/server.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { FunctionProperties, PickWith } from '@shared/typescript-utils' | ||
1 | import { ServerModel } from '../../../models/server/server' | 2 | import { ServerModel } from '../../../models/server/server' |
2 | import { FunctionProperties, PickWith } from '@shared/core-utils' | ||
3 | import { MAccountBlocklistId } from '../account' | 3 | import { MAccountBlocklistId } from '../account' |
4 | 4 | ||
5 | type Use<K extends keyof ServerModel, M> = PickWith<ServerModel, K, M> | 5 | type Use<K extends keyof ServerModel, M> = PickWith<ServerModel, K, M> |
diff --git a/server/types/models/user/user-notification.ts b/server/types/models/user/user-notification.ts index 918614dd1..db9ec0400 100644 --- a/server/types/models/user/user-notification.ts +++ b/server/types/models/user/user-notification.ts | |||
@@ -3,7 +3,7 @@ import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse | |||
3 | import { ApplicationModel } from '@server/models/application/application' | 3 | import { ApplicationModel } from '@server/models/application/application' |
4 | import { PluginModel } from '@server/models/server/plugin' | 4 | import { PluginModel } from '@server/models/server/plugin' |
5 | import { UserNotificationModel } from '@server/models/user/user-notification' | 5 | import { UserNotificationModel } from '@server/models/user/user-notification' |
6 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 6 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' |
7 | import { AbuseModel } from '../../../models/abuse/abuse' | 7 | import { AbuseModel } from '../../../models/abuse/abuse' |
8 | import { AccountModel } from '../../../models/account/account' | 8 | import { AccountModel } from '../../../models/account/account' |
9 | import { ActorModel } from '../../../models/actor/actor' | 9 | import { ActorModel } from '../../../models/actor/actor' |
diff --git a/server/types/models/user/user.ts b/server/types/models/user/user.ts index f79220e11..89092c242 100644 --- a/server/types/models/user/user.ts +++ b/server/types/models/user/user.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AccountModel } from '@server/models/account/account' | 1 | import { AccountModel } from '@server/models/account/account' |
2 | import { UserModel } from '@server/models/user/user' | 2 | import { UserModel } from '@server/models/user/user' |
3 | import { MVideoPlaylist } from '@server/types/models' | 3 | import { MVideoPlaylist } from '@server/types/models' |
4 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 4 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' |
5 | import { | 5 | import { |
6 | MAccount, | 6 | MAccount, |
7 | MAccountDefault, | 7 | MAccountDefault, |
diff --git a/server/types/models/video/thumbnail.ts b/server/types/models/video/thumbnail.ts index 81a29e062..c3b27681f 100644 --- a/server/types/models/video/thumbnail.ts +++ b/server/types/models/video/thumbnail.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith } from '@shared/core-utils' | 1 | import { PickWith } from '@shared/typescript-utils' |
2 | import { ThumbnailModel } from '../../../models/video/thumbnail' | 2 | import { ThumbnailModel } from '../../../models/video/thumbnail' |
3 | import { MVideo } from './video' | 3 | import { MVideo } from './video' |
4 | 4 | ||
diff --git a/server/types/models/video/video-blacklist.ts b/server/types/models/video/video-blacklist.ts index 2ac912405..048b63bd2 100644 --- a/server/types/models/video/video-blacklist.ts +++ b/server/types/models/video/video-blacklist.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { PickWith } from '@shared/typescript-utils' | ||
1 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' | 2 | import { VideoBlacklistModel } from '../../../models/video/video-blacklist' |
2 | import { PickWith } from '@shared/core-utils' | ||
3 | import { MVideo, MVideoFormattable } from './video' | 3 | import { MVideo, MVideoFormattable } from './video' |
4 | 4 | ||
5 | type Use<K extends keyof VideoBlacklistModel, M> = PickWith<VideoBlacklistModel, K, M> | 5 | type Use<K extends keyof VideoBlacklistModel, M> = PickWith<VideoBlacklistModel, K, M> |
diff --git a/server/types/models/video/video-caption.ts b/server/types/models/video/video-caption.ts index 1f761a866..8cd801064 100644 --- a/server/types/models/video/video-caption.ts +++ b/server/types/models/video/video-caption.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith } from '@shared/core-utils' | 1 | import { PickWith } from '@shared/typescript-utils' |
2 | import { VideoCaptionModel } from '../../../models/video/video-caption' | 2 | import { VideoCaptionModel } from '../../../models/video/video-caption' |
3 | import { MVideo, MVideoUUID } from './video' | 3 | import { MVideo, MVideoUUID } from './video' |
4 | 4 | ||
diff --git a/server/types/models/video/video-change-ownership.ts b/server/types/models/video/video-change-ownership.ts index 6cad48e4a..d99f25071 100644 --- a/server/types/models/video/video-change-ownership.ts +++ b/server/types/models/video/video-change-ownership.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoChangeOwnershipModel } from '@server/models/video/video-change-ownership' | 1 | import { VideoChangeOwnershipModel } from '@server/models/video/video-change-ownership' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MAccountDefault, MAccountFormattable } from '../account/account' | 3 | import { MAccountDefault, MAccountFormattable } from '../account/account' |
4 | import { MVideoWithAllFiles, MVideoFormattable } from './video' | 4 | import { MVideoFormattable, MVideoWithAllFiles } from './video' |
5 | 5 | ||
6 | type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwnershipModel, K, M> | 6 | type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwnershipModel, K, M> |
7 | 7 | ||
diff --git a/server/types/models/video/video-channels.ts b/server/types/models/video/video-channels.ts index c147567d9..af8c2ffe4 100644 --- a/server/types/models/video/video-channels.ts +++ b/server/types/models/video/video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/core-utils' | 1 | import { FunctionProperties, PickWith, PickWithOpt } from '@shared/typescript-utils' |
2 | import { VideoChannelModel } from '../../../models/video/video-channel' | 2 | import { VideoChannelModel } from '../../../models/video/video-channel' |
3 | import { | 3 | import { |
4 | MAccountActor, | 4 | MAccountActor, |
diff --git a/server/types/models/video/video-comment.ts b/server/types/models/video/video-comment.ts index 83479e7b2..b66de064f 100644 --- a/server/types/models/video/video-comment.ts +++ b/server/types/models/video/video-comment.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 1 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' |
2 | import { VideoCommentModel } from '../../../models/video/video-comment' | 2 | import { VideoCommentModel } from '../../../models/video/video-comment' |
3 | import { MAccountDefault, MAccountFormattable, MAccountUrl } from '../account' | 3 | import { MAccountDefault, MAccountFormattable, MAccountUrl } from '../account' |
4 | import { MVideo, MVideoAccountLight, MVideoFeed, MVideoIdUrl, MVideoUrl } from './video' | 4 | import { MVideo, MVideoAccountLight, MVideoFeed, MVideoIdUrl, MVideoUrl } from './video' |
diff --git a/server/types/models/video/video-file.ts b/server/types/models/video/video-file.ts index 327a148ce..55603e59c 100644 --- a/server/types/models/video/video-file.ts +++ b/server/types/models/video/video-file.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' | ||
1 | import { VideoFileModel } from '../../../models/video/video-file' | 2 | import { VideoFileModel } from '../../../models/video/video-file' |
2 | import { PickWith, PickWithOpt } from '@shared/core-utils' | ||
3 | import { MVideo, MVideoUUID } from './video' | 3 | import { MVideo, MVideoUUID } from './video' |
4 | import { MVideoRedundancy, MVideoRedundancyFileUrl } from './video-redundancy' | 4 | import { MVideoRedundancy, MVideoRedundancyFileUrl } from './video-redundancy' |
5 | import { MStreamingPlaylistVideo, MStreamingPlaylist } from './video-streaming-playlist' | 5 | import { MStreamingPlaylist, MStreamingPlaylistVideo } from './video-streaming-playlist' |
6 | 6 | ||
7 | type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> | 7 | type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> |
8 | 8 | ||
diff --git a/server/types/models/video/video-import.ts b/server/types/models/video/video-import.ts index 759b13c6e..650c293f7 100644 --- a/server/types/models/video/video-import.ts +++ b/server/types/models/video/video-import.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoImportModel } from '@server/models/video/video-import' | 1 | import { VideoImportModel } from '@server/models/video/video-import' |
2 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 2 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' |
3 | import { MVideo, MVideoAccountLight, MVideoFormattable, MVideoTag, MVideoThumbnail, MVideoWithFile } from './video' | ||
4 | import { MUser } from '../user/user' | 3 | import { MUser } from '../user/user' |
4 | import { MVideo, MVideoAccountLight, MVideoFormattable, MVideoTag, MVideoThumbnail, MVideoWithFile } from './video' | ||
5 | 5 | ||
6 | type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M> | 6 | type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M> |
7 | 7 | ||
diff --git a/server/types/models/video/video-live.ts b/server/types/models/video/video-live.ts index 346052417..903cea982 100644 --- a/server/types/models/video/video-live.ts +++ b/server/types/models/video/video-live.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { VideoLiveModel } from '@server/models/video/video-live' | 1 | import { VideoLiveModel } from '@server/models/video/video-live' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MVideo } from './video' | 3 | import { MVideo } from './video' |
4 | 4 | ||
5 | type Use<K extends keyof VideoLiveModel, M> = PickWith<VideoLiveModel, K, M> | 5 | type Use<K extends keyof VideoLiveModel, M> = PickWith<VideoLiveModel, K, M> |
diff --git a/server/types/models/video/video-playlist-element.ts b/server/types/models/video/video-playlist-element.ts index f46ff4d49..eae676096 100644 --- a/server/types/models/video/video-playlist-element.ts +++ b/server/types/models/video/video-playlist-element.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' | 1 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MVideoFormattable, MVideoThumbnail, MVideoUrl } from './video' | 3 | import { MVideoFormattable, MVideoThumbnail, MVideoUrl } from './video' |
4 | import { MVideoPlaylistPrivacy } from './video-playlist' | 4 | import { MVideoPlaylistPrivacy } from './video-playlist' |
5 | 5 | ||
diff --git a/server/types/models/video/video-playlist.ts b/server/types/models/video/video-playlist.ts index 2f9537cf5..33fe5416a 100644 --- a/server/types/models/video/video-playlist.ts +++ b/server/types/models/video/video-playlist.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import { MVideoPlaylistElementLight } from '@server/types/models/video/video-playlist-element' | ||
2 | import { PickWith } from '@shared/typescript-utils' | ||
1 | import { VideoPlaylistModel } from '../../../models/video/video-playlist' | 3 | import { VideoPlaylistModel } from '../../../models/video/video-playlist' |
2 | import { PickWith } from '@shared/core-utils' | ||
3 | import { MAccount, MAccountDefault, MAccountSummary, MAccountSummaryFormattable } from '../account' | 4 | import { MAccount, MAccountDefault, MAccountSummary, MAccountSummaryFormattable } from '../account' |
4 | import { MThumbnail } from './thumbnail' | 5 | import { MThumbnail } from './thumbnail' |
5 | import { MChannelDefault, MChannelSummary, MChannelSummaryFormattable, MChannelUrl } from './video-channels' | 6 | import { MChannelDefault, MChannelSummary, MChannelSummaryFormattable, MChannelUrl } from './video-channels' |
6 | import { MVideoPlaylistElementLight } from '@server/types/models/video/video-playlist-element' | ||
7 | 7 | ||
8 | type Use<K extends keyof VideoPlaylistModel, M> = PickWith<VideoPlaylistModel, K, M> | 8 | type Use<K extends keyof VideoPlaylistModel, M> = PickWith<VideoPlaylistModel, K, M> |
9 | 9 | ||
diff --git a/server/types/models/video/video-rate.ts b/server/types/models/video/video-rate.ts index 7bd54f7b0..0dbdf3c41 100644 --- a/server/types/models/video/video-rate.ts +++ b/server/types/models/video/video-rate.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { AccountVideoRateModel } from '@server/models/account/account-video-rate' | 1 | import { AccountVideoRateModel } from '@server/models/account/account-video-rate' |
2 | import { PickWith } from '@shared/core-utils' | 2 | import { PickWith } from '@shared/typescript-utils' |
3 | import { MAccountAudience, MAccountUrl } from '../account/account' | 3 | import { MAccountAudience, MAccountUrl } from '../account/account' |
4 | import { MVideo, MVideoFormattable } from './video' | 4 | import { MVideo, MVideoFormattable } from './video' |
5 | 5 | ||
diff --git a/server/types/models/video/video-redundancy.ts b/server/types/models/video/video-redundancy.ts index 411375c81..e2a9beb93 100644 --- a/server/types/models/video/video-redundancy.ts +++ b/server/types/models/video/video-redundancy.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | ||
2 | import { PickWith, PickWithOpt } from '@shared/core-utils' | ||
3 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | ||
4 | import { VideoFileModel } from '@server/models/video/video-file' | 1 | import { VideoFileModel } from '@server/models/video/video-file' |
2 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | ||
3 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' | ||
4 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | ||
5 | import { MVideoUrl } from './video' | ||
5 | import { MVideoFile, MVideoFileVideo } from './video-file' | 6 | import { MVideoFile, MVideoFileVideo } from './video-file' |
6 | import { MStreamingPlaylistVideo } from './video-streaming-playlist' | 7 | import { MStreamingPlaylistVideo } from './video-streaming-playlist' |
7 | import { MVideoUrl } from './video' | ||
8 | 8 | ||
9 | type Use<K extends keyof VideoRedundancyModel, M> = PickWith<VideoRedundancyModel, K, M> | 9 | type Use<K extends keyof VideoRedundancyModel, M> = PickWith<VideoRedundancyModel, K, M> |
10 | 10 | ||
diff --git a/server/types/models/video/video-share.ts b/server/types/models/video/video-share.ts index 78f44e58c..ffc0edad6 100644 --- a/server/types/models/video/video-share.ts +++ b/server/types/models/video/video-share.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith } from '@shared/core-utils' | 1 | import { PickWith } from '@shared/typescript-utils' |
2 | import { VideoShareModel } from '../../../models/video/video-share' | 2 | import { VideoShareModel } from '../../../models/video/video-share' |
3 | import { MActorDefault } from '../actor' | 3 | import { MActorDefault } from '../actor' |
4 | import { MVideo } from './video' | 4 | import { MVideo } from './video' |
diff --git a/server/types/models/video/video-streaming-playlist.ts b/server/types/models/video/video-streaming-playlist.ts index 1e4dccb8e..1c2f83489 100644 --- a/server/types/models/video/video-streaming-playlist.ts +++ b/server/types/models/video/video-streaming-playlist.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' | ||
1 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' | 2 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' |
2 | import { PickWith, PickWithOpt } from '@shared/core-utils' | ||
3 | import { MVideoRedundancyFileUrl, MVideoRedundancy } from './video-redundancy' | ||
4 | import { MVideo } from './video' | 3 | import { MVideo } from './video' |
5 | import { MVideoFile } from './video-file' | 4 | import { MVideoFile } from './video-file' |
5 | import { MVideoRedundancy, MVideoRedundancyFileUrl } from './video-redundancy' | ||
6 | 6 | ||
7 | type Use<K extends keyof VideoStreamingPlaylistModel, M> = PickWith<VideoStreamingPlaylistModel, K, M> | 7 | type Use<K extends keyof VideoStreamingPlaylistModel, M> = PickWith<VideoStreamingPlaylistModel, K, M> |
8 | 8 | ||
diff --git a/server/types/models/video/video.ts b/server/types/models/video/video.ts index 9a6b27888..d1af53b92 100644 --- a/server/types/models/video/video.ts +++ b/server/types/models/video/video.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { PickWith, PickWithOpt } from '@shared/core-utils' | 1 | import { PickWith, PickWithOpt } from '@shared/typescript-utils' |
2 | import { VideoModel } from '../../../models/video/video' | 2 | import { VideoModel } from '../../../models/video/video' |
3 | import { MTrackerUrl } from '../server/tracker' | 3 | import { MTrackerUrl } from '../server/tracker' |
4 | import { MUserVideoHistoryTime } from '../user/user-video-history' | 4 | import { MUserVideoHistoryTime } from '../user/user-video-history' |
diff --git a/server/types/plugins/register-server-option.model.ts b/server/types/plugins/register-server-option.model.ts index 8774bcd8c..9f472d900 100644 --- a/server/types/plugins/register-server-option.model.ts +++ b/server/types/plugins/register-server-option.model.ts | |||
@@ -13,6 +13,7 @@ import { | |||
13 | RegisterServerHookOptions, | 13 | RegisterServerHookOptions, |
14 | RegisterServerSettingOptions, | 14 | RegisterServerSettingOptions, |
15 | ServerConfig, | 15 | ServerConfig, |
16 | ThumbnailType, | ||
16 | UserRole, | 17 | UserRole, |
17 | VideoBlacklistCreate | 18 | VideoBlacklistCreate |
18 | } from '@shared/models' | 19 | } from '@shared/models' |
@@ -35,6 +36,35 @@ export type PeerTubeHelpers = { | |||
35 | loadByIdOrUUID: (id: number | string) => Promise<MVideoThumbnail> | 36 | loadByIdOrUUID: (id: number | string) => Promise<MVideoThumbnail> |
36 | 37 | ||
37 | removeVideo: (videoId: number) => Promise<void> | 38 | removeVideo: (videoId: number) => Promise<void> |
39 | |||
40 | ffprobe: (path: string) => Promise<any> | ||
41 | |||
42 | getFiles: (id: number | string) => Promise<{ | ||
43 | webtorrent: { | ||
44 | videoFiles: { | ||
45 | path: string // Could be null if using remote storage | ||
46 | url: string | ||
47 | resolution: number | ||
48 | size: number | ||
49 | fps: number | ||
50 | }[] | ||
51 | } | ||
52 | |||
53 | hls: { | ||
54 | videoFiles: { | ||
55 | path: string // Could be null if using remote storage | ||
56 | url: string | ||
57 | resolution: number | ||
58 | size: number | ||
59 | fps: number | ||
60 | }[] | ||
61 | } | ||
62 | |||
63 | thumbnails: { | ||
64 | type: ThumbnailType | ||
65 | path: string | ||
66 | }[] | ||
67 | }> | ||
38 | } | 68 | } |
39 | 69 | ||
40 | config: { | 70 | config: { |
diff --git a/server/types/sequelize.ts b/server/types/sequelize.ts index 535113d01..e399c3d5d 100644 --- a/server/types/sequelize.ts +++ b/server/types/sequelize.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { AttributesOnly } from '@shared/core-utils' | 1 | import { AttributesOnly } from '@shared/typescript-utils' |
2 | import { Model } from 'sequelize' | 2 | import { Model } from 'sequelize' |
3 | 3 | ||
4 | // Thanks to sequelize-typescript: https://github.com/RobinBuschmann/sequelize-typescript | 4 | // Thanks to sequelize-typescript: https://github.com/RobinBuschmann/sequelize-typescript |