diff options
Diffstat (limited to 'server')
372 files changed, 5185 insertions, 3678 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index 62412cd62..84828e7e0 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | // Intercept ActivityPub client requests | ||
2 | import * as express from 'express' | 1 | import * as express from 'express' |
3 | import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' | 2 | import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' |
4 | import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' | 3 | import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' |
@@ -14,7 +13,7 @@ import { | |||
14 | videosCustomGetValidator, | 13 | videosCustomGetValidator, |
15 | videosShareValidator | 14 | videosShareValidator |
16 | } from '../../middlewares' | 15 | } from '../../middlewares' |
17 | import { getAccountVideoRateValidator, videoCommentGetValidator } from '../../middlewares/validators' | 16 | import { getAccountVideoRateValidatorFactory, videoCommentGetValidator } from '../../middlewares/validators' |
18 | import { AccountModel } from '../../models/account/account' | 17 | import { AccountModel } from '../../models/account/account' |
19 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' | 18 | import { ActorFollowModel } from '../../models/activitypub/actor-follow' |
20 | import { VideoModel } from '../../models/video/video' | 19 | import { VideoModel } from '../../models/video/video' |
@@ -37,10 +36,12 @@ import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike' | |||
37 | import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists' | 36 | import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists' |
38 | import { VideoPlaylistModel } from '../../models/video/video-playlist' | 37 | import { VideoPlaylistModel } from '../../models/video/video-playlist' |
39 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' | 38 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' |
40 | import { MAccountId, MActorId, MVideo, MVideoAPWithoutCaption } from '@server/typings/models' | 39 | import { MAccountId, MActorId, MVideoAPWithoutCaption, MVideoId } from '@server/typings/models' |
41 | 40 | ||
42 | const activityPubClientRouter = express.Router() | 41 | const activityPubClientRouter = express.Router() |
43 | 42 | ||
43 | // Intercept ActivityPub client requests | ||
44 | |||
44 | activityPubClientRouter.get('/accounts?/:name', | 45 | activityPubClientRouter.get('/accounts?/:name', |
45 | executeIfActivityPub, | 46 | executeIfActivityPub, |
46 | asyncMiddleware(localAccountValidator), | 47 | asyncMiddleware(localAccountValidator), |
@@ -63,13 +64,13 @@ activityPubClientRouter.get('/accounts?/:name/playlists', | |||
63 | ) | 64 | ) |
64 | activityPubClientRouter.get('/accounts?/:name/likes/:videoId', | 65 | activityPubClientRouter.get('/accounts?/:name/likes/:videoId', |
65 | executeIfActivityPub, | 66 | executeIfActivityPub, |
66 | asyncMiddleware(getAccountVideoRateValidator('like')), | 67 | asyncMiddleware(getAccountVideoRateValidatorFactory('like')), |
67 | getAccountVideoRate('like') | 68 | getAccountVideoRateFactory('like') |
68 | ) | 69 | ) |
69 | activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', | 70 | activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', |
70 | executeIfActivityPub, | 71 | executeIfActivityPub, |
71 | asyncMiddleware(getAccountVideoRateValidator('dislike')), | 72 | asyncMiddleware(getAccountVideoRateValidatorFactory('dislike')), |
72 | getAccountVideoRate('dislike') | 73 | getAccountVideoRateFactory('dislike') |
73 | ) | 74 | ) |
74 | 75 | ||
75 | activityPubClientRouter.get('/videos/watch/:id', | 76 | activityPubClientRouter.get('/videos/watch/:id', |
@@ -85,7 +86,7 @@ activityPubClientRouter.get('/videos/watch/:id/activity', | |||
85 | ) | 86 | ) |
86 | activityPubClientRouter.get('/videos/watch/:id/announces', | 87 | activityPubClientRouter.get('/videos/watch/:id/announces', |
87 | executeIfActivityPub, | 88 | executeIfActivityPub, |
88 | asyncMiddleware(videosCustomGetValidator('only-video')), | 89 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
89 | asyncMiddleware(videoAnnouncesController) | 90 | asyncMiddleware(videoAnnouncesController) |
90 | ) | 91 | ) |
91 | activityPubClientRouter.get('/videos/watch/:id/announces/:actorId', | 92 | activityPubClientRouter.get('/videos/watch/:id/announces/:actorId', |
@@ -95,17 +96,17 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:actorId', | |||
95 | ) | 96 | ) |
96 | activityPubClientRouter.get('/videos/watch/:id/likes', | 97 | activityPubClientRouter.get('/videos/watch/:id/likes', |
97 | executeIfActivityPub, | 98 | executeIfActivityPub, |
98 | asyncMiddleware(videosCustomGetValidator('only-video')), | 99 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
99 | asyncMiddleware(videoLikesController) | 100 | asyncMiddleware(videoLikesController) |
100 | ) | 101 | ) |
101 | activityPubClientRouter.get('/videos/watch/:id/dislikes', | 102 | activityPubClientRouter.get('/videos/watch/:id/dislikes', |
102 | executeIfActivityPub, | 103 | executeIfActivityPub, |
103 | asyncMiddleware(videosCustomGetValidator('only-video')), | 104 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
104 | asyncMiddleware(videoDislikesController) | 105 | asyncMiddleware(videoDislikesController) |
105 | ) | 106 | ) |
106 | activityPubClientRouter.get('/videos/watch/:id/comments', | 107 | activityPubClientRouter.get('/videos/watch/:id/comments', |
107 | executeIfActivityPub, | 108 | executeIfActivityPub, |
108 | asyncMiddleware(videosCustomGetValidator('only-video')), | 109 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
109 | asyncMiddleware(videoCommentsController) | 110 | asyncMiddleware(videoCommentsController) |
110 | ) | 111 | ) |
111 | activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId', | 112 | activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId', |
@@ -122,7 +123,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity | |||
122 | activityPubClientRouter.get('/video-channels/:name', | 123 | activityPubClientRouter.get('/video-channels/:name', |
123 | executeIfActivityPub, | 124 | executeIfActivityPub, |
124 | asyncMiddleware(localVideoChannelValidator), | 125 | asyncMiddleware(localVideoChannelValidator), |
125 | asyncMiddleware(videoChannelController) | 126 | videoChannelController |
126 | ) | 127 | ) |
127 | activityPubClientRouter.get('/video-channels/:name/followers', | 128 | activityPubClientRouter.get('/video-channels/:name/followers', |
128 | executeIfActivityPub, | 129 | executeIfActivityPub, |
@@ -154,7 +155,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId', | |||
154 | activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', | 155 | activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', |
155 | executeIfActivityPub, | 156 | executeIfActivityPub, |
156 | asyncMiddleware(videoPlaylistElementAPGetValidator), | 157 | asyncMiddleware(videoPlaylistElementAPGetValidator), |
157 | asyncMiddleware(videoPlaylistElementController) | 158 | videoPlaylistElementController |
158 | ) | 159 | ) |
159 | 160 | ||
160 | // --------------------------------------------------------------------------- | 161 | // --------------------------------------------------------------------------- |
@@ -192,7 +193,7 @@ async function accountPlaylistsController (req: express.Request, res: express.Re | |||
192 | return activityPubResponse(activityPubContextify(activityPubResult), res) | 193 | return activityPubResponse(activityPubContextify(activityPubResult), res) |
193 | } | 194 | } |
194 | 195 | ||
195 | function getAccountVideoRate (rateType: VideoRateType) { | 196 | function getAccountVideoRateFactory (rateType: VideoRateType) { |
196 | return (req: express.Request, res: express.Response) => { | 197 | return (req: express.Request, res: express.Response) => { |
197 | const accountVideoRate = res.locals.accountVideoRate | 198 | const accountVideoRate = res.locals.accountVideoRate |
198 | 199 | ||
@@ -234,11 +235,11 @@ async function videoAnnounceController (req: express.Request, res: express.Respo | |||
234 | 235 | ||
235 | const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) | 236 | const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) |
236 | 237 | ||
237 | return activityPubResponse(activityPubContextify(activity), res) | 238 | return activityPubResponse(activityPubContextify(activity, 'Announce'), res) |
238 | } | 239 | } |
239 | 240 | ||
240 | async function videoAnnouncesController (req: express.Request, res: express.Response) { | 241 | async function videoAnnouncesController (req: express.Request, res: express.Response) { |
241 | const video = res.locals.onlyVideo | 242 | const video = res.locals.onlyImmutableVideo |
242 | 243 | ||
243 | const handler = async (start: number, count: number) => { | 244 | const handler = async (start: number, count: number) => { |
244 | const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count) | 245 | const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count) |
@@ -253,21 +254,21 @@ async function videoAnnouncesController (req: express.Request, res: express.Resp | |||
253 | } | 254 | } |
254 | 255 | ||
255 | async function videoLikesController (req: express.Request, res: express.Response) { | 256 | async function videoLikesController (req: express.Request, res: express.Response) { |
256 | const video = res.locals.onlyVideo | 257 | const video = res.locals.onlyImmutableVideo |
257 | const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video)) | 258 | const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video)) |
258 | 259 | ||
259 | return activityPubResponse(activityPubContextify(json), res) | 260 | return activityPubResponse(activityPubContextify(json), res) |
260 | } | 261 | } |
261 | 262 | ||
262 | async function videoDislikesController (req: express.Request, res: express.Response) { | 263 | async function videoDislikesController (req: express.Request, res: express.Response) { |
263 | const video = res.locals.onlyVideo | 264 | const video = res.locals.onlyImmutableVideo |
264 | const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video)) | 265 | const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video)) |
265 | 266 | ||
266 | return activityPubResponse(activityPubContextify(json), res) | 267 | return activityPubResponse(activityPubContextify(json), res) |
267 | } | 268 | } |
268 | 269 | ||
269 | async function videoCommentsController (req: express.Request, res: express.Response) { | 270 | async function videoCommentsController (req: express.Request, res: express.Response) { |
270 | const video = res.locals.onlyVideo | 271 | const video = res.locals.onlyImmutableVideo |
271 | 272 | ||
272 | const handler = async (start: number, count: number) => { | 273 | const handler = async (start: number, count: number) => { |
273 | const result = await VideoCommentModel.listAndCountByVideoId(video.id, start, count) | 274 | const result = await VideoCommentModel.listAndCountByVideoId(video.id, start, count) |
@@ -281,7 +282,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo | |||
281 | return activityPubResponse(activityPubContextify(json), res) | 282 | return activityPubResponse(activityPubContextify(json), res) |
282 | } | 283 | } |
283 | 284 | ||
284 | async function videoChannelController (req: express.Request, res: express.Response) { | 285 | function videoChannelController (req: express.Request, res: express.Response) { |
285 | const videoChannel = res.locals.videoChannel | 286 | const videoChannel = res.locals.videoChannel |
286 | 287 | ||
287 | return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) | 288 | return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) |
@@ -334,10 +335,10 @@ async function videoRedundancyController (req: express.Request, res: express.Res | |||
334 | 335 | ||
335 | if (req.path.endsWith('/activity')) { | 336 | if (req.path.endsWith('/activity')) { |
336 | const data = buildCreateActivity(videoRedundancy.url, serverActor, object, audience) | 337 | const data = buildCreateActivity(videoRedundancy.url, serverActor, object, audience) |
337 | return activityPubResponse(activityPubContextify(data), res) | 338 | return activityPubResponse(activityPubContextify(data, 'CacheFile'), res) |
338 | } | 339 | } |
339 | 340 | ||
340 | return activityPubResponse(activityPubContextify(object), res) | 341 | return activityPubResponse(activityPubContextify(object, 'CacheFile'), res) |
341 | } | 342 | } |
342 | 343 | ||
343 | async function videoPlaylistController (req: express.Request, res: express.Response) { | 344 | async function videoPlaylistController (req: express.Request, res: express.Response) { |
@@ -353,7 +354,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo | |||
353 | return activityPubResponse(activityPubContextify(object), res) | 354 | return activityPubResponse(activityPubContextify(object), res) |
354 | } | 355 | } |
355 | 356 | ||
356 | async function videoPlaylistElementController (req: express.Request, res: express.Response) { | 357 | function videoPlaylistElementController (req: express.Request, res: express.Response) { |
357 | const videoPlaylistElement = res.locals.videoPlaylistElementAP | 358 | const videoPlaylistElement = res.locals.videoPlaylistElementAP |
358 | 359 | ||
359 | const json = videoPlaylistElement.toActivityPubObject() | 360 | const json = videoPlaylistElement.toActivityPubObject() |
@@ -386,7 +387,7 @@ async function actorPlaylists (req: express.Request, account: MAccountId) { | |||
386 | return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page) | 387 | return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page) |
387 | } | 388 | } |
388 | 389 | ||
389 | function videoRates (req: express.Request, rateType: VideoRateType, video: MVideo, url: string) { | 390 | function videoRates (req: express.Request, rateType: VideoRateType, video: MVideoId, url: string) { |
390 | const handler = async (start: number, count: number) => { | 391 | const handler = async (start: number, count: number) => { |
391 | const result = await AccountVideoRateModel.listAndCountAccountUrlsByVideoId(rateType, video.id, start, count) | 392 | const result = await AccountVideoRateModel.listAndCountAccountUrlsByVideoId(rateType, video.id, start, count) |
392 | return { | 393 | return { |
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index ca42106b8..3b8fb34a8 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts | |||
@@ -46,11 +46,15 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => { | |||
46 | 46 | ||
47 | processActivities(task.activities, options) | 47 | processActivities(task.activities, options) |
48 | .then(() => cb()) | 48 | .then(() => cb()) |
49 | .catch(err => { | ||
50 | logger.error('Error in process activities.', { err }) | ||
51 | cb() | ||
52 | }) | ||
49 | }) | 53 | }) |
50 | 54 | ||
51 | function inboxController (req: express.Request, res: express.Response) { | 55 | function inboxController (req: express.Request, res: express.Response) { |
52 | const rootActivity: RootActivity = req.body | 56 | const rootActivity: RootActivity = req.body |
53 | let activities: Activity[] = [] | 57 | let activities: Activity[] |
54 | 58 | ||
55 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { | 59 | if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { |
56 | activities = (rootActivity as ActivityPubCollection).items | 60 | activities = (rootActivity as ActivityPubCollection).items |
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts index 05740318e..f354ccf24 100644 --- a/server/controllers/api/accounts.ts +++ b/server/controllers/api/accounts.ts | |||
@@ -16,21 +16,17 @@ import { | |||
16 | accountNameWithHostGetValidator, | 16 | accountNameWithHostGetValidator, |
17 | accountsSortValidator, | 17 | accountsSortValidator, |
18 | ensureAuthUserOwnsAccountValidator, | 18 | ensureAuthUserOwnsAccountValidator, |
19 | videosSortValidator, | 19 | videoChannelsSortValidator, |
20 | videoChannelsSortValidator | 20 | videosSortValidator |
21 | } from '../../middlewares/validators' | 21 | } from '../../middlewares/validators' |
22 | import { AccountModel } from '../../models/account/account' | 22 | import { AccountModel } from '../../models/account/account' |
23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' | 23 | import { AccountVideoRateModel } from '../../models/account/account-video-rate' |
24 | import { VideoModel } from '../../models/video/video' | 24 | import { VideoModel } from '../../models/video/video' |
25 | import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils' | 25 | import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils' |
26 | import { VideoChannelModel } from '../../models/video/video-channel' | 26 | import { VideoChannelModel } from '../../models/video/video-channel' |
27 | import { JobQueue } from '../../lib/job-queue' | 27 | import { JobQueue } from '../../lib/job-queue' |
28 | import { logger } from '../../helpers/logger' | ||
29 | import { VideoPlaylistModel } from '../../models/video/video-playlist' | 28 | import { VideoPlaylistModel } from '../../models/video/video-playlist' |
30 | import { | 29 | import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists' |
31 | commonVideoPlaylistFiltersValidator, | ||
32 | videoPlaylistsSearchValidator | ||
33 | } from '../../middlewares/validators/videos/video-playlists' | ||
34 | 30 | ||
35 | const accountsRouter = express.Router() | 31 | const accountsRouter = express.Router() |
36 | 32 | ||
@@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) { | |||
104 | 100 | ||
105 | if (account.isOutdated()) { | 101 | if (account.isOutdated()) { |
106 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) | 102 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) |
107 | .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err })) | ||
108 | } | 103 | } |
109 | 104 | ||
110 | return res.json(account.toFormattedJSON()) | 105 | return res.json(account.toFormattedJSON()) |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index ae4e00248..06fe30371 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -11,10 +11,9 @@ import { ClientHtml } from '../../lib/client-html' | |||
11 | import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' | 11 | import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' |
12 | import { remove, writeJSON } from 'fs-extra' | 12 | import { remove, writeJSON } from 'fs-extra' |
13 | import { getServerCommit } from '../../helpers/utils' | 13 | import { getServerCommit } from '../../helpers/utils' |
14 | import { Emailer } from '../../lib/emailer' | ||
15 | import validator from 'validator' | 14 | import validator from 'validator' |
16 | import { objectConverter } from '../../helpers/core-utils' | 15 | import { objectConverter } from '../../helpers/core-utils' |
17 | import { CONFIG, reloadConfig } from '../../initializers/config' | 16 | import { CONFIG, isEmailEnabled, reloadConfig } from '../../initializers/config' |
18 | import { PluginManager } from '../../lib/plugins/plugin-manager' | 17 | import { PluginManager } from '../../lib/plugins/plugin-manager' |
19 | import { getThemeOrDefault } from '../../lib/plugins/theme-utils' | 18 | import { getThemeOrDefault } from '../../lib/plugins/theme-utils' |
20 | import { Hooks } from '@server/lib/plugins/hooks' | 19 | import { Hooks } from '@server/lib/plugins/hooks' |
@@ -31,12 +30,12 @@ configRouter.get('/', | |||
31 | configRouter.get('/custom', | 30 | configRouter.get('/custom', |
32 | authenticate, | 31 | authenticate, |
33 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 32 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
34 | asyncMiddleware(getCustomConfig) | 33 | getCustomConfig |
35 | ) | 34 | ) |
36 | configRouter.put('/custom', | 35 | configRouter.put('/custom', |
37 | authenticate, | 36 | authenticate, |
38 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), | 37 | ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), |
39 | asyncMiddleware(customConfigUpdateValidator), | 38 | customConfigUpdateValidator, |
40 | asyncMiddleware(updateCustomConfig) | 39 | asyncMiddleware(updateCustomConfig) |
41 | ) | 40 | ) |
42 | configRouter.delete('/custom', | 41 | configRouter.delete('/custom', |
@@ -73,6 +72,12 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
73 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS | 72 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS |
74 | } | 73 | } |
75 | }, | 74 | }, |
75 | search: { | ||
76 | remoteUri: { | ||
77 | users: CONFIG.SEARCH.REMOTE_URI.USERS, | ||
78 | anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS | ||
79 | } | ||
80 | }, | ||
76 | plugin: { | 81 | plugin: { |
77 | registered: getRegisteredPlugins() | 82 | registered: getRegisteredPlugins() |
78 | }, | 83 | }, |
@@ -81,7 +86,7 @@ async function getConfig (req: express.Request, res: express.Response) { | |||
81 | default: defaultTheme | 86 | default: defaultTheme |
82 | }, | 87 | }, |
83 | email: { | 88 | email: { |
84 | enabled: Emailer.isEnabled() | 89 | enabled: isEmailEnabled() |
85 | }, | 90 | }, |
86 | contactForm: { | 91 | contactForm: { |
87 | enabled: CONFIG.CONTACT_FORM.ENABLED | 92 | enabled: CONFIG.CONTACT_FORM.ENABLED |
@@ -196,7 +201,7 @@ function getAbout (req: express.Request, res: express.Response) { | |||
196 | return res.json(about).end() | 201 | return res.json(about).end() |
197 | } | 202 | } |
198 | 203 | ||
199 | async function getCustomConfig (req: express.Request, res: express.Response) { | 204 | function getCustomConfig (req: express.Request, res: express.Response) { |
200 | const data = customConfig() | 205 | const data = customConfig() |
201 | 206 | ||
202 | return res.json(data).end() | 207 | return res.json(data).end() |
@@ -250,7 +255,7 @@ function getRegisteredThemes () { | |||
250 | 255 | ||
251 | function getEnabledResolutions () { | 256 | function getEnabledResolutions () { |
252 | return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) | 257 | return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) |
253 | .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true) | 258 | .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true) |
254 | .map(r => parseInt(r, 10)) | 259 | .map(r => parseInt(r, 10)) |
255 | } | 260 | } |
256 | 261 | ||
@@ -340,13 +345,13 @@ function customConfig (): CustomConfig { | |||
340 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, | 345 | allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, |
341 | threads: CONFIG.TRANSCODING.THREADS, | 346 | threads: CONFIG.TRANSCODING.THREADS, |
342 | resolutions: { | 347 | resolutions: { |
343 | '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ], | 348 | '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'], |
344 | '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], | 349 | '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'], |
345 | '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], | 350 | '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'], |
346 | '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], | 351 | '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'], |
347 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], | 352 | '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'], |
348 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], | 353 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'], |
349 | '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] | 354 | '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p'] |
350 | }, | 355 | }, |
351 | webtorrent: { | 356 | webtorrent: { |
352 | enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED | 357 | enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED |
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 6138a32de..7bec6c527 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import * as RateLimit from 'express-rate-limit' | ||
3 | import { configRouter } from './config' | 2 | import { configRouter } from './config' |
4 | import { jobsRouter } from './jobs' | 3 | import { jobsRouter } from './jobs' |
5 | import { oauthClientsRouter } from './oauth-clients' | 4 | import { oauthClientsRouter } from './oauth-clients' |
@@ -15,6 +14,7 @@ import { overviewsRouter } from './overviews' | |||
15 | import { videoPlaylistRouter } from './video-playlist' | 14 | import { videoPlaylistRouter } from './video-playlist' |
16 | import { CONFIG } from '../../initializers/config' | 15 | import { CONFIG } from '../../initializers/config' |
17 | import { pluginRouter } from './plugins' | 16 | import { pluginRouter } from './plugins' |
17 | import * as RateLimit from 'express-rate-limit' | ||
18 | 18 | ||
19 | const apiRouter = express.Router() | 19 | const apiRouter = express.Router() |
20 | 20 | ||
@@ -24,8 +24,6 @@ apiRouter.use(cors({ | |||
24 | credentials: true | 24 | credentials: true |
25 | })) | 25 | })) |
26 | 26 | ||
27 | // FIXME: https://github.com/nfriedly/express-rate-limit/issues/138 | ||
28 | // @ts-ignore | ||
29 | const apiRateLimiter = RateLimit({ | 27 | const apiRateLimiter = RateLimit({ |
30 | windowMs: CONFIG.RATES_LIMIT.API.WINDOW_MS, | 28 | windowMs: CONFIG.RATES_LIMIT.API.WINDOW_MS, |
31 | max: CONFIG.RATES_LIMIT.API.MAX | 29 | max: CONFIG.RATES_LIMIT.API.MAX |
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts index 05320311e..13fc04d18 100644 --- a/server/controllers/api/jobs.ts +++ b/server/controllers/api/jobs.ts | |||
@@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) { | |||
50 | }) | 50 | }) |
51 | const total = await JobQueue.Instance.count(state) | 51 | const total = await JobQueue.Instance.count(state) |
52 | 52 | ||
53 | const result: ResultList<any> = { | 53 | const result: ResultList<Job> = { |
54 | total, | 54 | total, |
55 | data: jobs.map(j => formatJob(j, state)) | 55 | data: jobs.map(j => formatJob(j, state)) |
56 | } | 56 | } |
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts index 46e76ac6b..75f3baedb 100644 --- a/server/controllers/api/overviews.ts +++ b/server/controllers/api/overviews.ts | |||
@@ -24,7 +24,7 @@ export { overviewsRouter } | |||
24 | const buildSamples = memoizee(async function () { | 24 | const buildSamples = memoizee(async function () { |
25 | const [ categories, channels, tags ] = await Promise.all([ | 25 | const [ categories, channels, tags ] = await Promise.all([ |
26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 26 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 27 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) | 28 | TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) |
29 | ]) | 29 | ]) |
30 | 30 | ||
diff --git a/server/controllers/api/server/debug.ts b/server/controllers/api/server/debug.ts index 4450038f6..e12fc1dd4 100644 --- a/server/controllers/api/server/debug.ts +++ b/server/controllers/api/server/debug.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../../shared/models/users' | 2 | import { UserRight } from '../../../../shared/models/users' |
3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' | 3 | import { authenticate, ensureUserHasRight } from '../../../middlewares' |
4 | 4 | ||
5 | const debugRouter = express.Router() | 5 | const debugRouter = express.Router() |
6 | 6 | ||
7 | debugRouter.get('/debug', | 7 | debugRouter.get('/debug', |
8 | authenticate, | 8 | authenticate, |
9 | ensureUserHasRight(UserRight.MANAGE_DEBUG), | 9 | ensureUserHasRight(UserRight.MANAGE_DEBUG), |
10 | asyncMiddleware(getDebug) | 10 | getDebug |
11 | ) | 11 | ) |
12 | 12 | ||
13 | // --------------------------------------------------------------------------- | 13 | // --------------------------------------------------------------------------- |
@@ -18,7 +18,7 @@ export { | |||
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
21 | async function getDebug (req: express.Request, res: express.Response) { | 21 | function getDebug (req: express.Request, res: express.Response) { |
22 | return res.json({ | 22 | return res.json({ |
23 | ip: req.ip | 23 | ip: req.ip |
24 | }).end() | 24 | }).end() |
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts index 29a403a43..0bc20bd60 100644 --- a/server/controllers/api/server/follows.ts +++ b/server/controllers/api/server/follows.ts | |||
@@ -24,7 +24,7 @@ import { | |||
24 | } from '../../../middlewares/validators' | 24 | } from '../../../middlewares/validators' |
25 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 25 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
26 | import { JobQueue } from '../../../lib/job-queue' | 26 | import { JobQueue } from '../../../lib/job-queue' |
27 | import { removeRedundancyOf } from '../../../lib/redundancy' | 27 | import { removeRedundanciesOfServer } from '../../../lib/redundancy' |
28 | import { sequelizeTypescript } from '../../../initializers/database' | 28 | import { sequelizeTypescript } from '../../../initializers/database' |
29 | import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow' | 29 | import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow' |
30 | 30 | ||
@@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) { | |||
135 | } | 135 | } |
136 | 136 | ||
137 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 137 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
138 | .catch(err => logger.error('Cannot create follow job for %s.', host, err)) | ||
139 | } | 138 | } |
140 | 139 | ||
141 | return res.status(204).end() | 140 | return res.status(204).end() |
@@ -153,7 +152,7 @@ async function removeFollowing (req: express.Request, res: express.Response) { | |||
153 | await server.save({ transaction: t }) | 152 | await server.save({ transaction: t }) |
154 | 153 | ||
155 | // Async, could be long | 154 | // Async, could be long |
156 | removeRedundancyOf(server.id) | 155 | removeRedundanciesOfServer(server.id) |
157 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) | 156 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) |
158 | 157 | ||
159 | await follow.destroy({ transaction: t }) | 158 | await follow.destroy({ transaction: t }) |
diff --git a/server/controllers/api/server/logs.ts b/server/controllers/api/server/logs.ts index cd1e0f5bf..4b543d686 100644 --- a/server/controllers/api/server/logs.ts +++ b/server/controllers/api/server/logs.ts | |||
@@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | async function generateOutput (options: { | 61 | async function generateOutput (options: { |
62 | startDateQuery: string, | 62 | startDateQuery: string |
63 | endDateQuery?: string, | 63 | endDateQuery?: string |
64 | level: LogLevel, | 64 | level: LogLevel |
65 | nameFilter: RegExp | 65 | nameFilter: RegExp |
66 | }) { | 66 | }) { |
67 | const { startDateQuery, level, nameFilter } = options | 67 | const { startDateQuery, level, nameFilter } = options |
@@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date, | |||
111 | const output: any[] = [] | 111 | const output: any[] = [] |
112 | 112 | ||
113 | for (let i = lines.length - 1; i >= 0; i--) { | 113 | for (let i = lines.length - 1; i >= 0; i--) { |
114 | const line = lines[ i ] | 114 | const line = lines[i] |
115 | let log: any | 115 | let log: any |
116 | 116 | ||
117 | try { | 117 | try { |
@@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date, | |||
122 | } | 122 | } |
123 | 123 | ||
124 | logTime = new Date(log.timestamp).getTime() | 124 | logTime = new Date(log.timestamp).getTime() |
125 | if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) { | 125 | if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) { |
126 | output.push(log) | 126 | output.push(log) |
127 | 127 | ||
128 | currentSize += line.length | 128 | currentSize += line.length |
diff --git a/server/controllers/api/server/redundancy.ts b/server/controllers/api/server/redundancy.ts index 4ea6164a3..1ced0759e 100644 --- a/server/controllers/api/server/redundancy.ts +++ b/server/controllers/api/server/redundancy.ts | |||
@@ -1,9 +1,24 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../../shared/models/users' | 2 | import { UserRight } from '../../../../shared/models/users' |
3 | import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' | 3 | import { |
4 | import { updateServerRedundancyValidator } from '../../../middlewares/validators/redundancy' | 4 | asyncMiddleware, |
5 | import { removeRedundancyOf } from '../../../lib/redundancy' | 5 | authenticate, |
6 | ensureUserHasRight, | ||
7 | paginationValidator, | ||
8 | setDefaultPagination, | ||
9 | setDefaultVideoRedundanciesSort, | ||
10 | videoRedundanciesSortValidator | ||
11 | } from '../../../middlewares' | ||
12 | import { | ||
13 | listVideoRedundanciesValidator, | ||
14 | updateServerRedundancyValidator, | ||
15 | addVideoRedundancyValidator, | ||
16 | removeVideoRedundancyValidator | ||
17 | } from '../../../middlewares/validators/redundancy' | ||
18 | import { removeRedundanciesOfServer, removeVideoRedundancy } from '../../../lib/redundancy' | ||
6 | import { logger } from '../../../helpers/logger' | 19 | import { logger } from '../../../helpers/logger' |
20 | import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy' | ||
21 | import { JobQueue } from '@server/lib/job-queue' | ||
7 | 22 | ||
8 | const serverRedundancyRouter = express.Router() | 23 | const serverRedundancyRouter = express.Router() |
9 | 24 | ||
@@ -14,6 +29,31 @@ serverRedundancyRouter.put('/redundancy/:host', | |||
14 | asyncMiddleware(updateRedundancy) | 29 | asyncMiddleware(updateRedundancy) |
15 | ) | 30 | ) |
16 | 31 | ||
32 | serverRedundancyRouter.get('/redundancy/videos', | ||
33 | authenticate, | ||
34 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
35 | listVideoRedundanciesValidator, | ||
36 | paginationValidator, | ||
37 | videoRedundanciesSortValidator, | ||
38 | setDefaultVideoRedundanciesSort, | ||
39 | setDefaultPagination, | ||
40 | asyncMiddleware(listVideoRedundancies) | ||
41 | ) | ||
42 | |||
43 | serverRedundancyRouter.post('/redundancy/videos', | ||
44 | authenticate, | ||
45 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
46 | addVideoRedundancyValidator, | ||
47 | asyncMiddleware(addVideoRedundancy) | ||
48 | ) | ||
49 | |||
50 | serverRedundancyRouter.delete('/redundancy/videos/:redundancyId', | ||
51 | authenticate, | ||
52 | ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES), | ||
53 | removeVideoRedundancyValidator, | ||
54 | asyncMiddleware(removeVideoRedundancyController) | ||
55 | ) | ||
56 | |||
17 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
18 | 58 | ||
19 | export { | 59 | export { |
@@ -22,6 +62,42 @@ export { | |||
22 | 62 | ||
23 | // --------------------------------------------------------------------------- | 63 | // --------------------------------------------------------------------------- |
24 | 64 | ||
65 | async function listVideoRedundancies (req: express.Request, res: express.Response) { | ||
66 | const resultList = await VideoRedundancyModel.listForApi({ | ||
67 | start: req.query.start, | ||
68 | count: req.query.count, | ||
69 | sort: req.query.sort, | ||
70 | target: req.query.target, | ||
71 | strategy: req.query.strategy | ||
72 | }) | ||
73 | |||
74 | const result = { | ||
75 | total: resultList.total, | ||
76 | data: resultList.data.map(r => VideoRedundancyModel.toFormattedJSONStatic(r)) | ||
77 | } | ||
78 | |||
79 | return res.json(result) | ||
80 | } | ||
81 | |||
82 | async function addVideoRedundancy (req: express.Request, res: express.Response) { | ||
83 | const payload = { | ||
84 | videoId: res.locals.onlyVideo.id | ||
85 | } | ||
86 | |||
87 | await JobQueue.Instance.createJobWithPromise({ | ||
88 | type: 'video-redundancy', | ||
89 | payload | ||
90 | }) | ||
91 | |||
92 | return res.sendStatus(204) | ||
93 | } | ||
94 | |||
95 | async function removeVideoRedundancyController (req: express.Request, res: express.Response) { | ||
96 | await removeVideoRedundancy(res.locals.videoRedundancy) | ||
97 | |||
98 | return res.sendStatus(204) | ||
99 | } | ||
100 | |||
25 | async function updateRedundancy (req: express.Request, res: express.Response) { | 101 | async function updateRedundancy (req: express.Request, res: express.Response) { |
26 | const server = res.locals.server | 102 | const server = res.locals.server |
27 | 103 | ||
@@ -30,7 +106,7 @@ async function updateRedundancy (req: express.Request, res: express.Response) { | |||
30 | await server.save() | 106 | await server.save() |
31 | 107 | ||
32 | // Async, could be long | 108 | // Async, could be long |
33 | removeRedundancyOf(server.id) | 109 | removeRedundanciesOfServer(server.id) |
34 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err })) | 110 | .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err })) |
35 | 111 | ||
36 | return res.sendStatus(204) | 112 | return res.sendStatus(204) |
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts index 3616c074d..6d508a481 100644 --- a/server/controllers/api/server/stats.ts +++ b/server/controllers/api/server/stats.ts | |||
@@ -10,6 +10,7 @@ import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants' | |||
10 | import { cacheRoute } from '../../../middlewares/cache' | 10 | import { cacheRoute } from '../../../middlewares/cache' |
11 | import { VideoFileModel } from '../../../models/video/video-file' | 11 | import { VideoFileModel } from '../../../models/video/video-file' |
12 | import { CONFIG } from '../../../initializers/config' | 12 | import { CONFIG } from '../../../initializers/config' |
13 | import { VideoRedundancyStrategyWithManual } from '@shared/models' | ||
13 | 14 | ||
14 | const statsRouter = express.Router() | 15 | const statsRouter = express.Router() |
15 | 16 | ||
@@ -25,8 +26,15 @@ async function getStats (req: express.Request, res: express.Response) { | |||
25 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() | 26 | const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() |
26 | const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() | 27 | const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() |
27 | 28 | ||
29 | const strategies: { strategy: VideoRedundancyStrategyWithManual, size: number }[] = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES | ||
30 | .map(r => ({ | ||
31 | strategy: r.strategy, | ||
32 | size: r.size | ||
33 | })) | ||
34 | strategies.push({ strategy: 'manual', size: null }) | ||
35 | |||
28 | const videosRedundancyStats = await Promise.all( | 36 | const videosRedundancyStats = await Promise.all( |
29 | CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => { | 37 | strategies.map(r => { |
30 | return VideoRedundancyModel.getStats(r.strategy) | 38 | return VideoRedundancyModel.getStats(r.strategy) |
31 | .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) | 39 | .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) |
32 | }) | 40 | }) |
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index b960e80c1..98eb2beed 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts | |||
@@ -2,7 +2,7 @@ import * as express from 'express' | |||
2 | import * as RateLimit from 'express-rate-limit' | 2 | import * as RateLimit from 'express-rate-limit' |
3 | import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared' | 3 | import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared' |
4 | import { logger } from '../../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { getFormattedObjects } from '../../../helpers/utils' | 5 | import { generateRandomString, getFormattedObjects } from '../../../helpers/utils' |
6 | import { WEBSERVER } from '../../../initializers/constants' | 6 | import { WEBSERVER } from '../../../initializers/constants' |
7 | import { Emailer } from '../../../lib/emailer' | 7 | import { Emailer } from '../../../lib/emailer' |
8 | import { Redis } from '../../../lib/redis' | 8 | import { Redis } from '../../../lib/redis' |
@@ -53,8 +53,6 @@ import { Hooks } from '@server/lib/plugins/hooks' | |||
53 | 53 | ||
54 | const auditLogger = auditLoggerFactory('users') | 54 | const auditLogger = auditLoggerFactory('users') |
55 | 55 | ||
56 | // FIXME: https://github.com/nfriedly/express-rate-limit/issues/138 | ||
57 | // @ts-ignore | ||
58 | const loginRateLimiter = RateLimit({ | 56 | const loginRateLimiter = RateLimit({ |
59 | windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS, | 57 | windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS, |
60 | max: CONFIG.RATES_LIMIT.LOGIN.MAX | 58 | max: CONFIG.RATES_LIMIT.LOGIN.MAX |
@@ -199,11 +197,25 @@ async function createUser (req: express.Request, res: express.Response) { | |||
199 | adminFlags: body.adminFlags || UserAdminFlag.NONE | 197 | adminFlags: body.adminFlags || UserAdminFlag.NONE |
200 | }) as MUser | 198 | }) as MUser |
201 | 199 | ||
200 | // NB: due to the validator usersAddValidator, password==='' can only be true if we can send the mail. | ||
201 | const createPassword = userToCreate.password === '' | ||
202 | if (createPassword) { | ||
203 | userToCreate.password = await generateRandomString(20) | ||
204 | } | ||
205 | |||
202 | const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate }) | 206 | const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate }) |
203 | 207 | ||
204 | auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) | 208 | auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) |
205 | logger.info('User %s with its channel and account created.', body.username) | 209 | logger.info('User %s with its channel and account created.', body.username) |
206 | 210 | ||
211 | if (createPassword) { | ||
212 | // this will send an email for newly created users, so then can set their first password. | ||
213 | logger.info('Sending to user %s a create password email', body.username) | ||
214 | const verificationString = await Redis.Instance.setCreatePasswordVerificationString(user.id) | ||
215 | const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString | ||
216 | await Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url) | ||
217 | } | ||
218 | |||
207 | Hooks.runAction('action:api.user.created', { body, user, account, videoChannel }) | 219 | Hooks.runAction('action:api.user.created', { body, user, account, videoChannel }) |
208 | 220 | ||
209 | return res.json({ | 221 | return res.json({ |
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts index ac7c62aab..23890e20c 100644 --- a/server/controllers/api/users/me.ts +++ b/server/controllers/api/users/me.ts | |||
@@ -39,7 +39,7 @@ meRouter.get('/me', | |||
39 | ) | 39 | ) |
40 | meRouter.delete('/me', | 40 | meRouter.delete('/me', |
41 | authenticate, | 41 | authenticate, |
42 | asyncMiddleware(deleteMeValidator), | 42 | deleteMeValidator, |
43 | asyncMiddleware(deleteMe) | 43 | asyncMiddleware(deleteMe) |
44 | ) | 44 | ) |
45 | 45 | ||
@@ -214,7 +214,7 @@ async function updateMe (req: express.Request, res: express.Response) { | |||
214 | } | 214 | } |
215 | 215 | ||
216 | async function updateMyAvatar (req: express.Request, res: express.Response) { | 216 | async function updateMyAvatar (req: express.Request, res: express.Response) { |
217 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] | 217 | const avatarPhysicalFile = req.files['avatarfile'][0] |
218 | const user = res.locals.oauth.token.user | 218 | const user = res.locals.oauth.token.user |
219 | 219 | ||
220 | const userAccount = await AccountModel.load(user.Account.id) | 220 | const userAccount = await AccountModel.load(user.Account.id) |
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts index 43c4c37d8..888392b8b 100644 --- a/server/controllers/api/users/my-subscriptions.ts +++ b/server/controllers/api/users/my-subscriptions.ts | |||
@@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils' | |||
19 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' | 19 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' |
20 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 20 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
21 | import { JobQueue } from '../../../lib/job-queue' | 21 | import { JobQueue } from '../../../lib/job-queue' |
22 | import { logger } from '../../../helpers/logger' | ||
23 | import { sequelizeTypescript } from '../../../initializers/database' | 22 | import { sequelizeTypescript } from '../../../initializers/database' |
24 | 23 | ||
25 | const mySubscriptionsRouter = express.Router() | 24 | const mySubscriptionsRouter = express.Router() |
@@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions', | |||
52 | mySubscriptionsRouter.post('/me/subscriptions', | 51 | mySubscriptionsRouter.post('/me/subscriptions', |
53 | authenticate, | 52 | authenticate, |
54 | userSubscriptionAddValidator, | 53 | userSubscriptionAddValidator, |
55 | asyncMiddleware(addUserSubscription) | 54 | addUserSubscription |
56 | ) | 55 | ) |
57 | 56 | ||
58 | mySubscriptionsRouter.get('/me/subscriptions/:uri', | 57 | mySubscriptionsRouter.get('/me/subscriptions/:uri', |
@@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons | |||
106 | return res.json(existObject) | 105 | return res.json(existObject) |
107 | } | 106 | } |
108 | 107 | ||
109 | async function addUserSubscription (req: express.Request, res: express.Response) { | 108 | function addUserSubscription (req: express.Request, res: express.Response) { |
110 | const user = res.locals.oauth.token.User | 109 | const user = res.locals.oauth.token.User |
111 | const [ name, host ] = req.body.uri.split('@') | 110 | const [ name, host ] = req.body.uri.split('@') |
112 | 111 | ||
@@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response) | |||
117 | } | 116 | } |
118 | 117 | ||
119 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 118 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
120 | .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err)) | ||
121 | 119 | ||
122 | return res.status(204).end() | 120 | return res.status(204).end() |
123 | } | 121 | } |
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts index e1f37a8fb..a808896ff 100644 --- a/server/controllers/api/video-channel.ts +++ b/server/controllers/api/video-channel.ts | |||
@@ -119,7 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) { | |||
119 | } | 119 | } |
120 | 120 | ||
121 | async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { | 121 | async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { |
122 | const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] | 122 | const avatarPhysicalFile = req.files['avatarfile'][0] |
123 | const videoChannel = res.locals.videoChannel | 123 | const videoChannel = res.locals.videoChannel |
124 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) | 124 | const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) |
125 | 125 | ||
@@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) { | |||
232 | 232 | ||
233 | if (videoChannelWithVideos.isOutdated()) { | 233 | if (videoChannelWithVideos.isOutdated()) { |
234 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) | 234 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) |
235 | .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err })) | ||
236 | } | 235 | } |
237 | 236 | ||
238 | return res.json(videoChannelWithVideos.toFormattedJSON()) | 237 | return res.json(videoChannelWithVideos.toFormattedJSON()) |
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index d9f0ff925..b51490bf9 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts | |||
@@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) { | |||
144 | 144 | ||
145 | if (videoPlaylist.isOutdated()) { | 145 | if (videoPlaylist.isOutdated()) { |
146 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) | 146 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) |
147 | .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err })) | ||
148 | } | 147 | } |
149 | 148 | ||
150 | return res.json(videoPlaylist.toFormattedJSON()) | 149 | return res.json(videoPlaylist.toFormattedJSON()) |
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts index 37481d12f..fd7b165fb 100644 --- a/server/controllers/api/videos/captions.ts +++ b/server/controllers/api/videos/captions.ts | |||
@@ -66,7 +66,7 @@ async function addVideoCaption (req: express.Request, res: express.Response) { | |||
66 | await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption) | 66 | await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption) |
67 | 67 | ||
68 | await sequelizeTypescript.transaction(async t => { | 68 | await sequelizeTypescript.transaction(async t => { |
69 | await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, t) | 69 | await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, null, t) |
70 | 70 | ||
71 | // Update video update | 71 | // Update video update |
72 | await federateVideoIfNeeded(video, false, t) | 72 | await federateVideoIfNeeded(video, false, t) |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 28ced5836..ed223cbc9 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
88 | const buf = await readFile(torrentfile.path) | 88 | const buf = await readFile(torrentfile.path) |
89 | const parsedTorrent = parseTorrent(buf) | 89 | const parsedTorrent = parseTorrent(buf) |
90 | 90 | ||
91 | videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string | 91 | videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string |
92 | } else { | 92 | } else { |
93 | magnetUri = body.magnetUri | 93 | magnetUri = body.magnetUri |
94 | 94 | ||
95 | const parsed = magnetUtil.decode(magnetUri) | 95 | const parsed = magnetUtil.decode(magnetUri) |
96 | videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string | 96 | videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string |
97 | } | 97 | } |
98 | 98 | ||
99 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) | 99 | const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) |
@@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to | |||
124 | videoImportId: videoImport.id, | 124 | videoImportId: videoImport.id, |
125 | magnetUri | 125 | magnetUri |
126 | } | 126 | } |
127 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 127 | await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload }) |
128 | 128 | ||
129 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) | 129 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
130 | 130 | ||
@@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
176 | downloadThumbnail: !thumbnailModel, | 176 | downloadThumbnail: !thumbnailModel, |
177 | downloadPreview: !previewModel | 177 | downloadPreview: !previewModel |
178 | } | 178 | } |
179 | await JobQueue.Instance.createJob({ type: 'video-import', payload }) | 179 | await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload }) |
180 | 180 | ||
181 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) | 181 | auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) |
182 | 182 | ||
@@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You | |||
211 | async function processThumbnail (req: express.Request, video: VideoModel) { | 211 | async function processThumbnail (req: express.Request, video: VideoModel) { |
212 | const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined | 212 | const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined |
213 | if (thumbnailField) { | 213 | if (thumbnailField) { |
214 | const thumbnailPhysicalFile = thumbnailField[ 0 ] | 214 | const thumbnailPhysicalFile = thumbnailField[0] |
215 | 215 | ||
216 | return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) | 216 | return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) |
217 | } | 217 | } |
@@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) { | |||
231 | } | 231 | } |
232 | 232 | ||
233 | function insertIntoDB (parameters: { | 233 | function insertIntoDB (parameters: { |
234 | video: MVideoThumbnailAccountDefault, | 234 | video: MVideoThumbnailAccountDefault |
235 | thumbnailModel: MThumbnail, | 235 | thumbnailModel: MThumbnail |
236 | previewModel: MThumbnail, | 236 | previewModel: MThumbnail |
237 | videoChannel: MChannelAccountDefault, | 237 | videoChannel: MChannelAccountDefault |
238 | tags: string[], | 238 | tags: string[] |
239 | videoImportAttributes: Partial<MVideoImport>, | 239 | videoImportAttributes: Partial<MVideoImport> |
240 | user: MUser | 240 | user: MUser |
241 | }): Bluebird<MVideoImportFormattable> { | 241 | }): Bluebird<MVideoImportFormattable> { |
242 | const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters | 242 | const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 8d4ff07eb..eb46ea01f 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -135,7 +135,7 @@ videosRouter.get('/:id', | |||
135 | asyncMiddleware(getVideo) | 135 | asyncMiddleware(getVideo) |
136 | ) | 136 | ) |
137 | videosRouter.post('/:id/views', | 137 | videosRouter.post('/:id/views', |
138 | asyncMiddleware(videosGetValidator), | 138 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
139 | asyncMiddleware(viewVideo) | 139 | asyncMiddleware(viewVideo) |
140 | ) | 140 | ) |
141 | 141 | ||
@@ -307,7 +307,7 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 310 | await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput }) |
311 | } | 311 | } |
312 | 312 | ||
313 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) | 313 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) |
@@ -452,14 +452,13 @@ async function getVideo (req: express.Request, res: express.Response) { | |||
452 | 452 | ||
453 | if (video.isOutdated()) { | 453 | if (video.isOutdated()) { |
454 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) | 454 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) |
455 | .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err })) | ||
456 | } | 455 | } |
457 | 456 | ||
458 | return res.json(video.toFormattedDetailsJSON()) | 457 | return res.json(video.toFormattedDetailsJSON()) |
459 | } | 458 | } |
460 | 459 | ||
461 | async function viewVideo (req: express.Request, res: express.Response) { | 460 | async function viewVideo (req: express.Request, res: express.Response) { |
462 | const videoInstance = res.locals.videoAll | 461 | const videoInstance = res.locals.onlyImmutableVideo |
463 | 462 | ||
464 | const ip = req.ip | 463 | const ip = req.ip |
465 | const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid) | 464 | const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid) |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 56685f102..20689fb58 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -72,7 +72,7 @@ export { | |||
72 | 72 | ||
73 | // --------------------------------------------------------------------------- | 73 | // --------------------------------------------------------------------------- |
74 | 74 | ||
75 | async function serveServerTranslations (req: express.Request, res: express.Response) { | 75 | function serveServerTranslations (req: express.Request, res: express.Response) { |
76 | const locale = req.params.locale | 76 | const locale = req.params.locale |
77 | const file = req.params.file | 77 | const file = req.params.file |
78 | 78 | ||
diff --git a/server/controllers/static.ts b/server/controllers/static.ts index a4bb3a4d9..271b788f6 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts | |||
@@ -1,15 +1,15 @@ | |||
1 | import * as cors from 'cors' | 1 | import * as cors from 'cors' |
2 | import * as express from 'express' | 2 | import * as express from 'express' |
3 | import { | 3 | import { |
4 | CONSTRAINTS_FIELDS, | ||
5 | DEFAULT_THEME_NAME, | ||
4 | HLS_STREAMING_PLAYLIST_DIRECTORY, | 6 | HLS_STREAMING_PLAYLIST_DIRECTORY, |
5 | PEERTUBE_VERSION, | 7 | PEERTUBE_VERSION, |
6 | ROUTE_CACHE_LIFETIME, | 8 | ROUTE_CACHE_LIFETIME, |
7 | STATIC_DOWNLOAD_PATHS, | 9 | STATIC_DOWNLOAD_PATHS, |
8 | STATIC_MAX_AGE, | 10 | STATIC_MAX_AGE, |
9 | STATIC_PATHS, | 11 | STATIC_PATHS, |
10 | WEBSERVER, | 12 | WEBSERVER |
11 | CONSTRAINTS_FIELDS, | ||
12 | DEFAULT_THEME_NAME | ||
13 | } from '../initializers/constants' | 13 | } from '../initializers/constants' |
14 | import { cacheRoute } from '../middlewares/cache' | 14 | import { cacheRoute } from '../middlewares/cache' |
15 | import { asyncMiddleware, videosDownloadValidator } from '../middlewares' | 15 | import { asyncMiddleware, videosDownloadValidator } from '../middlewares' |
@@ -19,8 +19,7 @@ import { VideoCommentModel } from '../models/video/video-comment' | |||
19 | import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo' | 19 | import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo' |
20 | import { join } from 'path' | 20 | import { join } from 'path' |
21 | import { root } from '../helpers/core-utils' | 21 | import { root } from '../helpers/core-utils' |
22 | import { CONFIG } from '../initializers/config' | 22 | import { CONFIG, isEmailEnabled } from '../initializers/config' |
23 | import { Emailer } from '../lib/emailer' | ||
24 | import { getPreview, getVideoCaption } from './lazy-static' | 23 | import { getPreview, getVideoCaption } from './lazy-static' |
25 | import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type' | 24 | import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type' |
26 | import { MVideoFile, MVideoFullLight } from '@server/typings/models' | 25 | import { MVideoFile, MVideoFullLight } from '@server/typings/models' |
@@ -45,12 +44,12 @@ staticRouter.use( | |||
45 | staticRouter.use( | 44 | staticRouter.use( |
46 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', | 45 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', |
47 | asyncMiddleware(videosDownloadValidator), | 46 | asyncMiddleware(videosDownloadValidator), |
48 | asyncMiddleware(downloadTorrent) | 47 | downloadTorrent |
49 | ) | 48 | ) |
50 | staticRouter.use( | 49 | staticRouter.use( |
51 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', | 50 | STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', |
52 | asyncMiddleware(videosDownloadValidator), | 51 | asyncMiddleware(videosDownloadValidator), |
53 | asyncMiddleware(downloadHLSVideoFileTorrent) | 52 | downloadHLSVideoFileTorrent |
54 | ) | 53 | ) |
55 | 54 | ||
56 | // Videos path for webseeding | 55 | // Videos path for webseeding |
@@ -68,13 +67,13 @@ staticRouter.use( | |||
68 | staticRouter.use( | 67 | staticRouter.use( |
69 | STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', | 68 | STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', |
70 | asyncMiddleware(videosDownloadValidator), | 69 | asyncMiddleware(videosDownloadValidator), |
71 | asyncMiddleware(downloadVideoFile) | 70 | downloadVideoFile |
72 | ) | 71 | ) |
73 | 72 | ||
74 | staticRouter.use( | 73 | staticRouter.use( |
75 | STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', | 74 | STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', |
76 | asyncMiddleware(videosDownloadValidator), | 75 | asyncMiddleware(videosDownloadValidator), |
77 | asyncMiddleware(downloadHLSVideoFile) | 76 | downloadHLSVideoFile |
78 | ) | 77 | ) |
79 | 78 | ||
80 | // HLS | 79 | // HLS |
@@ -235,6 +234,12 @@ async function generateNodeinfo (req: express.Request, res: express.Response) { | |||
235 | nodeName: CONFIG.INSTANCE.NAME, | 234 | nodeName: CONFIG.INSTANCE.NAME, |
236 | nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, | 235 | nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, |
237 | nodeConfig: { | 236 | nodeConfig: { |
237 | search: { | ||
238 | remoteUri: { | ||
239 | users: CONFIG.SEARCH.REMOTE_URI.USERS, | ||
240 | anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS | ||
241 | } | ||
242 | }, | ||
238 | plugin: { | 243 | plugin: { |
239 | registered: getRegisteredPlugins() | 244 | registered: getRegisteredPlugins() |
240 | }, | 245 | }, |
@@ -243,7 +248,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) { | |||
243 | default: getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) | 248 | default: getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) |
244 | }, | 249 | }, |
245 | email: { | 250 | email: { |
246 | enabled: Emailer.isEnabled() | 251 | enabled: isEmailEnabled() |
247 | }, | 252 | }, |
248 | contactForm: { | 253 | contactForm: { |
249 | enabled: CONFIG.CONTACT_FORM.ENABLED | 254 | enabled: CONFIG.CONTACT_FORM.ENABLED |
@@ -325,7 +330,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) { | |||
325 | return res.send(json).end() | 330 | return res.send(json).end() |
326 | } | 331 | } |
327 | 332 | ||
328 | async function downloadTorrent (req: express.Request, res: express.Response) { | 333 | function downloadTorrent (req: express.Request, res: express.Response) { |
329 | const video = res.locals.videoAll | 334 | const video = res.locals.videoAll |
330 | 335 | ||
331 | const videoFile = getVideoFile(req, video.VideoFiles) | 336 | const videoFile = getVideoFile(req, video.VideoFiles) |
@@ -334,7 +339,7 @@ async function downloadTorrent (req: express.Request, res: express.Response) { | |||
334 | return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) | 339 | return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) |
335 | } | 340 | } |
336 | 341 | ||
337 | async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { | 342 | function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { |
338 | const video = res.locals.videoAll | 343 | const video = res.locals.videoAll |
339 | 344 | ||
340 | const playlist = getHLSPlaylist(video) | 345 | const playlist = getHLSPlaylist(video) |
@@ -346,7 +351,7 @@ async function downloadHLSVideoFileTorrent (req: express.Request, res: express.R | |||
346 | return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) | 351 | return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) |
347 | } | 352 | } |
348 | 353 | ||
349 | async function downloadVideoFile (req: express.Request, res: express.Response) { | 354 | function downloadVideoFile (req: express.Request, res: express.Response) { |
350 | const video = res.locals.videoAll | 355 | const video = res.locals.videoAll |
351 | 356 | ||
352 | const videoFile = getVideoFile(req, video.VideoFiles) | 357 | const videoFile = getVideoFile(req, video.VideoFiles) |
@@ -355,7 +360,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) { | |||
355 | return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) | 360 | return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) |
356 | } | 361 | } |
357 | 362 | ||
358 | async function downloadHLSVideoFile (req: express.Request, res: express.Response) { | 363 | function downloadHLSVideoFile (req: express.Request, res: express.Response) { |
359 | const video = res.locals.videoAll | 364 | const video = res.locals.videoAll |
360 | const playlist = getHLSPlaylist(video) | 365 | const playlist = getHLSPlaylist(video) |
361 | if (!playlist) return res.status(404).end | 366 | if (!playlist) return res.status(404).end |
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts index 2ae1cf86c..e9c8a13da 100644 --- a/server/controllers/tracker.ts +++ b/server/controllers/tracker.ts | |||
@@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr' | |||
6 | import { Server as WebSocketServer } from 'ws' | 6 | import { Server as WebSocketServer } from 'ws' |
7 | import { TRACKER_RATE_LIMITS } from '../initializers/constants' | 7 | import { TRACKER_RATE_LIMITS } from '../initializers/constants' |
8 | import { VideoFileModel } from '../models/video/video-file' | 8 | import { VideoFileModel } from '../models/video/video-file' |
9 | import { parse } from 'url' | ||
10 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | 9 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' |
11 | import { CONFIG } from '../initializers/config' | 10 | import { CONFIG } from '../initializers/config' |
12 | 11 | ||
@@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({ | |||
38 | 37 | ||
39 | const key = ip + '-' + infoHash | 38 | const key = ip + '-' + infoHash |
40 | 39 | ||
41 | peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1 | 40 | peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1 |
42 | peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1 | 41 | peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1 |
43 | 42 | ||
44 | if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { | 43 | if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { |
45 | return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`)) | 44 | return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`)) |
46 | } | 45 | } |
47 | 46 | ||
48 | try { | 47 | try { |
@@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) { | |||
87 | trackerServer.onWebSocketConnection(ws) | 86 | trackerServer.onWebSocketConnection(ws) |
88 | }) | 87 | }) |
89 | 88 | ||
90 | server.on('upgrade', (request, socket, head) => { | 89 | server.on('upgrade', (request: express.Request, socket, head) => { |
91 | const pathname = parse(request.url).pathname | 90 | if (request.path === '/tracker/socket') { |
92 | |||
93 | if (pathname === '/tracker/socket') { | ||
94 | wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) | 91 | wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) |
95 | } | 92 | } |
96 | 93 | ||
diff --git a/server/controllers/webfinger.ts b/server/controllers/webfinger.ts index fc9575160..77c851880 100644 --- a/server/controllers/webfinger.ts +++ b/server/controllers/webfinger.ts | |||
@@ -18,7 +18,7 @@ export { | |||
18 | // --------------------------------------------------------------------------- | 18 | // --------------------------------------------------------------------------- |
19 | 19 | ||
20 | function webfingerController (req: express.Request, res: express.Response) { | 20 | function webfingerController (req: express.Request, res: express.Response) { |
21 | const actor = res.locals.actorFull | 21 | const actor = res.locals.actorUrl |
22 | 22 | ||
23 | const json = { | 23 | const json = { |
24 | subject: req.query.resource, | 24 | subject: req.query.resource, |
@@ -32,5 +32,5 @@ function webfingerController (req: express.Request, res: express.Response) { | |||
32 | ] | 32 | ] |
33 | } | 33 | } |
34 | 34 | ||
35 | return res.json(json).end() | 35 | return res.json(json) |
36 | } | 36 | } |
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index 239d8291d..2d49e6869 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts | |||
@@ -2,21 +2,36 @@ import * as Bluebird from 'bluebird' | |||
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { ResultList } from '../../shared/models' | 3 | import { ResultList } from '../../shared/models' |
4 | import { Activity } from '../../shared/models/activitypub' | 4 | import { Activity } from '../../shared/models/activitypub' |
5 | import { ACTIVITY_PUB } from '../initializers/constants' | 5 | import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants' |
6 | import { signJsonLDObject } from './peertube-crypto' | 6 | import { signJsonLDObject } from './peertube-crypto' |
7 | import { pageToStartAndCount } from './core-utils' | 7 | import { pageToStartAndCount } from './core-utils' |
8 | import { parse } from 'url' | 8 | import { URL } from 'url' |
9 | import { MActor } from '../typings/models' | 9 | import { MActor, MVideoAccountLight } from '../typings/models' |
10 | 10 | ||
11 | function activityPubContextify <T> (data: T) { | 11 | export type ContextType = 'All' | 'View' | 'Announce' | 'CacheFile' |
12 | return Object.assign(data, { | 12 | |
13 | '@context': [ | 13 | function getContextData (type: ContextType) { |
14 | 'https://www.w3.org/ns/activitystreams', | 14 | const context: any[] = [ |
15 | 'https://w3id.org/security/v1', | 15 | 'https://www.w3.org/ns/activitystreams', |
16 | { | 16 | 'https://w3id.org/security/v1', |
17 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017', | 17 | { |
18 | pt: 'https://joinpeertube.org/ns#', | 18 | RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' |
19 | sc: 'http://schema.org#', | 19 | } |
20 | ] | ||
21 | |||
22 | if (type !== 'View' && type !== 'Announce') { | ||
23 | const additional = { | ||
24 | pt: 'https://joinpeertube.org/ns#', | ||
25 | sc: 'http://schema.org#' | ||
26 | } | ||
27 | |||
28 | if (type === 'CacheFile') { | ||
29 | Object.assign(additional, { | ||
30 | expires: 'sc:expires', | ||
31 | CacheFile: 'pt:CacheFile' | ||
32 | }) | ||
33 | } else { | ||
34 | Object.assign(additional, { | ||
20 | Hashtag: 'as:Hashtag', | 35 | Hashtag: 'as:Hashtag', |
21 | uuid: 'sc:identifier', | 36 | uuid: 'sc:identifier', |
22 | category: 'sc:category', | 37 | category: 'sc:category', |
@@ -24,8 +39,7 @@ function activityPubContextify <T> (data: T) { | |||
24 | subtitleLanguage: 'sc:subtitleLanguage', | 39 | subtitleLanguage: 'sc:subtitleLanguage', |
25 | sensitive: 'as:sensitive', | 40 | sensitive: 'as:sensitive', |
26 | language: 'sc:inLanguage', | 41 | language: 'sc:inLanguage', |
27 | expires: 'sc:expires', | 42 | |
28 | CacheFile: 'pt:CacheFile', | ||
29 | Infohash: 'pt:Infohash', | 43 | Infohash: 'pt:Infohash', |
30 | originallyPublishedAt: 'sc:datePublished', | 44 | originallyPublishedAt: 'sc:datePublished', |
31 | views: { | 45 | views: { |
@@ -71,9 +85,7 @@ function activityPubContextify <T> (data: T) { | |||
71 | support: { | 85 | support: { |
72 | '@type': 'sc:Text', | 86 | '@type': 'sc:Text', |
73 | '@id': 'pt:support' | 87 | '@id': 'pt:support' |
74 | } | 88 | }, |
75 | }, | ||
76 | { | ||
77 | likes: { | 89 | likes: { |
78 | '@id': 'as:likes', | 90 | '@id': 'as:likes', |
79 | '@type': '@id' | 91 | '@type': '@id' |
@@ -94,9 +106,19 @@ function activityPubContextify <T> (data: T) { | |||
94 | '@id': 'as:comments', | 106 | '@id': 'as:comments', |
95 | '@type': '@id' | 107 | '@type': '@id' |
96 | } | 108 | } |
97 | } | 109 | }) |
98 | ] | 110 | } |
99 | }) | 111 | |
112 | context.push(additional) | ||
113 | } | ||
114 | |||
115 | return { | ||
116 | '@context': context | ||
117 | } | ||
118 | } | ||
119 | |||
120 | function activityPubContextify <T> (data: T, type: ContextType = 'All') { | ||
121 | return Object.assign({}, data, getContextData(type)) | ||
100 | } | 122 | } |
101 | 123 | ||
102 | type ActivityPubCollectionPaginationHandler = (start: number, count: number) => Bluebird<ResultList<any>> | Promise<ResultList<any>> | 124 | type ActivityPubCollectionPaginationHandler = (start: number, count: number) => Bluebird<ResultList<any>> | Promise<ResultList<any>> |
@@ -148,8 +170,8 @@ async function activityPubCollectionPagination ( | |||
148 | 170 | ||
149 | } | 171 | } |
150 | 172 | ||
151 | function buildSignedActivity (byActor: MActor, data: Object) { | 173 | function buildSignedActivity (byActor: MActor, data: Object, contextType?: ContextType) { |
152 | const activity = activityPubContextify(data) | 174 | const activity = activityPubContextify(data, contextType) |
153 | 175 | ||
154 | return signJsonLDObject(byActor, activity) as Promise<Activity> | 176 | return signJsonLDObject(byActor, activity) as Promise<Activity> |
155 | } | 177 | } |
@@ -161,12 +183,18 @@ function getAPId (activity: string | { id: string }) { | |||
161 | } | 183 | } |
162 | 184 | ||
163 | function checkUrlsSameHost (url1: string, url2: string) { | 185 | function checkUrlsSameHost (url1: string, url2: string) { |
164 | const idHost = parse(url1).host | 186 | const idHost = new URL(url1).host |
165 | const actorHost = parse(url2).host | 187 | const actorHost = new URL(url2).host |
166 | 188 | ||
167 | return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() | 189 | return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() |
168 | } | 190 | } |
169 | 191 | ||
192 | function buildRemoteVideoBaseUrl (video: MVideoAccountLight, path: string) { | ||
193 | const host = video.VideoChannel.Account.Actor.Server.host | ||
194 | |||
195 | return REMOTE_SCHEME.HTTP + '://' + host + path | ||
196 | } | ||
197 | |||
170 | // --------------------------------------------------------------------------- | 198 | // --------------------------------------------------------------------------- |
171 | 199 | ||
172 | export { | 200 | export { |
@@ -174,5 +202,6 @@ export { | |||
174 | getAPId, | 202 | getAPId, |
175 | activityPubContextify, | 203 | activityPubContextify, |
176 | activityPubCollectionPagination, | 204 | activityPubCollectionPagination, |
177 | buildSignedActivity | 205 | buildSignedActivity, |
206 | buildRemoteVideoBaseUrl | ||
178 | } | 207 | } |
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 9b258dc3a..a4cfeef76 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -81,7 +81,8 @@ function auditLoggerFactory (domain: string) { | |||
81 | } | 81 | } |
82 | 82 | ||
83 | abstract class EntityAuditView { | 83 | abstract class EntityAuditView { |
84 | constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { } | 84 | constructor (private readonly keysToKeep: string[], private readonly prefix: string, private readonly entityInfos: object) { } |
85 | |||
85 | toLogKeys (): object { | 86 | toLogKeys (): object { |
86 | return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) | 87 | return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) |
87 | .pick(this.keysToKeep) | 88 | .pick(this.keysToKeep) |
@@ -121,7 +122,7 @@ const videoKeysToKeep = [ | |||
121 | 'downloadEnabled' | 122 | 'downloadEnabled' |
122 | ] | 123 | ] |
123 | class VideoAuditView extends EntityAuditView { | 124 | class VideoAuditView extends EntityAuditView { |
124 | constructor (private video: VideoDetails) { | 125 | constructor (private readonly video: VideoDetails) { |
125 | super(videoKeysToKeep, 'video', video) | 126 | super(videoKeysToKeep, 'video', video) |
126 | } | 127 | } |
127 | } | 128 | } |
@@ -132,7 +133,7 @@ const videoImportKeysToKeep = [ | |||
132 | 'video-name' | 133 | 'video-name' |
133 | ] | 134 | ] |
134 | class VideoImportAuditView extends EntityAuditView { | 135 | class VideoImportAuditView extends EntityAuditView { |
135 | constructor (private videoImport: VideoImport) { | 136 | constructor (private readonly videoImport: VideoImport) { |
136 | super(videoImportKeysToKeep, 'video-import', videoImport) | 137 | super(videoImportKeysToKeep, 'video-import', videoImport) |
137 | } | 138 | } |
138 | } | 139 | } |
@@ -151,7 +152,7 @@ const commentKeysToKeep = [ | |||
151 | 'account-name' | 152 | 'account-name' |
152 | ] | 153 | ] |
153 | class CommentAuditView extends EntityAuditView { | 154 | class CommentAuditView extends EntityAuditView { |
154 | constructor (private comment: VideoComment) { | 155 | constructor (private readonly comment: VideoComment) { |
155 | super(commentKeysToKeep, 'comment', comment) | 156 | super(commentKeysToKeep, 'comment', comment) |
156 | } | 157 | } |
157 | } | 158 | } |
@@ -180,7 +181,7 @@ const userKeysToKeep = [ | |||
180 | 'videoChannels' | 181 | 'videoChannels' |
181 | ] | 182 | ] |
182 | class UserAuditView extends EntityAuditView { | 183 | class UserAuditView extends EntityAuditView { |
183 | constructor (private user: User) { | 184 | constructor (private readonly user: User) { |
184 | super(userKeysToKeep, 'user', user) | 185 | super(userKeysToKeep, 'user', user) |
185 | } | 186 | } |
186 | } | 187 | } |
@@ -206,7 +207,7 @@ const channelKeysToKeep = [ | |||
206 | 'ownerAccount-displayedName' | 207 | 'ownerAccount-displayedName' |
207 | ] | 208 | ] |
208 | class VideoChannelAuditView extends EntityAuditView { | 209 | class VideoChannelAuditView extends EntityAuditView { |
209 | constructor (private channel: VideoChannel) { | 210 | constructor (private readonly channel: VideoChannel) { |
210 | super(channelKeysToKeep, 'channel', channel) | 211 | super(channelKeysToKeep, 'channel', channel) |
211 | } | 212 | } |
212 | } | 213 | } |
@@ -221,7 +222,7 @@ const videoAbuseKeysToKeep = [ | |||
221 | 'createdAt' | 222 | 'createdAt' |
222 | ] | 223 | ] |
223 | class VideoAbuseAuditView extends EntityAuditView { | 224 | class VideoAbuseAuditView extends EntityAuditView { |
224 | constructor (private videoAbuse: VideoAbuse) { | 225 | constructor (private readonly videoAbuse: VideoAbuse) { |
225 | super(videoAbuseKeysToKeep, 'abuse', videoAbuse) | 226 | super(videoAbuseKeysToKeep, 'abuse', videoAbuse) |
226 | } | 227 | } |
227 | } | 228 | } |
@@ -253,9 +254,12 @@ class CustomConfigAuditView extends EntityAuditView { | |||
253 | const infos: any = customConfig | 254 | const infos: any = customConfig |
254 | const resolutionsDict = infos.transcoding.resolutions | 255 | const resolutionsDict = infos.transcoding.resolutions |
255 | const resolutionsArray = [] | 256 | const resolutionsArray = [] |
256 | Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => { | 257 | |
257 | if (isEnabled) resolutionsArray.push(resolution) | 258 | Object.entries(resolutionsDict) |
258 | }) | 259 | .forEach(([ resolution, isEnabled ]) => { |
260 | if (isEnabled) resolutionsArray.push(resolution) | ||
261 | }) | ||
262 | |||
259 | Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) | 263 | Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) |
260 | super(customConfigKeysToKeep, 'config', infos) | 264 | super(customConfigKeysToKeep, 'config', infos) |
261 | } | 265 | } |
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index 7e8252aa4..b1f5d9610 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -1,9 +1,11 @@ | |||
1 | /* eslint-disable no-useless-call */ | ||
2 | |||
1 | /* | 3 | /* |
2 | Different from 'utils' because we don't not import other PeerTube modules. | 4 | Different from 'utils' because we don't import other PeerTube modules. |
3 | Useful to avoid circular dependencies. | 5 | Useful to avoid circular dependencies. |
4 | */ | 6 | */ |
5 | 7 | ||
6 | import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto' | 8 | import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto' |
7 | import { basename, isAbsolute, join, resolve } from 'path' | 9 | import { basename, isAbsolute, join, resolve } from 'path' |
8 | import * as pem from 'pem' | 10 | import * as pem from 'pem' |
9 | import { URL } from 'url' | 11 | import { URL } from 'url' |
@@ -22,31 +24,31 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va | |||
22 | const newObject = {} | 24 | const newObject = {} |
23 | Object.keys(oldObject).forEach(oldKey => { | 25 | Object.keys(oldObject).forEach(oldKey => { |
24 | const newKey = keyConverter(oldKey) | 26 | const newKey = keyConverter(oldKey) |
25 | newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter) | 27 | newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter) |
26 | }) | 28 | }) |
27 | 29 | ||
28 | return newObject | 30 | return newObject |
29 | } | 31 | } |
30 | 32 | ||
31 | const timeTable = { | 33 | const timeTable = { |
32 | ms: 1, | 34 | ms: 1, |
33 | second: 1000, | 35 | second: 1000, |
34 | minute: 60000, | 36 | minute: 60000, |
35 | hour: 3600000, | 37 | hour: 3600000, |
36 | day: 3600000 * 24, | 38 | day: 3600000 * 24, |
37 | week: 3600000 * 24 * 7, | 39 | week: 3600000 * 24 * 7, |
38 | month: 3600000 * 24 * 30 | 40 | month: 3600000 * 24 * 30 |
39 | } | 41 | } |
40 | 42 | ||
41 | export function parseDurationToMs (duration: number | string): number { | 43 | export function parseDurationToMs (duration: number | string): number { |
42 | if (typeof duration === 'number') return duration | 44 | if (typeof duration === 'number') return duration |
43 | 45 | ||
44 | if (typeof duration === 'string') { | 46 | if (typeof duration === 'string') { |
45 | const split = duration.match(/^([\d\.,]+)\s?(\w+)$/) | 47 | const split = duration.match(/^([\d.,]+)\s?(\w+)$/) |
46 | 48 | ||
47 | if (split.length === 3) { | 49 | if (split.length === 3) { |
48 | const len = parseFloat(split[1]) | 50 | const len = parseFloat(split[1]) |
49 | let unit = split[2].replace(/s$/i,'').toLowerCase() | 51 | let unit = split[2].replace(/s$/i, '').toLowerCase() |
50 | if (unit === 'm') { | 52 | if (unit === 'm') { |
51 | unit = 'ms' | 53 | unit = 'ms' |
52 | } | 54 | } |
@@ -73,21 +75,21 @@ export function parseBytes (value: string | number): number { | |||
73 | 75 | ||
74 | if (value.match(tgm)) { | 76 | if (value.match(tgm)) { |
75 | match = value.match(tgm) | 77 | match = value.match(tgm) |
76 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 78 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
77 | + parseInt(match[2], 10) * 1024 * 1024 * 1024 | 79 | parseInt(match[2], 10) * 1024 * 1024 * 1024 + |
78 | + parseInt(match[3], 10) * 1024 * 1024 | 80 | parseInt(match[3], 10) * 1024 * 1024 |
79 | } else if (value.match(tg)) { | 81 | } else if (value.match(tg)) { |
80 | match = value.match(tg) | 82 | match = value.match(tg) |
81 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 83 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
82 | + parseInt(match[2], 10) * 1024 * 1024 * 1024 | 84 | parseInt(match[2], 10) * 1024 * 1024 * 1024 |
83 | } else if (value.match(tm)) { | 85 | } else if (value.match(tm)) { |
84 | match = value.match(tm) | 86 | match = value.match(tm) |
85 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 87 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 + |
86 | + parseInt(match[2], 10) * 1024 * 1024 | 88 | parseInt(match[2], 10) * 1024 * 1024 |
87 | } else if (value.match(gm)) { | 89 | } else if (value.match(gm)) { |
88 | match = value.match(gm) | 90 | match = value.match(gm) |
89 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 | 91 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 + |
90 | + parseInt(match[2], 10) * 1024 * 1024 | 92 | parseInt(match[2], 10) * 1024 * 1024 |
91 | } else if (value.match(t)) { | 93 | } else if (value.match(t)) { |
92 | match = value.match(t) | 94 | match = value.match(t) |
93 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 | 95 | return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 |
@@ -137,6 +139,7 @@ function getAppNumber () { | |||
137 | } | 139 | } |
138 | 140 | ||
139 | let rootPath: string | 141 | let rootPath: string |
142 | |||
140 | function root () { | 143 | function root () { |
141 | if (rootPath) return rootPath | 144 | if (rootPath) return rootPath |
142 | 145 | ||
@@ -163,7 +166,7 @@ function escapeHTML (stringParam) { | |||
163 | '=': '=' | 166 | '=': '=' |
164 | } | 167 | } |
165 | 168 | ||
166 | return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s]) | 169 | return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s]) |
167 | } | 170 | } |
168 | 171 | ||
169 | function pageToStartAndCount (page: number, itemsPerPage: number) { | 172 | function pageToStartAndCount (page: number, itemsPerPage: number) { |
@@ -202,6 +205,7 @@ function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex') | |||
202 | function execShell (command: string, options?: ExecOptions) { | 205 | function execShell (command: string, options?: ExecOptions) { |
203 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { | 206 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { |
204 | exec(command, options, (err, stdout, stderr) => { | 207 | exec(command, options, (err, stdout, stderr) => { |
208 | // eslint-disable-next-line prefer-promise-reject-errors | ||
205 | if (err) return rej({ err, stdout, stderr }) | 209 | if (err) return rej({ err, stdout, stderr }) |
206 | 210 | ||
207 | return res({ stdout, stderr }) | 211 | return res({ stdout, stderr }) |
@@ -226,14 +230,6 @@ function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) => | |||
226 | } | 230 | } |
227 | } | 231 | } |
228 | 232 | ||
229 | function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> { | ||
230 | return function promisified (arg: T): Promise<void> { | ||
231 | return new Promise<void>((resolve: () => void, reject: (err: any) => void) => { | ||
232 | func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ]) | ||
233 | }) | ||
234 | } | ||
235 | } | ||
236 | |||
237 | function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> { | 233 | function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> { |
238 | return function promisified (arg1: T, arg2: U): Promise<A> { | 234 | return function promisified (arg1: T, arg2: U): Promise<A> { |
239 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { | 235 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { |
@@ -242,15 +238,7 @@ function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) | |||
242 | } | 238 | } |
243 | } | 239 | } |
244 | 240 | ||
245 | function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> { | 241 | const randomBytesPromise = promisify1<number, Buffer>(randomBytes) |
246 | return function promisified (arg1: T, arg2: U): Promise<void> { | ||
247 | return new Promise<void>((resolve: () => void, reject: (err: any) => void) => { | ||
248 | func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ]) | ||
249 | }) | ||
250 | } | ||
251 | } | ||
252 | |||
253 | const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes) | ||
254 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) | 242 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) |
255 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) | 243 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) |
256 | const execPromise2 = promisify2<string, any, string>(exec) | 244 | const execPromise2 = promisify2<string, any, string>(exec) |
@@ -280,7 +268,7 @@ export { | |||
280 | promisify1, | 268 | promisify1, |
281 | promisify2, | 269 | promisify2, |
282 | 270 | ||
283 | pseudoRandomBytesPromise, | 271 | randomBytesPromise, |
284 | createPrivateKey, | 272 | createPrivateKey, |
285 | getPublicKey, | 273 | getPublicKey, |
286 | execPromise2, | 274 | execPromise2, |
diff --git a/server/helpers/custom-jsonld-signature.ts b/server/helpers/custom-jsonld-signature.ts index a407a9fec..749c50cb3 100644 --- a/server/helpers/custom-jsonld-signature.ts +++ b/server/helpers/custom-jsonld-signature.ts | |||
@@ -5,52 +5,52 @@ import { logger } from './logger' | |||
5 | const CACHE = { | 5 | const CACHE = { |
6 | 'https://w3id.org/security/v1': { | 6 | 'https://w3id.org/security/v1': { |
7 | '@context': { | 7 | '@context': { |
8 | 'id': '@id', | 8 | id: '@id', |
9 | 'type': '@type', | 9 | type: '@type', |
10 | 10 | ||
11 | 'dc': 'http://purl.org/dc/terms/', | 11 | dc: 'http://purl.org/dc/terms/', |
12 | 'sec': 'https://w3id.org/security#', | 12 | sec: 'https://w3id.org/security#', |
13 | 'xsd': 'http://www.w3.org/2001/XMLSchema#', | 13 | xsd: 'http://www.w3.org/2001/XMLSchema#', |
14 | 14 | ||
15 | 'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016', | 15 | EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016', |
16 | 'Ed25519Signature2018': 'sec:Ed25519Signature2018', | 16 | Ed25519Signature2018: 'sec:Ed25519Signature2018', |
17 | 'EncryptedMessage': 'sec:EncryptedMessage', | 17 | EncryptedMessage: 'sec:EncryptedMessage', |
18 | 'GraphSignature2012': 'sec:GraphSignature2012', | 18 | GraphSignature2012: 'sec:GraphSignature2012', |
19 | 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', | 19 | LinkedDataSignature2015: 'sec:LinkedDataSignature2015', |
20 | 'LinkedDataSignature2016': 'sec:LinkedDataSignature2016', | 20 | LinkedDataSignature2016: 'sec:LinkedDataSignature2016', |
21 | 'CryptographicKey': 'sec:Key', | 21 | CryptographicKey: 'sec:Key', |
22 | 22 | ||
23 | 'authenticationTag': 'sec:authenticationTag', | 23 | authenticationTag: 'sec:authenticationTag', |
24 | 'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm', | 24 | canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm', |
25 | 'cipherAlgorithm': 'sec:cipherAlgorithm', | 25 | cipherAlgorithm: 'sec:cipherAlgorithm', |
26 | 'cipherData': 'sec:cipherData', | 26 | cipherData: 'sec:cipherData', |
27 | 'cipherKey': 'sec:cipherKey', | 27 | cipherKey: 'sec:cipherKey', |
28 | 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, | 28 | created: { '@id': 'dc:created', '@type': 'xsd:dateTime' }, |
29 | 'creator': { '@id': 'dc:creator', '@type': '@id' }, | 29 | creator: { '@id': 'dc:creator', '@type': '@id' }, |
30 | 'digestAlgorithm': 'sec:digestAlgorithm', | 30 | digestAlgorithm: 'sec:digestAlgorithm', |
31 | 'digestValue': 'sec:digestValue', | 31 | digestValue: 'sec:digestValue', |
32 | 'domain': 'sec:domain', | 32 | domain: 'sec:domain', |
33 | 'encryptionKey': 'sec:encryptionKey', | 33 | encryptionKey: 'sec:encryptionKey', |
34 | 'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, | 34 | expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, |
35 | 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, | 35 | expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, |
36 | 'initializationVector': 'sec:initializationVector', | 36 | initializationVector: 'sec:initializationVector', |
37 | 'iterationCount': 'sec:iterationCount', | 37 | iterationCount: 'sec:iterationCount', |
38 | 'nonce': 'sec:nonce', | 38 | nonce: 'sec:nonce', |
39 | 'normalizationAlgorithm': 'sec:normalizationAlgorithm', | 39 | normalizationAlgorithm: 'sec:normalizationAlgorithm', |
40 | 'owner': { '@id': 'sec:owner', '@type': '@id' }, | 40 | owner: { '@id': 'sec:owner', '@type': '@id' }, |
41 | 'password': 'sec:password', | 41 | password: 'sec:password', |
42 | 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, | 42 | privateKey: { '@id': 'sec:privateKey', '@type': '@id' }, |
43 | 'privateKeyPem': 'sec:privateKeyPem', | 43 | privateKeyPem: 'sec:privateKeyPem', |
44 | 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, | 44 | publicKey: { '@id': 'sec:publicKey', '@type': '@id' }, |
45 | 'publicKeyBase58': 'sec:publicKeyBase58', | 45 | publicKeyBase58: 'sec:publicKeyBase58', |
46 | 'publicKeyPem': 'sec:publicKeyPem', | 46 | publicKeyPem: 'sec:publicKeyPem', |
47 | 'publicKeyWif': 'sec:publicKeyWif', | 47 | publicKeyWif: 'sec:publicKeyWif', |
48 | 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, | 48 | publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' }, |
49 | 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, | 49 | revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, |
50 | 'salt': 'sec:salt', | 50 | salt: 'sec:salt', |
51 | 'signature': 'sec:signature', | 51 | signature: 'sec:signature', |
52 | 'signatureAlgorithm': 'sec:signingAlgorithm', | 52 | signatureAlgorithm: 'sec:signingAlgorithm', |
53 | 'signatureValue': 'sec:signatureValue' | 53 | signatureValue: 'sec:signatureValue' |
54 | } | 54 | } |
55 | } | 55 | } |
56 | } | 56 | } |
@@ -60,12 +60,12 @@ const nodeDocumentLoader = jsonld.documentLoaders.node() | |||
60 | const lru = new AsyncLRU({ | 60 | const lru = new AsyncLRU({ |
61 | max: 10, | 61 | max: 10, |
62 | load: (url, cb) => { | 62 | load: (url, cb) => { |
63 | if (CACHE[ url ] !== undefined) { | 63 | if (CACHE[url] !== undefined) { |
64 | logger.debug('Using cache for JSON-LD %s.', url) | 64 | logger.debug('Using cache for JSON-LD %s.', url) |
65 | 65 | ||
66 | return cb(null, { | 66 | return cb(null, { |
67 | contextUrl: null, | 67 | contextUrl: null, |
68 | document: CACHE[ url ], | 68 | document: CACHE[url], |
69 | documentUrl: url | 69 | documentUrl: url |
70 | }) | 70 | }) |
71 | } | 71 | } |
diff --git a/server/helpers/custom-validators/activitypub/actor.ts b/server/helpers/custom-validators/activitypub/actor.ts index fa58e163f..fec67823d 100644 --- a/server/helpers/custom-validators/activitypub/actor.ts +++ b/server/helpers/custom-validators/activitypub/actor.ts | |||
@@ -6,7 +6,7 @@ import { isHostValid } from '../servers' | |||
6 | import { peertubeTruncate } from '@server/helpers/core-utils' | 6 | import { peertubeTruncate } from '@server/helpers/core-utils' |
7 | 7 | ||
8 | function isActorEndpointsObjectValid (endpointObject: any) { | 8 | function isActorEndpointsObjectValid (endpointObject: any) { |
9 | if (endpointObject && endpointObject.sharedInbox) { | 9 | if (endpointObject?.sharedInbox) { |
10 | return isActivityPubUrlValid(endpointObject.sharedInbox) | 10 | return isActivityPubUrlValid(endpointObject.sharedInbox) |
11 | } | 11 | } |
12 | 12 | ||
@@ -101,8 +101,6 @@ function normalizeActor (actor: any) { | |||
101 | actor.summary = null | 101 | actor.summary = null |
102 | } | 102 | } |
103 | } | 103 | } |
104 | |||
105 | return | ||
106 | } | 104 | } |
107 | 105 | ||
108 | function isValidActorHandle (handle: string) { | 106 | function isValidActorHandle (handle: string) { |
diff --git a/server/helpers/custom-validators/activitypub/cache-file.ts b/server/helpers/custom-validators/activitypub/cache-file.ts index 21d5c53ca..c5b3b4d9f 100644 --- a/server/helpers/custom-validators/activitypub/cache-file.ts +++ b/server/helpers/custom-validators/activitypub/cache-file.ts | |||
@@ -6,7 +6,7 @@ import { CacheFileObject } from '../../../../shared/models/activitypub/objects' | |||
6 | function isCacheFileObjectValid (object: CacheFileObject) { | 6 | function isCacheFileObjectValid (object: CacheFileObject) { |
7 | return exists(object) && | 7 | return exists(object) && |
8 | object.type === 'CacheFile' && | 8 | object.type === 'CacheFile' && |
9 | isDateValid(object.expires) && | 9 | (object.expires === null || isDateValid(object.expires)) && |
10 | isActivityPubUrlValid(object.object) && | 10 | isActivityPubUrlValid(object.object) && |
11 | (isRemoteVideoUrlValid(object.url) || isPlaylistRedundancyUrlValid(object.url)) | 11 | (isRemoteVideoUrlValid(object.url) || isPlaylistRedundancyUrlValid(object.url)) |
12 | } | 12 | } |
diff --git a/server/helpers/custom-validators/activitypub/video-comments.ts b/server/helpers/custom-validators/activitypub/video-comments.ts index aa3c246b5..ea852c491 100644 --- a/server/helpers/custom-validators/activitypub/video-comments.ts +++ b/server/helpers/custom-validators/activitypub/video-comments.ts | |||
@@ -48,8 +48,6 @@ function normalizeComment (comment: any) { | |||
48 | if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url | 48 | if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url |
49 | else comment.url = comment.id | 49 | else comment.url = comment.id |
50 | } | 50 | } |
51 | |||
52 | return | ||
53 | } | 51 | } |
54 | 52 | ||
55 | function isCommentTypeValid (comment: any): boolean { | 53 | function isCommentTypeValid (comment: any): boolean { |
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index fe94bd58a..22b5e14a2 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts | |||
@@ -51,11 +51,16 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { | |||
51 | logger.debug('Video has invalid captions', { video }) | 51 | logger.debug('Video has invalid captions', { video }) |
52 | return false | 52 | return false |
53 | } | 53 | } |
54 | if (!setValidRemoteIcon(video)) { | ||
55 | logger.debug('Video has invalid icons', { video }) | ||
56 | return false | ||
57 | } | ||
54 | 58 | ||
55 | // Default attributes | 59 | // Default attributes |
56 | if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED | 60 | if (!isVideoStateValid(video.state)) video.state = VideoState.PUBLISHED |
57 | if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false | 61 | if (!isBooleanValid(video.waitTranscoding)) video.waitTranscoding = false |
58 | if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true | 62 | if (!isBooleanValid(video.downloadEnabled)) video.downloadEnabled = true |
63 | if (!isBooleanValid(video.commentsEnabled)) video.commentsEnabled = false | ||
59 | 64 | ||
60 | return isActivityPubUrlValid(video.id) && | 65 | return isActivityPubUrlValid(video.id) && |
61 | isVideoNameValid(video.name) && | 66 | isVideoNameValid(video.name) && |
@@ -72,7 +77,6 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { | |||
72 | isDateValid(video.updated) && | 77 | isDateValid(video.updated) && |
73 | (!video.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) && | 78 | (!video.originallyPublishedAt || isDateValid(video.originallyPublishedAt)) && |
74 | (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) && | 79 | (!video.content || isRemoteVideoContentValid(video.mediaType, video.content)) && |
75 | isRemoteVideoIconValid(video.icon) && | ||
76 | video.url.length !== 0 && | 80 | video.url.length !== 0 && |
77 | video.attributedTo.length !== 0 | 81 | video.attributedTo.length !== 0 |
78 | } | 82 | } |
@@ -131,6 +135,8 @@ function setValidRemoteCaptions (video: any) { | |||
131 | if (Array.isArray(video.subtitleLanguage) === false) return false | 135 | if (Array.isArray(video.subtitleLanguage) === false) return false |
132 | 136 | ||
133 | video.subtitleLanguage = video.subtitleLanguage.filter(caption => { | 137 | video.subtitleLanguage = video.subtitleLanguage.filter(caption => { |
138 | if (!isActivityPubUrlValid(caption.url)) caption.url = null | ||
139 | |||
134 | return isRemoteStringIdentifierValid(caption) | 140 | return isRemoteStringIdentifierValid(caption) |
135 | }) | 141 | }) |
136 | 142 | ||
@@ -149,12 +155,19 @@ function isRemoteVideoContentValid (mediaType: string, content: string) { | |||
149 | return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content) | 155 | return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content) |
150 | } | 156 | } |
151 | 157 | ||
152 | function isRemoteVideoIconValid (icon: any) { | 158 | function setValidRemoteIcon (video: any) { |
153 | return icon.type === 'Image' && | 159 | if (video.icon && !isArray(video.icon)) video.icon = [ video.icon ] |
154 | isActivityPubUrlValid(icon.url) && | 160 | if (!video.icon) video.icon = [] |
155 | icon.mediaType === 'image/jpeg' && | 161 | |
156 | validator.isInt(icon.width + '', { min: 0 }) && | 162 | video.icon = video.icon.filter(icon => { |
157 | validator.isInt(icon.height + '', { min: 0 }) | 163 | return icon.type === 'Image' && |
164 | isActivityPubUrlValid(icon.url) && | ||
165 | icon.mediaType === 'image/jpeg' && | ||
166 | validator.isInt(icon.width + '', { min: 0 }) && | ||
167 | validator.isInt(icon.height + '', { min: 0 }) | ||
168 | }) | ||
169 | |||
170 | return video.icon.length !== 0 | ||
158 | } | 171 | } |
159 | 172 | ||
160 | function setValidRemoteVideoUrls (video: any) { | 173 | function setValidRemoteVideoUrls (video: any) { |
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 89149b3e0..cf32201c4 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts | |||
@@ -94,13 +94,13 @@ function isFileValid ( | |||
94 | if (isArray(files)) return optional | 94 | if (isArray(files)) return optional |
95 | 95 | ||
96 | // Should have a file | 96 | // Should have a file |
97 | const fileArray = files[ field ] | 97 | const fileArray = files[field] |
98 | if (!fileArray || fileArray.length === 0) { | 98 | if (!fileArray || fileArray.length === 0) { |
99 | return optional | 99 | return optional |
100 | } | 100 | } |
101 | 101 | ||
102 | // The file should exist | 102 | // The file should exist |
103 | const file = fileArray[ 0 ] | 103 | const file = fileArray[0] |
104 | if (!file || !file.originalname) return false | 104 | if (!file || !file.originalname) return false |
105 | 105 | ||
106 | // Check size | 106 | // Check size |
diff --git a/server/helpers/custom-validators/plugins.ts b/server/helpers/custom-validators/plugins.ts index 3af72547b..5a4531f72 100644 --- a/server/helpers/custom-validators/plugins.ts +++ b/server/helpers/custom-validators/plugins.ts | |||
@@ -14,7 +14,7 @@ function isPluginTypeValid (value: any) { | |||
14 | function isPluginNameValid (value: string) { | 14 | function isPluginNameValid (value: string) { |
15 | return exists(value) && | 15 | return exists(value) && |
16 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && | 16 | validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && |
17 | validator.matches(value, /^[a-z\-]+$/) | 17 | validator.matches(value, /^[a-z-]+$/) |
18 | } | 18 | } |
19 | 19 | ||
20 | function isNpmPluginNameValid (value: string) { | 20 | function isNpmPluginNameValid (value: string) { |
@@ -146,8 +146,8 @@ function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginT | |||
146 | } | 146 | } |
147 | 147 | ||
148 | function isLibraryCodeValid (library: any) { | 148 | function isLibraryCodeValid (library: any) { |
149 | return typeof library.register === 'function' | 149 | return typeof library.register === 'function' && |
150 | && typeof library.unregister === 'function' | 150 | typeof library.unregister === 'function' |
151 | } | 151 | } |
152 | 152 | ||
153 | export { | 153 | export { |
diff --git a/server/helpers/custom-validators/user-notifications.ts b/server/helpers/custom-validators/user-notifications.ts index 5a4d10504..8a33b895b 100644 --- a/server/helpers/custom-validators/user-notifications.ts +++ b/server/helpers/custom-validators/user-notifications.ts | |||
@@ -9,7 +9,8 @@ function isUserNotificationTypeValid (value: any) { | |||
9 | 9 | ||
10 | function isUserNotificationSettingValid (value: any) { | 10 | function isUserNotificationSettingValid (value: any) { |
11 | return exists(value) && | 11 | return exists(value) && |
12 | validator.isInt('' + value) && ( | 12 | validator.isInt('' + value) && |
13 | ( | ||
13 | value === UserNotificationSettingValue.NONE || | 14 | value === UserNotificationSettingValue.NONE || |
14 | value === UserNotificationSettingValue.WEB || | 15 | value === UserNotificationSettingValue.WEB || |
15 | value === UserNotificationSettingValue.EMAIL || | 16 | value === UserNotificationSettingValue.EMAIL || |
diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index b4d5751e7..1ddbe0815 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts | |||
@@ -3,6 +3,7 @@ import { UserRole } from '../../../shared' | |||
3 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers/constants' | 3 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers/constants' |
4 | import { exists, isArray, isBooleanValid, isFileValid } from './misc' | 4 | import { exists, isArray, isBooleanValid, isFileValid } from './misc' |
5 | import { values } from 'lodash' | 5 | import { values } from 'lodash' |
6 | import { isEmailEnabled } from '../../initializers/config' | ||
6 | 7 | ||
7 | const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS | 8 | const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS |
8 | 9 | ||
@@ -10,6 +11,13 @@ function isUserPasswordValid (value: string) { | |||
10 | return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD) | 11 | return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD) |
11 | } | 12 | } |
12 | 13 | ||
14 | function isUserPasswordValidOrEmpty (value: string) { | ||
15 | // Empty password is only possible if emailing is enabled. | ||
16 | if (value === '') return isEmailEnabled() | ||
17 | |||
18 | return isUserPasswordValid(value) | ||
19 | } | ||
20 | |||
13 | function isUserVideoQuotaValid (value: string) { | 21 | function isUserVideoQuotaValid (value: string) { |
14 | return exists(value) && validator.isInt(value + '', USERS_CONSTRAINTS_FIELDS.VIDEO_QUOTA) | 22 | return exists(value) && validator.isInt(value + '', USERS_CONSTRAINTS_FIELDS.VIDEO_QUOTA) |
15 | } | 23 | } |
@@ -103,6 +111,7 @@ export { | |||
103 | isUserVideosHistoryEnabledValid, | 111 | isUserVideosHistoryEnabledValid, |
104 | isUserBlockedValid, | 112 | isUserBlockedValid, |
105 | isUserPasswordValid, | 113 | isUserPasswordValid, |
114 | isUserPasswordValidOrEmpty, | ||
106 | isUserVideoLanguages, | 115 | isUserVideoLanguages, |
107 | isUserBlockedReasonValid, | 116 | isUserBlockedReasonValid, |
108 | isUserRoleValid, | 117 | isUserRoleValid, |
diff --git a/server/helpers/custom-validators/video-abuses.ts b/server/helpers/custom-validators/video-abuses.ts index a9478c76a..5c7bc6fd9 100644 --- a/server/helpers/custom-validators/video-abuses.ts +++ b/server/helpers/custom-validators/video-abuses.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import { Response } from 'express' | ||
2 | import validator from 'validator' | 1 | import validator from 'validator' |
3 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 2 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
4 | import { exists } from './misc' | 3 | import { exists } from './misc' |
5 | import { VideoAbuseModel } from '../../models/video/video-abuse' | ||
6 | 4 | ||
7 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES | 5 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES |
8 | 6 | ||
@@ -15,7 +13,7 @@ function isVideoAbuseModerationCommentValid (value: string) { | |||
15 | } | 13 | } |
16 | 14 | ||
17 | function isVideoAbuseStateValid (value: string) { | 15 | function isVideoAbuseStateValid (value: string) { |
18 | return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined | 16 | return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined |
19 | } | 17 | } |
20 | 18 | ||
21 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/video-captions.ts b/server/helpers/custom-validators/video-captions.ts index d06eb3695..9abbce04a 100644 --- a/server/helpers/custom-validators/video-captions.ts +++ b/server/helpers/custom-validators/video-captions.ts | |||
@@ -2,7 +2,7 @@ import { CONSTRAINTS_FIELDS, MIMETYPES, VIDEO_LANGUAGES } from '../../initialize | |||
2 | import { exists, isFileValid } from './misc' | 2 | import { exists, isFileValid } from './misc' |
3 | 3 | ||
4 | function isVideoCaptionLanguageValid (value: any) { | 4 | function isVideoCaptionLanguageValid (value: any) { |
5 | return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined | 5 | return exists(value) && VIDEO_LANGUAGES[value] !== undefined |
6 | } | 6 | } |
7 | 7 | ||
8 | const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT) | 8 | const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT) |
diff --git a/server/helpers/custom-validators/video-imports.ts b/server/helpers/custom-validators/video-imports.ts index ffad482b4..c571f5ddd 100644 --- a/server/helpers/custom-validators/video-imports.ts +++ b/server/helpers/custom-validators/video-imports.ts | |||
@@ -20,7 +20,7 @@ function isVideoImportTargetUrlValid (url: string) { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | function isVideoImportStateValid (value: any) { | 22 | function isVideoImportStateValid (value: any) { |
23 | return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined | 23 | return exists(value) && VIDEO_IMPORT_STATES[value] !== undefined |
24 | } | 24 | } |
25 | 25 | ||
26 | const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`) | 26 | const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`) |
diff --git a/server/helpers/custom-validators/video-playlists.ts b/server/helpers/custom-validators/video-playlists.ts index 4bb8384ab..180018fc5 100644 --- a/server/helpers/custom-validators/video-playlists.ts +++ b/server/helpers/custom-validators/video-playlists.ts | |||
@@ -1,8 +1,6 @@ | |||
1 | import { exists } from './misc' | 1 | import { exists } from './misc' |
2 | import validator from 'validator' | 2 | import validator from 'validator' |
3 | import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' | 3 | import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' |
4 | import * as express from 'express' | ||
5 | import { VideoPlaylistModel } from '../../models/video/video-playlist' | ||
6 | 4 | ||
7 | const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS | 5 | const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS |
8 | 6 | ||
@@ -15,7 +13,7 @@ function isVideoPlaylistDescriptionValid (value: any) { | |||
15 | } | 13 | } |
16 | 14 | ||
17 | function isVideoPlaylistPrivacyValid (value: number) { | 15 | function isVideoPlaylistPrivacyValid (value: number) { |
18 | return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[ value ] !== undefined | 16 | return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[value] !== undefined |
19 | } | 17 | } |
20 | 18 | ||
21 | function isVideoPlaylistTimestampValid (value: any) { | 19 | function isVideoPlaylistTimestampValid (value: any) { |
@@ -23,7 +21,7 @@ function isVideoPlaylistTimestampValid (value: any) { | |||
23 | } | 21 | } |
24 | 22 | ||
25 | function isVideoPlaylistTypeValid (value: any) { | 23 | function isVideoPlaylistTypeValid (value: any) { |
26 | return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined | 24 | return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined |
27 | } | 25 | } |
28 | 26 | ||
29 | // --------------------------------------------------------------------------- | 27 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/video-redundancies.ts b/server/helpers/custom-validators/video-redundancies.ts new file mode 100644 index 000000000..50a559c4f --- /dev/null +++ b/server/helpers/custom-validators/video-redundancies.ts | |||
@@ -0,0 +1,12 @@ | |||
1 | import { exists } from './misc' | ||
2 | |||
3 | function isVideoRedundancyTarget (value: any) { | ||
4 | return exists(value) && | ||
5 | (value === 'my-videos' || value === 'remote-videos') | ||
6 | } | ||
7 | |||
8 | // --------------------------------------------------------------------------- | ||
9 | |||
10 | export { | ||
11 | isVideoRedundancyTarget | ||
12 | } | ||
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index a9e859e54..cfb430c63 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -20,15 +20,15 @@ function isVideoFilterValid (filter: VideoFilter) { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | function isVideoCategoryValid (value: any) { | 22 | function isVideoCategoryValid (value: any) { |
23 | return value === null || VIDEO_CATEGORIES[ value ] !== undefined | 23 | return value === null || VIDEO_CATEGORIES[value] !== undefined |
24 | } | 24 | } |
25 | 25 | ||
26 | function isVideoStateValid (value: any) { | 26 | function isVideoStateValid (value: any) { |
27 | return exists(value) && VIDEO_STATES[ value ] !== undefined | 27 | return exists(value) && VIDEO_STATES[value] !== undefined |
28 | } | 28 | } |
29 | 29 | ||
30 | function isVideoLicenceValid (value: any) { | 30 | function isVideoLicenceValid (value: any) { |
31 | return value === null || VIDEO_LICENCES[ value ] !== undefined | 31 | return value === null || VIDEO_LICENCES[value] !== undefined |
32 | } | 32 | } |
33 | 33 | ||
34 | function isVideoLanguageValid (value: any) { | 34 | function isVideoLanguageValid (value: any) { |
@@ -98,7 +98,7 @@ function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | | |||
98 | } | 98 | } |
99 | 99 | ||
100 | function isVideoPrivacyValid (value: number) { | 100 | function isVideoPrivacyValid (value: number) { |
101 | return VIDEO_PRIVACIES[ value ] !== undefined | 101 | return VIDEO_PRIVACIES[value] !== undefined |
102 | } | 102 | } |
103 | 103 | ||
104 | function isScheduleVideoUpdatePrivacyValid (value: number) { | 104 | function isScheduleVideoUpdatePrivacyValid (value: number) { |
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 9bf6d85a8..f46812977 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -12,7 +12,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { | |||
12 | if (paramNSFW === 'false') return false | 12 | if (paramNSFW === 'false') return false |
13 | if (paramNSFW === 'both') return undefined | 13 | if (paramNSFW === 'both') return undefined |
14 | 14 | ||
15 | if (res && res.locals.oauth) { | 15 | if (res?.locals.oauth) { |
16 | const user = res.locals.oauth.token.User | 16 | const user = res.locals.oauth.token.User |
17 | 17 | ||
18 | // User does not want NSFW videos | 18 | // User does not want NSFW videos |
@@ -28,7 +28,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) { | |||
28 | return null | 28 | return null |
29 | } | 29 | } |
30 | 30 | ||
31 | function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) { | 31 | function cleanUpReqFiles (req: { files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] }) { |
32 | const files = req.files | 32 | const files = req.files |
33 | 33 | ||
34 | if (!files) return | 34 | if (!files) return |
@@ -39,7 +39,7 @@ function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer. | |||
39 | } | 39 | } |
40 | 40 | ||
41 | for (const key of Object.keys(files)) { | 41 | for (const key of Object.keys(files)) { |
42 | const file = files[ key ] | 42 | const file = files[key] |
43 | 43 | ||
44 | if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) | 44 | if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) |
45 | else deleteFileAsync(file.path) | 45 | else deleteFileAsync(file.path) |
@@ -65,18 +65,18 @@ function badRequest (req: express.Request, res: express.Response) { | |||
65 | 65 | ||
66 | function createReqFiles ( | 66 | function createReqFiles ( |
67 | fieldNames: string[], | 67 | fieldNames: string[], |
68 | mimeTypes: { [ id: string ]: string }, | 68 | mimeTypes: { [id: string]: string }, |
69 | destinations: { [ fieldName: string ]: string } | 69 | destinations: { [fieldName: string]: string } |
70 | ) { | 70 | ) { |
71 | const storage = multer.diskStorage({ | 71 | const storage = multer.diskStorage({ |
72 | destination: (req, file, cb) => { | 72 | destination: (req, file, cb) => { |
73 | cb(null, destinations[ file.fieldname ]) | 73 | cb(null, destinations[file.fieldname]) |
74 | }, | 74 | }, |
75 | 75 | ||
76 | filename: async (req, file, cb) => { | 76 | filename: async (req, file, cb) => { |
77 | let extension: string | 77 | let extension: string |
78 | const fileExtension = extname(file.originalname) | 78 | const fileExtension = extname(file.originalname) |
79 | const extensionFromMimetype = mimeTypes[ file.mimetype ] | 79 | const extensionFromMimetype = mimeTypes[file.mimetype] |
80 | 80 | ||
81 | // Take the file extension if we don't understand the mime type | 81 | // Take the file extension if we don't understand the mime type |
82 | // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file | 82 | // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file |
@@ -99,7 +99,7 @@ function createReqFiles ( | |||
99 | } | 99 | } |
100 | }) | 100 | }) |
101 | 101 | ||
102 | let fields: { name: string, maxCount: number }[] = [] | 102 | const fields: { name: string, maxCount: number }[] = [] |
103 | for (const fieldName of fieldNames) { | 103 | for (const fieldName of fieldNames) { |
104 | fields.push({ | 104 | fields.push({ |
105 | name: fieldName, | 105 | name: fieldName, |
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 00c32e99a..084516e55 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as ffmpeg from 'fluent-ffmpeg' | 1 | import * as ffmpeg from 'fluent-ffmpeg' |
2 | import { dirname, join } from 'path' | 2 | import { dirname, join } from 'path' |
3 | import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos' | 3 | import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos' |
4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' | 4 | import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants' |
5 | import { processImage } from './image-utils' | 5 | import { processImage } from './image-utils' |
6 | import { logger } from './logger' | 6 | import { logger } from './logger' |
@@ -8,6 +8,71 @@ import { checkFFmpegEncoders } from '../initializers/checker-before-init' | |||
8 | import { readFile, remove, writeFile } from 'fs-extra' | 8 | import { readFile, remove, writeFile } from 'fs-extra' |
9 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
10 | 10 | ||
11 | /** | ||
12 | * A toolbox to play with audio | ||
13 | */ | ||
14 | namespace audio { | ||
15 | export const get = (videoPath: string) => { | ||
16 | // without position, ffprobe considers the last input only | ||
17 | // we make it consider the first input only | ||
18 | // if you pass a file path to pos, then ffprobe acts on that file directly | ||
19 | return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => { | ||
20 | |||
21 | function parseFfprobe (err: any, data: ffmpeg.FfprobeData) { | ||
22 | if (err) return rej(err) | ||
23 | |||
24 | if ('streams' in data) { | ||
25 | const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio') | ||
26 | if (audioStream) { | ||
27 | return res({ | ||
28 | absolutePath: data.format.filename, | ||
29 | audioStream | ||
30 | }) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | return res({ absolutePath: data.format.filename }) | ||
35 | } | ||
36 | |||
37 | return ffmpeg.ffprobe(videoPath, parseFfprobe) | ||
38 | }) | ||
39 | } | ||
40 | |||
41 | export namespace bitrate { | ||
42 | const baseKbitrate = 384 | ||
43 | |||
44 | const toBits = (kbits: number) => kbits * 8000 | ||
45 | |||
46 | export const aac = (bitrate: number): number => { | ||
47 | switch (true) { | ||
48 | case bitrate > toBits(baseKbitrate): | ||
49 | return baseKbitrate | ||
50 | |||
51 | default: | ||
52 | return -1 // we interpret it as a signal to copy the audio stream as is | ||
53 | } | ||
54 | } | ||
55 | |||
56 | export const mp3 = (bitrate: number): number => { | ||
57 | /* | ||
58 | a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac. | ||
59 | That's why, when using aac, we can go to lower kbit/sec. The equivalences | ||
60 | made here are not made to be accurate, especially with good mp3 encoders. | ||
61 | */ | ||
62 | switch (true) { | ||
63 | case bitrate <= toBits(192): | ||
64 | return 128 | ||
65 | |||
66 | case bitrate <= toBits(384): | ||
67 | return 256 | ||
68 | |||
69 | default: | ||
70 | return baseKbitrate | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
11 | function computeResolutionsToTranscode (videoFileHeight: number) { | 76 | function computeResolutionsToTranscode (videoFileHeight: number) { |
12 | const resolutionsEnabled: number[] = [] | 77 | const resolutionsEnabled: number[] = [] |
13 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS | 78 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS |
@@ -24,7 +89,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) { | |||
24 | ] | 89 | ] |
25 | 90 | ||
26 | for (const resolution of resolutions) { | 91 | for (const resolution of resolutions) { |
27 | if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { | 92 | if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) { |
28 | resolutionsEnabled.push(resolution) | 93 | resolutionsEnabled.push(resolution) |
29 | } | 94 | } |
30 | } | 95 | } |
@@ -48,9 +113,9 @@ async function getVideoStreamCodec (path: string) { | |||
48 | const videoCodec = videoStream.codec_tag_string | 113 | const videoCodec = videoStream.codec_tag_string |
49 | 114 | ||
50 | const baseProfileMatrix = { | 115 | const baseProfileMatrix = { |
51 | 'High': '6400', | 116 | High: '6400', |
52 | 'Main': '4D40', | 117 | Main: '4D40', |
53 | 'Baseline': '42E0' | 118 | Baseline: '42E0' |
54 | } | 119 | } |
55 | 120 | ||
56 | let baseProfile = baseProfileMatrix[videoStream.profile] | 121 | let baseProfile = baseProfileMatrix[videoStream.profile] |
@@ -91,7 +156,7 @@ async function getVideoFileFPS (path: string) { | |||
91 | if (videoStream === null) return 0 | 156 | if (videoStream === null) return 0 |
92 | 157 | ||
93 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { | 158 | for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { |
94 | const valuesText: string = videoStream[ key ] | 159 | const valuesText: string = videoStream[key] |
95 | if (!valuesText) continue | 160 | if (!valuesText) continue |
96 | 161 | ||
97 | const [ frames, seconds ] = valuesText.split('/') | 162 | const [ frames, seconds ] = valuesText.split('/') |
@@ -191,7 +256,8 @@ interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions { | |||
191 | type: 'only-audio' | 256 | type: 'only-audio' |
192 | } | 257 | } |
193 | 258 | ||
194 | type TranscodeOptions = HLSTranscodeOptions | 259 | type TranscodeOptions = |
260 | HLSTranscodeOptions | ||
195 | | VideoTranscodeOptions | 261 | | VideoTranscodeOptions |
196 | | MergeAudioTranscodeOptions | 262 | | MergeAudioTranscodeOptions |
197 | | OnlyAudioTranscodeOptions | 263 | | OnlyAudioTranscodeOptions |
@@ -204,13 +270,13 @@ function transcode (options: TranscodeOptions) { | |||
204 | .output(options.outputPath) | 270 | .output(options.outputPath) |
205 | 271 | ||
206 | if (options.type === 'quick-transcode') { | 272 | if (options.type === 'quick-transcode') { |
207 | command = await buildQuickTranscodeCommand(command) | 273 | command = buildQuickTranscodeCommand(command) |
208 | } else if (options.type === 'hls') { | 274 | } else if (options.type === 'hls') { |
209 | command = await buildHLSCommand(command, options) | 275 | command = await buildHLSCommand(command, options) |
210 | } else if (options.type === 'merge-audio') { | 276 | } else if (options.type === 'merge-audio') { |
211 | command = await buildAudioMergeCommand(command, options) | 277 | command = await buildAudioMergeCommand(command, options) |
212 | } else if (options.type === 'only-audio') { | 278 | } else if (options.type === 'only-audio') { |
213 | command = await buildOnlyAudioCommand(command, options) | 279 | command = buildOnlyAudioCommand(command, options) |
214 | } else { | 280 | } else { |
215 | command = await buildx264Command(command, options) | 281 | command = await buildx264Command(command, options) |
216 | } | 282 | } |
@@ -247,22 +313,27 @@ async function canDoQuickTranscode (path: string): Promise<boolean> { | |||
247 | 313 | ||
248 | // check video params | 314 | // check video params |
249 | if (videoStream == null) return false | 315 | if (videoStream == null) return false |
250 | if (videoStream[ 'codec_name' ] !== 'h264') return false | 316 | if (videoStream['codec_name'] !== 'h264') return false |
251 | if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false | 317 | if (videoStream['pix_fmt'] !== 'yuv420p') return false |
252 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false | 318 | if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false |
253 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false | 319 | if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false |
254 | 320 | ||
255 | // check audio params (if audio stream exists) | 321 | // check audio params (if audio stream exists) |
256 | if (parsedAudio.audioStream) { | 322 | if (parsedAudio.audioStream) { |
257 | if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false | 323 | if (parsedAudio.audioStream['codec_name'] !== 'aac') return false |
258 | 324 | ||
259 | const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ]) | 325 | const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate']) |
260 | if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false | 326 | if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false |
261 | } | 327 | } |
262 | 328 | ||
263 | return true | 329 | return true |
264 | } | 330 | } |
265 | 331 | ||
332 | function getClosestFramerateStandard (fps: number, type: 'HD_STANDARD' | 'STANDARD'): number { | ||
333 | return VIDEO_TRANSCODING_FPS[type].slice(0) | ||
334 | .sort((a, b) => fps % a - fps % b)[0] | ||
335 | } | ||
336 | |||
266 | // --------------------------------------------------------------------------- | 337 | // --------------------------------------------------------------------------- |
267 | 338 | ||
268 | export { | 339 | export { |
@@ -286,13 +357,14 @@ export { | |||
286 | 357 | ||
287 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { | 358 | async function buildx264Command (command: ffmpeg.FfmpegCommand, options: TranscodeOptions) { |
288 | let fps = await getVideoFileFPS(options.inputPath) | 359 | let fps = await getVideoFileFPS(options.inputPath) |
289 | // On small/medium resolutions, limit FPS | ||
290 | if ( | 360 | if ( |
361 | // On small/medium resolutions, limit FPS | ||
291 | options.resolution !== undefined && | 362 | options.resolution !== undefined && |
292 | options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && | 363 | options.resolution < VIDEO_TRANSCODING_FPS.KEEP_ORIGIN_FPS_RESOLUTION_MIN && |
293 | fps > VIDEO_TRANSCODING_FPS.AVERAGE | 364 | fps > VIDEO_TRANSCODING_FPS.AVERAGE |
294 | ) { | 365 | ) { |
295 | fps = VIDEO_TRANSCODING_FPS.AVERAGE | 366 | // Get closest standard framerate by modulo: downsampling has to be done to a divisor of the nominal fps value |
367 | fps = getClosestFramerateStandard(fps, 'STANDARD') | ||
296 | } | 368 | } |
297 | 369 | ||
298 | command = await presetH264(command, options.inputPath, options.resolution, fps) | 370 | command = await presetH264(command, options.inputPath, options.resolution, fps) |
@@ -305,7 +377,7 @@ async function buildx264Command (command: ffmpeg.FfmpegCommand, options: Transco | |||
305 | 377 | ||
306 | if (fps) { | 378 | if (fps) { |
307 | // Hard FPS limits | 379 | // Hard FPS limits |
308 | if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = VIDEO_TRANSCODING_FPS.MAX | 380 | if (fps > VIDEO_TRANSCODING_FPS.MAX) fps = getClosestFramerateStandard(fps, 'HD_STANDARD') |
309 | else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN | 381 | else if (fps < VIDEO_TRANSCODING_FPS.MIN) fps = VIDEO_TRANSCODING_FPS.MIN |
310 | 382 | ||
311 | command = command.withFPS(fps) | 383 | command = command.withFPS(fps) |
@@ -327,14 +399,14 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M | |||
327 | return command | 399 | return command |
328 | } | 400 | } |
329 | 401 | ||
330 | async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { | 402 | function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { |
331 | command = await presetOnlyAudio(command) | 403 | command = presetOnlyAudio(command) |
332 | 404 | ||
333 | return command | 405 | return command |
334 | } | 406 | } |
335 | 407 | ||
336 | async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { | 408 | function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { |
337 | command = await presetCopy(command) | 409 | command = presetCopy(command) |
338 | 410 | ||
339 | command = command.outputOption('-map_metadata -1') // strip all metadata | 411 | command = command.outputOption('-map_metadata -1') // strip all metadata |
340 | .outputOption('-movflags faststart') | 412 | .outputOption('-movflags faststart') |
@@ -345,7 +417,7 @@ async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { | |||
345 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { | 417 | async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { |
346 | const videoPath = getHLSVideoPath(options) | 418 | const videoPath = getHLSVideoPath(options) |
347 | 419 | ||
348 | if (options.copyCodecs) command = await presetCopy(command) | 420 | if (options.copyCodecs) command = presetCopy(command) |
349 | else command = await buildx264Command(command, options) | 421 | else command = await buildx264Command(command, options) |
350 | 422 | ||
351 | command = command.outputOption('-hls_time 4') | 423 | command = command.outputOption('-hls_time 4') |
@@ -413,71 +485,6 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string, | |||
413 | } | 485 | } |
414 | 486 | ||
415 | /** | 487 | /** |
416 | * A toolbox to play with audio | ||
417 | */ | ||
418 | namespace audio { | ||
419 | export const get = (videoPath: string) => { | ||
420 | // without position, ffprobe considers the last input only | ||
421 | // we make it consider the first input only | ||
422 | // if you pass a file path to pos, then ffprobe acts on that file directly | ||
423 | return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => { | ||
424 | |||
425 | function parseFfprobe (err: any, data: ffmpeg.FfprobeData) { | ||
426 | if (err) return rej(err) | ||
427 | |||
428 | if ('streams' in data) { | ||
429 | const audioStream = data.streams.find(stream => stream[ 'codec_type' ] === 'audio') | ||
430 | if (audioStream) { | ||
431 | return res({ | ||
432 | absolutePath: data.format.filename, | ||
433 | audioStream | ||
434 | }) | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return res({ absolutePath: data.format.filename }) | ||
439 | } | ||
440 | |||
441 | return ffmpeg.ffprobe(videoPath, parseFfprobe) | ||
442 | }) | ||
443 | } | ||
444 | |||
445 | export namespace bitrate { | ||
446 | const baseKbitrate = 384 | ||
447 | |||
448 | const toBits = (kbits: number) => kbits * 8000 | ||
449 | |||
450 | export const aac = (bitrate: number): number => { | ||
451 | switch (true) { | ||
452 | case bitrate > toBits(baseKbitrate): | ||
453 | return baseKbitrate | ||
454 | |||
455 | default: | ||
456 | return -1 // we interpret it as a signal to copy the audio stream as is | ||
457 | } | ||
458 | } | ||
459 | |||
460 | export const mp3 = (bitrate: number): number => { | ||
461 | /* | ||
462 | a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac. | ||
463 | That's why, when using aac, we can go to lower kbit/sec. The equivalences | ||
464 | made here are not made to be accurate, especially with good mp3 encoders. | ||
465 | */ | ||
466 | switch (true) { | ||
467 | case bitrate <= toBits(192): | ||
468 | return 128 | ||
469 | |||
470 | case bitrate <= toBits(384): | ||
471 | return 256 | ||
472 | |||
473 | default: | ||
474 | return baseKbitrate | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * Standard profile, with variable bitrate audio and faststart. | 488 | * Standard profile, with variable bitrate audio and faststart. |
482 | * | 489 | * |
483 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel | 490 | * As for the audio, quality '5' is the highest and ensures 96-112kbps/channel |
@@ -507,10 +514,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut | |||
507 | // of course this is far from perfect, but it might save some space in the end | 514 | // of course this is far from perfect, but it might save some space in the end |
508 | localCommand = localCommand.audioCodec('aac') | 515 | localCommand = localCommand.audioCodec('aac') |
509 | 516 | ||
510 | const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] | 517 | const audioCodecName = parsedAudio.audioStream['codec_name'] |
511 | 518 | ||
512 | if (audio.bitrate[ audioCodecName ]) { | 519 | if (audio.bitrate[audioCodecName]) { |
513 | const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) | 520 | const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate']) |
514 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) | 521 | if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) |
515 | } | 522 | } |
516 | } | 523 | } |
@@ -531,14 +538,14 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut | |||
531 | return localCommand | 538 | return localCommand |
532 | } | 539 | } |
533 | 540 | ||
534 | async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | 541 | function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand { |
535 | return command | 542 | return command |
536 | .format('mp4') | 543 | .format('mp4') |
537 | .videoCodec('copy') | 544 | .videoCodec('copy') |
538 | .audioCodec('copy') | 545 | .audioCodec('copy') |
539 | } | 546 | } |
540 | 547 | ||
541 | async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { | 548 | function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand { |
542 | return command | 549 | return command |
543 | .format('mp4') | 550 | .format('mp4') |
544 | .audioCodec('copy') | 551 | .audioCodec('copy') |
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts index 395417612..b8ae28b3f 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts | |||
@@ -5,7 +5,7 @@ import * as winston from 'winston' | |||
5 | import { FileTransportOptions } from 'winston/lib/winston/transports' | 5 | import { FileTransportOptions } from 'winston/lib/winston/transports' |
6 | import { CONFIG } from '../initializers/config' | 6 | import { CONFIG } from '../initializers/config' |
7 | import { omit } from 'lodash' | 7 | import { omit } from 'lodash' |
8 | import { LOG_FILENAME } from '@server/initializers/constants' | 8 | import { LOG_FILENAME } from '../initializers/constants' |
9 | 9 | ||
10 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT | 10 | const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT |
11 | 11 | ||
@@ -27,7 +27,7 @@ function getLoggerReplacer () { | |||
27 | if (value instanceof Error) { | 27 | if (value instanceof Error) { |
28 | const error = {} | 28 | const error = {} |
29 | 29 | ||
30 | Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ]) | 30 | Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] }) |
31 | 31 | ||
32 | return error | 32 | return error |
33 | } | 33 | } |
@@ -98,19 +98,20 @@ function bunyanLogFactory (level: string) { | |||
98 | let args: any[] = [] | 98 | let args: any[] = [] |
99 | args.concat(arguments) | 99 | args.concat(arguments) |
100 | 100 | ||
101 | if (arguments[ 0 ] instanceof Error) { | 101 | if (arguments[0] instanceof Error) { |
102 | meta = arguments[ 0 ].toString() | 102 | meta = arguments[0].toString() |
103 | args = Array.prototype.slice.call(arguments, 1) | 103 | args = Array.prototype.slice.call(arguments, 1) |
104 | args.push(meta) | 104 | args.push(meta) |
105 | } else if (typeof (args[ 0 ]) !== 'string') { | 105 | } else if (typeof (args[0]) !== 'string') { |
106 | meta = arguments[ 0 ] | 106 | meta = arguments[0] |
107 | args = Array.prototype.slice.call(arguments, 1) | 107 | args = Array.prototype.slice.call(arguments, 1) |
108 | args.push(meta) | 108 | args.push(meta) |
109 | } | 109 | } |
110 | 110 | ||
111 | logger[ level ].apply(logger, args) | 111 | logger[level].apply(logger, args) |
112 | } | 112 | } |
113 | } | 113 | } |
114 | |||
114 | const bunyanLogger = { | 115 | const bunyanLogger = { |
115 | trace: bunyanLogFactory('debug'), | 116 | trace: bunyanLogFactory('debug'), |
116 | debug: bunyanLogFactory('debug'), | 117 | debug: bunyanLogFactory('debug'), |
diff --git a/server/helpers/middlewares/videos.ts b/server/helpers/middlewares/videos.ts index 74f529804..409f78650 100644 --- a/server/helpers/middlewares/videos.ts +++ b/server/helpers/middlewares/videos.ts | |||
@@ -2,7 +2,16 @@ import { Response } from 'express' | |||
2 | import { fetchVideo, VideoFetchType } from '../video' | 2 | import { fetchVideo, VideoFetchType } from '../video' |
3 | import { UserRight } from '../../../shared/models/users' | 3 | import { UserRight } from '../../../shared/models/users' |
4 | import { VideoChannelModel } from '../../models/video/video-channel' | 4 | import { VideoChannelModel } from '../../models/video/video-channel' |
5 | import { MUser, MUserAccountId, MVideoAccountLight, MVideoFullLight, MVideoThumbnail, MVideoWithRights } from '@server/typings/models' | 5 | import { |
6 | MUser, | ||
7 | MUserAccountId, | ||
8 | MVideoAccountLight, | ||
9 | MVideoFullLight, | ||
10 | MVideoIdThumbnail, | ||
11 | MVideoImmutable, | ||
12 | MVideoThumbnail, | ||
13 | MVideoWithRights | ||
14 | } from '@server/typings/models' | ||
6 | 15 | ||
7 | async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { | 16 | async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { |
8 | const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined | 17 | const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined |
@@ -22,8 +31,12 @@ async function doesVideoExist (id: number | string, res: Response, fetchType: Vi | |||
22 | res.locals.videoAll = video as MVideoFullLight | 31 | res.locals.videoAll = video as MVideoFullLight |
23 | break | 32 | break |
24 | 33 | ||
34 | case 'only-immutable-attributes': | ||
35 | res.locals.onlyImmutableVideo = video as MVideoImmutable | ||
36 | break | ||
37 | |||
25 | case 'id': | 38 | case 'id': |
26 | res.locals.videoId = video | 39 | res.locals.videoId = video as MVideoIdThumbnail |
27 | break | 40 | break |
28 | 41 | ||
29 | case 'only-video': | 42 | case 'only-video': |
diff --git a/server/helpers/regexp.ts b/server/helpers/regexp.ts index 2336654b0..cfc2be488 100644 --- a/server/helpers/regexp.ts +++ b/server/helpers/regexp.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | // Thanks to https://regex101.com | 1 | // Thanks to https://regex101.com |
2 | function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { | 2 | function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { |
3 | const result: RegExpExecArray[] = [] | ||
3 | let m: RegExpExecArray | 4 | let m: RegExpExecArray |
4 | let i = 0 | 5 | let i = 0 |
5 | let result: RegExpExecArray[] = [] | ||
6 | 6 | ||
7 | // tslint:disable:no-conditional-assignment | 7 | // tslint:disable:no-conditional-assignment |
8 | while ((m = regex.exec(str)) !== null && i < maxIterations) { | 8 | while ((m = regex.exec(str)) !== null && i < maxIterations) { |
diff --git a/server/helpers/register-ts-paths.ts b/server/helpers/register-ts-paths.ts index e8db369e3..eec7fed3e 100644 --- a/server/helpers/register-ts-paths.ts +++ b/server/helpers/register-ts-paths.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { resolve } from 'path' | 1 | import { resolve } from 'path' |
2 | const tsConfigPaths = require('tsconfig-paths') | 2 | import tsConfigPaths = require('tsconfig-paths') |
3 | 3 | ||
4 | const tsConfig = require('../../tsconfig.json') | 4 | const tsConfig = require('../../tsconfig.json') |
5 | 5 | ||
diff --git a/server/helpers/signup.ts b/server/helpers/signup.ts index 7c73f7c5c..d34ff2db5 100644 --- a/server/helpers/signup.ts +++ b/server/helpers/signup.ts | |||
@@ -21,7 +21,7 @@ async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: st | |||
21 | 21 | ||
22 | function isSignupAllowedForCurrentIP (ip: string) { | 22 | function isSignupAllowedForCurrentIP (ip: string) { |
23 | const addr = ipaddr.parse(ip) | 23 | const addr = ipaddr.parse(ip) |
24 | let excludeList = [ 'blacklist' ] | 24 | const excludeList = [ 'blacklist' ] |
25 | let matched = '' | 25 | let matched = '' |
26 | 26 | ||
27 | // if there is a valid, non-empty whitelist, we exclude all unknown adresses too | 27 | // if there is a valid, non-empty whitelist, we exclude all unknown adresses too |
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index 4c6f200f8..7a4c781cc 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { ResultList } from '../../shared' | 1 | import { ResultList } from '../../shared' |
2 | import { ApplicationModel } from '../models/application/application' | 2 | import { ApplicationModel } from '../models/application/application' |
3 | import { execPromise, execPromise2, pseudoRandomBytesPromise, sha256 } from './core-utils' | 3 | import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils' |
4 | import { logger } from './logger' | 4 | import { logger } from './logger' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { Instance as ParseTorrent } from 'parse-torrent' | 6 | import { Instance as ParseTorrent } from 'parse-torrent' |
@@ -14,7 +14,7 @@ function deleteFileAsync (path: string) { | |||
14 | } | 14 | } |
15 | 15 | ||
16 | async function generateRandomString (size: number) { | 16 | async function generateRandomString (size: number) { |
17 | const raw = await pseudoRandomBytesPromise(size) | 17 | const raw = await randomBytesPromise(size) |
18 | 18 | ||
19 | return raw.toString('hex') | 19 | return raw.toString('hex') |
20 | } | 20 | } |
diff --git a/server/helpers/video.ts b/server/helpers/video.ts index 5b9c026b1..4fe2a60f0 100644 --- a/server/helpers/video.ts +++ b/server/helpers/video.ts | |||
@@ -5,13 +5,15 @@ import { | |||
5 | MVideoFullLight, | 5 | MVideoFullLight, |
6 | MVideoIdThumbnail, | 6 | MVideoIdThumbnail, |
7 | MVideoThumbnail, | 7 | MVideoThumbnail, |
8 | MVideoWithRights | 8 | MVideoWithRights, |
9 | MVideoImmutable | ||
9 | } from '@server/typings/models' | 10 | } from '@server/typings/models' |
10 | import { Response } from 'express' | 11 | import { Response } from 'express' |
11 | 12 | ||
12 | type VideoFetchType = 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' | 13 | type VideoFetchType = 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' | 'only-immutable-attributes' |
13 | 14 | ||
14 | function fetchVideo (id: number | string, fetchType: 'all', userId?: number): Bluebird<MVideoFullLight> | 15 | function fetchVideo (id: number | string, fetchType: 'all', userId?: number): Bluebird<MVideoFullLight> |
16 | function fetchVideo (id: number | string, fetchType: 'only-immutable-attributes'): Bluebird<MVideoImmutable> | ||
15 | function fetchVideo (id: number | string, fetchType: 'only-video', userId?: number): Bluebird<MVideoThumbnail> | 17 | function fetchVideo (id: number | string, fetchType: 'only-video', userId?: number): Bluebird<MVideoThumbnail> |
16 | function fetchVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Bluebird<MVideoWithRights> | 18 | function fetchVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Bluebird<MVideoWithRights> |
17 | function fetchVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Bluebird<MVideoIdThumbnail> | 19 | function fetchVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Bluebird<MVideoIdThumbnail> |
@@ -19,14 +21,16 @@ function fetchVideo ( | |||
19 | id: number | string, | 21 | id: number | string, |
20 | fetchType: VideoFetchType, | 22 | fetchType: VideoFetchType, |
21 | userId?: number | 23 | userId?: number |
22 | ): Bluebird<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail> | 24 | ): Bluebird<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable> |
23 | function fetchVideo ( | 25 | function fetchVideo ( |
24 | id: number | string, | 26 | id: number | string, |
25 | fetchType: VideoFetchType, | 27 | fetchType: VideoFetchType, |
26 | userId?: number | 28 | userId?: number |
27 | ): Bluebird<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail> { | 29 | ): Bluebird<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable> { |
28 | if (fetchType === 'all') return VideoModel.loadAndPopulateAccountAndServerAndTags(id, undefined, userId) | 30 | if (fetchType === 'all') return VideoModel.loadAndPopulateAccountAndServerAndTags(id, undefined, userId) |
29 | 31 | ||
32 | if (fetchType === 'only-immutable-attributes') return VideoModel.loadImmutableAttributes(id) | ||
33 | |||
30 | if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id) | 34 | if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id) |
31 | 35 | ||
32 | if (fetchType === 'only-video') return VideoModel.load(id) | 36 | if (fetchType === 'only-video') return VideoModel.load(id) |
@@ -34,14 +38,23 @@ function fetchVideo ( | |||
34 | if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id) | 38 | if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id) |
35 | } | 39 | } |
36 | 40 | ||
37 | type VideoFetchByUrlType = 'all' | 'only-video' | 41 | type VideoFetchByUrlType = 'all' | 'only-video' | 'only-immutable-attributes' |
38 | 42 | ||
39 | function fetchVideoByUrl (url: string, fetchType: 'all'): Bluebird<MVideoAccountLightBlacklistAllFiles> | 43 | function fetchVideoByUrl (url: string, fetchType: 'all'): Bluebird<MVideoAccountLightBlacklistAllFiles> |
44 | function fetchVideoByUrl (url: string, fetchType: 'only-immutable-attributes'): Bluebird<MVideoImmutable> | ||
40 | function fetchVideoByUrl (url: string, fetchType: 'only-video'): Bluebird<MVideoThumbnail> | 45 | function fetchVideoByUrl (url: string, fetchType: 'only-video'): Bluebird<MVideoThumbnail> |
41 | function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail> | 46 | function fetchVideoByUrl ( |
42 | function fetchVideoByUrl (url: string, fetchType: VideoFetchByUrlType): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail> { | 47 | url: string, |
48 | fetchType: VideoFetchByUrlType | ||
49 | ): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> | ||
50 | function fetchVideoByUrl ( | ||
51 | url: string, | ||
52 | fetchType: VideoFetchByUrlType | ||
53 | ): Bluebird<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> { | ||
43 | if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url) | 54 | if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url) |
44 | 55 | ||
56 | if (fetchType === 'only-immutable-attributes') return VideoModel.loadByUrlImmutableAttributes(url) | ||
57 | |||
45 | if (fetchType === 'only-video') return VideoModel.loadByUrl(url) | 58 | if (fetchType === 'only-video') return VideoModel.loadByUrl(url) |
46 | } | 59 | } |
47 | 60 | ||
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index 3a99518c6..b25e44fcd 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -9,12 +9,12 @@ import { promisify2 } from './core-utils' | |||
9 | import { MVideo } from '@server/typings/models/video/video' | 9 | import { MVideo } from '@server/typings/models/video/video' |
10 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/typings/models/video/video-file' | 10 | import { MVideoFile, MVideoFileRedundanciesOpt } from '@server/typings/models/video/video-file' |
11 | import { isStreamingPlaylist, MStreamingPlaylistVideo } from '@server/typings/models/video/video-streaming-playlist' | 11 | import { isStreamingPlaylist, MStreamingPlaylistVideo } from '@server/typings/models/video/video-streaming-playlist' |
12 | import { STATIC_PATHS, WEBSERVER } from '@server/initializers/constants' | 12 | import { WEBSERVER } from '@server/initializers/constants' |
13 | import * as parseTorrent from 'parse-torrent' | 13 | import * as parseTorrent from 'parse-torrent' |
14 | import * as magnetUtil from 'magnet-uri' | 14 | import * as magnetUtil from 'magnet-uri' |
15 | import { isArray } from '@server/helpers/custom-validators/misc' | 15 | import { isArray } from '@server/helpers/custom-validators/misc' |
16 | import { extractVideo } from '@server/lib/videos' | 16 | import { extractVideo } from '@server/lib/videos' |
17 | import { getTorrentFileName, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | 17 | import { getTorrentFileName, getVideoFilePath } from '@server/lib/video-paths' |
18 | 18 | ||
19 | const createTorrentPromise = promisify2<string, any, any>(createTorrent) | 19 | const createTorrentPromise = promisify2<string, any, any>(createTorrent) |
20 | 20 | ||
@@ -39,7 +39,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
39 | if (torrent.files.length !== 1) { | 39 | if (torrent.files.length !== 1) { |
40 | if (timer) clearTimeout(timer) | 40 | if (timer) clearTimeout(timer) |
41 | 41 | ||
42 | for (let file of torrent.files) { | 42 | for (const file of torrent.files) { |
43 | deleteDownloadedFile({ directoryPath, filepath: file.path }) | 43 | deleteDownloadedFile({ directoryPath, filepath: file.path }) |
44 | } | 44 | } |
45 | 45 | ||
@@ -47,15 +47,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
47 | .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) | 47 | .then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) |
48 | } | 48 | } |
49 | 49 | ||
50 | file = torrent.files[ 0 ] | 50 | file = torrent.files[0] |
51 | 51 | ||
52 | // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed | 52 | // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed |
53 | const writeStream = createWriteStream(path) | 53 | const writeStream = createWriteStream(path) |
54 | writeStream.on('finish', () => { | 54 | writeStream.on('finish', () => { |
55 | if (timer) clearTimeout(timer) | 55 | if (timer) clearTimeout(timer) |
56 | 56 | ||
57 | return safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName) | 57 | safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName) |
58 | .then(() => res(path)) | 58 | .then(() => res(path)) |
59 | .catch(err => logger.error('Cannot destroy webtorrent.', { err })) | ||
59 | }) | 60 | }) |
60 | 61 | ||
61 | file.createReadStream().pipe(writeStream) | 62 | file.createReadStream().pipe(writeStream) |
@@ -63,9 +64,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName | |||
63 | 64 | ||
64 | torrent.on('error', err => rej(err)) | 65 | torrent.on('error', err => rej(err)) |
65 | 66 | ||
66 | timer = setTimeout(async () => { | 67 | timer = setTimeout(() => { |
67 | return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) | 68 | const err = new Error('Webtorrent download timeout.') |
68 | .then(() => rej(new Error('Webtorrent download timeout.'))) | 69 | |
70 | safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) | ||
71 | .then(() => rej(err)) | ||
72 | .catch(destroyErr => { | ||
73 | logger.error('Cannot destroy webtorrent.', { err: destroyErr }) | ||
74 | rej(err) | ||
75 | }) | ||
76 | |||
69 | }, timeout) | 77 | }, timeout) |
70 | }) | 78 | }) |
71 | } | 79 | } |
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts index 577a59dbf..fc9d416a1 100644 --- a/server/helpers/youtube-dl.ts +++ b/server/helpers/youtube-dl.ts | |||
@@ -24,20 +24,23 @@ const processOptions = { | |||
24 | } | 24 | } |
25 | 25 | ||
26 | function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { | 26 | function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { |
27 | return new Promise<YoutubeDLInfo>(async (res, rej) => { | 27 | return new Promise<YoutubeDLInfo>((res, rej) => { |
28 | let args = opts || [ '-j', '--flat-playlist' ] | 28 | let args = opts || [ '-j', '--flat-playlist' ] |
29 | args = wrapWithProxyOptions(args) | 29 | args = wrapWithProxyOptions(args) |
30 | 30 | ||
31 | const youtubeDL = await safeGetYoutubeDL() | 31 | safeGetYoutubeDL() |
32 | youtubeDL.getInfo(url, args, processOptions, (err, info) => { | 32 | .then(youtubeDL => { |
33 | if (err) return rej(err) | 33 | youtubeDL.getInfo(url, args, processOptions, (err, info) => { |
34 | if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) | 34 | if (err) return rej(err) |
35 | if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) | ||
35 | 36 | ||
36 | const obj = buildVideoInfo(normalizeObject(info)) | 37 | const obj = buildVideoInfo(normalizeObject(info)) |
37 | if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video' | 38 | if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video' |
38 | 39 | ||
39 | return res(obj) | 40 | return res(obj) |
40 | }) | 41 | }) |
42 | }) | ||
43 | .catch(err => rej(err)) | ||
41 | }) | 44 | }) |
42 | } | 45 | } |
43 | 46 | ||
@@ -54,26 +57,34 @@ function downloadYoutubeDLVideo (url: string, timeout: number) { | |||
54 | options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) | 57 | options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) |
55 | } | 58 | } |
56 | 59 | ||
57 | return new Promise<string>(async (res, rej) => { | 60 | return new Promise<string>((res, rej) => { |
58 | const youtubeDL = await safeGetYoutubeDL() | 61 | safeGetYoutubeDL() |
59 | youtubeDL.exec(url, options, processOptions, err => { | 62 | .then(youtubeDL => { |
60 | clearTimeout(timer) | 63 | youtubeDL.exec(url, options, processOptions, err => { |
64 | clearTimeout(timer) | ||
61 | 65 | ||
62 | if (err) { | 66 | if (err) { |
63 | remove(path) | 67 | remove(path) |
64 | .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err })) | 68 | .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err })) |
65 | 69 | ||
66 | return rej(err) | 70 | return rej(err) |
67 | } | 71 | } |
68 | 72 | ||
69 | return res(path) | 73 | return res(path) |
70 | }) | 74 | }) |
71 | 75 | ||
72 | timer = setTimeout(async () => { | 76 | timer = setTimeout(() => { |
73 | await remove(path) | 77 | const err = new Error('YoutubeDL download timeout.') |
74 | 78 | ||
75 | return rej(new Error('YoutubeDL download timeout.')) | 79 | remove(path) |
76 | }, timeout) | 80 | .finally(() => rej(err)) |
81 | .catch(err => { | ||
82 | logger.error('Cannot remove %s in youtubeDL timeout.', path, { err }) | ||
83 | return rej(err) | ||
84 | }) | ||
85 | }, timeout) | ||
86 | }) | ||
87 | .catch(err => rej(err)) | ||
77 | }) | 88 | }) |
78 | } | 89 | } |
79 | 90 | ||
@@ -103,7 +114,7 @@ async function updateYoutubeDLBinary () { | |||
103 | 114 | ||
104 | const url = result.headers.location | 115 | const url = result.headers.location |
105 | const downloadFile = request.get(url) | 116 | const downloadFile = request.get(url) |
106 | const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ] | 117 | const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1] |
107 | 118 | ||
108 | downloadFile.on('response', result => { | 119 | downloadFile.on('response', result => { |
109 | if (result.statusCode !== 200) { | 120 | if (result.statusCode !== 200) { |
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts index 44efd346c..e01609eef 100644 --- a/server/initializers/checker-after-init.ts +++ b/server/initializers/checker-after-init.ts | |||
@@ -3,20 +3,19 @@ import { isProdInstance, isTestInstance } from '../helpers/core-utils' | |||
3 | import { UserModel } from '../models/account/user' | 3 | import { UserModel } from '../models/account/user' |
4 | import { ApplicationModel } from '../models/application/application' | 4 | import { ApplicationModel } from '../models/application/application' |
5 | import { OAuthClientModel } from '../models/oauth/oauth-client' | 5 | import { OAuthClientModel } from '../models/oauth/oauth-client' |
6 | import { parse } from 'url' | 6 | import { URL } from 'url' |
7 | import { CONFIG } from './config' | 7 | import { CONFIG, isEmailEnabled } from './config' |
8 | import { logger } from '../helpers/logger' | 8 | import { logger } from '../helpers/logger' |
9 | import { getServerActor } from '../helpers/utils' | 9 | import { getServerActor } from '../helpers/utils' |
10 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' | 10 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' |
11 | import { isArray } from '../helpers/custom-validators/misc' | 11 | import { isArray } from '../helpers/custom-validators/misc' |
12 | import { uniq } from 'lodash' | 12 | import { uniq } from 'lodash' |
13 | import { Emailer } from '../lib/emailer' | ||
14 | import { WEBSERVER } from './constants' | 13 | import { WEBSERVER } from './constants' |
15 | 14 | ||
16 | async function checkActivityPubUrls () { | 15 | async function checkActivityPubUrls () { |
17 | const actor = await getServerActor() | 16 | const actor = await getServerActor() |
18 | 17 | ||
19 | const parsed = parse(actor.url) | 18 | const parsed = new URL(actor.url) |
20 | if (WEBSERVER.HOST !== parsed.host) { | 19 | if (WEBSERVER.HOST !== parsed.host) { |
21 | const NODE_ENV = config.util.getEnv('NODE_ENV') | 20 | const NODE_ENV = config.util.getEnv('NODE_ENV') |
22 | const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') | 21 | const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') |
@@ -41,7 +40,7 @@ function checkConfig () { | |||
41 | } | 40 | } |
42 | 41 | ||
43 | // Email verification | 42 | // Email verification |
44 | if (!Emailer.isEnabled()) { | 43 | if (!isEmailEnabled()) { |
45 | if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { | 44 | if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { |
46 | return 'Emailer is disabled but you require signup email verification.' | 45 | return 'Emailer is disabled but you require signup email verification.' |
47 | } | 46 | } |
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 9731a0af9..a75f2cec2 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -35,8 +35,8 @@ function checkMissedConfig () { | |||
35 | ] | 35 | ] |
36 | const requiredAlternatives = [ | 36 | const requiredAlternatives = [ |
37 | [ // set | 37 | [ // set |
38 | ['redis.hostname', 'redis.port'], // alternative | 38 | [ 'redis.hostname', 'redis.port' ], // alternative |
39 | ['redis.socket'] | 39 | [ 'redis.socket' ] |
40 | ] | 40 | ] |
41 | ] | 41 | ] |
42 | const miss: string[] = [] | 42 | const miss: string[] = [] |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index 7fd77f3e8..950ca61bd 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { IConfig } from 'config' | 1 | import { IConfig } from 'config' |
2 | import { dirname, join } from 'path' | 2 | import { dirname, join } from 'path' |
3 | import { VideosRedundancy } from '../../shared/models' | 3 | import { VideosRedundancyStrategy } from '../../shared/models' |
4 | // Do not use barrels, remain constants as independent as possible | 4 | // Do not use barrels, remain constants as independent as possible |
5 | import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils' | 5 | import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils' |
6 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 6 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
@@ -284,11 +284,16 @@ function registerConfigChangedHandler (fun: Function) { | |||
284 | configChangedHandlers.push(fun) | 284 | configChangedHandlers.push(fun) |
285 | } | 285 | } |
286 | 286 | ||
287 | function isEmailEnabled () { | ||
288 | return !!CONFIG.SMTP.HOSTNAME && !!CONFIG.SMTP.PORT | ||
289 | } | ||
290 | |||
287 | // --------------------------------------------------------------------------- | 291 | // --------------------------------------------------------------------------- |
288 | 292 | ||
289 | export { | 293 | export { |
290 | CONFIG, | 294 | CONFIG, |
291 | registerConfigChangedHandler | 295 | registerConfigChangedHandler, |
296 | isEmailEnabled | ||
292 | } | 297 | } |
293 | 298 | ||
294 | // --------------------------------------------------------------------------- | 299 | // --------------------------------------------------------------------------- |
@@ -301,10 +306,10 @@ function getLocalConfigFilePath () { | |||
301 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` | 306 | if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` |
302 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` | 307 | if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` |
303 | 308 | ||
304 | return join(dirname(configSources[ 0 ].name), filename + '.json') | 309 | return join(dirname(configSources[0].name), filename + '.json') |
305 | } | 310 | } |
306 | 311 | ||
307 | function buildVideosRedundancy (objs: any[]): VideosRedundancy[] { | 312 | function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] { |
308 | if (!objs) return [] | 313 | if (!objs) return [] |
309 | 314 | ||
310 | if (!Array.isArray(objs)) return objs | 315 | if (!Array.isArray(objs)) return objs |
@@ -330,7 +335,7 @@ export function reloadConfig () { | |||
330 | 335 | ||
331 | function purge () { | 336 | function purge () { |
332 | for (const fileName in require.cache) { | 337 | for (const fileName in require.cache) { |
333 | if (-1 === fileName.indexOf(directory())) { | 338 | if (fileName.indexOf(directory()) === -1) { |
334 | continue | 339 | continue |
335 | } | 340 | } |
336 | 341 | ||
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 13e32b6d2..3da06402c 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -4,7 +4,7 @@ import { ActivityPubActorType } from '../../shared/models/activitypub' | |||
4 | import { FollowState } from '../../shared/models/actors' | 4 | import { FollowState } from '../../shared/models/actors' |
5 | import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' | 5 | import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' |
6 | // Do not use barrels, remain constants as independent as possible | 6 | // Do not use barrels, remain constants as independent as possible |
7 | import { isTestInstance, sanitizeHost, sanitizeUrl, root, parseDurationToMs } from '../helpers/core-utils' | 7 | import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils' |
8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 8 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
9 | import { invert } from 'lodash' | 9 | import { invert } from 'lodash' |
10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' | 10 | import { CronRepeatOptions, EveryRepeatOptions } from 'bull' |
@@ -14,7 +14,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
14 | 14 | ||
15 | // --------------------------------------------------------------------------- | 15 | // --------------------------------------------------------------------------- |
16 | 16 | ||
17 | const LAST_MIGRATION_VERSION = 470 | 17 | const LAST_MIGRATION_VERSION = 480 |
18 | 18 | ||
19 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
20 | 20 | ||
@@ -73,7 +73,9 @@ const SORTABLE_COLUMNS = { | |||
73 | 73 | ||
74 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ], | 74 | PLUGINS: [ 'name', 'createdAt', 'updatedAt' ], |
75 | 75 | ||
76 | AVAILABLE_PLUGINS: [ 'npmName', 'popularity' ] | 76 | AVAILABLE_PLUGINS: [ 'npmName', 'popularity' ], |
77 | |||
78 | VIDEO_REDUNDANCIES: [ 'name' ] | ||
77 | } | 79 | } |
78 | 80 | ||
79 | const OAUTH_LIFETIME = { | 81 | const OAUTH_LIFETIME = { |
@@ -117,45 +119,44 @@ const REMOTE_SCHEME = { | |||
117 | WS: 'wss' | 119 | WS: 'wss' |
118 | } | 120 | } |
119 | 121 | ||
120 | // TODO: remove 'video-file' | 122 | const JOB_ATTEMPTS: { [id in JobType]: number } = { |
121 | const JOB_ATTEMPTS: { [id in (JobType | 'video-file')]: number } = { | ||
122 | 'activitypub-http-broadcast': 5, | 123 | 'activitypub-http-broadcast': 5, |
123 | 'activitypub-http-unicast': 5, | 124 | 'activitypub-http-unicast': 5, |
124 | 'activitypub-http-fetcher': 5, | 125 | 'activitypub-http-fetcher': 5, |
125 | 'activitypub-follow': 5, | 126 | 'activitypub-follow': 5, |
126 | 'video-file-import': 1, | 127 | 'video-file-import': 1, |
127 | 'video-transcoding': 1, | 128 | 'video-transcoding': 1, |
128 | 'video-file': 1, | ||
129 | 'video-import': 1, | 129 | 'video-import': 1, |
130 | 'email': 5, | 130 | 'email': 5, |
131 | 'videos-views': 1, | 131 | 'videos-views': 1, |
132 | 'activitypub-refresher': 1 | 132 | 'activitypub-refresher': 1, |
133 | 'video-redundancy': 1 | ||
133 | } | 134 | } |
134 | const JOB_CONCURRENCY: { [id in (JobType | 'video-file')]: number } = { | 135 | const JOB_CONCURRENCY: { [id in JobType]: number } = { |
135 | 'activitypub-http-broadcast': 1, | 136 | 'activitypub-http-broadcast': 1, |
136 | 'activitypub-http-unicast': 5, | 137 | 'activitypub-http-unicast': 5, |
137 | 'activitypub-http-fetcher': 1, | 138 | 'activitypub-http-fetcher': 1, |
138 | 'activitypub-follow': 1, | 139 | 'activitypub-follow': 1, |
139 | 'video-file-import': 1, | 140 | 'video-file-import': 1, |
140 | 'video-transcoding': 1, | 141 | 'video-transcoding': 1, |
141 | 'video-file': 1, | ||
142 | 'video-import': 1, | 142 | 'video-import': 1, |
143 | 'email': 5, | 143 | 'email': 5, |
144 | 'videos-views': 1, | 144 | 'videos-views': 1, |
145 | 'activitypub-refresher': 1 | 145 | 'activitypub-refresher': 1, |
146 | 'video-redundancy': 1 | ||
146 | } | 147 | } |
147 | const JOB_TTL: { [id in (JobType | 'video-file')]: number } = { | 148 | const JOB_TTL: { [id in JobType]: number } = { |
148 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes | 149 | 'activitypub-http-broadcast': 60000 * 10, // 10 minutes |
149 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes | 150 | 'activitypub-http-unicast': 60000 * 10, // 10 minutes |
150 | 'activitypub-http-fetcher': 60000 * 10, // 10 minutes | 151 | 'activitypub-http-fetcher': 60000 * 10, // 10 minutes |
151 | 'activitypub-follow': 60000 * 10, // 10 minutes | 152 | 'activitypub-follow': 60000 * 10, // 10 minutes |
152 | 'video-file-import': 1000 * 3600, // 1 hour | 153 | 'video-file-import': 1000 * 3600, // 1 hour |
153 | 'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long | 154 | 'video-transcoding': 1000 * 3600 * 48, // 2 days, transcoding could be long |
154 | 'video-file': 1000 * 3600 * 48, // 2 days, transcoding could be long | ||
155 | 'video-import': 1000 * 3600 * 2, // hours | 155 | 'video-import': 1000 * 3600 * 2, // hours |
156 | 'email': 60000 * 10, // 10 minutes | 156 | 'email': 60000 * 10, // 10 minutes |
157 | 'videos-views': undefined, // Unlimited | 157 | 'videos-views': undefined, // Unlimited |
158 | 'activitypub-refresher': 60000 * 10 // 10 minutes | 158 | 'activitypub-refresher': 60000 * 10, // 10 minutes |
159 | 'video-redundancy': 1000 * 3600 * 3 // 3 hours | ||
159 | } | 160 | } |
160 | const REPEAT_JOBS: { [ id: string ]: EveryRepeatOptions | CronRepeatOptions } = { | 161 | const REPEAT_JOBS: { [ id: string ]: EveryRepeatOptions | CronRepeatOptions } = { |
161 | 'videos-views': { | 162 | 'videos-views': { |
@@ -309,6 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour | |||
309 | 310 | ||
310 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { | 311 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { |
311 | MIN: 10, | 312 | MIN: 10, |
313 | STANDARD: [ 24, 25, 30 ], | ||
314 | HD_STANDARD: [ 50, 60 ], | ||
312 | AVERAGE: 30, | 315 | AVERAGE: 30, |
313 | MAX: 60, | 316 | MAX: 60, |
314 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) | 317 | KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) |
@@ -358,42 +361,42 @@ const VIDEO_LICENCES = { | |||
358 | 7: 'Public Domain Dedication' | 361 | 7: 'Public Domain Dedication' |
359 | } | 362 | } |
360 | 363 | ||
361 | let VIDEO_LANGUAGES: { [id: string]: string } = {} | 364 | const VIDEO_LANGUAGES: { [id: string]: string } = {} |
362 | 365 | ||
363 | const VIDEO_PRIVACIES = { | 366 | const VIDEO_PRIVACIES = { |
364 | [ VideoPrivacy.PUBLIC ]: 'Public', | 367 | [VideoPrivacy.PUBLIC]: 'Public', |
365 | [ VideoPrivacy.UNLISTED ]: 'Unlisted', | 368 | [VideoPrivacy.UNLISTED]: 'Unlisted', |
366 | [ VideoPrivacy.PRIVATE ]: 'Private', | 369 | [VideoPrivacy.PRIVATE]: 'Private', |
367 | [ VideoPrivacy.INTERNAL ]: 'Internal' | 370 | [VideoPrivacy.INTERNAL]: 'Internal' |
368 | } | 371 | } |
369 | 372 | ||
370 | const VIDEO_STATES = { | 373 | const VIDEO_STATES = { |
371 | [ VideoState.PUBLISHED ]: 'Published', | 374 | [VideoState.PUBLISHED]: 'Published', |
372 | [ VideoState.TO_TRANSCODE ]: 'To transcode', | 375 | [VideoState.TO_TRANSCODE]: 'To transcode', |
373 | [ VideoState.TO_IMPORT ]: 'To import' | 376 | [VideoState.TO_IMPORT]: 'To import' |
374 | } | 377 | } |
375 | 378 | ||
376 | const VIDEO_IMPORT_STATES = { | 379 | const VIDEO_IMPORT_STATES = { |
377 | [ VideoImportState.FAILED ]: 'Failed', | 380 | [VideoImportState.FAILED]: 'Failed', |
378 | [ VideoImportState.PENDING ]: 'Pending', | 381 | [VideoImportState.PENDING]: 'Pending', |
379 | [ VideoImportState.SUCCESS ]: 'Success' | 382 | [VideoImportState.SUCCESS]: 'Success' |
380 | } | 383 | } |
381 | 384 | ||
382 | const VIDEO_ABUSE_STATES = { | 385 | const VIDEO_ABUSE_STATES = { |
383 | [ VideoAbuseState.PENDING ]: 'Pending', | 386 | [VideoAbuseState.PENDING]: 'Pending', |
384 | [ VideoAbuseState.REJECTED ]: 'Rejected', | 387 | [VideoAbuseState.REJECTED]: 'Rejected', |
385 | [ VideoAbuseState.ACCEPTED ]: 'Accepted' | 388 | [VideoAbuseState.ACCEPTED]: 'Accepted' |
386 | } | 389 | } |
387 | 390 | ||
388 | const VIDEO_PLAYLIST_PRIVACIES = { | 391 | const VIDEO_PLAYLIST_PRIVACIES = { |
389 | [ VideoPlaylistPrivacy.PUBLIC ]: 'Public', | 392 | [VideoPlaylistPrivacy.PUBLIC]: 'Public', |
390 | [ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted', | 393 | [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', |
391 | [ VideoPlaylistPrivacy.PRIVATE ]: 'Private' | 394 | [VideoPlaylistPrivacy.PRIVATE]: 'Private' |
392 | } | 395 | } |
393 | 396 | ||
394 | const VIDEO_PLAYLIST_TYPES = { | 397 | const VIDEO_PLAYLIST_TYPES = { |
395 | [ VideoPlaylistType.REGULAR ]: 'Regular', | 398 | [VideoPlaylistType.REGULAR]: 'Regular', |
396 | [ VideoPlaylistType.WATCH_LATER ]: 'Watch later' | 399 | [VideoPlaylistType.WATCH_LATER]: 'Watch later' |
397 | } | 400 | } |
398 | 401 | ||
399 | const MIMETYPES = { | 402 | const MIMETYPES = { |
@@ -419,7 +422,8 @@ const MIMETYPES = { | |||
419 | 'image/png': '.png', | 422 | 'image/png': '.png', |
420 | 'image/jpg': '.jpg', | 423 | 'image/jpg': '.jpg', |
421 | 'image/jpeg': '.jpg' | 424 | 'image/jpeg': '.jpg' |
422 | } | 425 | }, |
426 | EXT_MIMETYPE: null as { [ id: string ]: string } | ||
423 | }, | 427 | }, |
424 | VIDEO_CAPTIONS: { | 428 | VIDEO_CAPTIONS: { |
425 | MIMETYPE_EXT: { | 429 | MIMETYPE_EXT: { |
@@ -435,6 +439,7 @@ const MIMETYPES = { | |||
435 | } | 439 | } |
436 | } | 440 | } |
437 | MIMETYPES.AUDIO.EXT_MIMETYPE = invert(MIMETYPES.AUDIO.MIMETYPE_EXT) | 441 | MIMETYPES.AUDIO.EXT_MIMETYPE = invert(MIMETYPES.AUDIO.MIMETYPE_EXT) |
442 | MIMETYPES.IMAGE.EXT_MIMETYPE = invert(MIMETYPES.IMAGE.MIMETYPE_EXT) | ||
438 | 443 | ||
439 | // --------------------------------------------------------------------------- | 444 | // --------------------------------------------------------------------------- |
440 | 445 | ||
@@ -497,6 +502,7 @@ let PRIVATE_RSA_KEY_SIZE = 2048 | |||
497 | const BCRYPT_SALT_SIZE = 10 | 502 | const BCRYPT_SALT_SIZE = 10 |
498 | 503 | ||
499 | const USER_PASSWORD_RESET_LIFETIME = 60000 * 60 // 60 minutes | 504 | const USER_PASSWORD_RESET_LIFETIME = 60000 * 60 // 60 minutes |
505 | const USER_PASSWORD_CREATE_LIFETIME = 60000 * 60 * 24 * 7 // 7 days | ||
500 | 506 | ||
501 | const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes | 507 | const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes |
502 | 508 | ||
@@ -533,7 +539,7 @@ const LAZY_STATIC_PATHS = { | |||
533 | } | 539 | } |
534 | 540 | ||
535 | // Cache control | 541 | // Cache control |
536 | let STATIC_MAX_AGE = { | 542 | const STATIC_MAX_AGE = { |
537 | SERVER: '2h', | 543 | SERVER: '2h', |
538 | CLIENT: '30d' | 544 | CLIENT: '30d' |
539 | } | 545 | } |
@@ -541,11 +547,13 @@ let STATIC_MAX_AGE = { | |||
541 | // Videos thumbnail size | 547 | // Videos thumbnail size |
542 | const THUMBNAILS_SIZE = { | 548 | const THUMBNAILS_SIZE = { |
543 | width: 223, | 549 | width: 223, |
544 | height: 122 | 550 | height: 122, |
551 | minWidth: 150 | ||
545 | } | 552 | } |
546 | const PREVIEWS_SIZE = { | 553 | const PREVIEWS_SIZE = { |
547 | width: 850, | 554 | width: 850, |
548 | height: 480 | 555 | height: 480, |
556 | minWidth: 400 | ||
549 | } | 557 | } |
550 | const AVATARS_SIZE = { | 558 | const AVATARS_SIZE = { |
551 | width: 120, | 559 | width: 120, |
@@ -669,14 +677,14 @@ if (isTestInstance() === true) { | |||
669 | SCHEDULER_INTERVALS_MS.removeOldViews = 5000 | 677 | SCHEDULER_INTERVALS_MS.removeOldViews = 5000 |
670 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 | 678 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 |
671 | SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 | 679 | SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 |
672 | REPEAT_JOBS[ 'videos-views' ] = { every: 5000 } | 680 | REPEAT_JOBS['videos-views'] = { every: 5000 } |
673 | 681 | ||
674 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 | 682 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 |
675 | 683 | ||
676 | VIDEO_VIEW_LIFETIME = 1000 // 1 second | 684 | VIDEO_VIEW_LIFETIME = 1000 // 1 second |
677 | CONTACT_FORM_LIFETIME = 1000 // 1 second | 685 | CONTACT_FORM_LIFETIME = 1000 // 1 second |
678 | 686 | ||
679 | JOB_ATTEMPTS[ 'email' ] = 1 | 687 | JOB_ATTEMPTS['email'] = 1 |
680 | 688 | ||
681 | FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 | 689 | FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 |
682 | MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 | 690 | MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 |
@@ -757,6 +765,7 @@ export { | |||
757 | LRU_CACHE, | 765 | LRU_CACHE, |
758 | JOB_REQUEST_TIMEOUT, | 766 | JOB_REQUEST_TIMEOUT, |
759 | USER_PASSWORD_RESET_LIFETIME, | 767 | USER_PASSWORD_RESET_LIFETIME, |
768 | USER_PASSWORD_CREATE_LIFETIME, | ||
760 | MEMOIZE_TTL, | 769 | MEMOIZE_TTL, |
761 | USER_EMAIL_VERIFY_LIFETIME, | 770 | USER_EMAIL_VERIFY_LIFETIME, |
762 | OVERVIEWS, | 771 | OVERVIEWS, |
@@ -837,42 +846,42 @@ function loadLanguages () { | |||
837 | function buildLanguages () { | 846 | function buildLanguages () { |
838 | const iso639 = require('iso-639-3') | 847 | const iso639 = require('iso-639-3') |
839 | 848 | ||
840 | const languages: { [ id: string ]: string } = {} | 849 | const languages: { [id: string]: string } = {} |
841 | 850 | ||
842 | const additionalLanguages = { | 851 | const additionalLanguages = { |
843 | 'sgn': true, // Sign languages (macro language) | 852 | sgn: true, // Sign languages (macro language) |
844 | 'ase': true, // American sign language | 853 | ase: true, // American sign language |
845 | 'sdl': true, // Arabian sign language | 854 | sdl: true, // Arabian sign language |
846 | 'bfi': true, // British sign language | 855 | bfi: true, // British sign language |
847 | 'bzs': true, // Brazilian sign language | 856 | bzs: true, // Brazilian sign language |
848 | 'csl': true, // Chinese sign language | 857 | csl: true, // Chinese sign language |
849 | 'cse': true, // Czech sign language | 858 | cse: true, // Czech sign language |
850 | 'dsl': true, // Danish sign language | 859 | dsl: true, // Danish sign language |
851 | 'fsl': true, // French sign language | 860 | fsl: true, // French sign language |
852 | 'gsg': true, // German sign language | 861 | gsg: true, // German sign language |
853 | 'pks': true, // Pakistan sign language | 862 | pks: true, // Pakistan sign language |
854 | 'jsl': true, // Japanese sign language | 863 | jsl: true, // Japanese sign language |
855 | 'sfs': true, // South African sign language | 864 | sfs: true, // South African sign language |
856 | 'swl': true, // Swedish sign language | 865 | swl: true, // Swedish sign language |
857 | 'rsl': true, // Russian sign language: true | 866 | rsl: true, // Russian sign language: true |
858 | 867 | ||
859 | 'epo': true, // Esperanto | 868 | epo: true, // Esperanto |
860 | 'tlh': true, // Klingon | 869 | tlh: true, // Klingon |
861 | 'jbo': true, // Lojban | 870 | jbo: true, // Lojban |
862 | 'avk': true // Kotava | 871 | avk: true // Kotava |
863 | } | 872 | } |
864 | 873 | ||
865 | // Only add ISO639-1 languages and some sign languages (ISO639-3) | 874 | // Only add ISO639-1 languages and some sign languages (ISO639-3) |
866 | iso639 | 875 | iso639 |
867 | .filter(l => { | 876 | .filter(l => { |
868 | return (l.iso6391 !== null && l.type === 'living') || | 877 | return (l.iso6391 !== undefined && l.type === 'living') || |
869 | additionalLanguages[ l.iso6393 ] === true | 878 | additionalLanguages[l.iso6393] === true |
870 | }) | 879 | }) |
871 | .forEach(l => languages[ l.iso6391 || l.iso6393 ] = l.name) | 880 | .forEach(l => { languages[l.iso6391 || l.iso6393] = l.name }) |
872 | 881 | ||
873 | // Override Occitan label | 882 | // Override Occitan label |
874 | languages[ 'oc' ] = 'Occitan' | 883 | languages['oc'] = 'Occitan' |
875 | languages[ 'el' ] = 'Greek' | 884 | languages['el'] = 'Greek' |
876 | 885 | ||
877 | return languages | 886 | return languages |
878 | } | 887 | } |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 9ec146ab1..eedaf3c4e 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -119,8 +119,6 @@ async function initDatabaseModels (silent: boolean) { | |||
119 | await createFunctions() | 119 | await createFunctions() |
120 | 120 | ||
121 | if (!silent) logger.info('Database %s is ready.', dbname) | 121 | if (!silent) logger.info('Database %s is ready.', dbname) |
122 | |||
123 | return | ||
124 | } | 122 | } |
125 | 123 | ||
126 | // --------------------------------------------------------------------------- | 124 | // --------------------------------------------------------------------------- |
diff --git a/server/initializers/migrations/0005-email-pod.ts b/server/initializers/migrations/0005-email-pod.ts index c34a12255..417c33b1f 100644 --- a/server/initializers/migrations/0005-email-pod.ts +++ b/server/initializers/migrations/0005-email-pod.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0010-email-user.ts b/server/initializers/migrations/0010-email-user.ts index 37a7b0bb3..f7d01f6d6 100644 --- a/server/initializers/migrations/0010-email-user.ts +++ b/server/initializers/migrations/0010-email-user.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0015-video-views.ts b/server/initializers/migrations/0015-video-views.ts index 25164ff4d..47dd4069b 100644 --- a/server/initializers/migrations/0015-video-views.ts +++ b/server/initializers/migrations/0015-video-views.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0020-video-likes.ts b/server/initializers/migrations/0020-video-likes.ts index 945be5a98..44333f3b0 100644 --- a/server/initializers/migrations/0020-video-likes.ts +++ b/server/initializers/migrations/0020-video-likes.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0025-video-dislikes.ts b/server/initializers/migrations/0025-video-dislikes.ts index 27144c437..2aa22e2d7 100644 --- a/server/initializers/migrations/0025-video-dislikes.ts +++ b/server/initializers/migrations/0025-video-dislikes.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0030-video-category.ts b/server/initializers/migrations/0030-video-category.ts index f784f820d..00cd2d8cf 100644 --- a/server/initializers/migrations/0030-video-category.ts +++ b/server/initializers/migrations/0030-video-category.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0035-video-licence.ts b/server/initializers/migrations/0035-video-licence.ts index 3d0b0bac9..61d666c5e 100644 --- a/server/initializers/migrations/0035-video-licence.ts +++ b/server/initializers/migrations/0035-video-licence.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0040-video-nsfw.ts b/server/initializers/migrations/0040-video-nsfw.ts index f7f70d3c4..44aec8a6c 100644 --- a/server/initializers/migrations/0040-video-nsfw.ts +++ b/server/initializers/migrations/0040-video-nsfw.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0045-user-display-nsfw.ts b/server/initializers/migrations/0045-user-display-nsfw.ts index aef420f0e..07795bd75 100644 --- a/server/initializers/migrations/0045-user-display-nsfw.ts +++ b/server/initializers/migrations/0045-user-display-nsfw.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0050-video-language.ts b/server/initializers/migrations/0050-video-language.ts index 796fa5f95..6f90abb44 100644 --- a/server/initializers/migrations/0050-video-language.ts +++ b/server/initializers/migrations/0050-video-language.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0055-video-uuid.ts b/server/initializers/migrations/0055-video-uuid.ts index e0f904080..8a58aebb8 100644 --- a/server/initializers/migrations/0055-video-uuid.ts +++ b/server/initializers/migrations/0055-video-uuid.ts | |||
@@ -3,8 +3,8 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0060-video-file.ts b/server/initializers/migrations/0060-video-file.ts index c362cf71a..00647e60e 100644 --- a/server/initializers/migrations/0060-video-file.ts +++ b/server/initializers/migrations/0060-video-file.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0065-video-file-size.ts b/server/initializers/migrations/0065-video-file-size.ts index e9ce77e50..0bdc675c2 100644 --- a/server/initializers/migrations/0065-video-file-size.ts +++ b/server/initializers/migrations/0065-video-file-size.ts | |||
@@ -5,9 +5,9 @@ import { VideoModel } from '../../models/video/video' | |||
5 | import { getVideoFilePath } from '@server/lib/video-paths' | 5 | import { getVideoFilePath } from '@server/lib/video-paths' |
6 | 6 | ||
7 | function up (utils: { | 7 | function up (utils: { |
8 | transaction: Sequelize.Transaction, | 8 | transaction: Sequelize.Transaction |
9 | queryInterface: Sequelize.QueryInterface, | 9 | queryInterface: Sequelize.QueryInterface |
10 | sequelize: Sequelize.Sequelize, | 10 | sequelize: Sequelize.Sequelize |
11 | db: any | 11 | db: any |
12 | }): Promise<void> { | 12 | }): Promise<void> { |
13 | return utils.db.Video.listOwnedAndPopulateAuthorAndTags() | 13 | return utils.db.Video.listOwnedAndPopulateAuthorAndTags() |
diff --git a/server/initializers/migrations/0070-user-video-quota.ts b/server/initializers/migrations/0070-user-video-quota.ts index 37683432f..1d073f244 100644 --- a/server/initializers/migrations/0070-user-video-quota.ts +++ b/server/initializers/migrations/0070-user-video-quota.ts | |||
@@ -3,9 +3,9 @@ import * as Promise from 'bluebird' | |||
3 | import { Migration } from '../../models/migrations' | 3 | import { Migration } from '../../models/migrations' |
4 | 4 | ||
5 | function up (utils: { | 5 | function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize, | 8 | sequelize: Sequelize.Sequelize |
9 | db: any | 9 | db: any |
10 | }): Promise<void> { | 10 | }): Promise<void> { |
11 | const q = utils.queryInterface | 11 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0075-video-resolutions.ts b/server/initializers/migrations/0075-video-resolutions.ts index e4f26cb77..f56c1b2c3 100644 --- a/server/initializers/migrations/0075-video-resolutions.ts +++ b/server/initializers/migrations/0075-video-resolutions.ts | |||
@@ -5,9 +5,9 @@ import { getVideoFileResolution } from '../../helpers/ffmpeg-utils' | |||
5 | import { readdir, rename } from 'fs-extra' | 5 | import { readdir, rename } from 'fs-extra' |
6 | 6 | ||
7 | function up (utils: { | 7 | function up (utils: { |
8 | transaction: Sequelize.Transaction, | 8 | transaction: Sequelize.Transaction |
9 | queryInterface: Sequelize.QueryInterface, | 9 | queryInterface: Sequelize.QueryInterface |
10 | sequelize: Sequelize.Sequelize, | 10 | sequelize: Sequelize.Sequelize |
11 | db: any | 11 | db: any |
12 | }): Promise<void> { | 12 | }): Promise<void> { |
13 | const torrentDir = CONFIG.STORAGE.TORRENTS_DIR | 13 | const torrentDir = CONFIG.STORAGE.TORRENTS_DIR |
diff --git a/server/initializers/migrations/0080-video-channels.ts b/server/initializers/migrations/0080-video-channels.ts index 5512bdcf1..b8e9bd6d0 100644 --- a/server/initializers/migrations/0080-video-channels.ts +++ b/server/initializers/migrations/0080-video-channels.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as uuidv4 from 'uuid/v4' | 2 | import * as uuidv4 from 'uuid/v4' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | const q = utils.queryInterface | 10 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0085-user-role.ts b/server/initializers/migrations/0085-user-role.ts index de75faec2..ec7428fd5 100644 --- a/server/initializers/migrations/0085-user-role.ts +++ b/server/initializers/migrations/0085-user-role.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0090-videos-description.ts b/server/initializers/migrations/0090-videos-description.ts index 6f98dcade..32e518d75 100644 --- a/server/initializers/migrations/0090-videos-description.ts +++ b/server/initializers/migrations/0090-videos-description.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0095-videos-privacy.ts b/server/initializers/migrations/0095-videos-privacy.ts index 4c2bf91d0..c732d6f6a 100644 --- a/server/initializers/migrations/0095-videos-privacy.ts +++ b/server/initializers/migrations/0095-videos-privacy.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0100-activitypub.ts b/server/initializers/migrations/0100-activitypub.ts index 96d44a7ce..05fd37406 100644 --- a/server/initializers/migrations/0100-activitypub.ts +++ b/server/initializers/migrations/0100-activitypub.ts | |||
@@ -7,9 +7,9 @@ import { ApplicationModel } from '../../models/application/application' | |||
7 | import { SERVER_ACTOR_NAME } from '../constants' | 7 | import { SERVER_ACTOR_NAME } from '../constants' |
8 | 8 | ||
9 | async function up (utils: { | 9 | async function up (utils: { |
10 | transaction: Sequelize.Transaction, | 10 | transaction: Sequelize.Transaction |
11 | queryInterface: Sequelize.QueryInterface, | 11 | queryInterface: Sequelize.QueryInterface |
12 | sequelize: Sequelize.Sequelize, | 12 | sequelize: Sequelize.Sequelize |
13 | db: any | 13 | db: any |
14 | }): Promise<void> { | 14 | }): Promise<void> { |
15 | const q = utils.queryInterface | 15 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0105-server-mail.ts b/server/initializers/migrations/0105-server-mail.ts index 4b9600e91..5ee37c418 100644 --- a/server/initializers/migrations/0105-server-mail.ts +++ b/server/initializers/migrations/0105-server-mail.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('Servers', 'email') | 9 | await utils.queryInterface.removeColumn('Servers', 'email') |
diff --git a/server/initializers/migrations/0110-server-key.ts b/server/initializers/migrations/0110-server-key.ts index 5ff6daf69..354cd7e76 100644 --- a/server/initializers/migrations/0110-server-key.ts +++ b/server/initializers/migrations/0110-server-key.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('Servers', 'publicKey') | 9 | await utils.queryInterface.removeColumn('Servers', 'publicKey') |
diff --git a/server/initializers/migrations/0115-account-avatar.ts b/server/initializers/migrations/0115-account-avatar.ts index b318e8163..604b6394a 100644 --- a/server/initializers/migrations/0115-account-avatar.ts +++ b/server/initializers/migrations/0115-account-avatar.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.db.Avatar.sync() | 9 | await utils.db.Avatar.sync() |
diff --git a/server/initializers/migrations/0120-video-null.ts b/server/initializers/migrations/0120-video-null.ts index 6d253f04f..1b407b270 100644 --- a/server/initializers/migrations/0120-video-null.ts +++ b/server/initializers/migrations/0120-video-null.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0125-table-lowercase.ts b/server/initializers/migrations/0125-table-lowercase.ts index 78041ccb0..f75a56791 100644 --- a/server/initializers/migrations/0125-table-lowercase.ts +++ b/server/initializers/migrations/0125-table-lowercase.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.renameTable('Applications', 'application') | 8 | await utils.queryInterface.renameTable('Applications', 'application') |
diff --git a/server/initializers/migrations/0130-user-autoplay-video.ts b/server/initializers/migrations/0130-user-autoplay-video.ts index 9f6878e39..d57934588 100644 --- a/server/initializers/migrations/0130-user-autoplay-video.ts +++ b/server/initializers/migrations/0130-user-autoplay-video.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | function up (utils: { | 4 | function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const q = utils.queryInterface | 9 | const q = utils.queryInterface |
diff --git a/server/initializers/migrations/0135-video-channel-actor.ts b/server/initializers/migrations/0135-video-channel-actor.ts index 5ace0f4d2..c0c343384 100644 --- a/server/initializers/migrations/0135-video-channel-actor.ts +++ b/server/initializers/migrations/0135-video-channel-actor.ts | |||
@@ -3,8 +3,8 @@ import { DataType } from 'sequelize-typescript' | |||
3 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 3 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
4 | 4 | ||
5 | async function up (utils: { | 5 | async function up (utils: { |
6 | transaction: Sequelize.Transaction, | 6 | transaction: Sequelize.Transaction |
7 | queryInterface: Sequelize.QueryInterface, | 7 | queryInterface: Sequelize.QueryInterface |
8 | sequelize: Sequelize.Sequelize | 8 | sequelize: Sequelize.Sequelize |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | // Create actor table | 10 | // Create actor table |
@@ -64,10 +64,10 @@ async function up (utils: { | |||
64 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 64 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
65 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 65 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
66 | ) | 66 | ) |
67 | SELECT | 67 | SELECT |
68 | 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 68 | 'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
69 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 69 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
70 | FROM account | 70 | FROM account |
71 | WHERE "applicationId" IS NOT NULL | 71 | WHERE "applicationId" IS NOT NULL |
72 | ` | 72 | ` |
73 | await utils.sequelize.query(query1) | 73 | await utils.sequelize.query(query1) |
@@ -79,10 +79,10 @@ async function up (utils: { | |||
79 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 79 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
80 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 80 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
81 | ) | 81 | ) |
82 | SELECT | 82 | SELECT |
83 | 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 83 | 'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
84 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 84 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
85 | FROM account | 85 | FROM account |
86 | WHERE "applicationId" IS NULL | 86 | WHERE "applicationId" IS NULL |
87 | ` | 87 | ` |
88 | await utils.sequelize.query(query2) | 88 | await utils.sequelize.query(query2) |
@@ -108,17 +108,17 @@ async function up (utils: { | |||
108 | } | 108 | } |
109 | 109 | ||
110 | { | 110 | { |
111 | const query = ` | 111 | const query = ` |
112 | INSERT INTO actor | 112 | INSERT INTO actor |
113 | ( | 113 | ( |
114 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", | 114 | type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", |
115 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" | 115 | "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" |
116 | ) | 116 | ) |
117 | SELECT | 117 | SELECT |
118 | 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', | 118 | 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', |
119 | "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following', | 119 | "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following', |
120 | null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" | 120 | null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" |
121 | FROM "videoChannel" | 121 | FROM "videoChannel" |
122 | INNER JOIN "account" on "videoChannel"."accountId" = "account".id | 122 | INNER JOIN "account" on "videoChannel"."accountId" = "account".id |
123 | ` | 123 | ` |
124 | await utils.sequelize.query(query) | 124 | await utils.sequelize.query(query) |
@@ -157,13 +157,13 @@ async function up (utils: { | |||
157 | } | 157 | } |
158 | 158 | ||
159 | { | 159 | { |
160 | const query1 = `UPDATE "actorFollow" | 160 | const query1 = `UPDATE "actorFollow" |
161 | SET "actorId" = | 161 | SET "actorId" = |
162 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")` | 162 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")` |
163 | await utils.sequelize.query(query1) | 163 | await utils.sequelize.query(query1) |
164 | 164 | ||
165 | const query2 = `UPDATE "actorFollow" | 165 | const query2 = `UPDATE "actorFollow" |
166 | SET "targetActorId" = | 166 | SET "targetActorId" = |
167 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")` | 167 | (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")` |
168 | 168 | ||
169 | await utils.sequelize.query(query2) | 169 | await utils.sequelize.query(query2) |
@@ -189,8 +189,8 @@ async function up (utils: { | |||
189 | await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey') | 189 | await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey') |
190 | } | 190 | } |
191 | 191 | ||
192 | const query = `UPDATE "videoShare" | 192 | const query = `UPDATE "videoShare" |
193 | SET "actorId" = | 193 | SET "actorId" = |
194 | (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")` | 194 | (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")` |
195 | await utils.sequelize.query(query) | 195 | await utils.sequelize.query(query) |
196 | 196 | ||
diff --git a/server/initializers/migrations/0140-actor-url.ts b/server/initializers/migrations/0140-actor-url.ts index 020499391..d790988ad 100644 --- a/server/initializers/migrations/0140-actor-url.ts +++ b/server/initializers/migrations/0140-actor-url.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { WEBSERVER } from '../constants' | 2 | import { WEBSERVER } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const toReplace = WEBSERVER.HOSTNAME + ':443' | 9 | const toReplace = WEBSERVER.HOSTNAME + ':443' |
diff --git a/server/initializers/migrations/0145-delete-author.ts b/server/initializers/migrations/0145-delete-author.ts index cb23d1cc2..6c9427997 100644 --- a/server/initializers/migrations/0145-delete-author.ts +++ b/server/initializers/migrations/0145-delete-author.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.dropTable('Authors') | 8 | await utils.queryInterface.dropTable('Authors') |
diff --git a/server/initializers/migrations/0150-avatar-cascade.ts b/server/initializers/migrations/0150-avatar-cascade.ts index 821696717..fb3b25773 100644 --- a/server/initializers/migrations/0150-avatar-cascade.ts +++ b/server/initializers/migrations/0150-avatar-cascade.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') | 8 | await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') |
diff --git a/server/initializers/migrations/0155-video-comments-enabled.ts b/server/initializers/migrations/0155-video-comments-enabled.ts index 6949d3a0c..691640b35 100644 --- a/server/initializers/migrations/0155-video-comments-enabled.ts +++ b/server/initializers/migrations/0155-video-comments-enabled.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { Migration } from '../../models/migrations' | 2 | import { Migration } from '../../models/migrations' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0160-account-route.ts b/server/initializers/migrations/0160-account-route.ts index cab4c72f1..97469948b 100644 --- a/server/initializers/migrations/0160-account-route.ts +++ b/server/initializers/migrations/0160-account-route.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0165-video-route.ts b/server/initializers/migrations/0165-video-route.ts index 56d98bc69..aa7c75128 100644 --- a/server/initializers/migrations/0165-video-route.ts +++ b/server/initializers/migrations/0165-video-route.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0170-actor-follow-score.ts b/server/initializers/migrations/0170-actor-follow-score.ts index a12b35da9..901a3c799 100644 --- a/server/initializers/migrations/0170-actor-follow-score.ts +++ b/server/initializers/migrations/0170-actor-follow-score.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { ACTOR_FOLLOW_SCORE } from '../constants' | 2 | import { ACTOR_FOLLOW_SCORE } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('server', 'score') | 9 | await utils.queryInterface.removeColumn('server', 'score') |
diff --git a/server/initializers/migrations/0175-actor-follow-counts.ts b/server/initializers/migrations/0175-actor-follow-counts.ts index 4fb524181..d7853f8dc 100644 --- a/server/initializers/migrations/0175-actor-follow-counts.ts +++ b/server/initializers/migrations/0175-actor-follow-counts.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | const query = 'UPDATE "actor" SET ' + | 8 | const query = 'UPDATE "actor" SET ' + |
diff --git a/server/initializers/migrations/0180-job-table-delete.ts b/server/initializers/migrations/0180-job-table-delete.ts index df29145d0..fb48a0c9d 100644 --- a/server/initializers/migrations/0180-job-table-delete.ts +++ b/server/initializers/migrations/0180-job-table-delete.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | await utils.queryInterface.dropTable('job') | 8 | await utils.queryInterface.dropTable('job') |
diff --git a/server/initializers/migrations/0185-video-share-url.ts b/server/initializers/migrations/0185-video-share-url.ts index f7eeb0878..f59931e0f 100644 --- a/server/initializers/migrations/0185-video-share-url.ts +++ b/server/initializers/migrations/0185-video-share-url.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0190-video-comment-unique-url.ts b/server/initializers/migrations/0190-video-comment-unique-url.ts index b196c9352..a8769ed41 100644 --- a/server/initializers/migrations/0190-video-comment-unique-url.ts +++ b/server/initializers/migrations/0190-video-comment-unique-url.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0195-support.ts b/server/initializers/migrations/0195-support.ts index 3b9eabe79..3f7c75dce 100644 --- a/server/initializers/migrations/0195-support.ts +++ b/server/initializers/migrations/0195-support.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0200-video-published-at.ts b/server/initializers/migrations/0200-video-published-at.ts index 1701ea07a..d8c7b42a7 100644 --- a/server/initializers/migrations/0200-video-published-at.ts +++ b/server/initializers/migrations/0200-video-published-at.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0205-user-nsfw-policy.ts b/server/initializers/migrations/0205-user-nsfw-policy.ts index d0f6e8962..9c2786f12 100644 --- a/server/initializers/migrations/0205-user-nsfw-policy.ts +++ b/server/initializers/migrations/0205-user-nsfw-policy.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0210-video-language.ts b/server/initializers/migrations/0210-video-language.ts index ca95c7527..ee4ce9266 100644 --- a/server/initializers/migrations/0210-video-language.ts +++ b/server/initializers/migrations/0210-video-language.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { CONSTRAINTS_FIELDS } from '../constants' | 2 | import { CONSTRAINTS_FIELDS } from '../constants' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0215-video-support-length.ts b/server/initializers/migrations/0215-video-support-length.ts index ba395050f..26c0ca700 100644 --- a/server/initializers/migrations/0215-video-support-length.ts +++ b/server/initializers/migrations/0215-video-support-length.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | { | 8 | { |
diff --git a/server/initializers/migrations/0255-video-blacklist-reason.ts b/server/initializers/migrations/0255-video-blacklist-reason.ts index 69d6efb9e..7de982f93 100644 --- a/server/initializers/migrations/0255-video-blacklist-reason.ts +++ b/server/initializers/migrations/0255-video-blacklist-reason.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { VideoAbuseState } from '../../../shared/models/videos' | ||
3 | 2 | ||
4 | async function up (utils: { | 3 | async function up (utils: { |
5 | transaction: Sequelize.Transaction | 4 | transaction: Sequelize.Transaction |
diff --git a/server/initializers/migrations/0285-description-support.ts b/server/initializers/migrations/0285-description-support.ts index 85ef4ef39..aab3a938f 100644 --- a/server/initializers/migrations/0285-description-support.ts +++ b/server/initializers/migrations/0285-description-support.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0290-account-video-rate-url.ts b/server/initializers/migrations/0290-account-video-rate-url.ts index bdabf2929..b974b1a81 100644 --- a/server/initializers/migrations/0290-account-video-rate-url.ts +++ b/server/initializers/migrations/0290-account-video-rate-url.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0295-video-file-extname.ts b/server/initializers/migrations/0295-video-file-extname.ts index dbf249f66..e1999b072 100644 --- a/server/initializers/migrations/0295-video-file-extname.ts +++ b/server/initializers/migrations/0295-video-file-extname.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0300-user-videos-history-enabled.ts b/server/initializers/migrations/0300-user-videos-history-enabled.ts index aa5fc21fb..5e35e14ba 100644 --- a/server/initializers/migrations/0300-user-videos-history-enabled.ts +++ b/server/initializers/migrations/0300-user-videos-history-enabled.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0305-fix-unfederated-videos.ts b/server/initializers/migrations/0305-fix-unfederated-videos.ts index be206601f..9c5d56b7b 100644 --- a/server/initializers/migrations/0305-fix-unfederated-videos.ts +++ b/server/initializers/migrations/0305-fix-unfederated-videos.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0310-drop-unused-video-indexes.ts b/server/initializers/migrations/0310-drop-unused-video-indexes.ts index d51f430c0..181858d3d 100644 --- a/server/initializers/migrations/0310-drop-unused-video-indexes.ts +++ b/server/initializers/migrations/0310-drop-unused-video-indexes.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const indexNames = [ | 9 | const indexNames = [ |
diff --git a/server/initializers/migrations/0315-user-notifications.ts b/server/initializers/migrations/0315-user-notifications.ts index 8284c58a0..0e3f4fbef 100644 --- a/server/initializers/migrations/0315-user-notifications.ts +++ b/server/initializers/migrations/0315-user-notifications.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0320-blacklist-unfederate.ts b/server/initializers/migrations/0320-blacklist-unfederate.ts index 6fb7bbb90..41de41c55 100644 --- a/server/initializers/migrations/0320-blacklist-unfederate.ts +++ b/server/initializers/migrations/0320-blacklist-unfederate.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0325-video-abuse-fields.ts b/server/initializers/migrations/0325-video-abuse-fields.ts index fca6d666f..d88724a20 100644 --- a/server/initializers/migrations/0325-video-abuse-fields.ts +++ b/server/initializers/migrations/0325-video-abuse-fields.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0330-video-streaming-playlist.ts b/server/initializers/migrations/0330-video-streaming-playlist.ts index c85a762ab..f75541a7f 100644 --- a/server/initializers/migrations/0330-video-streaming-playlist.ts +++ b/server/initializers/migrations/0330-video-streaming-playlist.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0335-video-downloading-enabled.ts b/server/initializers/migrations/0335-video-downloading-enabled.ts index e79466447..c745f1f02 100644 --- a/server/initializers/migrations/0335-video-downloading-enabled.ts +++ b/server/initializers/migrations/0335-video-downloading-enabled.ts | |||
@@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize' | |||
2 | import { Migration } from '../../models/migrations' | 2 | import { Migration } from '../../models/migrations' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize | 7 | sequelize: Sequelize.Sequelize |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0340-add-originally-published-at.ts b/server/initializers/migrations/0340-add-originally-published-at.ts index fe4f4a5f9..7cbc14ab5 100644 --- a/server/initializers/migrations/0340-add-originally-published-at.ts +++ b/server/initializers/migrations/0340-add-originally-published-at.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize | 6 | sequelize: Sequelize.Sequelize |
7 | }): Promise<void> { | 7 | }): Promise<void> { |
8 | 8 | ||
diff --git a/server/initializers/migrations/0345-video-playlists.ts b/server/initializers/migrations/0345-video-playlists.ts index de69f5b9e..76813f93f 100644 --- a/server/initializers/migrations/0345-video-playlists.ts +++ b/server/initializers/migrations/0345-video-playlists.ts | |||
@@ -4,8 +4,8 @@ import * as uuidv4 from 'uuid/v4' | |||
4 | import { WEBSERVER } from '../constants' | 4 | import { WEBSERVER } from '../constants' |
5 | 5 | ||
6 | async function up (utils: { | 6 | async function up (utils: { |
7 | transaction: Sequelize.Transaction, | 7 | transaction: Sequelize.Transaction |
8 | queryInterface: Sequelize.QueryInterface, | 8 | queryInterface: Sequelize.QueryInterface |
9 | sequelize: Sequelize.Sequelize | 9 | sequelize: Sequelize.Sequelize |
10 | }): Promise<void> { | 10 | }): Promise<void> { |
11 | const transaction = utils.transaction | 11 | const transaction = utils.transaction |
diff --git a/server/initializers/migrations/0350-video-blacklist-type.ts b/server/initializers/migrations/0350-video-blacklist-type.ts index 4849020ef..f79ae5ec7 100644 --- a/server/initializers/migrations/0350-video-blacklist-type.ts +++ b/server/initializers/migrations/0350-video-blacklist-type.ts | |||
@@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize' | |||
2 | import { VideoBlacklistType } from '../../../shared/models/videos' | 2 | import { VideoBlacklistType } from '../../../shared/models/videos' |
3 | 3 | ||
4 | async function up (utils: { | 4 | async function up (utils: { |
5 | transaction: Sequelize.Transaction, | 5 | transaction: Sequelize.Transaction |
6 | queryInterface: Sequelize.QueryInterface, | 6 | queryInterface: Sequelize.QueryInterface |
7 | sequelize: Sequelize.Sequelize, | 7 | sequelize: Sequelize.Sequelize |
8 | db: any | 8 | db: any |
9 | }): Promise<void> { | 9 | }): Promise<void> { |
10 | { | 10 | { |
diff --git a/server/initializers/migrations/0355-p2p-peer-version.ts b/server/initializers/migrations/0355-p2p-peer-version.ts index 18f23d9b7..89af28d07 100644 --- a/server/initializers/migrations/0355-p2p-peer-version.ts +++ b/server/initializers/migrations/0355-p2p-peer-version.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | 9 | ||
diff --git a/server/initializers/migrations/0360-notification-instance-follower.ts b/server/initializers/migrations/0360-notification-instance-follower.ts index 05caf8e1d..6f9a01a9c 100644 --- a/server/initializers/migrations/0360-notification-instance-follower.ts +++ b/server/initializers/migrations/0360-notification-instance-follower.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0365-user-admin-flags.ts b/server/initializers/migrations/0365-user-admin-flags.ts index 20553100a..b705387da 100644 --- a/server/initializers/migrations/0365-user-admin-flags.ts +++ b/server/initializers/migrations/0365-user-admin-flags.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0370-thumbnail.ts b/server/initializers/migrations/0370-thumbnail.ts index 384ca1a15..07c25436a 100644 --- a/server/initializers/migrations/0370-thumbnail.ts +++ b/server/initializers/migrations/0370-thumbnail.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0375-account-description.ts b/server/initializers/migrations/0375-account-description.ts index 1258563fd..f9af942e0 100644 --- a/server/initializers/migrations/0375-account-description.ts +++ b/server/initializers/migrations/0375-account-description.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0380-cleanup-timestamps.ts b/server/initializers/migrations/0380-cleanup-timestamps.ts index 2a9fd6f02..18ecfb997 100644 --- a/server/initializers/migrations/0380-cleanup-timestamps.ts +++ b/server/initializers/migrations/0380-cleanup-timestamps.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | try { | 9 | try { |
diff --git a/server/initializers/migrations/0385-remove-actor-uuid.ts b/server/initializers/migrations/0385-remove-actor-uuid.ts index 032c0562b..eefbc386b 100644 --- a/server/initializers/migrations/0385-remove-actor-uuid.ts +++ b/server/initializers/migrations/0385-remove-actor-uuid.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.queryInterface.removeColumn('actor', 'uuid') | 9 | await utils.queryInterface.removeColumn('actor', 'uuid') |
diff --git a/server/initializers/migrations/0390-user-pending-email.ts b/server/initializers/migrations/0390-user-pending-email.ts index 5ca871746..9cf0affa5 100644 --- a/server/initializers/migrations/0390-user-pending-email.ts +++ b/server/initializers/migrations/0390-user-pending-email.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0395-user-video-languages.ts b/server/initializers/migrations/0395-user-video-languages.ts index 278698bf4..9c24fbc9a 100644 --- a/server/initializers/migrations/0395-user-video-languages.ts +++ b/server/initializers/migrations/0395-user-video-languages.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0400-user-theme.ts b/server/initializers/migrations/0400-user-theme.ts index f74d76115..7addb1bb3 100644 --- a/server/initializers/migrations/0400-user-theme.ts +++ b/server/initializers/migrations/0400-user-theme.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0405-plugin.ts b/server/initializers/migrations/0405-plugin.ts index c55b81960..5c290b986 100644 --- a/server/initializers/migrations/0405-plugin.ts +++ b/server/initializers/migrations/0405-plugin.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0410-video-playlist-element.ts b/server/initializers/migrations/0410-video-playlist-element.ts index f536632a2..1b4692357 100644 --- a/server/initializers/migrations/0410-video-playlist-element.ts +++ b/server/initializers/migrations/0410-video-playlist-element.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0415-thumbnail-auto-generated.ts b/server/initializers/migrations/0415-thumbnail-auto-generated.ts index f822a4c05..98d563c88 100644 --- a/server/initializers/migrations/0415-thumbnail-auto-generated.ts +++ b/server/initializers/migrations/0415-thumbnail-auto-generated.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0420-avatar-lazy.ts b/server/initializers/migrations/0420-avatar-lazy.ts index 5fc57aac2..5c74819d2 100644 --- a/server/initializers/migrations/0420-avatar-lazy.ts +++ b/server/initializers/migrations/0420-avatar-lazy.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0425-nullable-actor-fields.ts b/server/initializers/migrations/0425-nullable-actor-fields.ts index 4e5f9e6ab..720b99ccc 100644 --- a/server/initializers/migrations/0425-nullable-actor-fields.ts +++ b/server/initializers/migrations/0425-nullable-actor-fields.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | const data = { | 9 | const data = { |
diff --git a/server/initializers/migrations/0430-auto-follow-notification-setting.ts b/server/initializers/migrations/0430-auto-follow-notification-setting.ts index 034bdd46d..1734828a4 100644 --- a/server/initializers/migrations/0430-auto-follow-notification-setting.ts +++ b/server/initializers/migrations/0430-auto-follow-notification-setting.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0435-user-modals.ts b/server/initializers/migrations/0435-user-modals.ts index 5c2aa85b5..737440e9b 100644 --- a/server/initializers/migrations/0435-user-modals.ts +++ b/server/initializers/migrations/0435-user-modals.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0440-user-auto-play-next-video.ts b/server/initializers/migrations/0440-user-auto-play-next-video.ts index f0baafe7b..f3f663f59 100644 --- a/server/initializers/migrations/0440-user-auto-play-next-video.ts +++ b/server/initializers/migrations/0440-user-auto-play-next-video.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0445-shared-inbox-optional.ts b/server/initializers/migrations/0445-shared-inbox-optional.ts index dad2d6569..ade1a2a57 100644 --- a/server/initializers/migrations/0445-shared-inbox-optional.ts +++ b/server/initializers/migrations/0445-shared-inbox-optional.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0450-streaming-playlist-files.ts b/server/initializers/migrations/0450-streaming-playlist-files.ts index 460dac8be..08e2e3989 100644 --- a/server/initializers/migrations/0450-streaming-playlist-files.ts +++ b/server/initializers/migrations/0450-streaming-playlist-files.ts | |||
@@ -1,15 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import { join } from 'path' | ||
3 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, WEBSERVER } from '@server/initializers/constants' | ||
4 | import { CONFIG } from '@server/initializers/config' | ||
5 | import { pathExists, stat, writeFile } from 'fs-extra' | ||
6 | import * as parseTorrent from 'parse-torrent' | ||
7 | import { createTorrentPromise } from '@server/helpers/webtorrent' | ||
8 | 2 | ||
9 | async function up (utils: { | 3 | async function up (utils: { |
10 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
11 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
12 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
13 | db: any | 7 | db: any |
14 | }): Promise<void> { | 8 | }): Promise<void> { |
15 | { | 9 | { |
@@ -42,8 +36,8 @@ async function up (utils: { | |||
42 | { | 36 | { |
43 | const query = 'insert into "videoFile" ' + | 37 | const query = 'insert into "videoFile" ' + |
44 | '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + | 38 | '(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' + |
45 | '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", "videoFile"."fps", ' + | 39 | '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", ' + |
46 | '"videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + | 40 | '"videoFile"."fps", "videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' + |
47 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' | 41 | 'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)' |
48 | 42 | ||
49 | await utils.sequelize.query(query, { transaction: utils.transaction }) | 43 | await utils.sequelize.query(query, { transaction: utils.transaction }) |
diff --git a/server/initializers/migrations/0455-soft-delete-video-comments.ts b/server/initializers/migrations/0455-soft-delete-video-comments.ts index bcfb97b56..00e56015f 100644 --- a/server/initializers/migrations/0455-soft-delete-video-comments.ts +++ b/server/initializers/migrations/0455-soft-delete-video-comments.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0460-user-playlist-autoplay.ts b/server/initializers/migrations/0460-user-playlist-autoplay.ts index 3067ac1a4..d6f5081ab 100644 --- a/server/initializers/migrations/0460-user-playlist-autoplay.ts +++ b/server/initializers/migrations/0460-user-playlist-autoplay.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0465-thumbnail-file-url-length.ts b/server/initializers/migrations/0465-thumbnail-file-url-length.ts index db8c85c29..84a4fa0ba 100644 --- a/server/initializers/migrations/0465-thumbnail-file-url-length.ts +++ b/server/initializers/migrations/0465-thumbnail-file-url-length.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | { | 9 | { |
diff --git a/server/initializers/migrations/0470-cleaup-indexes.ts b/server/initializers/migrations/0470-cleaup-indexes.ts index 53e401c2b..7365c30f8 100644 --- a/server/initializers/migrations/0470-cleaup-indexes.ts +++ b/server/initializers/migrations/0470-cleaup-indexes.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | async function up (utils: { | 3 | async function up (utils: { |
4 | transaction: Sequelize.Transaction, | 4 | transaction: Sequelize.Transaction |
5 | queryInterface: Sequelize.QueryInterface, | 5 | queryInterface: Sequelize.QueryInterface |
6 | sequelize: Sequelize.Sequelize, | 6 | sequelize: Sequelize.Sequelize |
7 | db: any | 7 | db: any |
8 | }): Promise<void> { | 8 | }): Promise<void> { |
9 | await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;') | 9 | await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;') |
diff --git a/server/initializers/migrations/0475-redundancy-expires-on.ts b/server/initializers/migrations/0475-redundancy-expires-on.ts new file mode 100644 index 000000000..edbddba37 --- /dev/null +++ b/server/initializers/migrations/0475-redundancy-expires-on.ts | |||
@@ -0,0 +1,27 @@ | |||
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 | { | ||
10 | const data = { | ||
11 | type: Sequelize.DATE, | ||
12 | allowNull: true, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.changeColumn('videoRedundancy', 'expiresOn', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrations/0480-caption-file-url.ts b/server/initializers/migrations/0480-caption-file-url.ts new file mode 100644 index 000000000..1f88206d3 --- /dev/null +++ b/server/initializers/migrations/0480-caption-file-url.ts | |||
@@ -0,0 +1,27 @@ | |||
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 | { | ||
10 | const data = { | ||
11 | type: Sequelize.STRING, | ||
12 | allowNull: true, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.addColumn('videoCaption', 'fileUrl', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 1cb0116b7..77203ae24 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts | |||
@@ -20,7 +20,7 @@ async function migrate () { | |||
20 | } | 20 | } |
21 | 21 | ||
22 | const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options) | 22 | const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options) |
23 | if (rows && rows[0] && rows[0].migrationVersion) { | 23 | if (rows?.[0]?.migrationVersion) { |
24 | actualVersion = rows[0].migrationVersion | 24 | actualVersion = rows[0].migrationVersion |
25 | } | 25 | } |
26 | 26 | ||
@@ -60,7 +60,7 @@ export { | |||
60 | async function getMigrationScripts () { | 60 | async function getMigrationScripts () { |
61 | const files = await readdir(path.join(__dirname, 'migrations')) | 61 | const files = await readdir(path.join(__dirname, 'migrations')) |
62 | const filesToMigrate: { | 62 | const filesToMigrate: { |
63 | version: string, | 63 | version: string |
64 | script: string | 64 | script: string |
65 | }[] = [] | 65 | }[] = [] |
66 | 66 | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 0b21de0ca..9eabef4b0 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { Transaction } from 'sequelize' | 2 | import { Transaction } from 'sequelize' |
3 | import * as url from 'url' | 3 | import { URL } from 'url' |
4 | import * as uuidv4 from 'uuid/v4' | 4 | import * as uuidv4 from 'uuid/v4' |
5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' | 5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' |
6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
@@ -33,9 +33,9 @@ import { | |||
33 | MActorFull, | 33 | MActorFull, |
34 | MActorFullActor, | 34 | MActorFullActor, |
35 | MActorId, | 35 | MActorId, |
36 | MChannel, | 36 | MChannel |
37 | MChannelAccountDefault | ||
38 | } from '../../typings/models' | 37 | } from '../../typings/models' |
38 | import { extname } from 'path' | ||
39 | 39 | ||
40 | // Set account keys, this could be long so process after the account creation and do not block the client | 40 | // Set account keys, this could be long so process after the account creation and do not block the client |
41 | function setAsyncActorKeys <T extends MActor> (actor: T) { | 41 | function setAsyncActorKeys <T extends MActor> (actor: T) { |
@@ -121,13 +121,13 @@ async function getOrCreateActorAndServerAndModel ( | |||
121 | 121 | ||
122 | if ((created === true || refreshed === true) && updateCollections === true) { | 122 | if ((created === true || refreshed === true) && updateCollections === true) { |
123 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } | 123 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } |
124 | await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 124 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) |
125 | } | 125 | } |
126 | 126 | ||
127 | // We created a new account: fetch the playlists | 127 | // We created a new account: fetch the playlists |
128 | if (created === true && actor.Account && accountPlaylistsUrl) { | 128 | if (created === true && actor.Account && accountPlaylistsUrl) { |
129 | const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } | 129 | const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } |
130 | await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 130 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) |
131 | } | 131 | } |
132 | 132 | ||
133 | return actorRefreshed | 133 | return actorRefreshed |
@@ -215,20 +215,28 @@ async function fetchActorTotalItems (url: string) { | |||
215 | } | 215 | } |
216 | } | 216 | } |
217 | 217 | ||
218 | async function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { | 218 | function getAvatarInfoIfExists (actorJSON: ActivityPubActor) { |
219 | if ( | 219 | const mimetypes = MIMETYPES.IMAGE |
220 | actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined && | 220 | const icon = actorJSON.icon |
221 | isActivityPubUrlValid(actorJSON.icon.url) | ||
222 | ) { | ||
223 | const extension = MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] | ||
224 | 221 | ||
225 | return { | 222 | if (!icon || icon.type !== 'Image' || !isActivityPubUrlValid(icon.url)) return undefined |
226 | name: uuidv4() + extension, | 223 | |
227 | fileUrl: actorJSON.icon.url | 224 | let extension: string |
228 | } | 225 | |
226 | if (icon.mediaType) { | ||
227 | extension = mimetypes.MIMETYPE_EXT[icon.mediaType] | ||
228 | } else { | ||
229 | const tmp = extname(icon.url) | ||
230 | |||
231 | if (mimetypes.EXT_MIMETYPE[tmp] !== undefined) extension = tmp | ||
229 | } | 232 | } |
230 | 233 | ||
231 | return undefined | 234 | if (!extension) return undefined |
235 | |||
236 | return { | ||
237 | name: uuidv4() + extension, | ||
238 | fileUrl: icon.url | ||
239 | } | ||
232 | } | 240 | } |
233 | 241 | ||
234 | async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) { | 242 | async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) { |
@@ -271,7 +279,10 @@ async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannel | |||
271 | 279 | ||
272 | if (statusCode === 404) { | 280 | if (statusCode === 404) { |
273 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) | 281 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) |
274 | actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() | 282 | actor.Account |
283 | ? await actor.Account.destroy() | ||
284 | : await actor.VideoChannel.destroy() | ||
285 | |||
275 | return { actor: undefined, refreshed: false } | 286 | return { actor: undefined, refreshed: false } |
276 | } | 287 | } |
277 | 288 | ||
@@ -337,14 +348,14 @@ function saveActorAndServerAndModelIfNotExist ( | |||
337 | ownerActor?: MActorFullActor, | 348 | ownerActor?: MActorFullActor, |
338 | t?: Transaction | 349 | t?: Transaction |
339 | ): Bluebird<MActorFullActor> | Promise<MActorFullActor> { | 350 | ): Bluebird<MActorFullActor> | Promise<MActorFullActor> { |
340 | let actor = result.actor | 351 | const actor = result.actor |
341 | 352 | ||
342 | if (t !== undefined) return save(t) | 353 | if (t !== undefined) return save(t) |
343 | 354 | ||
344 | return sequelizeTypescript.transaction(t => save(t)) | 355 | return sequelizeTypescript.transaction(t => save(t)) |
345 | 356 | ||
346 | async function save (t: Transaction) { | 357 | async function save (t: Transaction) { |
347 | const actorHost = url.parse(actor.url).host | 358 | const actorHost = new URL(actor.url).host |
348 | 359 | ||
349 | const serverOptions = { | 360 | const serverOptions = { |
350 | where: { | 361 | where: { |
@@ -402,7 +413,7 @@ type FetchRemoteActorResult = { | |||
402 | support?: string | 413 | support?: string |
403 | playlists?: string | 414 | playlists?: string |
404 | avatar?: { | 415 | avatar?: { |
405 | name: string, | 416 | name: string |
406 | fileUrl: string | 417 | fileUrl: string |
407 | } | 418 | } |
408 | attributedTo: ActivityPubAttributedTo[] | 419 | attributedTo: ActivityPubAttributedTo[] |
diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index f2ab54cf7..9933ae2b5 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts | |||
@@ -4,11 +4,11 @@ import { ACTIVITY_PUB } from '../../initializers/constants' | |||
4 | import { ActorModel } from '../../models/activitypub/actor' | 4 | import { ActorModel } from '../../models/activitypub/actor' |
5 | import { VideoModel } from '../../models/video/video' | 5 | import { VideoModel } from '../../models/video/video' |
6 | import { VideoShareModel } from '../../models/video/video-share' | 6 | import { VideoShareModel } from '../../models/video/video-share' |
7 | import { MActorFollowersUrl, MActorLight, MCommentOwner, MCommentOwnerVideo, MVideo, MVideoAccountLight } from '../../typings/models' | 7 | import { MActorFollowersUrl, MActorLight, MActorUrl, MCommentOwner, MCommentOwnerVideo, MVideoId } from '../../typings/models' |
8 | 8 | ||
9 | function getRemoteVideoAudience (video: MVideoAccountLight, actorsInvolvedInVideo: MActorFollowersUrl[]): ActivityAudience { | 9 | function getRemoteVideoAudience (accountActor: MActorUrl, actorsInvolvedInVideo: MActorFollowersUrl[]): ActivityAudience { |
10 | return { | 10 | return { |
11 | to: [ video.VideoChannel.Account.Actor.url ], | 11 | to: [ accountActor.url ], |
12 | cc: actorsInvolvedInVideo.map(a => a.followersUrl) | 12 | cc: actorsInvolvedInVideo.map(a => a.followersUrl) |
13 | } | 13 | } |
14 | } | 14 | } |
@@ -48,7 +48,7 @@ function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[ | |||
48 | } | 48 | } |
49 | } | 49 | } |
50 | 50 | ||
51 | async function getActorsInvolvedInVideo (video: MVideo, t: Transaction) { | 51 | async function getActorsInvolvedInVideo (video: MVideoId, t: Transaction) { |
52 | const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t) | 52 | const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t) |
53 | 53 | ||
54 | const videoAll = video as VideoModel | 54 | const videoAll = video as VideoModel |
diff --git a/server/lib/activitypub/cache-file.ts b/server/lib/activitypub/cache-file.ts index 65b2dcb49..8252e95e9 100644 --- a/server/lib/activitypub/cache-file.ts +++ b/server/lib/activitypub/cache-file.ts | |||
@@ -13,7 +13,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject | |||
13 | if (!playlist) throw new Error('Cannot find HLS playlist of video ' + video.url) | 13 | if (!playlist) throw new Error('Cannot find HLS playlist of video ' + video.url) |
14 | 14 | ||
15 | return { | 15 | return { |
16 | expiresOn: new Date(cacheFileObject.expires), | 16 | expiresOn: cacheFileObject.expires ? new Date(cacheFileObject.expires) : null, |
17 | url: cacheFileObject.id, | 17 | url: cacheFileObject.id, |
18 | fileUrl: url.href, | 18 | fileUrl: url.href, |
19 | strategy: null, | 19 | strategy: null, |
@@ -30,7 +30,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject | |||
30 | if (!videoFile) throw new Error(`Cannot find video file ${url.height} ${url.fps} of video ${video.url}`) | 30 | if (!videoFile) throw new Error(`Cannot find video file ${url.height} ${url.fps} of video ${video.url}`) |
31 | 31 | ||
32 | return { | 32 | return { |
33 | expiresOn: new Date(cacheFileObject.expires), | 33 | expiresOn: cacheFileObject.expires ? new Date(cacheFileObject.expires) : null, |
34 | url: cacheFileObject.id, | 34 | url: cacheFileObject.id, |
35 | fileUrl: url.href, | 35 | fileUrl: url.href, |
36 | strategy: null, | 36 | strategy: null, |
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts index 9e469e3e6..eeafdf4ba 100644 --- a/server/lib/activitypub/crawl.ts +++ b/server/lib/activitypub/crawl.ts | |||
@@ -3,7 +3,7 @@ import { doRequest } from '../../helpers/requests' | |||
3 | import { logger } from '../../helpers/logger' | 3 | import { logger } from '../../helpers/logger' |
4 | import * as Bluebird from 'bluebird' | 4 | import * as Bluebird from 'bluebird' |
5 | import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' | 5 | import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' |
6 | import { parse } from 'url' | 6 | import { URL } from 'url' |
7 | 7 | ||
8 | type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) | 8 | type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>) |
9 | type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) | 9 | type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>) |
@@ -24,7 +24,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T> | |||
24 | const response = await doRequest<ActivityPubOrderedCollection<T>>(options) | 24 | const response = await doRequest<ActivityPubOrderedCollection<T>>(options) |
25 | const firstBody = response.body | 25 | const firstBody = response.body |
26 | 26 | ||
27 | let limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT | 27 | const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT |
28 | let i = 0 | 28 | let i = 0 |
29 | let nextLink = firstBody.first | 29 | let nextLink = firstBody.first |
30 | while (nextLink && i < limit) { | 30 | while (nextLink && i < limit) { |
@@ -32,7 +32,7 @@ async function crawlCollectionPage <T> (uri: string, handler: HandlerFunction<T> | |||
32 | 32 | ||
33 | if (typeof nextLink === 'string') { | 33 | if (typeof nextLink === 'string') { |
34 | // Don't crawl ourselves | 34 | // Don't crawl ourselves |
35 | const remoteHost = parse(nextLink).host | 35 | const remoteHost = new URL(nextLink).host |
36 | if (remoteHost === WEBSERVER.HOST) continue | 36 | if (remoteHost === WEBSERVER.HOST) continue |
37 | 37 | ||
38 | options.uri = nextLink | 38 | options.uri = nextLink |
diff --git a/server/lib/activitypub/follow.ts b/server/lib/activitypub/follow.ts index 1abf43cd4..a1c95504e 100644 --- a/server/lib/activitypub/follow.ts +++ b/server/lib/activitypub/follow.ts | |||
@@ -27,7 +27,6 @@ async function autoFollowBackIfNeeded (actorFollow: MActorFollowActors) { | |||
27 | } | 27 | } |
28 | 28 | ||
29 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 29 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
30 | .catch(err => logger.error('Cannot create auto follow back job for %s.', host, err)) | ||
31 | } | 30 | } |
32 | } | 31 | } |
33 | 32 | ||
diff --git a/server/lib/activitypub/process/process-view.ts b/server/lib/activitypub/process/process-view.ts index df29ee968..b3b6c933d 100644 --- a/server/lib/activitypub/process/process-view.ts +++ b/server/lib/activitypub/process/process-view.ts | |||
@@ -23,7 +23,8 @@ async function processCreateView (activity: ActivityView | ActivityCreate, byAct | |||
23 | 23 | ||
24 | const options = { | 24 | const options = { |
25 | videoObject, | 25 | videoObject, |
26 | fetchType: 'only-video' as 'only-video' | 26 | fetchType: 'only-immutable-attributes' as 'only-immutable-attributes', |
27 | allowRefresh: false as false | ||
27 | } | 28 | } |
28 | const { video } = await getOrCreateVideoAndAccountAndChannel(options) | 29 | const { video } = await getOrCreateVideoAndAccountAndChannel(options) |
29 | 30 | ||
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts index 9f0225b64..c4c6b849b 100644 --- a/server/lib/activitypub/send/send-accept.ts +++ b/server/lib/activitypub/send/send-accept.ts | |||
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow' | |||
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { MActor, MActorFollowActors } from '../../../typings/models' | 6 | import { MActor, MActorFollowActors } from '../../../typings/models' |
7 | 7 | ||
8 | async function sendAccept (actorFollow: MActorFollowActors) { | 8 | function sendAccept (actorFollow: MActorFollowActors) { |
9 | const follower = actorFollow.ActorFollower | 9 | const follower = actorFollow.ActorFollower |
10 | const me = actorFollow.ActorFollowing | 10 | const me = actorFollow.ActorFollowing |
11 | 11 | ||
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index a0f33852c..d03b358f1 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -28,7 +28,7 @@ async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, | |||
28 | logger.info('Creating job to send announce %s.', videoShare.url) | 28 | logger.info('Creating job to send announce %s.', videoShare.url) |
29 | 29 | ||
30 | const followersException = [ byActor ] | 30 | const followersException = [ byActor ] |
31 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException) | 31 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException, 'Announce') |
32 | } | 32 | } |
33 | 33 | ||
34 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { | 34 | function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce { |
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index 1709d8348..8bdcf6417 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -16,6 +16,7 @@ import { | |||
16 | MVideoRedundancyFileVideo, | 16 | MVideoRedundancyFileVideo, |
17 | MVideoRedundancyStreamingPlaylistVideo | 17 | MVideoRedundancyStreamingPlaylistVideo |
18 | } from '../../../typings/models' | 18 | } from '../../../typings/models' |
19 | import { ContextType } from '@server/helpers/activitypub' | ||
19 | 20 | ||
20 | async function sendCreateVideo (video: MVideoAP, t: Transaction) { | 21 | async function sendCreateVideo (video: MVideoAP, t: Transaction) { |
21 | if (!video.hasPrivacyForFederation()) return undefined | 22 | if (!video.hasPrivacyForFederation()) return undefined |
@@ -42,7 +43,8 @@ async function sendCreateCacheFile ( | |||
42 | byActor, | 43 | byActor, |
43 | video, | 44 | video, |
44 | url: fileRedundancy.url, | 45 | url: fileRedundancy.url, |
45 | object: fileRedundancy.toActivityPubObject() | 46 | object: fileRedundancy.toActivityPubObject(), |
47 | contextType: 'CacheFile' | ||
46 | }) | 48 | }) |
47 | } | 49 | } |
48 | 50 | ||
@@ -130,11 +132,12 @@ export { | |||
130 | // --------------------------------------------------------------------------- | 132 | // --------------------------------------------------------------------------- |
131 | 133 | ||
132 | async function sendVideoRelatedCreateActivity (options: { | 134 | async function sendVideoRelatedCreateActivity (options: { |
133 | byActor: MActorLight, | 135 | byActor: MActorLight |
134 | video: MVideoAccountLight, | 136 | video: MVideoAccountLight |
135 | url: string, | 137 | url: string |
136 | object: any, | 138 | object: any |
137 | transaction?: Transaction | 139 | transaction?: Transaction |
140 | contextType?: ContextType | ||
138 | }) { | 141 | }) { |
139 | const activityBuilder = (audience: ActivityAudience) => { | 142 | const activityBuilder = (audience: ActivityAudience) => { |
140 | return buildCreateActivity(options.url, options.byActor, options.object, audience) | 143 | return buildCreateActivity(options.url, options.byActor, options.object, audience) |
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts index 6e41f241f..600469c71 100644 --- a/server/lib/activitypub/send/send-dislike.ts +++ b/server/lib/activitypub/send/send-dislike.ts | |||
@@ -6,7 +6,7 @@ import { sendVideoRelatedActivity } from './utils' | |||
6 | import { audiencify, getAudience } from '../audience' | 6 | import { audiencify, getAudience } from '../audience' |
7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' | 7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' |
8 | 8 | ||
9 | async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { |
10 | logger.info('Creating job to dislike %s.', video.url) | 10 | logger.info('Creating job to dislike %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts index da7638a7b..e4e523631 100644 --- a/server/lib/activitypub/send/send-flag.ts +++ b/server/lib/activitypub/send/send-flag.ts | |||
@@ -7,7 +7,7 @@ import { Transaction } from 'sequelize' | |||
7 | import { MActor, MVideoFullLight } from '../../../typings/models' | 7 | import { MActor, MVideoFullLight } from '../../../typings/models' |
8 | import { MVideoAbuseVideo } from '../../../typings/models/video' | 8 | import { MVideoAbuseVideo } from '../../../typings/models/video' |
9 | 9 | ||
10 | async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { | 10 | function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { |
11 | if (!video.VideoChannel.Account.Actor.serverId) return // Local user | 11 | if (!video.VideoChannel.Account.Actor.serverId) return // Local user |
12 | 12 | ||
13 | const url = getVideoAbuseActivityPubUrl(videoAbuse) | 13 | const url = getVideoAbuseActivityPubUrl(videoAbuse) |
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index e84a6f98b..5db252325 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts | |||
@@ -6,7 +6,7 @@ import { audiencify, getAudience } from '../audience' | |||
6 | import { logger } from '../../../helpers/logger' | 6 | import { logger } from '../../../helpers/logger' |
7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' | 7 | import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' |
8 | 8 | ||
9 | async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { | 9 | function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { |
10 | logger.info('Creating job to like %s.', video.url) | 10 | logger.info('Creating job to like %s.', video.url) |
11 | 11 | ||
12 | const activityBuilder = (audience: ActivityAudience) => { | 12 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts index 4258a3c36..643c468a9 100644 --- a/server/lib/activitypub/send/send-reject.ts +++ b/server/lib/activitypub/send/send-reject.ts | |||
@@ -5,7 +5,7 @@ import { buildFollowActivity } from './send-follow' | |||
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { MActor } from '../../../typings/models' | 6 | import { MActor } from '../../../typings/models' |
7 | 7 | ||
8 | async function sendReject (follower: MActor, following: MActor) { | 8 | function sendReject (follower: MActor, following: MActor) { |
9 | if (!follower.serverId) { // This should never happen | 9 | if (!follower.serverId) { // This should never happen |
10 | logger.warn('Do not sending reject to local follower.') | 10 | logger.warn('Do not sending reject to local follower.') |
11 | return | 11 | return |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index e9ab5b3c5..33f1d4921 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -28,7 +28,7 @@ import { | |||
28 | MVideoShare | 28 | MVideoShare |
29 | } from '../../../typings/models' | 29 | } from '../../../typings/models' |
30 | 30 | ||
31 | async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { | 31 | function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { |
32 | const me = actorFollow.ActorFollower | 32 | const me = actorFollow.ActorFollower |
33 | const following = actorFollow.ActorFollowing | 33 | const following = actorFollow.ActorFollowing |
34 | 34 | ||
@@ -118,10 +118,10 @@ function undoActivityData ( | |||
118 | } | 118 | } |
119 | 119 | ||
120 | async function sendUndoVideoRelatedActivity (options: { | 120 | async function sendUndoVideoRelatedActivity (options: { |
121 | byActor: MActor, | 121 | byActor: MActor |
122 | video: MVideoAccountLight, | 122 | video: MVideoAccountLight |
123 | url: string, | 123 | url: string |
124 | activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, | 124 | activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce |
125 | transaction: Transaction | 125 | transaction: Transaction |
126 | }) { | 126 | }) { |
127 | const activityBuilder = (audience: ActivityAudience) => { | 127 | const activityBuilder = (audience: ActivityAudience) => { |
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 9c76671b5..2b01ca5e7 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -8,7 +8,6 @@ import { getUpdateActivityPubUrl } from '../url' | |||
8 | import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' | 8 | import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' |
9 | import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' | 9 | import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' |
10 | import { logger } from '../../../helpers/logger' | 10 | import { logger } from '../../../helpers/logger' |
11 | import { VideoCaptionModel } from '../../../models/video/video-caption' | ||
12 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | 11 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' |
13 | import { getServerActor } from '../../../helpers/utils' | 12 | import { getServerActor } from '../../../helpers/utils' |
14 | import { | 13 | import { |
@@ -29,7 +28,7 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction | |||
29 | 28 | ||
30 | logger.info('Creating job to update video %s.', video.url) | 29 | logger.info('Creating job to update video %s.', video.url) |
31 | 30 | ||
32 | const byActor = overrodeByActor ? overrodeByActor : video.VideoChannel.Account.Actor | 31 | const byActor = overrodeByActor || video.VideoChannel.Account.Actor |
33 | 32 | ||
34 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) | 33 | const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString()) |
35 | 34 | ||
@@ -85,7 +84,7 @@ async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVide | |||
85 | return buildUpdateActivity(url, byActor, redundancyObject, audience) | 84 | return buildUpdateActivity(url, byActor, redundancyObject, audience) |
86 | } | 85 | } |
87 | 86 | ||
88 | return sendVideoRelatedActivity(activityBuilder, { byActor, video }) | 87 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, contextType: 'CacheFile' }) |
89 | } | 88 | } |
90 | 89 | ||
91 | async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) { | 90 | async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) { |
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts index 8809417f9..1f864ea52 100644 --- a/server/lib/activitypub/send/send-view.ts +++ b/server/lib/activitypub/send/send-view.ts | |||
@@ -5,9 +5,9 @@ import { getVideoLikeActivityPubUrl } from '../url' | |||
5 | import { sendVideoRelatedActivity } from './utils' | 5 | import { sendVideoRelatedActivity } from './utils' |
6 | import { audiencify, getAudience } from '../audience' | 6 | import { audiencify, getAudience } from '../audience' |
7 | import { logger } from '../../../helpers/logger' | 7 | import { logger } from '../../../helpers/logger' |
8 | import { MActorAudience, MVideoAccountLight, MVideoUrl } from '@server/typings/models' | 8 | import { MActorAudience, MVideoImmutable, MVideoUrl } from '@server/typings/models' |
9 | 9 | ||
10 | async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Transaction) { | 10 | async function sendView (byActor: ActorModel, video: MVideoImmutable, t: Transaction) { |
11 | logger.info('Creating job to send view of %s.', video.url) | 11 | logger.info('Creating job to send view of %s.', video.url) |
12 | 12 | ||
13 | const activityBuilder = (audience: ActivityAudience) => { | 13 | const activityBuilder = (audience: ActivityAudience) => { |
@@ -16,7 +16,7 @@ async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Tran | |||
16 | return buildViewActivity(url, byActor, video, audience) | 16 | return buildViewActivity(url, byActor, video, audience) |
17 | } | 17 | } |
18 | 18 | ||
19 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) | 19 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t, contextType: 'View' }) |
20 | } | 20 | } |
21 | 21 | ||
22 | function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView { | 22 | function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView { |
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts index 77b723479..b57bae8fd 100644 --- a/server/lib/activitypub/send/utils.ts +++ b/server/lib/activitypub/send/utils.ts | |||
@@ -7,24 +7,28 @@ import { JobQueue } from '../../job-queue' | |||
7 | import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' | 7 | import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' |
8 | import { getServerActor } from '../../../helpers/utils' | 8 | import { getServerActor } from '../../../helpers/utils' |
9 | import { afterCommitIfTransaction } from '../../../helpers/database-utils' | 9 | import { afterCommitIfTransaction } from '../../../helpers/database-utils' |
10 | import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models' | 10 | import { MActor, MActorId, MActorLight, MActorWithInboxes, MVideoAccountLight, MVideoId, MVideoImmutable } from '../../../typings/models' |
11 | import { ContextType } from '@server/helpers/activitypub' | ||
11 | 12 | ||
12 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { | 13 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { |
13 | byActor: MActorLight, | 14 | byActor: MActorLight |
14 | video: MVideoAccountLight, | 15 | video: MVideoImmutable | MVideoAccountLight |
15 | transaction?: Transaction | 16 | transaction?: Transaction |
17 | contextType?: ContextType | ||
16 | }) { | 18 | }) { |
17 | const { byActor, video, transaction } = options | 19 | const { byActor, video, transaction, contextType } = options |
18 | 20 | ||
19 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) | 21 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) |
20 | 22 | ||
21 | // Send to origin | 23 | // Send to origin |
22 | if (video.isOwned() === false) { | 24 | if (video.isOwned() === false) { |
23 | const audience = getRemoteVideoAudience(video, actorsInvolvedInVideo) | 25 | const accountActor = (video as MVideoAccountLight).VideoChannel?.Account?.Actor || await ActorModel.loadAccountActorByVideoId(video.id) |
26 | |||
27 | const audience = getRemoteVideoAudience(accountActor, actorsInvolvedInVideo) | ||
24 | const activity = activityBuilder(audience) | 28 | const activity = activityBuilder(audience) |
25 | 29 | ||
26 | return afterCommitIfTransaction(transaction, () => { | 30 | return afterCommitIfTransaction(transaction, () => { |
27 | return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.getSharedInbox()) | 31 | return unicastTo(activity, byActor, accountActor.getSharedInbox(), contextType) |
28 | }) | 32 | }) |
29 | } | 33 | } |
30 | 34 | ||
@@ -34,14 +38,14 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud | |||
34 | 38 | ||
35 | const actorsException = [ byActor ] | 39 | const actorsException = [ byActor ] |
36 | 40 | ||
37 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException) | 41 | return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType) |
38 | } | 42 | } |
39 | 43 | ||
40 | async function forwardVideoRelatedActivity ( | 44 | async function forwardVideoRelatedActivity ( |
41 | activity: Activity, | 45 | activity: Activity, |
42 | t: Transaction, | 46 | t: Transaction, |
43 | followersException: MActorWithInboxes[] = [], | 47 | followersException: MActorWithInboxes[] = [], |
44 | video: MVideo | 48 | video: MVideoId |
45 | ) { | 49 | ) { |
46 | // Mastodon does not add our announces in audience, so we forward to them manually | 50 | // Mastodon does not add our announces in audience, so we forward to them manually |
47 | const additionalActors = await getActorsInvolvedInVideo(video, t) | 51 | const additionalActors = await getActorsInvolvedInVideo(video, t) |
@@ -90,11 +94,12 @@ async function broadcastToFollowers ( | |||
90 | byActor: MActorId, | 94 | byActor: MActorId, |
91 | toFollowersOf: MActorId[], | 95 | toFollowersOf: MActorId[], |
92 | t: Transaction, | 96 | t: Transaction, |
93 | actorsException: MActorWithInboxes[] = [] | 97 | actorsException: MActorWithInboxes[] = [], |
98 | contextType?: ContextType | ||
94 | ) { | 99 | ) { |
95 | const uris = await computeFollowerUris(toFollowersOf, actorsException, t) | 100 | const uris = await computeFollowerUris(toFollowersOf, actorsException, t) |
96 | 101 | ||
97 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) | 102 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) |
98 | } | 103 | } |
99 | 104 | ||
100 | async function broadcastToActors ( | 105 | async function broadcastToActors ( |
@@ -102,13 +107,14 @@ async function broadcastToActors ( | |||
102 | byActor: MActorId, | 107 | byActor: MActorId, |
103 | toActors: MActor[], | 108 | toActors: MActor[], |
104 | t?: Transaction, | 109 | t?: Transaction, |
105 | actorsException: MActorWithInboxes[] = [] | 110 | actorsException: MActorWithInboxes[] = [], |
111 | contextType?: ContextType | ||
106 | ) { | 112 | ) { |
107 | const uris = await computeUris(toActors, actorsException) | 113 | const uris = await computeUris(toActors, actorsException) |
108 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) | 114 | return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType)) |
109 | } | 115 | } |
110 | 116 | ||
111 | function broadcastTo (uris: string[], data: any, byActor: MActorId) { | 117 | function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) { |
112 | if (uris.length === 0) return undefined | 118 | if (uris.length === 0) return undefined |
113 | 119 | ||
114 | logger.debug('Creating broadcast job.', { uris }) | 120 | logger.debug('Creating broadcast job.', { uris }) |
@@ -116,19 +122,21 @@ function broadcastTo (uris: string[], data: any, byActor: MActorId) { | |||
116 | const payload = { | 122 | const payload = { |
117 | uris, | 123 | uris, |
118 | signatureActorId: byActor.id, | 124 | signatureActorId: byActor.id, |
119 | body: data | 125 | body: data, |
126 | contextType | ||
120 | } | 127 | } |
121 | 128 | ||
122 | return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) | 129 | return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) |
123 | } | 130 | } |
124 | 131 | ||
125 | function unicastTo (data: any, byActor: MActorId, toActorUrl: string) { | 132 | function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) { |
126 | logger.debug('Creating unicast job.', { uri: toActorUrl }) | 133 | logger.debug('Creating unicast job.', { uri: toActorUrl }) |
127 | 134 | ||
128 | const payload = { | 135 | const payload = { |
129 | uri: toActorUrl, | 136 | uri: toActorUrl, |
130 | signatureActorId: byActor.id, | 137 | signatureActorId: byActor.id, |
131 | body: data | 138 | body: data, |
139 | contextType | ||
132 | } | 140 | } |
133 | 141 | ||
134 | JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload }) | 142 | JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload }) |
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index d5c078a29..8642d2432 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts | |||
@@ -10,9 +10,9 @@ import { checkUrlsSameHost } from '../../helpers/activitypub' | |||
10 | import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' | 10 | import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' |
11 | 11 | ||
12 | type ResolveThreadParams = { | 12 | type ResolveThreadParams = { |
13 | url: string, | 13 | url: string |
14 | comments?: MCommentOwner[], | 14 | comments?: MCommentOwner[] |
15 | isVideo?: boolean, | 15 | isVideo?: boolean |
16 | commentCreated?: boolean | 16 | commentCreated?: boolean |
17 | } | 17 | } |
18 | type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> | 18 | type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> |
@@ -28,7 +28,7 @@ async function resolveThread (params: ResolveThreadParams): ResolveThreadResult | |||
28 | if (params.commentCreated === undefined) params.commentCreated = false | 28 | if (params.commentCreated === undefined) params.commentCreated = false |
29 | if (params.comments === undefined) params.comments = [] | 29 | if (params.comments === undefined) params.comments = [] |
30 | 30 | ||
31 | // Already have this comment? | 31 | // Already have this comment? |
32 | if (isVideo !== true) { | 32 | if (isVideo !== true) { |
33 | const result = await resolveCommentFromDB(params) | 33 | const result = await resolveCommentFromDB(params) |
34 | if (result) return result | 34 | if (result) return result |
@@ -87,7 +87,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { | |||
87 | 87 | ||
88 | let resultComment: MCommentOwnerVideo | 88 | let resultComment: MCommentOwnerVideo |
89 | if (comments.length !== 0) { | 89 | if (comments.length !== 0) { |
90 | const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo | 90 | const firstReply = comments[comments.length - 1] as MCommentOwnerVideo |
91 | firstReply.inReplyToCommentId = null | 91 | firstReply.inReplyToCommentId = null |
92 | firstReply.originCommentId = null | 92 | firstReply.originCommentId = null |
93 | firstReply.videoId = video.id | 93 | firstReply.videoId = video.id |
@@ -97,9 +97,9 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { | |||
97 | comments[comments.length - 1] = await firstReply.save() | 97 | comments[comments.length - 1] = await firstReply.save() |
98 | 98 | ||
99 | for (let i = comments.length - 2; i >= 0; i--) { | 99 | for (let i = comments.length - 2; i >= 0; i--) { |
100 | const comment = comments[ i ] as MCommentOwnerVideo | 100 | const comment = comments[i] as MCommentOwnerVideo |
101 | comment.originCommentId = firstReply.id | 101 | comment.originCommentId = firstReply.id |
102 | comment.inReplyToCommentId = comments[ i + 1 ].id | 102 | comment.inReplyToCommentId = comments[i + 1].id |
103 | comment.videoId = video.id | 103 | comment.videoId = video.id |
104 | comment.changed('updatedAt', true) | 104 | comment.changed('updatedAt', true) |
105 | comment.Video = video | 105 | comment.Video = video |
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts index 6bd46bb58..79ccfbc7e 100644 --- a/server/lib/activitypub/video-rates.ts +++ b/server/lib/activitypub/video-rates.ts | |||
@@ -58,8 +58,6 @@ async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateTy | |||
58 | const field = rate === 'like' ? 'likes' : 'dislikes' | 58 | const field = rate === 'like' ? 'likes' : 'dislikes' |
59 | await video.increment(field, { by: rateCounts }) | 59 | await video.increment(field, { by: rateCounts }) |
60 | } | 60 | } |
61 | |||
62 | return | ||
63 | } | 61 | } |
64 | 62 | ||
65 | async function sendVideoRateChange ( | 63 | async function sendVideoRateChange ( |
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index ade93150f..d182ca5a2 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -6,7 +6,8 @@ import { | |||
6 | ActivityHashTagObject, | 6 | ActivityHashTagObject, |
7 | ActivityMagnetUrlObject, | 7 | ActivityMagnetUrlObject, |
8 | ActivityPlaylistSegmentHashesObject, | 8 | ActivityPlaylistSegmentHashesObject, |
9 | ActivityPlaylistUrlObject, ActivityTagObject, | 9 | ActivityPlaylistUrlObject, |
10 | ActivityTagObject, | ||
10 | ActivityUrlObject, | 11 | ActivityUrlObject, |
11 | ActivityVideoUrlObject, | 12 | ActivityVideoUrlObject, |
12 | VideoState | 13 | VideoState |
@@ -17,14 +18,14 @@ import { sanitizeAndCheckVideoTorrentObject } from '../../helpers/custom-validat | |||
17 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 18 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
18 | import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils' | 19 | import { deleteNonExistingModels, resetSequelizeInstance, retryTransactionWrapper } from '../../helpers/database-utils' |
19 | import { logger } from '../../helpers/logger' | 20 | import { logger } from '../../helpers/logger' |
20 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 21 | import { doRequest } from '../../helpers/requests' |
21 | import { | 22 | import { |
22 | ACTIVITY_PUB, | 23 | ACTIVITY_PUB, |
23 | MIMETYPES, | 24 | MIMETYPES, |
24 | P2P_MEDIA_LOADER_PEER_VERSION, | 25 | P2P_MEDIA_LOADER_PEER_VERSION, |
25 | PREVIEWS_SIZE, | 26 | PREVIEWS_SIZE, |
26 | REMOTE_SCHEME, | 27 | REMOTE_SCHEME, |
27 | STATIC_PATHS | 28 | STATIC_PATHS, THUMBNAILS_SIZE |
28 | } from '../../initializers/constants' | 29 | } from '../../initializers/constants' |
29 | import { TagModel } from '../../models/video/tag' | 30 | import { TagModel } from '../../models/video/tag' |
30 | import { VideoModel } from '../../models/video/video' | 31 | import { VideoModel } from '../../models/video/video' |
@@ -40,7 +41,7 @@ import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub | |||
40 | import { createRates } from './video-rates' | 41 | import { createRates } from './video-rates' |
41 | import { addVideoShares, shareVideoByServerAndChannel } from './share' | 42 | import { addVideoShares, shareVideoByServerAndChannel } from './share' |
42 | import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' | 43 | import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' |
43 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' | 44 | import { buildRemoteVideoBaseUrl, checkUrlsSameHost, getAPId } from '../../helpers/activitypub' |
44 | import { Notifier } from '../notifier' | 45 | import { Notifier } from '../notifier' |
45 | import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' | 46 | import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' |
46 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 47 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
@@ -67,10 +68,11 @@ import { | |||
67 | MVideoAPWithoutCaption, | 68 | MVideoAPWithoutCaption, |
68 | MVideoFile, | 69 | MVideoFile, |
69 | MVideoFullLight, | 70 | MVideoFullLight, |
70 | MVideoId, | 71 | MVideoId, MVideoImmutable, |
71 | MVideoThumbnail | 72 | MVideoThumbnail |
72 | } from '../../typings/models' | 73 | } from '../../typings/models' |
73 | import { MThumbnail } from '../../typings/models/video/thumbnail' | 74 | import { MThumbnail } from '../../typings/models/video/thumbnail' |
75 | import { maxBy, minBy } from 'lodash' | ||
74 | 76 | ||
75 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { | 77 | async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { |
76 | const video = videoArg as MVideoAP | 78 | const video = videoArg as MVideoAP |
@@ -131,19 +133,6 @@ async function fetchRemoteVideoDescription (video: MVideoAccountLight) { | |||
131 | return body.description ? body.description : '' | 133 | return body.description ? body.description : '' |
132 | } | 134 | } |
133 | 135 | ||
134 | function fetchRemoteVideoStaticFile (video: MVideoAccountLight, path: string, destPath: string) { | ||
135 | const url = buildRemoteBaseUrl(video, path) | ||
136 | |||
137 | // We need to provide a callback, if no we could have an uncaught exception | ||
138 | return doRequestAndSaveToFile({ uri: url }, destPath) | ||
139 | } | ||
140 | |||
141 | function buildRemoteBaseUrl (video: MVideoAccountLight, path: string) { | ||
142 | const host = video.VideoChannel.Account.Actor.Server.host | ||
143 | |||
144 | return REMOTE_SCHEME.HTTP + '://' + host + path | ||
145 | } | ||
146 | |||
147 | function getOrCreateVideoChannelFromVideoObject (videoObject: VideoTorrentObject) { | 136 | function getOrCreateVideoChannelFromVideoObject (videoObject: VideoTorrentObject) { |
148 | const channel = videoObject.attributedTo.find(a => a.type === 'Group') | 137 | const channel = videoObject.attributedTo.find(a => a.type === 'Group') |
149 | if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) | 138 | if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) |
@@ -173,7 +162,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
173 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'like' as 'like', crawlStartDate) | 162 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'like' as 'like', crawlStartDate) |
174 | 163 | ||
175 | await crawlCollectionPage<string>(fetchedVideo.likes, handler, cleaner) | 164 | await crawlCollectionPage<string>(fetchedVideo.likes, handler, cleaner) |
176 | .catch(err => logger.error('Cannot add likes of video %s.', video.uuid, { err })) | 165 | .catch(err => logger.error('Cannot add likes of video %s.', video.uuid, { err, rootUrl: fetchedVideo.likes })) |
177 | } else { | 166 | } else { |
178 | jobPayloads.push({ uri: fetchedVideo.likes, videoId: video.id, type: 'video-likes' as 'video-likes' }) | 167 | jobPayloads.push({ uri: fetchedVideo.likes, videoId: video.id, type: 'video-likes' as 'video-likes' }) |
179 | } | 168 | } |
@@ -183,7 +172,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
183 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'dislike' as 'dislike', crawlStartDate) | 172 | const cleaner = crawlStartDate => AccountVideoRateModel.cleanOldRatesOf(video.id, 'dislike' as 'dislike', crawlStartDate) |
184 | 173 | ||
185 | await crawlCollectionPage<string>(fetchedVideo.dislikes, handler, cleaner) | 174 | await crawlCollectionPage<string>(fetchedVideo.dislikes, handler, cleaner) |
186 | .catch(err => logger.error('Cannot add dislikes of video %s.', video.uuid, { err })) | 175 | .catch(err => logger.error('Cannot add dislikes of video %s.', video.uuid, { err, rootUrl: fetchedVideo.dislikes })) |
187 | } else { | 176 | } else { |
188 | jobPayloads.push({ uri: fetchedVideo.dislikes, videoId: video.id, type: 'video-dislikes' as 'video-dislikes' }) | 177 | jobPayloads.push({ uri: fetchedVideo.dislikes, videoId: video.id, type: 'video-dislikes' as 'video-dislikes' }) |
189 | } | 178 | } |
@@ -193,7 +182,7 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
193 | const cleaner = crawlStartDate => VideoShareModel.cleanOldSharesOf(video.id, crawlStartDate) | 182 | const cleaner = crawlStartDate => VideoShareModel.cleanOldSharesOf(video.id, crawlStartDate) |
194 | 183 | ||
195 | await crawlCollectionPage<string>(fetchedVideo.shares, handler, cleaner) | 184 | await crawlCollectionPage<string>(fetchedVideo.shares, handler, cleaner) |
196 | .catch(err => logger.error('Cannot add shares of video %s.', video.uuid, { err })) | 185 | .catch(err => logger.error('Cannot add shares of video %s.', video.uuid, { err, rootUrl: fetchedVideo.shares })) |
197 | } else { | 186 | } else { |
198 | jobPayloads.push({ uri: fetchedVideo.shares, videoId: video.id, type: 'video-shares' as 'video-shares' }) | 187 | jobPayloads.push({ uri: fetchedVideo.shares, videoId: video.id, type: 'video-shares' as 'video-shares' }) |
199 | } | 188 | } |
@@ -203,32 +192,49 @@ async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTo | |||
203 | const cleaner = crawlStartDate => VideoCommentModel.cleanOldCommentsOf(video.id, crawlStartDate) | 192 | const cleaner = crawlStartDate => VideoCommentModel.cleanOldCommentsOf(video.id, crawlStartDate) |
204 | 193 | ||
205 | await crawlCollectionPage<string>(fetchedVideo.comments, handler, cleaner) | 194 | await crawlCollectionPage<string>(fetchedVideo.comments, handler, cleaner) |
206 | .catch(err => logger.error('Cannot add comments of video %s.', video.uuid, { err })) | 195 | .catch(err => logger.error('Cannot add comments of video %s.', video.uuid, { err, rootUrl: fetchedVideo.comments })) |
207 | } else { | 196 | } else { |
208 | jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) | 197 | jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' }) |
209 | } | 198 | } |
210 | 199 | ||
211 | await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) | 200 | await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })) |
212 | } | 201 | } |
213 | 202 | ||
214 | function getOrCreateVideoAndAccountAndChannel (options: { | 203 | type GetVideoResult <T> = Promise<{ |
215 | videoObject: { id: string } | string, | 204 | video: T |
216 | syncParam?: SyncParam, | 205 | created: boolean |
217 | fetchType?: 'all', | 206 | autoBlacklisted?: boolean |
207 | }> | ||
208 | |||
209 | type GetVideoParamAll = { | ||
210 | videoObject: { id: string } | string | ||
211 | syncParam?: SyncParam | ||
212 | fetchType?: 'all' | ||
218 | allowRefresh?: boolean | 213 | allowRefresh?: boolean |
219 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }> | 214 | } |
220 | function getOrCreateVideoAndAccountAndChannel (options: { | 215 | |
221 | videoObject: { id: string } | string, | 216 | type GetVideoParamImmutable = { |
222 | syncParam?: SyncParam, | 217 | videoObject: { id: string } | string |
223 | fetchType?: VideoFetchByUrlType, | 218 | syncParam?: SyncParam |
219 | fetchType: 'only-immutable-attributes' | ||
220 | allowRefresh: false | ||
221 | } | ||
222 | |||
223 | type GetVideoParamOther = { | ||
224 | videoObject: { id: string } | string | ||
225 | syncParam?: SyncParam | ||
226 | fetchType?: 'all' | 'only-video' | ||
224 | allowRefresh?: boolean | 227 | allowRefresh?: boolean |
225 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> | 228 | } |
226 | async function getOrCreateVideoAndAccountAndChannel (options: { | 229 | |
227 | videoObject: { id: string } | string, | 230 | function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamAll): GetVideoResult<MVideoAccountLightBlacklistAllFiles> |
228 | syncParam?: SyncParam, | 231 | function getOrCreateVideoAndAccountAndChannel (options: GetVideoParamImmutable): GetVideoResult<MVideoImmutable> |
229 | fetchType?: VideoFetchByUrlType, | 232 | function getOrCreateVideoAndAccountAndChannel ( |
230 | allowRefresh?: boolean // true by default | 233 | options: GetVideoParamOther |
231 | }): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { | 234 | ): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail> |
235 | async function getOrCreateVideoAndAccountAndChannel ( | ||
236 | options: GetVideoParamAll | GetVideoParamImmutable | GetVideoParamOther | ||
237 | ): GetVideoResult<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> { | ||
232 | // Default params | 238 | // Default params |
233 | const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } | 239 | const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } |
234 | const fetchType = options.fetchType || 'all' | 240 | const fetchType = options.fetchType || 'all' |
@@ -236,18 +242,25 @@ async function getOrCreateVideoAndAccountAndChannel (options: { | |||
236 | 242 | ||
237 | // Get video url | 243 | // Get video url |
238 | const videoUrl = getAPId(options.videoObject) | 244 | const videoUrl = getAPId(options.videoObject) |
239 | |||
240 | let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType) | 245 | let videoFromDatabase = await fetchVideoByUrl(videoUrl, fetchType) |
246 | |||
241 | if (videoFromDatabase) { | 247 | if (videoFromDatabase) { |
242 | if (videoFromDatabase.isOutdated() && allowRefresh === true) { | 248 | // If allowRefresh is true, we could not call this function using 'only-immutable-attributes' fetch type |
249 | if (allowRefresh === true && (videoFromDatabase as MVideoThumbnail).isOutdated()) { | ||
243 | const refreshOptions = { | 250 | const refreshOptions = { |
244 | video: videoFromDatabase, | 251 | video: videoFromDatabase as MVideoThumbnail, |
245 | fetchedType: fetchType, | 252 | fetchedType: fetchType, |
246 | syncParam | 253 | syncParam |
247 | } | 254 | } |
248 | 255 | ||
249 | if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) | 256 | if (syncParam.refreshVideo === true) { |
250 | else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } }) | 257 | videoFromDatabase = await refreshVideoIfNeeded(refreshOptions) |
258 | } else { | ||
259 | await JobQueue.Instance.createJobWithPromise({ | ||
260 | type: 'activitypub-refresher', | ||
261 | payload: { type: 'video', url: videoFromDatabase.url } | ||
262 | }) | ||
263 | } | ||
251 | } | 264 | } |
252 | 265 | ||
253 | return { video: videoFromDatabase, created: false } | 266 | return { video: videoFromDatabase, created: false } |
@@ -266,10 +279,10 @@ async function getOrCreateVideoAndAccountAndChannel (options: { | |||
266 | } | 279 | } |
267 | 280 | ||
268 | async function updateVideoFromAP (options: { | 281 | async function updateVideoFromAP (options: { |
269 | video: MVideoAccountLightBlacklistAllFiles, | 282 | video: MVideoAccountLightBlacklistAllFiles |
270 | videoObject: VideoTorrentObject, | 283 | videoObject: VideoTorrentObject |
271 | account: MAccountIdActor, | 284 | account: MAccountIdActor |
272 | channel: MChannelDefault, | 285 | channel: MChannelDefault |
273 | overrideTo?: string[] | 286 | overrideTo?: string[] |
274 | }) { | 287 | }) { |
275 | const { video, videoObject, account, channel, overrideTo } = options | 288 | const { video, videoObject, account, channel, overrideTo } = options |
@@ -284,7 +297,7 @@ async function updateVideoFromAP (options: { | |||
284 | let thumbnailModel: MThumbnail | 297 | let thumbnailModel: MThumbnail |
285 | 298 | ||
286 | try { | 299 | try { |
287 | thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) | 300 | thumbnailModel = await createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) |
288 | } catch (err) { | 301 | } catch (err) { |
289 | logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) | 302 | logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) |
290 | } | 303 | } |
@@ -300,7 +313,7 @@ async function updateVideoFromAP (options: { | |||
300 | throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) | 313 | throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url) |
301 | } | 314 | } |
302 | 315 | ||
303 | const to = overrideTo ? overrideTo : videoObject.to | 316 | const to = overrideTo || videoObject.to |
304 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) | 317 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to) |
305 | video.name = videoData.name | 318 | video.name = videoData.name |
306 | video.uuid = videoData.uuid | 319 | video.uuid = videoData.uuid |
@@ -327,10 +340,11 @@ async function updateVideoFromAP (options: { | |||
327 | 340 | ||
328 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) | 341 | if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) |
329 | 342 | ||
330 | // FIXME: use icon URL instead | 343 | if (videoUpdated.getPreview()) { |
331 | const previewUrl = buildRemoteBaseUrl(videoUpdated, join(STATIC_PATHS.PREVIEWS, videoUpdated.getPreview().filename)) | 344 | const previewUrl = videoUpdated.getPreview().getFileUrl(videoUpdated) |
332 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 345 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) |
333 | await videoUpdated.addAndSaveThumbnail(previewModel, t) | 346 | await videoUpdated.addAndSaveThumbnail(previewModel, t) |
347 | } | ||
334 | 348 | ||
335 | { | 349 | { |
336 | const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject.url) | 350 | const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject.url) |
@@ -391,7 +405,7 @@ async function updateVideoFromAP (options: { | |||
391 | await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t) | 405 | await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t) |
392 | 406 | ||
393 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { | 407 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { |
394 | return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, t) | 408 | return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, c.url, t) |
395 | }) | 409 | }) |
396 | await Promise.all(videoCaptionsPromises) | 410 | await Promise.all(videoCaptionsPromises) |
397 | } | 411 | } |
@@ -424,8 +438,8 @@ async function updateVideoFromAP (options: { | |||
424 | } | 438 | } |
425 | 439 | ||
426 | async function refreshVideoIfNeeded (options: { | 440 | async function refreshVideoIfNeeded (options: { |
427 | video: MVideoThumbnail, | 441 | video: MVideoThumbnail |
428 | fetchedType: VideoFetchByUrlType, | 442 | fetchedType: VideoFetchByUrlType |
429 | syncParam: SyncParam | 443 | syncParam: SyncParam |
430 | }): Promise<MVideoThumbnail> { | 444 | }): Promise<MVideoThumbnail> { |
431 | if (!options.video.isOutdated()) return options.video | 445 | if (!options.video.isOutdated()) return options.video |
@@ -483,7 +497,6 @@ export { | |||
483 | federateVideoIfNeeded, | 497 | federateVideoIfNeeded, |
484 | fetchRemoteVideo, | 498 | fetchRemoteVideo, |
485 | getOrCreateVideoAndAccountAndChannel, | 499 | getOrCreateVideoAndAccountAndChannel, |
486 | fetchRemoteVideoStaticFile, | ||
487 | fetchRemoteVideoDescription, | 500 | fetchRemoteVideoDescription, |
488 | getOrCreateVideoChannelFromVideoObject | 501 | getOrCreateVideoChannelFromVideoObject |
489 | } | 502 | } |
@@ -519,7 +532,11 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
519 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) | 532 | const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) |
520 | const video = VideoModel.build(videoData) as MVideoThumbnail | 533 | const video = VideoModel.build(videoData) as MVideoThumbnail |
521 | 534 | ||
522 | const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) | 535 | const promiseThumbnail = createVideoMiniatureFromUrl(getThumbnailFromIcons(videoObject).url, video, ThumbnailType.MINIATURE) |
536 | .catch(err => { | ||
537 | logger.error('Cannot create miniature from url.', { err }) | ||
538 | return undefined | ||
539 | }) | ||
523 | 540 | ||
524 | let thumbnailModel: MThumbnail | 541 | let thumbnailModel: MThumbnail |
525 | if (waitThumbnail === true) { | 542 | if (waitThumbnail === true) { |
@@ -534,9 +551,12 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
534 | 551 | ||
535 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) | 552 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) |
536 | 553 | ||
537 | // FIXME: use icon URL instead | 554 | const previewIcon = getPreviewFromIcons(videoObject) |
538 | const previewUrl = buildRemoteBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | 555 | const previewUrl = previewIcon |
539 | const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | 556 | ? previewIcon.url |
557 | : buildRemoteVideoBaseUrl(videoCreated, join(STATIC_PATHS.PREVIEWS, video.generatePreviewName())) | ||
558 | const previewModel = createPlaceholderThumbnail(previewUrl, videoCreated, ThumbnailType.PREVIEW, PREVIEWS_SIZE) | ||
559 | |||
540 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) | 560 | if (thumbnailModel) await videoCreated.addAndSaveThumbnail(previewModel, t) |
541 | 561 | ||
542 | // Process files | 562 | // Process files |
@@ -567,7 +587,7 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
567 | 587 | ||
568 | // Process captions | 588 | // Process captions |
569 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { | 589 | const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { |
570 | return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t) | 590 | return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, c.url, t) |
571 | }) | 591 | }) |
572 | await Promise.all(videoCaptionsPromises) | 592 | await Promise.all(videoCaptionsPromises) |
573 | 593 | ||
@@ -588,7 +608,11 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
588 | }) | 608 | }) |
589 | 609 | ||
590 | if (waitThumbnail === false) { | 610 | if (waitThumbnail === false) { |
611 | // Error is already caught above | ||
612 | // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
591 | promiseThumbnail.then(thumbnailModel => { | 613 | promiseThumbnail.then(thumbnailModel => { |
614 | if (!thumbnailModel) return | ||
615 | |||
592 | thumbnailModel = videoCreated.id | 616 | thumbnailModel = videoCreated.id |
593 | 617 | ||
594 | return thumbnailModel.save() | 618 | return thumbnailModel.save() |
@@ -598,24 +622,19 @@ async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAc | |||
598 | return { autoBlacklisted, videoCreated } | 622 | return { autoBlacklisted, videoCreated } |
599 | } | 623 | } |
600 | 624 | ||
601 | async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { | 625 | function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { |
602 | const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED | 626 | const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED |
603 | const duration = videoObject.duration.replace(/[^\d]+/, '') | 627 | const duration = videoObject.duration.replace(/[^\d]+/, '') |
604 | 628 | ||
605 | let language: string | undefined | 629 | const language = videoObject.language?.identifier |
606 | if (videoObject.language) { | ||
607 | language = videoObject.language.identifier | ||
608 | } | ||
609 | 630 | ||
610 | let category: number | undefined | 631 | const category = videoObject.category |
611 | if (videoObject.category) { | 632 | ? parseInt(videoObject.category.identifier, 10) |
612 | category = parseInt(videoObject.category.identifier, 10) | 633 | : undefined |
613 | } | ||
614 | 634 | ||
615 | let licence: number | undefined | 635 | const licence = videoObject.licence |
616 | if (videoObject.licence) { | 636 | ? parseInt(videoObject.licence.identifier, 10) |
617 | licence = parseInt(videoObject.licence.identifier, 10) | 637 | : undefined |
618 | } | ||
619 | 638 | ||
620 | const description = videoObject.content || null | 639 | const description = videoObject.content || null |
621 | const support = videoObject.support || null | 640 | const support = videoObject.support || null |
@@ -638,8 +657,11 @@ async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, vide | |||
638 | duration: parseInt(duration, 10), | 657 | duration: parseInt(duration, 10), |
639 | createdAt: new Date(videoObject.published), | 658 | createdAt: new Date(videoObject.published), |
640 | publishedAt: new Date(videoObject.published), | 659 | publishedAt: new Date(videoObject.published), |
641 | originallyPublishedAt: videoObject.originallyPublishedAt ? new Date(videoObject.originallyPublishedAt) : null, | 660 | |
642 | // FIXME: updatedAt does not seems to be considered by Sequelize | 661 | originallyPublishedAt: videoObject.originallyPublishedAt |
662 | ? new Date(videoObject.originallyPublishedAt) | ||
663 | : null, | ||
664 | |||
643 | updatedAt: new Date(videoObject.updated), | 665 | updatedAt: new Date(videoObject.updated), |
644 | views: videoObject.views, | 666 | views: videoObject.views, |
645 | likes: 0, | 667 | likes: 0, |
@@ -672,7 +694,7 @@ function videoFileActivityUrlToDBAttributes ( | |||
672 | 694 | ||
673 | const mediaType = fileUrl.mediaType | 695 | const mediaType = fileUrl.mediaType |
674 | const attribute = { | 696 | const attribute = { |
675 | extname: MIMETYPES.VIDEO.MIMETYPE_EXT[ mediaType ], | 697 | extname: MIMETYPES.VIDEO.MIMETYPE_EXT[mediaType], |
676 | infoHash: parsed.infoHash, | 698 | infoHash: parsed.infoHash, |
677 | resolution: fileUrl.height, | 699 | resolution: fileUrl.height, |
678 | size: fileUrl.size, | 700 | size: fileUrl.size, |
@@ -722,3 +744,19 @@ function streamingPlaylistActivityUrlToDBAttributes (video: MVideoId, videoObjec | |||
722 | 744 | ||
723 | return attributes | 745 | return attributes |
724 | } | 746 | } |
747 | |||
748 | function getThumbnailFromIcons (videoObject: VideoTorrentObject) { | ||
749 | let validIcons = videoObject.icon.filter(i => i.width > THUMBNAILS_SIZE.minWidth) | ||
750 | // Fallback if there are not valid icons | ||
751 | if (validIcons.length === 0) validIcons = videoObject.icon | ||
752 | |||
753 | return minBy(validIcons, 'width') | ||
754 | } | ||
755 | |||
756 | function getPreviewFromIcons (videoObject: VideoTorrentObject) { | ||
757 | const validIcons = videoObject.icon.filter(i => i.width > PREVIEWS_SIZE.minWidth) | ||
758 | |||
759 | // FIXME: don't put a fallback here for compatibility with PeerTube <2.2 | ||
760 | |||
761 | return maxBy(validIcons, 'width') | ||
762 | } | ||
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 1d8a08ed0..572bd03bd 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -17,7 +17,7 @@ import { MAccountActor, MChannelActor, MVideo } from '../typings/models' | |||
17 | 17 | ||
18 | export class ClientHtml { | 18 | export class ClientHtml { |
19 | 19 | ||
20 | private static htmlCache: { [ path: string ]: string } = {} | 20 | private static htmlCache: { [path: string]: string } = {} |
21 | 21 | ||
22 | static invalidCache () { | 22 | static invalidCache () { |
23 | logger.info('Cleaning HTML cache.') | 23 | logger.info('Cleaning HTML cache.') |
@@ -94,7 +94,7 @@ export class ClientHtml { | |||
94 | 94 | ||
95 | private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) { | 95 | private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) { |
96 | const path = ClientHtml.getIndexPath(req, res, paramLang) | 96 | const path = ClientHtml.getIndexPath(req, res, paramLang) |
97 | if (ClientHtml.htmlCache[ path ]) return ClientHtml.htmlCache[ path ] | 97 | if (ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] |
98 | 98 | ||
99 | const buffer = await readFile(path) | 99 | const buffer = await readFile(path) |
100 | 100 | ||
@@ -104,7 +104,7 @@ export class ClientHtml { | |||
104 | html = ClientHtml.addCustomCSS(html) | 104 | html = ClientHtml.addCustomCSS(html) |
105 | html = await ClientHtml.addAsyncPluginCSS(html) | 105 | html = await ClientHtml.addAsyncPluginCSS(html) |
106 | 106 | ||
107 | ClientHtml.htmlCache[ path ] = html | 107 | ClientHtml.htmlCache[path] = html |
108 | 108 | ||
109 | return html | 109 | return html |
110 | } | 110 | } |
@@ -214,21 +214,21 @@ export class ClientHtml { | |||
214 | const schemaTags = { | 214 | const schemaTags = { |
215 | '@context': 'http://schema.org', | 215 | '@context': 'http://schema.org', |
216 | '@type': 'VideoObject', | 216 | '@type': 'VideoObject', |
217 | name: videoNameEscaped, | 217 | 'name': videoNameEscaped, |
218 | description: videoDescriptionEscaped, | 218 | 'description': videoDescriptionEscaped, |
219 | thumbnailUrl: previewUrl, | 219 | 'thumbnailUrl': previewUrl, |
220 | uploadDate: video.createdAt.toISOString(), | 220 | 'uploadDate': video.createdAt.toISOString(), |
221 | duration: getActivityStreamDuration(video.duration), | 221 | 'duration': getActivityStreamDuration(video.duration), |
222 | contentUrl: videoUrl, | 222 | 'contentUrl': videoUrl, |
223 | embedUrl: embedUrl, | 223 | 'embedUrl': embedUrl, |
224 | interactionCount: video.views | 224 | 'interactionCount': video.views |
225 | } | 225 | } |
226 | 226 | ||
227 | let tagsString = '' | 227 | let tagsString = '' |
228 | 228 | ||
229 | // Opengraph | 229 | // Opengraph |
230 | Object.keys(openGraphMetaTags).forEach(tagName => { | 230 | Object.keys(openGraphMetaTags).forEach(tagName => { |
231 | const tagValue = openGraphMetaTags[ tagName ] | 231 | const tagValue = openGraphMetaTags[tagName] |
232 | 232 | ||
233 | tagsString += `<meta property="${tagName}" content="${tagValue}" />` | 233 | tagsString += `<meta property="${tagName}" content="${tagValue}" />` |
234 | }) | 234 | }) |
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 7484524a4..26262972d 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { createTransport, Transporter } from 'nodemailer' | 1 | import { createTransport, Transporter } from 'nodemailer' |
2 | import { isTestInstance } from '../helpers/core-utils' | 2 | import { isTestInstance } from '../helpers/core-utils' |
3 | import { bunyanLogger, logger } from '../helpers/logger' | 3 | import { bunyanLogger, logger } from '../helpers/logger' |
4 | import { CONFIG } from '../initializers/config' | 4 | import { CONFIG, isEmailEnabled } from '../initializers/config' |
5 | import { JobQueue } from './job-queue' | 5 | import { JobQueue } from './job-queue' |
6 | import { EmailPayload } from './job-queue/handlers/email' | 6 | import { EmailPayload } from './job-queue/handlers/email' |
7 | import { readFileSync } from 'fs-extra' | 7 | import { readFileSync } from 'fs-extra' |
@@ -32,14 +32,15 @@ class Emailer { | |||
32 | private initialized = false | 32 | private initialized = false |
33 | private transporter: Transporter | 33 | private transporter: Transporter |
34 | 34 | ||
35 | private constructor () {} | 35 | private constructor () { |
36 | } | ||
36 | 37 | ||
37 | init () { | 38 | init () { |
38 | // Already initialized | 39 | // Already initialized |
39 | if (this.initialized === true) return | 40 | if (this.initialized === true) return |
40 | this.initialized = true | 41 | this.initialized = true |
41 | 42 | ||
42 | if (Emailer.isEnabled()) { | 43 | if (isEmailEnabled()) { |
43 | logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT) | 44 | logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT) |
44 | 45 | ||
45 | let tls | 46 | let tls |
@@ -97,12 +98,12 @@ class Emailer { | |||
97 | const channelName = video.VideoChannel.getDisplayName() | 98 | const channelName = video.VideoChannel.getDisplayName() |
98 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() | 99 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
99 | 100 | ||
100 | const text = `Hi dear user,\n\n` + | 101 | const text = 'Hi dear user,\n\n' + |
101 | `Your subscription ${channelName} just published a new video: ${video.name}` + | 102 | `Your subscription ${channelName} just published a new video: ${video.name}` + |
102 | `\n\n` + | 103 | '\n\n' + |
103 | `You can view it on ${videoUrl} ` + | 104 | `You can view it on ${videoUrl} ` + |
104 | `\n\n` + | 105 | '\n\n' + |
105 | `Cheers,\n` + | 106 | 'Cheers,\n' + |
106 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 107 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
107 | 108 | ||
108 | const emailPayload: EmailPayload = { | 109 | const emailPayload: EmailPayload = { |
@@ -118,10 +119,10 @@ class Emailer { | |||
118 | const followerName = actorFollow.ActorFollower.Account.getDisplayName() | 119 | const followerName = actorFollow.ActorFollower.Account.getDisplayName() |
119 | const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() | 120 | const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() |
120 | 121 | ||
121 | const text = `Hi dear user,\n\n` + | 122 | const text = 'Hi dear user,\n\n' + |
122 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + | 123 | `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + |
123 | `\n\n` + | 124 | '\n\n' + |
124 | `Cheers,\n` + | 125 | 'Cheers,\n' + |
125 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 126 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
126 | 127 | ||
127 | const emailPayload: EmailPayload = { | 128 | const emailPayload: EmailPayload = { |
@@ -136,10 +137,10 @@ class Emailer { | |||
136 | addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { | 137 | addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { |
137 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' | 138 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' |
138 | 139 | ||
139 | const text = `Hi dear admin,\n\n` + | 140 | const text = 'Hi dear admin,\n\n' + |
140 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + | 141 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + |
141 | `\n\n` + | 142 | '\n\n' + |
142 | `Cheers,\n` + | 143 | 'Cheers,\n' + |
143 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 144 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
144 | 145 | ||
145 | const emailPayload: EmailPayload = { | 146 | const emailPayload: EmailPayload = { |
@@ -152,10 +153,10 @@ class Emailer { | |||
152 | } | 153 | } |
153 | 154 | ||
154 | addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) { | 155 | addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) { |
155 | const text = `Hi dear admin,\n\n` + | 156 | const text = 'Hi dear admin,\n\n' + |
156 | `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` + | 157 | `Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` + |
157 | `\n\n` + | 158 | '\n\n' + |
158 | `Cheers,\n` + | 159 | 'Cheers,\n' + |
159 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 160 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
160 | 161 | ||
161 | const emailPayload: EmailPayload = { | 162 | const emailPayload: EmailPayload = { |
@@ -170,12 +171,12 @@ class Emailer { | |||
170 | myVideoPublishedNotification (to: string[], video: MVideo) { | 171 | myVideoPublishedNotification (to: string[], video: MVideo) { |
171 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() | 172 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
172 | 173 | ||
173 | const text = `Hi dear user,\n\n` + | 174 | const text = 'Hi dear user,\n\n' + |
174 | `Your video ${video.name} has been published.` + | 175 | `Your video ${video.name} has been published.` + |
175 | `\n\n` + | 176 | '\n\n' + |
176 | `You can view it on ${videoUrl} ` + | 177 | `You can view it on ${videoUrl} ` + |
177 | `\n\n` + | 178 | '\n\n' + |
178 | `Cheers,\n` + | 179 | 'Cheers,\n' + |
179 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 180 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
180 | 181 | ||
181 | const emailPayload: EmailPayload = { | 182 | const emailPayload: EmailPayload = { |
@@ -190,12 +191,12 @@ class Emailer { | |||
190 | myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { | 191 | myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { |
191 | const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() | 192 | const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() |
192 | 193 | ||
193 | const text = `Hi dear user,\n\n` + | 194 | const text = 'Hi dear user,\n\n' + |
194 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + | 195 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + |
195 | `\n\n` + | 196 | '\n\n' + |
196 | `You can view the imported video on ${videoUrl} ` + | 197 | `You can view the imported video on ${videoUrl} ` + |
197 | `\n\n` + | 198 | '\n\n' + |
198 | `Cheers,\n` + | 199 | 'Cheers,\n' + |
199 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 200 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
200 | 201 | ||
201 | const emailPayload: EmailPayload = { | 202 | const emailPayload: EmailPayload = { |
@@ -210,12 +211,12 @@ class Emailer { | |||
210 | myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { | 211 | myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { |
211 | const importUrl = WEBSERVER.URL + '/my-account/video-imports' | 212 | const importUrl = WEBSERVER.URL + '/my-account/video-imports' |
212 | 213 | ||
213 | const text = `Hi dear user,\n\n` + | 214 | const text = 'Hi dear user,\n\n' + |
214 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + | 215 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + |
215 | `\n\n` + | 216 | '\n\n' + |
216 | `See your videos import dashboard for more information: ${importUrl}` + | 217 | `See your videos import dashboard for more information: ${importUrl}` + |
217 | `\n\n` + | 218 | '\n\n' + |
218 | `Cheers,\n` + | 219 | 'Cheers,\n' + |
219 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 220 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
220 | 221 | ||
221 | const emailPayload: EmailPayload = { | 222 | const emailPayload: EmailPayload = { |
@@ -232,12 +233,12 @@ class Emailer { | |||
232 | const video = comment.Video | 233 | const video = comment.Video |
233 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() | 234 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
234 | 235 | ||
235 | const text = `Hi dear user,\n\n` + | 236 | const text = 'Hi dear user,\n\n' + |
236 | `A new comment has been posted by ${accountName} on your video ${video.name}` + | 237 | `A new comment has been posted by ${accountName} on your video ${video.name}` + |
237 | `\n\n` + | 238 | '\n\n' + |
238 | `You can view it on ${commentUrl} ` + | 239 | `You can view it on ${commentUrl} ` + |
239 | `\n\n` + | 240 | '\n\n' + |
240 | `Cheers,\n` + | 241 | 'Cheers,\n' + |
241 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 242 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
242 | 243 | ||
243 | const emailPayload: EmailPayload = { | 244 | const emailPayload: EmailPayload = { |
@@ -254,12 +255,12 @@ class Emailer { | |||
254 | const video = comment.Video | 255 | const video = comment.Video |
255 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() | 256 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
256 | 257 | ||
257 | const text = `Hi dear user,\n\n` + | 258 | const text = 'Hi dear user,\n\n' + |
258 | `${accountName} mentioned you on video ${video.name}` + | 259 | `${accountName} mentioned you on video ${video.name}` + |
259 | `\n\n` + | 260 | '\n\n' + |
260 | `You can view the comment on ${commentUrl} ` + | 261 | `You can view the comment on ${commentUrl} ` + |
261 | `\n\n` + | 262 | '\n\n' + |
262 | `Cheers,\n` + | 263 | 'Cheers,\n' + |
263 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 264 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
264 | 265 | ||
265 | const emailPayload: EmailPayload = { | 266 | const emailPayload: EmailPayload = { |
@@ -274,9 +275,9 @@ class Emailer { | |||
274 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { | 275 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { |
275 | const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() | 276 | const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() |
276 | 277 | ||
277 | const text = `Hi,\n\n` + | 278 | const text = 'Hi,\n\n' + |
278 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + | 279 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + |
279 | `Cheers,\n` + | 280 | 'Cheers,\n' + |
280 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 281 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
281 | 282 | ||
282 | const emailPayload: EmailPayload = { | 283 | const emailPayload: EmailPayload = { |
@@ -292,14 +293,14 @@ class Emailer { | |||
292 | const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' | 293 | const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' |
293 | const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() | 294 | const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() |
294 | 295 | ||
295 | const text = `Hi,\n\n` + | 296 | const text = 'Hi,\n\n' + |
296 | `A recently added video was auto-blacklisted and requires moderator review before publishing.` + | 297 | 'A recently added video was auto-blacklisted and requires moderator review before publishing.' + |
297 | `\n\n` + | 298 | '\n\n' + |
298 | `You can view it and take appropriate action on ${videoUrl}` + | 299 | `You can view it and take appropriate action on ${videoUrl}` + |
299 | `\n\n` + | 300 | '\n\n' + |
300 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + | 301 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + |
301 | `\n\n` + | 302 | '\n\n' + |
302 | `Cheers,\n` + | 303 | 'Cheers,\n' + |
303 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 304 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
304 | 305 | ||
305 | const emailPayload: EmailPayload = { | 306 | const emailPayload: EmailPayload = { |
@@ -312,9 +313,9 @@ class Emailer { | |||
312 | } | 313 | } |
313 | 314 | ||
314 | addNewUserRegistrationNotification (to: string[], user: MUser) { | 315 | addNewUserRegistrationNotification (to: string[], user: MUser) { |
315 | const text = `Hi,\n\n` + | 316 | const text = 'Hi,\n\n' + |
316 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + | 317 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + |
317 | `Cheers,\n` + | 318 | 'Cheers,\n' + |
318 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 319 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
319 | 320 | ||
320 | const emailPayload: EmailPayload = { | 321 | const emailPayload: EmailPayload = { |
@@ -367,11 +368,11 @@ class Emailer { | |||
367 | } | 368 | } |
368 | 369 | ||
369 | addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { | 370 | addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { |
370 | const text = `Hi dear user,\n\n` + | 371 | const text = 'Hi dear user,\n\n' + |
371 | `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + | 372 | `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + |
372 | `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` + | 373 | `Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` + |
373 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 374 | 'If you are not the person who initiated this request, please ignore this email.\n\n' + |
374 | `Cheers,\n` + | 375 | 'Cheers,\n' + |
375 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 376 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
376 | 377 | ||
377 | const emailPayload: EmailPayload = { | 378 | const emailPayload: EmailPayload = { |
@@ -383,12 +384,28 @@ class Emailer { | |||
383 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 384 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
384 | } | 385 | } |
385 | 386 | ||
387 | addPasswordCreateEmailJob (username: string, to: string, resetPasswordUrl: string) { | ||
388 | const text = 'Hi,\n\n' + | ||
389 | `Welcome to your ${WEBSERVER.HOST} PeerTube instance. Your username is: ${username}.\n\n` + | ||
390 | `Please set your password by following this link: ${resetPasswordUrl} (this link will expire within seven days).\n\n` + | ||
391 | 'Cheers,\n' + | ||
392 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | ||
393 | |||
394 | const emailPayload: EmailPayload = { | ||
395 | to: [ to ], | ||
396 | subject: CONFIG.EMAIL.SUBJECT.PREFIX + 'New PeerTube account password', | ||
397 | text | ||
398 | } | ||
399 | |||
400 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
401 | } | ||
402 | |||
386 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { | 403 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { |
387 | const text = `Welcome to PeerTube,\n\n` + | 404 | const text = 'Welcome to PeerTube,\n\n' + |
388 | `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + | 405 | `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + |
389 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + | 406 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + |
390 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 407 | 'If you are not the person who initiated this request, please ignore this email.\n\n' + |
391 | `Cheers,\n` + | 408 | 'Cheers,\n' + |
392 | `${CONFIG.EMAIL.BODY.SIGNATURE}` | 409 | `${CONFIG.EMAIL.BODY.SIGNATURE}` |
393 | 410 | ||
394 | const emailPayload: EmailPayload = { | 411 | const emailPayload: EmailPayload = { |
@@ -442,7 +459,7 @@ class Emailer { | |||
442 | } | 459 | } |
443 | 460 | ||
444 | async sendMail (options: EmailPayload) { | 461 | async sendMail (options: EmailPayload) { |
445 | if (!Emailer.isEnabled()) { | 462 | if (!isEmailEnabled()) { |
446 | throw new Error('Cannot send mail because SMTP is not configured.') | 463 | throw new Error('Cannot send mail because SMTP is not configured.') |
447 | } | 464 | } |
448 | 465 | ||
diff --git a/server/lib/files-cache/videos-caption-cache.ts b/server/lib/files-cache/videos-caption-cache.ts index 440c3fde8..26ab3bd0d 100644 --- a/server/lib/files-cache/videos-caption-cache.ts +++ b/server/lib/files-cache/videos-caption-cache.ts | |||
@@ -5,7 +5,7 @@ import { VideoCaptionModel } from '../../models/video/video-caption' | |||
5 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | 5 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' |
6 | import { CONFIG } from '../../initializers/config' | 6 | import { CONFIG } from '../../initializers/config' |
7 | import { logger } from '../../helpers/logger' | 7 | import { logger } from '../../helpers/logger' |
8 | import { fetchRemoteVideoStaticFile } from '../activitypub' | 8 | import { doRequestAndSaveToFile } from '@server/helpers/requests' |
9 | 9 | ||
10 | type GetPathParam = { videoId: string, language: string } | 10 | type GetPathParam = { videoId: string, language: string } |
11 | 11 | ||
@@ -46,11 +46,10 @@ class VideosCaptionCache extends AbstractVideoStaticFileCache <GetPathParam> { | |||
46 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) | 46 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoId) |
47 | if (!video) return undefined | 47 | if (!video) return undefined |
48 | 48 | ||
49 | // FIXME: use URL | 49 | const remoteUrl = videoCaption.getFileUrl(video) |
50 | const remoteStaticPath = videoCaption.getCaptionStaticPath() | ||
51 | const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.getCaptionName()) | 50 | const destPath = join(FILES_CACHE.VIDEO_CAPTIONS.DIRECTORY, videoCaption.getCaptionName()) |
52 | 51 | ||
53 | await fetchRemoteVideoStaticFile(video, remoteStaticPath, destPath) | 52 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) |
54 | 53 | ||
55 | return { isOwned: false, path: destPath } | 54 | return { isOwned: false, path: destPath } |
56 | } | 55 | } |
diff --git a/server/lib/files-cache/videos-preview-cache.ts b/server/lib/files-cache/videos-preview-cache.ts index 3da6bb138..d0d4fc5b5 100644 --- a/server/lib/files-cache/videos-preview-cache.ts +++ b/server/lib/files-cache/videos-preview-cache.ts | |||
@@ -1,9 +1,8 @@ | |||
1 | import { join } from 'path' | 1 | import { join } from 'path' |
2 | import { FILES_CACHE, STATIC_PATHS } from '../../initializers/constants' | 2 | import { FILES_CACHE } from '../../initializers/constants' |
3 | import { VideoModel } from '../../models/video/video' | 3 | import { VideoModel } from '../../models/video/video' |
4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' | 4 | import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache' |
5 | import { CONFIG } from '../../initializers/config' | 5 | import { doRequestAndSaveToFile } from '@server/helpers/requests' |
6 | import { fetchRemoteVideoStaticFile } from '../activitypub' | ||
7 | 6 | ||
8 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | 7 | class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { |
9 | 8 | ||
@@ -32,11 +31,11 @@ class VideosPreviewCache extends AbstractVideoStaticFileCache <string> { | |||
32 | 31 | ||
33 | if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') | 32 | if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.') |
34 | 33 | ||
35 | // FIXME: use URL | 34 | const preview = video.getPreview() |
36 | const remoteStaticPath = join(STATIC_PATHS.PREVIEWS, video.getPreview().filename) | 35 | const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, preview.filename) |
37 | const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, video.getPreview().filename) | ||
38 | 36 | ||
39 | await fetchRemoteVideoStaticFile(video, remoteStaticPath, destPath) | 37 | const remoteUrl = preview.getFileUrl(video) |
38 | await doRequestAndSaveToFile({ uri: remoteUrl }, destPath) | ||
40 | 39 | ||
41 | return { isOwned: false, path: destPath } | 40 | return { isOwned: false, path: destPath } |
42 | } | 41 | } |
diff --git a/server/lib/job-queue/handlers/activitypub-http-broadcast.ts b/server/lib/job-queue/handlers/activitypub-http-broadcast.ts index 0ff7b44a0..7d9dd61e9 100644 --- a/server/lib/job-queue/handlers/activitypub-http-broadcast.ts +++ b/server/lib/job-queue/handlers/activitypub-http-broadcast.ts | |||
@@ -5,11 +5,13 @@ import { doRequest } from '../../../helpers/requests' | |||
5 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' | 5 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' |
6 | import { BROADCAST_CONCURRENCY, JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' | 6 | import { BROADCAST_CONCURRENCY, JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' |
7 | import { ActorFollowScoreCache } from '../../files-cache' | 7 | import { ActorFollowScoreCache } from '../../files-cache' |
8 | import { ContextType } from '@server/helpers/activitypub' | ||
8 | 9 | ||
9 | export type ActivitypubHttpBroadcastPayload = { | 10 | export type ActivitypubHttpBroadcastPayload = { |
10 | uris: string[] | 11 | uris: string[] |
11 | signatureActorId?: number | 12 | signatureActorId?: number |
12 | body: any | 13 | body: any |
14 | contextType?: ContextType | ||
13 | } | 15 | } |
14 | 16 | ||
15 | async function processActivityPubHttpBroadcast (job: Bull.Job) { | 17 | async function processActivityPubHttpBroadcast (job: Bull.Job) { |
diff --git a/server/lib/job-queue/handlers/activitypub-http-unicast.ts b/server/lib/job-queue/handlers/activitypub-http-unicast.ts index c70ce3be9..6b71e2891 100644 --- a/server/lib/job-queue/handlers/activitypub-http-unicast.ts +++ b/server/lib/job-queue/handlers/activitypub-http-unicast.ts | |||
@@ -4,11 +4,13 @@ import { doRequest } from '../../../helpers/requests' | |||
4 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' | 4 | import { buildGlobalHeaders, buildSignedRequestOptions, computeBody } from './utils/activitypub-http-utils' |
5 | import { JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' | 5 | import { JOB_REQUEST_TIMEOUT } from '../../../initializers/constants' |
6 | import { ActorFollowScoreCache } from '../../files-cache' | 6 | import { ActorFollowScoreCache } from '../../files-cache' |
7 | import { ContextType } from '@server/helpers/activitypub' | ||
7 | 8 | ||
8 | export type ActivitypubHttpUnicastPayload = { | 9 | export type ActivitypubHttpUnicastPayload = { |
9 | uri: string | 10 | uri: string |
10 | signatureActorId?: number | 11 | signatureActorId?: number |
11 | body: any | 12 | body: any |
13 | contextType?: ContextType | ||
12 | } | 14 | } |
13 | 15 | ||
14 | async function processActivityPubHttpUnicast (job: Bull.Job) { | 16 | async function processActivityPubHttpUnicast (job: Bull.Job) { |
diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts index d3bde6e6a..54b35840d 100644 --- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts +++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { buildSignedActivity } from '../../../../helpers/activitypub' | 1 | import { buildSignedActivity, ContextType } from '../../../../helpers/activitypub' |
2 | import { getServerActor } from '../../../../helpers/utils' | 2 | import { getServerActor } from '../../../../helpers/utils' |
3 | import { ActorModel } from '../../../../models/activitypub/actor' | 3 | import { ActorModel } from '../../../../models/activitypub/actor' |
4 | import { sha256 } from '../../../../helpers/core-utils' | 4 | import { sha256 } from '../../../../helpers/core-utils' |
5 | import { HTTP_SIGNATURE } from '../../../../initializers/constants' | 5 | import { HTTP_SIGNATURE } from '../../../../initializers/constants' |
6 | import { MActor } from '../../../../typings/models' | 6 | import { MActor } from '../../../../typings/models' |
7 | 7 | ||
8 | type Payload = { body: any, signatureActorId?: number } | 8 | type Payload = { body: any, contextType?: ContextType, signatureActorId?: number } |
9 | 9 | ||
10 | async function computeBody (payload: Payload) { | 10 | async function computeBody (payload: Payload) { |
11 | let body = payload.body | 11 | let body = payload.body |
@@ -13,7 +13,7 @@ async function computeBody (payload: Payload) { | |||
13 | if (payload.signatureActorId) { | 13 | if (payload.signatureActorId) { |
14 | const actorSignature = await ActorModel.load(payload.signatureActorId) | 14 | const actorSignature = await ActorModel.load(payload.signatureActorId) |
15 | if (!actorSignature) throw new Error('Unknown signature actor id.') | 15 | if (!actorSignature) throw new Error('Unknown signature actor id.') |
16 | body = await buildSignedActivity(actorSignature, payload.body) | 16 | body = await buildSignedActivity(actorSignature, payload.body, payload.contextType) |
17 | } | 17 | } |
18 | 18 | ||
19 | return body | 19 | return body |
@@ -42,7 +42,7 @@ async function buildSignedRequestOptions (payload: Payload) { | |||
42 | 42 | ||
43 | function buildGlobalHeaders (body: any) { | 43 | function buildGlobalHeaders (body: any) { |
44 | return { | 44 | return { |
45 | 'Digest': buildDigest(body) | 45 | Digest: buildDigest(body) |
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index 99c991e72..be9e7d181 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts | |||
@@ -11,7 +11,7 @@ import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | |||
11 | import { getVideoFilePath } from '@server/lib/video-paths' | 11 | import { getVideoFilePath } from '@server/lib/video-paths' |
12 | 12 | ||
13 | export type VideoFileImportPayload = { | 13 | export type VideoFileImportPayload = { |
14 | videoUUID: string, | 14 | videoUUID: string |
15 | filePath: string | 15 | filePath: string |
16 | } | 16 | } |
17 | 17 | ||
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 1fca17584..09f225cec 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts | |||
@@ -221,7 +221,7 @@ async function processFile (downloader: () => Promise<string>, videoImport: MVid | |||
221 | isNewVideo: true | 221 | isNewVideo: true |
222 | } | 222 | } |
223 | 223 | ||
224 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 224 | await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput }) |
225 | } | 225 | } |
226 | 226 | ||
227 | } catch (err) { | 227 | } catch (err) { |
diff --git a/server/lib/job-queue/handlers/video-redundancy.ts b/server/lib/job-queue/handlers/video-redundancy.ts new file mode 100644 index 000000000..319d7090e --- /dev/null +++ b/server/lib/job-queue/handlers/video-redundancy.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import * as Bull from 'bull' | ||
2 | import { logger } from '../../../helpers/logger' | ||
3 | import { VideosRedundancyScheduler } from '@server/lib/schedulers/videos-redundancy-scheduler' | ||
4 | |||
5 | export type VideoRedundancyPayload = { | ||
6 | videoId: number | ||
7 | } | ||
8 | |||
9 | async function processVideoRedundancy (job: Bull.Job) { | ||
10 | const payload = job.data as VideoRedundancyPayload | ||
11 | logger.info('Processing video redundancy in job %d.', job.id) | ||
12 | |||
13 | return VideosRedundancyScheduler.Instance.createManualRedundancy(payload.videoId) | ||
14 | } | ||
15 | |||
16 | // --------------------------------------------------------------------------- | ||
17 | |||
18 | export { | ||
19 | processVideoRedundancy | ||
20 | } | ||
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 39b9fac98..c020057c9 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -6,7 +6,6 @@ import { JobQueue } from '../job-queue' | |||
6 | import { federateVideoIfNeeded } from '../../activitypub' | 6 | import { federateVideoIfNeeded } from '../../activitypub' |
7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | 7 | import { retryTransactionWrapper } from '../../../helpers/database-utils' |
8 | import { sequelizeTypescript } from '../../../initializers' | 8 | import { sequelizeTypescript } from '../../../initializers' |
9 | import * as Bluebird from 'bluebird' | ||
10 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' | 9 | import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' |
11 | import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' | 10 | import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' |
12 | import { Notifier } from '../../notifier' | 11 | import { Notifier } from '../../notifier' |
@@ -40,8 +39,11 @@ interface OptimizeTranscodingPayload extends BaseTranscodingPayload { | |||
40 | type: 'optimize' | 39 | type: 'optimize' |
41 | } | 40 | } |
42 | 41 | ||
43 | export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload | 42 | export type VideoTranscodingPayload = |
44 | | OptimizeTranscodingPayload | MergeAudioTranscodingPayload | 43 | HLSTranscodingPayload |
44 | | NewResolutionTranscodingPayload | ||
45 | | OptimizeTranscodingPayload | ||
46 | | MergeAudioTranscodingPayload | ||
45 | 47 | ||
46 | async function processVideoTranscoding (job: Bull.Job) { | 48 | async function processVideoTranscoding (job: Bull.Job) { |
47 | const payload = job.data as VideoTranscodingPayload | 49 | const payload = job.data as VideoTranscodingPayload |
@@ -105,7 +107,7 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
105 | 107 | ||
106 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { | 108 | const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { |
107 | // Maybe the video changed in database, refresh it | 109 | // Maybe the video changed in database, refresh it |
108 | let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) | 110 | const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t) |
109 | // Video does not exist anymore | 111 | // Video does not exist anymore |
110 | if (!videoDatabase) return undefined | 112 | if (!videoDatabase) return undefined |
111 | 113 | ||
@@ -122,8 +124,6 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
122 | await createHlsJobIfEnabled(hlsPayload) | 124 | await createHlsJobIfEnabled(hlsPayload) |
123 | 125 | ||
124 | if (resolutionsEnabled.length !== 0) { | 126 | if (resolutionsEnabled.length !== 0) { |
125 | const tasks: (Bluebird<Bull.Job<any>> | Promise<Bull.Job<any>>)[] = [] | ||
126 | |||
127 | for (const resolution of resolutionsEnabled) { | 127 | for (const resolution of resolutionsEnabled) { |
128 | let dataInput: VideoTranscodingPayload | 128 | let dataInput: VideoTranscodingPayload |
129 | 129 | ||
@@ -143,12 +143,9 @@ async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: O | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | const p = JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | 146 | JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) |
147 | tasks.push(p) | ||
148 | } | 147 | } |
149 | 148 | ||
150 | await Promise.all(tasks) | ||
151 | |||
152 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) | 149 | logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) |
153 | } else { | 150 | } else { |
154 | // No transcoding to do, it's now published | 151 | // No transcoding to do, it's now published |
diff --git a/server/lib/job-queue/handlers/video-views.ts b/server/lib/job-queue/handlers/video-views.ts index 73fa5ed04..2258cd029 100644 --- a/server/lib/job-queue/handlers/video-views.ts +++ b/server/lib/job-queue/handlers/video-views.ts | |||
@@ -23,6 +23,8 @@ async function processVideosViews () { | |||
23 | for (const videoId of videoIds) { | 23 | for (const videoId of videoIds) { |
24 | try { | 24 | try { |
25 | const views = await Redis.Instance.getVideoViews(videoId, hour) | 25 | const views = await Redis.Instance.getVideoViews(videoId, hour) |
26 | await Redis.Instance.deleteVideoViews(videoId, hour) | ||
27 | |||
26 | if (views) { | 28 | if (views) { |
27 | logger.debug('Adding %d views to video %d in hour %d.', views, videoId, hour) | 29 | logger.debug('Adding %d views to video %d in hour %d.', views, videoId, hour) |
28 | 30 | ||
@@ -52,8 +54,6 @@ async function processVideosViews () { | |||
52 | logger.error('Cannot create video views for video %d in hour %d.', videoId, hour, { err }) | 54 | logger.error('Cannot create video views for video %d in hour %d.', videoId, hour, { err }) |
53 | } | 55 | } |
54 | } | 56 | } |
55 | |||
56 | await Redis.Instance.deleteVideoViews(videoId, hour) | ||
57 | } catch (err) { | 57 | } catch (err) { |
58 | logger.error('Cannot update video views of video %d in hour %d.', videoId, hour, { err }) | 58 | logger.error('Cannot update video views of video %d in hour %d.', videoId, hour, { err }) |
59 | } | 59 | } |
diff --git a/server/lib/job-queue/job-queue.ts b/server/lib/job-queue/job-queue.ts index ec601e9ea..14acace7d 100644 --- a/server/lib/job-queue/job-queue.ts +++ b/server/lib/job-queue/job-queue.ts | |||
@@ -13,6 +13,7 @@ import { processVideoImport, VideoImportPayload } from './handlers/video-import' | |||
13 | import { processVideosViews } from './handlers/video-views' | 13 | import { processVideosViews } from './handlers/video-views' |
14 | import { refreshAPObject, RefreshPayload } from './handlers/activitypub-refresher' | 14 | import { refreshAPObject, RefreshPayload } from './handlers/activitypub-refresher' |
15 | import { processVideoFileImport, VideoFileImportPayload } from './handlers/video-file-import' | 15 | import { processVideoFileImport, VideoFileImportPayload } from './handlers/video-file-import' |
16 | import { processVideoRedundancy, VideoRedundancyPayload } from '@server/lib/job-queue/handlers/video-redundancy' | ||
16 | 17 | ||
17 | type CreateJobArgument = | 18 | type CreateJobArgument = |
18 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | | 19 | { type: 'activitypub-http-broadcast', payload: ActivitypubHttpBroadcastPayload } | |
@@ -24,20 +25,21 @@ type CreateJobArgument = | |||
24 | { type: 'email', payload: EmailPayload } | | 25 | { type: 'email', payload: EmailPayload } | |
25 | { type: 'video-import', payload: VideoImportPayload } | | 26 | { type: 'video-import', payload: VideoImportPayload } | |
26 | { type: 'activitypub-refresher', payload: RefreshPayload } | | 27 | { type: 'activitypub-refresher', payload: RefreshPayload } | |
27 | { type: 'videos-views', payload: {} } | 28 | { type: 'videos-views', payload: {} } | |
29 | { type: 'video-redundancy', payload: VideoRedundancyPayload } | ||
28 | 30 | ||
29 | const handlers: { [ id in (JobType | 'video-file') ]: (job: Bull.Job) => Promise<any>} = { | 31 | const handlers: { [id in JobType]: (job: Bull.Job) => Promise<any> } = { |
30 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, | 32 | 'activitypub-http-broadcast': processActivityPubHttpBroadcast, |
31 | 'activitypub-http-unicast': processActivityPubHttpUnicast, | 33 | 'activitypub-http-unicast': processActivityPubHttpUnicast, |
32 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, | 34 | 'activitypub-http-fetcher': processActivityPubHttpFetcher, |
33 | 'activitypub-follow': processActivityPubFollow, | 35 | 'activitypub-follow': processActivityPubFollow, |
34 | 'video-file-import': processVideoFileImport, | 36 | 'video-file-import': processVideoFileImport, |
35 | 'video-transcoding': processVideoTranscoding, | 37 | 'video-transcoding': processVideoTranscoding, |
36 | 'video-file': processVideoTranscoding, // TODO: remove it (changed in 1.3) | ||
37 | 'email': processEmail, | 38 | 'email': processEmail, |
38 | 'video-import': processVideoImport, | 39 | 'video-import': processVideoImport, |
39 | 'videos-views': processVideosViews, | 40 | 'videos-views': processVideosViews, |
40 | 'activitypub-refresher': refreshAPObject | 41 | 'activitypub-refresher': refreshAPObject, |
42 | 'video-redundancy': processVideoRedundancy | ||
41 | } | 43 | } |
42 | 44 | ||
43 | const jobTypes: JobType[] = [ | 45 | const jobTypes: JobType[] = [ |
@@ -50,20 +52,22 @@ const jobTypes: JobType[] = [ | |||
50 | 'video-file-import', | 52 | 'video-file-import', |
51 | 'video-import', | 53 | 'video-import', |
52 | 'videos-views', | 54 | 'videos-views', |
53 | 'activitypub-refresher' | 55 | 'activitypub-refresher', |
56 | 'video-redundancy' | ||
54 | ] | 57 | ] |
55 | 58 | ||
56 | class JobQueue { | 59 | class JobQueue { |
57 | 60 | ||
58 | private static instance: JobQueue | 61 | private static instance: JobQueue |
59 | 62 | ||
60 | private queues: { [ id in JobType ]?: Bull.Queue } = {} | 63 | private queues: { [id in JobType]?: Bull.Queue } = {} |
61 | private initialized = false | 64 | private initialized = false |
62 | private jobRedisPrefix: string | 65 | private jobRedisPrefix: string |
63 | 66 | ||
64 | private constructor () {} | 67 | private constructor () { |
68 | } | ||
65 | 69 | ||
66 | async init () { | 70 | init () { |
67 | // Already initialized | 71 | // Already initialized |
68 | if (this.initialized === true) return | 72 | if (this.initialized === true) return |
69 | this.initialized = true | 73 | this.initialized = true |
@@ -105,11 +109,16 @@ class JobQueue { | |||
105 | } | 109 | } |
106 | } | 110 | } |
107 | 111 | ||
108 | createJob (obj: CreateJobArgument) { | 112 | createJob (obj: CreateJobArgument): void { |
113 | this.createJobWithPromise(obj) | ||
114 | .catch(err => logger.error('Cannot create job.', { err, obj })) | ||
115 | } | ||
116 | |||
117 | createJobWithPromise (obj: CreateJobArgument) { | ||
109 | const queue = this.queues[obj.type] | 118 | const queue = this.queues[obj.type] |
110 | if (queue === undefined) { | 119 | if (queue === undefined) { |
111 | logger.error('Unknown queue %s: cannot create job.', obj.type) | 120 | logger.error('Unknown queue %s: cannot create job.', obj.type) |
112 | throw Error('Unknown queue, cannot create job') | 121 | return |
113 | } | 122 | } |
114 | 123 | ||
115 | const jobArgs: Bull.JobOptions = { | 124 | const jobArgs: Bull.JobOptions = { |
@@ -122,10 +131,10 @@ class JobQueue { | |||
122 | } | 131 | } |
123 | 132 | ||
124 | async listForApi (options: { | 133 | async listForApi (options: { |
125 | state: JobState, | 134 | state: JobState |
126 | start: number, | 135 | start: number |
127 | count: number, | 136 | count: number |
128 | asc?: boolean, | 137 | asc?: boolean |
129 | jobType: JobType | 138 | jobType: JobType |
130 | }): Promise<Bull.Job[]> { | 139 | }): Promise<Bull.Job[]> { |
131 | const { state, start, count, asc, jobType } = options | 140 | const { state, start, count, asc, jobType } = options |
@@ -133,16 +142,14 @@ class JobQueue { | |||
133 | 142 | ||
134 | const filteredJobTypes = this.filterJobTypes(jobType) | 143 | const filteredJobTypes = this.filterJobTypes(jobType) |
135 | 144 | ||
136 | // TODO: optimize | ||
137 | for (const jobType of filteredJobTypes) { | 145 | for (const jobType of filteredJobTypes) { |
138 | const queue = this.queues[ jobType ] | 146 | const queue = this.queues[jobType] |
139 | if (queue === undefined) { | 147 | if (queue === undefined) { |
140 | logger.error('Unknown queue %s to list jobs.', jobType) | 148 | logger.error('Unknown queue %s to list jobs.', jobType) |
141 | continue | 149 | continue |
142 | } | 150 | } |
143 | 151 | ||
144 | // FIXME: Bull queue typings does not have getJobs method | 152 | const jobs = await queue.getJobs([ state ], 0, start + count, asc) |
145 | const jobs = await (queue as any).getJobs(state, 0, start + count, asc) | ||
146 | results = results.concat(jobs) | 153 | results = results.concat(jobs) |
147 | } | 154 | } |
148 | 155 | ||
@@ -164,7 +171,7 @@ class JobQueue { | |||
164 | const filteredJobTypes = this.filterJobTypes(jobType) | 171 | const filteredJobTypes = this.filterJobTypes(jobType) |
165 | 172 | ||
166 | for (const type of filteredJobTypes) { | 173 | for (const type of filteredJobTypes) { |
167 | const queue = this.queues[ type ] | 174 | const queue = this.queues[type] |
168 | if (queue === undefined) { | 175 | if (queue === undefined) { |
169 | logger.error('Unknown queue %s to count jobs.', type) | 176 | logger.error('Unknown queue %s to count jobs.', type) |
170 | continue | 177 | continue |
@@ -172,7 +179,7 @@ class JobQueue { | |||
172 | 179 | ||
173 | const counts = await queue.getJobCounts() | 180 | const counts = await queue.getJobCounts() |
174 | 181 | ||
175 | total += counts[ state ] | 182 | total += counts[state] |
176 | } | 183 | } |
177 | 184 | ||
178 | return total | 185 | return total |
@@ -188,7 +195,7 @@ class JobQueue { | |||
188 | private addRepeatableJobs () { | 195 | private addRepeatableJobs () { |
189 | this.queues['videos-views'].add({}, { | 196 | this.queues['videos-views'].add({}, { |
190 | repeat: REPEAT_JOBS['videos-views'] | 197 | repeat: REPEAT_JOBS['videos-views'] |
191 | }) | 198 | }).catch(err => logger.error('Cannot add repeatable job.', { err })) |
192 | } | 199 | } |
193 | 200 | ||
194 | private filterJobTypes (jobType?: JobType) { | 201 | private filterJobTypes (jobType?: JobType) { |
diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index b609f4585..55f7a985d 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts | |||
@@ -15,41 +15,41 @@ export type AcceptResult = { | |||
15 | 15 | ||
16 | // Can be filtered by plugins | 16 | // Can be filtered by plugins |
17 | function isLocalVideoAccepted (object: { | 17 | function isLocalVideoAccepted (object: { |
18 | videoBody: VideoCreate, | 18 | videoBody: VideoCreate |
19 | videoFile: Express.Multer.File & { duration?: number }, | 19 | videoFile: Express.Multer.File & { duration?: number } |
20 | user: UserModel | 20 | user: UserModel |
21 | }): AcceptResult { | 21 | }): AcceptResult { |
22 | return { accepted: true } | 22 | return { accepted: true } |
23 | } | 23 | } |
24 | 24 | ||
25 | function isLocalVideoThreadAccepted (_object: { | 25 | function isLocalVideoThreadAccepted (_object: { |
26 | commentBody: VideoCommentCreate, | 26 | commentBody: VideoCommentCreate |
27 | video: VideoModel, | 27 | video: VideoModel |
28 | user: UserModel | 28 | user: UserModel |
29 | }): AcceptResult { | 29 | }): AcceptResult { |
30 | return { accepted: true } | 30 | return { accepted: true } |
31 | } | 31 | } |
32 | 32 | ||
33 | function isLocalVideoCommentReplyAccepted (_object: { | 33 | function isLocalVideoCommentReplyAccepted (_object: { |
34 | commentBody: VideoCommentCreate, | 34 | commentBody: VideoCommentCreate |
35 | parentComment: VideoCommentModel, | 35 | parentComment: VideoCommentModel |
36 | video: VideoModel, | 36 | video: VideoModel |
37 | user: UserModel | 37 | user: UserModel |
38 | }): AcceptResult { | 38 | }): AcceptResult { |
39 | return { accepted: true } | 39 | return { accepted: true } |
40 | } | 40 | } |
41 | 41 | ||
42 | function isRemoteVideoAccepted (_object: { | 42 | function isRemoteVideoAccepted (_object: { |
43 | activity: ActivityCreate, | 43 | activity: ActivityCreate |
44 | videoAP: VideoTorrentObject, | 44 | videoAP: VideoTorrentObject |
45 | byActor: ActorModel | 45 | byActor: ActorModel |
46 | }): AcceptResult { | 46 | }): AcceptResult { |
47 | return { accepted: true } | 47 | return { accepted: true } |
48 | } | 48 | } |
49 | 49 | ||
50 | function isRemoteVideoCommentAccepted (_object: { | 50 | function isRemoteVideoCommentAccepted (_object: { |
51 | activity: ActivityCreate, | 51 | activity: ActivityCreate |
52 | commentAP: VideoCommentObject, | 52 | commentAP: VideoCommentObject |
53 | byActor: ActorModel | 53 | byActor: ActorModel |
54 | }): AcceptResult { | 54 | }): AcceptResult { |
55 | return { accepted: true } | 55 | return { accepted: true } |
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index 679b9bcf6..63197eee1 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -6,7 +6,6 @@ import { UserModel } from '../models/account/user' | |||
6 | import { PeerTubeSocket } from './peertube-socket' | 6 | import { PeerTubeSocket } from './peertube-socket' |
7 | import { CONFIG } from '../initializers/config' | 7 | import { CONFIG } from '../initializers/config' |
8 | import { VideoPrivacy, VideoState } from '../../shared/models/videos' | 8 | import { VideoPrivacy, VideoState } from '../../shared/models/videos' |
9 | import * as Bluebird from 'bluebird' | ||
10 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | 9 | import { AccountBlocklistModel } from '../models/account/account-blocklist' |
11 | import { | 10 | import { |
12 | MCommentOwnerVideo, | 11 | MCommentOwnerVideo, |
@@ -17,7 +16,8 @@ import { | |||
17 | MVideoFullLight | 16 | MVideoFullLight |
18 | } from '../typings/models/video' | 17 | } from '../typings/models/video' |
19 | import { | 18 | import { |
20 | MUser, MUserAccount, | 19 | MUser, |
20 | MUserAccount, | ||
21 | MUserDefault, | 21 | MUserDefault, |
22 | MUserNotifSettingAccount, | 22 | MUserNotifSettingAccount, |
23 | MUserWithNotificationSetting, | 23 | MUserWithNotificationSetting, |
@@ -32,14 +32,15 @@ class Notifier { | |||
32 | 32 | ||
33 | private static instance: Notifier | 33 | private static instance: Notifier |
34 | 34 | ||
35 | private constructor () {} | 35 | private constructor () { |
36 | } | ||
36 | 37 | ||
37 | notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { | 38 | notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { |
38 | // Only notify on public and published videos which are not blacklisted | 39 | // Only notify on public and published videos which are not blacklisted |
39 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return | 40 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return |
40 | 41 | ||
41 | this.notifySubscribersOfNewVideo(video) | 42 | this.notifySubscribersOfNewVideo(video) |
42 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) | 43 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) |
43 | } | 44 | } |
44 | 45 | ||
45 | notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { | 46 | notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { |
@@ -63,7 +64,9 @@ class Notifier { | |||
63 | if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return | 64 | if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return |
64 | 65 | ||
65 | this.notifyOwnedVideoHasBeenPublished(video) | 66 | this.notifyOwnedVideoHasBeenPublished(video) |
66 | .catch(err => logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })) // tslint:disable-line:max-line-length | 67 | .catch(err => { |
68 | logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err }) | ||
69 | }) | ||
67 | } | 70 | } |
68 | 71 | ||
69 | notifyOnNewComment (comment: MCommentOwnerVideo): void { | 72 | notifyOnNewComment (comment: MCommentOwnerVideo): void { |
@@ -76,17 +79,17 @@ class Notifier { | |||
76 | 79 | ||
77 | notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { | 80 | notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { |
78 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) | 81 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) |
79 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) | 82 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) |
80 | } | 83 | } |
81 | 84 | ||
82 | notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void { | 85 | notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void { |
83 | this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist) | 86 | this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist) |
84 | .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err })) | 87 | .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err })) |
85 | } | 88 | } |
86 | 89 | ||
87 | notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { | 90 | notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { |
88 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) | 91 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) |
89 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) | 92 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) |
90 | } | 93 | } |
91 | 94 | ||
92 | notifyOnVideoUnblacklist (video: MVideoFullLight): void { | 95 | notifyOnVideoUnblacklist (video: MVideoFullLight): void { |
@@ -96,7 +99,7 @@ class Notifier { | |||
96 | 99 | ||
97 | notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { | 100 | notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { |
98 | this.notifyOwnerVideoImportIsFinished(videoImport, success) | 101 | this.notifyOwnerVideoImportIsFinished(videoImport, success) |
99 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) | 102 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) |
100 | } | 103 | } |
101 | 104 | ||
102 | notifyOnNewUserRegistration (user: MUserDefault): void { | 105 | notifyOnNewUserRegistration (user: MUserDefault): void { |
@@ -106,14 +109,14 @@ class Notifier { | |||
106 | 109 | ||
107 | notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { | 110 | notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { |
108 | this.notifyUserOfNewActorFollow(actorFollow) | 111 | this.notifyUserOfNewActorFollow(actorFollow) |
109 | .catch(err => { | 112 | .catch(err => { |
110 | logger.error( | 113 | logger.error( |
111 | 'Cannot notify owner of channel %s of a new follow by %s.', | 114 | 'Cannot notify owner of channel %s of a new follow by %s.', |
112 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), | 115 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), |
113 | actorFollow.ActorFollower.Account.getDisplayName(), | 116 | actorFollow.ActorFollower.Account.getDisplayName(), |
114 | { err } | 117 | { err } |
115 | ) | 118 | ) |
116 | }) | 119 | }) |
117 | } | 120 | } |
118 | 121 | ||
119 | notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void { | 122 | notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void { |
@@ -548,10 +551,10 @@ class Notifier { | |||
548 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) | 551 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) |
549 | } | 552 | } |
550 | 553 | ||
551 | private async notify <T extends MUserWithNotificationSetting> (options: { | 554 | private async notify<T extends MUserWithNotificationSetting> (options: { |
552 | users: T[], | 555 | users: T[] |
553 | notificationCreator: (user: T) => Promise<UserNotificationModelForApi>, | 556 | notificationCreator: (user: T) => Promise<UserNotificationModelForApi> |
554 | emailSender: (emails: string[]) => Promise<any> | Bluebird<any>, | 557 | emailSender: (emails: string[]) => void |
555 | settingGetter: (user: T) => UserNotificationSettingValue | 558 | settingGetter: (user: T) => UserNotificationSettingValue |
556 | }) { | 559 | }) { |
557 | const emails: string[] = [] | 560 | const emails: string[] = [] |
@@ -569,7 +572,7 @@ class Notifier { | |||
569 | } | 572 | } |
570 | 573 | ||
571 | if (emails.length !== 0) { | 574 | if (emails.length !== 0) { |
572 | await options.emailSender(emails) | 575 | options.emailSender(emails) |
573 | } | 576 | } |
574 | } | 577 | } |
575 | 578 | ||
diff --git a/server/lib/plugins/plugin-index.ts b/server/lib/plugins/plugin-index.ts index 25b4f3c61..dcdfba28c 100644 --- a/server/lib/plugins/plugin-index.ts +++ b/server/lib/plugins/plugin-index.ts | |||
@@ -31,7 +31,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) | |||
31 | 31 | ||
32 | logger.debug('Got result from PeerTube index.', { body }) | 32 | logger.debug('Got result from PeerTube index.', { body }) |
33 | 33 | ||
34 | await addInstanceInformation(body) | 34 | addInstanceInformation(body) |
35 | 35 | ||
36 | return body as ResultList<PeerTubePluginIndex> | 36 | return body as ResultList<PeerTubePluginIndex> |
37 | } catch (err) { | 37 | } catch (err) { |
@@ -40,7 +40,7 @@ async function listAvailablePluginsFromIndex (options: PeertubePluginIndexList) | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | async function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { | 43 | function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) { |
44 | for (const d of result.data) { | 44 | for (const d of result.data) { |
45 | d.installed = PluginManager.Instance.isRegistered(d.npmName) | 45 | d.installed = PluginManager.Instance.isRegistered(d.npmName) |
46 | d.name = PluginModel.normalizePluginName(d.npmName) | 46 | d.name = PluginModel.normalizePluginName(d.npmName) |
diff --git a/server/lib/plugins/plugin-manager.ts b/server/lib/plugins/plugin-manager.ts index 7ebdabd34..73f7a71ce 100644 --- a/server/lib/plugins/plugin-manager.ts +++ b/server/lib/plugins/plugin-manager.ts | |||
@@ -55,30 +55,30 @@ export interface HookInformationValue { | |||
55 | } | 55 | } |
56 | 56 | ||
57 | type AlterableVideoConstant = 'language' | 'licence' | 'category' | 57 | type AlterableVideoConstant = 'language' | 'licence' | 'category' |
58 | type VideoConstant = { [ key in number | string ]: string } | 58 | type VideoConstant = { [key in number | string]: string } |
59 | type UpdatedVideoConstant = { | 59 | type UpdatedVideoConstant = { |
60 | [ name in AlterableVideoConstant ]: { | 60 | [name in AlterableVideoConstant]: { |
61 | [ npmName: string ]: { | 61 | [npmName: string]: { |
62 | added: { key: number | string, label: string }[], | 62 | added: { key: number | string, label: string }[] |
63 | deleted: { key: number | string, label: string }[] | 63 | deleted: { key: number | string, label: string }[] |
64 | } | 64 | } |
65 | } | 65 | } |
66 | } | 66 | } |
67 | 67 | ||
68 | type PluginLocalesTranslations = { | 68 | type PluginLocalesTranslations = { |
69 | [ locale: string ]: PluginTranslation | 69 | [locale: string]: PluginTranslation |
70 | } | 70 | } |
71 | 71 | ||
72 | export class PluginManager implements ServerHook { | 72 | export class PluginManager implements ServerHook { |
73 | 73 | ||
74 | private static instance: PluginManager | 74 | private static instance: PluginManager |
75 | 75 | ||
76 | private registeredPlugins: { [ name: string ]: RegisteredPlugin } = {} | 76 | private registeredPlugins: { [name: string]: RegisteredPlugin } = {} |
77 | private settings: { [ name: string ]: RegisterServerSettingOptions[] } = {} | 77 | private settings: { [name: string]: RegisterServerSettingOptions[] } = {} |
78 | private hooks: { [ name: string ]: HookInformationValue[] } = {} | 78 | private hooks: { [name: string]: HookInformationValue[] } = {} |
79 | private translations: PluginLocalesTranslations = {} | 79 | private translations: PluginLocalesTranslations = {} |
80 | 80 | ||
81 | private updatedVideoConstants: UpdatedVideoConstant = { | 81 | private readonly updatedVideoConstants: UpdatedVideoConstant = { |
82 | language: {}, | 82 | language: {}, |
83 | licence: {}, | 83 | licence: {}, |
84 | category: {} | 84 | category: {} |
@@ -133,7 +133,7 @@ export class PluginManager implements ServerHook { | |||
133 | 133 | ||
134 | // ###################### Hooks ###################### | 134 | // ###################### Hooks ###################### |
135 | 135 | ||
136 | async runHook <T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> { | 136 | async runHook<T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> { |
137 | if (!this.hooks[hookName]) return Promise.resolve(result) | 137 | if (!this.hooks[hookName]) return Promise.resolve(result) |
138 | 138 | ||
139 | const hookType = getHookType(hookName) | 139 | const hookType = getHookType(hookName) |
@@ -312,7 +312,7 @@ export class PluginManager implements ServerHook { | |||
312 | clientScripts[c.script] = c | 312 | clientScripts[c.script] = c |
313 | } | 313 | } |
314 | 314 | ||
315 | this.registeredPlugins[ npmName ] = { | 315 | this.registeredPlugins[npmName] = { |
316 | npmName, | 316 | npmName, |
317 | name: plugin.name, | 317 | name: plugin.name, |
318 | type: plugin.type, | 318 | type: plugin.type, |
@@ -438,7 +438,7 @@ export class PluginManager implements ServerHook { | |||
438 | const plugins: RegisteredPlugin[] = [] | 438 | const plugins: RegisteredPlugin[] = [] |
439 | 439 | ||
440 | for (const npmName of Object.keys(this.registeredPlugins)) { | 440 | for (const npmName of Object.keys(this.registeredPlugins)) { |
441 | const plugin = this.registeredPlugins[ npmName ] | 441 | const plugin = this.registeredPlugins[npmName] |
442 | if (plugin.type !== type) continue | 442 | if (plugin.type !== type) continue |
443 | 443 | ||
444 | plugins.push(plugin) | 444 | plugins.push(plugin) |
@@ -518,11 +518,11 @@ export class PluginManager implements ServerHook { | |||
518 | } | 518 | } |
519 | } | 519 | } |
520 | 520 | ||
521 | private addConstant <T extends string | number> (parameters: { | 521 | private addConstant<T extends string | number> (parameters: { |
522 | npmName: string, | 522 | npmName: string |
523 | type: AlterableVideoConstant, | 523 | type: AlterableVideoConstant |
524 | obj: VideoConstant, | 524 | obj: VideoConstant |
525 | key: T, | 525 | key: T |
526 | label: string | 526 | label: string |
527 | }) { | 527 | }) { |
528 | const { npmName, type, obj, key, label } = parameters | 528 | const { npmName, type, obj, key, label } = parameters |
@@ -545,10 +545,10 @@ export class PluginManager implements ServerHook { | |||
545 | return true | 545 | return true |
546 | } | 546 | } |
547 | 547 | ||
548 | private deleteConstant <T extends string | number> (parameters: { | 548 | private deleteConstant<T extends string | number> (parameters: { |
549 | npmName: string, | 549 | npmName: string |
550 | type: AlterableVideoConstant, | 550 | type: AlterableVideoConstant |
551 | obj: VideoConstant, | 551 | obj: VideoConstant |
552 | key: T | 552 | key: T |
553 | }) { | 553 | }) { |
554 | const { npmName, type, obj, key } = parameters | 554 | const { npmName, type, obj, key } = parameters |
@@ -604,7 +604,7 @@ export class PluginManager implements ServerHook { | |||
604 | const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType) | 604 | const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType) |
605 | if (!packageJSONValid) { | 605 | if (!packageJSONValid) { |
606 | const formattedFields = badFields.map(f => `"${f}"`) | 606 | const formattedFields = badFields.map(f => `"${f}"`) |
607 | .join(', ') | 607 | .join(', ') |
608 | 608 | ||
609 | throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`) | 609 | throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`) |
610 | } | 610 | } |
diff --git a/server/lib/redis.ts b/server/lib/redis.ts index f77d0b62c..b4cd6f8e7 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts | |||
@@ -6,13 +6,14 @@ import { | |||
6 | CONTACT_FORM_LIFETIME, | 6 | CONTACT_FORM_LIFETIME, |
7 | USER_EMAIL_VERIFY_LIFETIME, | 7 | USER_EMAIL_VERIFY_LIFETIME, |
8 | USER_PASSWORD_RESET_LIFETIME, | 8 | USER_PASSWORD_RESET_LIFETIME, |
9 | USER_PASSWORD_CREATE_LIFETIME, | ||
9 | VIDEO_VIEW_LIFETIME, | 10 | VIDEO_VIEW_LIFETIME, |
10 | WEBSERVER | 11 | WEBSERVER |
11 | } from '../initializers/constants' | 12 | } from '../initializers/constants' |
12 | import { CONFIG } from '../initializers/config' | 13 | import { CONFIG } from '../initializers/config' |
13 | 14 | ||
14 | type CachedRoute = { | 15 | type CachedRoute = { |
15 | body: string, | 16 | body: string |
16 | contentType?: string | 17 | contentType?: string |
17 | statusCode?: string | 18 | statusCode?: string |
18 | } | 19 | } |
@@ -24,7 +25,8 @@ class Redis { | |||
24 | private client: RedisClient | 25 | private client: RedisClient |
25 | private prefix: string | 26 | private prefix: string |
26 | 27 | ||
27 | private constructor () {} | 28 | private constructor () { |
29 | } | ||
28 | 30 | ||
29 | init () { | 31 | init () { |
30 | // Already initialized | 32 | // Already initialized |
@@ -49,9 +51,9 @@ class Redis { | |||
49 | return Object.assign({}, | 51 | return Object.assign({}, |
50 | (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, | 52 | (CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {}, |
51 | (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, | 53 | (CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {}, |
52 | (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) ? | 54 | (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) |
53 | { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } : | 55 | ? { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } |
54 | { path: CONFIG.REDIS.SOCKET } | 56 | : { path: CONFIG.REDIS.SOCKET } |
55 | ) | 57 | ) |
56 | } | 58 | } |
57 | 59 | ||
@@ -63,7 +65,7 @@ class Redis { | |||
63 | return this.prefix | 65 | return this.prefix |
64 | } | 66 | } |
65 | 67 | ||
66 | /************* Forgot password *************/ | 68 | /* ************ Forgot password ************ */ |
67 | 69 | ||
68 | async setResetPasswordVerificationString (userId: number) { | 70 | async setResetPasswordVerificationString (userId: number) { |
69 | const generatedString = await generateRandomString(32) | 71 | const generatedString = await generateRandomString(32) |
@@ -73,11 +75,19 @@ class Redis { | |||
73 | return generatedString | 75 | return generatedString |
74 | } | 76 | } |
75 | 77 | ||
78 | async setCreatePasswordVerificationString (userId: number) { | ||
79 | const generatedString = await generateRandomString(32) | ||
80 | |||
81 | await this.setValue(this.generateResetPasswordKey(userId), generatedString, USER_PASSWORD_CREATE_LIFETIME) | ||
82 | |||
83 | return generatedString | ||
84 | } | ||
85 | |||
76 | async getResetPasswordLink (userId: number) { | 86 | async getResetPasswordLink (userId: number) { |
77 | return this.getValue(this.generateResetPasswordKey(userId)) | 87 | return this.getValue(this.generateResetPasswordKey(userId)) |
78 | } | 88 | } |
79 | 89 | ||
80 | /************* Email verification *************/ | 90 | /* ************ Email verification ************ */ |
81 | 91 | ||
82 | async setVerifyEmailVerificationString (userId: number) { | 92 | async setVerifyEmailVerificationString (userId: number) { |
83 | const generatedString = await generateRandomString(32) | 93 | const generatedString = await generateRandomString(32) |
@@ -91,7 +101,7 @@ class Redis { | |||
91 | return this.getValue(this.generateVerifyEmailKey(userId)) | 101 | return this.getValue(this.generateVerifyEmailKey(userId)) |
92 | } | 102 | } |
93 | 103 | ||
94 | /************* Contact form per IP *************/ | 104 | /* ************ Contact form per IP ************ */ |
95 | 105 | ||
96 | async setContactFormIp (ip: string) { | 106 | async setContactFormIp (ip: string) { |
97 | return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME) | 107 | return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME) |
@@ -101,7 +111,7 @@ class Redis { | |||
101 | return this.exists(this.generateContactFormKey(ip)) | 111 | return this.exists(this.generateContactFormKey(ip)) |
102 | } | 112 | } |
103 | 113 | ||
104 | /************* Views per IP *************/ | 114 | /* ************ Views per IP ************ */ |
105 | 115 | ||
106 | setIPVideoView (ip: string, videoUUID: string) { | 116 | setIPVideoView (ip: string, videoUUID: string) { |
107 | return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) | 117 | return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) |
@@ -111,7 +121,7 @@ class Redis { | |||
111 | return this.exists(this.generateViewKey(ip, videoUUID)) | 121 | return this.exists(this.generateViewKey(ip, videoUUID)) |
112 | } | 122 | } |
113 | 123 | ||
114 | /************* API cache *************/ | 124 | /* ************ API cache ************ */ |
115 | 125 | ||
116 | async getCachedRoute (req: express.Request) { | 126 | async getCachedRoute (req: express.Request) { |
117 | const cached = await this.getObject(this.generateCachedRouteKey(req)) | 127 | const cached = await this.getObject(this.generateCachedRouteKey(req)) |
@@ -120,17 +130,17 @@ class Redis { | |||
120 | } | 130 | } |
121 | 131 | ||
122 | setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { | 132 | setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) { |
123 | const cached: CachedRoute = Object.assign({}, { | 133 | const cached: CachedRoute = Object.assign( |
124 | body: body.toString() | 134 | {}, |
125 | }, | 135 | { body: body.toString() }, |
126 | (contentType) ? { contentType } : null, | 136 | (contentType) ? { contentType } : null, |
127 | (statusCode) ? { statusCode: statusCode.toString() } : null | 137 | (statusCode) ? { statusCode: statusCode.toString() } : null |
128 | ) | 138 | ) |
129 | 139 | ||
130 | return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) | 140 | return this.setObject(this.generateCachedRouteKey(req), cached, lifetime) |
131 | } | 141 | } |
132 | 142 | ||
133 | /************* Video views *************/ | 143 | /* ************ Video views ************ */ |
134 | 144 | ||
135 | addVideoView (videoId: number) { | 145 | addVideoView (videoId: number) { |
136 | const keyIncr = this.generateVideoViewKey(videoId) | 146 | const keyIncr = this.generateVideoViewKey(videoId) |
@@ -173,7 +183,7 @@ class Redis { | |||
173 | ]) | 183 | ]) |
174 | } | 184 | } |
175 | 185 | ||
176 | /************* Keys generation *************/ | 186 | /* ************ Keys generation ************ */ |
177 | 187 | ||
178 | generateCachedRouteKey (req: express.Request) { | 188 | generateCachedRouteKey (req: express.Request) { |
179 | return req.method + '-' + req.originalUrl | 189 | return req.method + '-' + req.originalUrl |
@@ -207,7 +217,7 @@ class Redis { | |||
207 | return 'contact-form-' + ip | 217 | return 'contact-form-' + ip |
208 | } | 218 | } |
209 | 219 | ||
210 | /************* Redis helpers *************/ | 220 | /* ************ Redis helpers ************ */ |
211 | 221 | ||
212 | private getValue (key: string) { | 222 | private getValue (key: string) { |
213 | return new Promise<string>((res, rej) => { | 223 | return new Promise<string>((res, rej) => { |
@@ -265,7 +275,7 @@ class Redis { | |||
265 | }) | 275 | }) |
266 | } | 276 | } |
267 | 277 | ||
268 | private setObject (key: string, obj: { [ id: string ]: string }, expirationMilliseconds: number) { | 278 | private setObject (key: string, obj: { [id: string]: string }, expirationMilliseconds: number) { |
269 | return new Promise<void>((res, rej) => { | 279 | return new Promise<void>((res, rej) => { |
270 | this.client.hmset(this.prefix + key, obj, (err, ok) => { | 280 | this.client.hmset(this.prefix + key, obj, (err, ok) => { |
271 | if (err) return rej(err) | 281 | if (err) return rej(err) |
@@ -282,7 +292,7 @@ class Redis { | |||
282 | } | 292 | } |
283 | 293 | ||
284 | private getObject (key: string) { | 294 | private getObject (key: string) { |
285 | return new Promise<{ [ id: string ]: string }>((res, rej) => { | 295 | return new Promise<{ [id: string]: string }>((res, rej) => { |
286 | this.client.hgetall(this.prefix + key, (err, value) => { | 296 | this.client.hgetall(this.prefix + key, (err, value) => { |
287 | if (err) return rej(err) | 297 | if (err) return rej(err) |
288 | 298 | ||
diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts index 1b4ecd7c0..78d84e02e 100644 --- a/server/lib/redundancy.ts +++ b/server/lib/redundancy.ts | |||
@@ -13,10 +13,10 @@ async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t? | |||
13 | await videoRedundancy.destroy({ transaction: t }) | 13 | await videoRedundancy.destroy({ transaction: t }) |
14 | } | 14 | } |
15 | 15 | ||
16 | async function removeRedundancyOf (serverId: number) { | 16 | async function removeRedundanciesOfServer (serverId: number) { |
17 | const videosRedundancy = await VideoRedundancyModel.listLocalOfServer(serverId) | 17 | const redundancies = await VideoRedundancyModel.listLocalOfServer(serverId) |
18 | 18 | ||
19 | for (const redundancy of videosRedundancy) { | 19 | for (const redundancy of redundancies) { |
20 | await removeVideoRedundancy(redundancy) | 20 | await removeVideoRedundancy(redundancy) |
21 | } | 21 | } |
22 | } | 22 | } |
@@ -24,6 +24,6 @@ async function removeRedundancyOf (serverId: number) { | |||
24 | // --------------------------------------------------------------------------- | 24 | // --------------------------------------------------------------------------- |
25 | 25 | ||
26 | export { | 26 | export { |
27 | removeRedundancyOf, | 27 | removeRedundanciesOfServer, |
28 | removeVideoRedundancy | 28 | removeVideoRedundancy |
29 | } | 29 | } |
diff --git a/server/lib/schedulers/auto-follow-index-instances.ts b/server/lib/schedulers/auto-follow-index-instances.ts index dd326bc1e..d700a99f0 100644 --- a/server/lib/schedulers/auto-follow-index-instances.ts +++ b/server/lib/schedulers/auto-follow-index-instances.ts | |||
@@ -57,8 +57,7 @@ export class AutoFollowIndexInstances extends AbstractScheduler { | |||
57 | isAutoFollow: true | 57 | isAutoFollow: true |
58 | } | 58 | } |
59 | 59 | ||
60 | await JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) | 60 | JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) |
61 | .catch(err => logger.error('Cannot create follow job for %s.', unfollowedHost, err)) | ||
62 | } | 61 | } |
63 | } | 62 | } |
64 | 63 | ||
diff --git a/server/lib/schedulers/plugins-check-scheduler.ts b/server/lib/schedulers/plugins-check-scheduler.ts index 7ff41e639..014993e94 100644 --- a/server/lib/schedulers/plugins-check-scheduler.ts +++ b/server/lib/schedulers/plugins-check-scheduler.ts | |||
@@ -43,7 +43,7 @@ export class PluginsCheckScheduler extends AbstractScheduler { | |||
43 | const results = await getLatestPluginsVersion(npmNames) | 43 | const results = await getLatestPluginsVersion(npmNames) |
44 | 44 | ||
45 | for (const result of results) { | 45 | for (const result of results) { |
46 | const plugin = pluginIndex[ result.npmName ] | 46 | const plugin = pluginIndex[result.npmName] |
47 | if (!result.latestVersion) continue | 47 | if (!result.latestVersion) continue |
48 | 48 | ||
49 | if ( | 49 | if ( |
diff --git a/server/lib/schedulers/remove-old-views-scheduler.ts b/server/lib/schedulers/remove-old-views-scheduler.ts index 39fbb9163..5ae87fe50 100644 --- a/server/lib/schedulers/remove-old-views-scheduler.ts +++ b/server/lib/schedulers/remove-old-views-scheduler.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | import { logger } from '../../helpers/logger' | 1 | import { logger } from '../../helpers/logger' |
2 | import { AbstractScheduler } from './abstract-scheduler' | 2 | import { AbstractScheduler } from './abstract-scheduler' |
3 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 3 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
4 | import { UserVideoHistoryModel } from '../../models/account/user-video-history' | ||
5 | import { CONFIG } from '../../initializers/config' | 4 | import { CONFIG } from '../../initializers/config' |
6 | import { isTestInstance } from '../../helpers/core-utils' | ||
7 | import { VideoViewModel } from '../../models/video/video-views' | 5 | import { VideoViewModel } from '../../models/video/video-views' |
8 | 6 | ||
9 | export class RemoveOldViewsScheduler extends AbstractScheduler { | 7 | export class RemoveOldViewsScheduler extends AbstractScheduler { |
diff --git a/server/lib/schedulers/update-videos-scheduler.ts b/server/lib/schedulers/update-videos-scheduler.ts index 350a335d3..956780a77 100644 --- a/server/lib/schedulers/update-videos-scheduler.ts +++ b/server/lib/schedulers/update-videos-scheduler.ts | |||
@@ -4,7 +4,6 @@ import { ScheduleVideoUpdateModel } from '../../models/video/schedule-video-upda | |||
4 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 4 | import { retryTransactionWrapper } from '../../helpers/database-utils' |
5 | import { federateVideoIfNeeded } from '../activitypub' | 5 | import { federateVideoIfNeeded } from '../activitypub' |
6 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' | 6 | import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants' |
7 | import { VideoPrivacy } from '../../../shared/models/videos' | ||
8 | import { Notifier } from '../notifier' | 7 | import { Notifier } from '../notifier' |
9 | import { sequelizeTypescript } from '../../initializers/database' | 8 | import { sequelizeTypescript } from '../../initializers/database' |
10 | import { MVideoFullLight } from '@server/typings/models' | 9 | import { MVideoFullLight } from '@server/typings/models' |
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index c1c91b656..e33a4133a 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { AbstractScheduler } from './abstract-scheduler' | 1 | import { AbstractScheduler } from './abstract-scheduler' |
2 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' | 2 | import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } from '../../initializers/constants' |
3 | import { logger } from '../../helpers/logger' | 3 | import { logger } from '../../helpers/logger' |
4 | import { VideosRedundancy } from '../../../shared/models/redundancy' | 4 | import { VideosRedundancyStrategy } from '../../../shared/models/redundancy' |
5 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 5 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
6 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' | 6 | import { downloadWebTorrentVideo, generateMagnetUri } from '../../helpers/webtorrent' |
7 | import { join } from 'path' | 7 | import { join } from 'path' |
@@ -25,11 +25,12 @@ import { | |||
25 | MVideoWithAllFiles | 25 | MVideoWithAllFiles |
26 | } from '@server/typings/models' | 26 | } from '@server/typings/models' |
27 | import { getVideoFilename } from '../video-paths' | 27 | import { getVideoFilename } from '../video-paths' |
28 | import { VideoModel } from '@server/models/video/video' | ||
28 | 29 | ||
29 | type CandidateToDuplicate = { | 30 | type CandidateToDuplicate = { |
30 | redundancy: VideosRedundancy, | 31 | redundancy: VideosRedundancyStrategy |
31 | video: MVideoWithAllFiles, | 32 | video: MVideoWithAllFiles |
32 | files: MVideoFile[], | 33 | files: MVideoFile[] |
33 | streamingPlaylists: MStreamingPlaylistFiles[] | 34 | streamingPlaylists: MStreamingPlaylistFiles[] |
34 | } | 35 | } |
35 | 36 | ||
@@ -41,7 +42,7 @@ function isMVideoRedundancyFileVideo ( | |||
41 | 42 | ||
42 | export class VideosRedundancyScheduler extends AbstractScheduler { | 43 | export class VideosRedundancyScheduler extends AbstractScheduler { |
43 | 44 | ||
44 | private static instance: AbstractScheduler | 45 | private static instance: VideosRedundancyScheduler |
45 | 46 | ||
46 | protected schedulerIntervalMs = CONFIG.REDUNDANCY.VIDEOS.CHECK_INTERVAL | 47 | protected schedulerIntervalMs = CONFIG.REDUNDANCY.VIDEOS.CHECK_INTERVAL |
47 | 48 | ||
@@ -49,6 +50,22 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
49 | super() | 50 | super() |
50 | } | 51 | } |
51 | 52 | ||
53 | async createManualRedundancy (videoId: number) { | ||
54 | const videoToDuplicate = await VideoModel.loadWithFiles(videoId) | ||
55 | |||
56 | if (!videoToDuplicate) { | ||
57 | logger.warn('Video to manually duplicate %d does not exist anymore.', videoId) | ||
58 | return | ||
59 | } | ||
60 | |||
61 | return this.createVideoRedundancies({ | ||
62 | video: videoToDuplicate, | ||
63 | redundancy: null, | ||
64 | files: videoToDuplicate.VideoFiles, | ||
65 | streamingPlaylists: videoToDuplicate.VideoStreamingPlaylists | ||
66 | }) | ||
67 | } | ||
68 | |||
52 | protected async internalExecute () { | 69 | protected async internalExecute () { |
53 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { | 70 | for (const redundancyConfig of CONFIG.REDUNDANCY.VIDEOS.STRATEGIES) { |
54 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) | 71 | logger.info('Running redundancy scheduler for strategy %s.', redundancyConfig.strategy) |
@@ -94,7 +111,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
94 | for (const redundancyModel of expired) { | 111 | for (const redundancyModel of expired) { |
95 | try { | 112 | try { |
96 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) | 113 | const redundancyConfig = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) |
97 | const candidate = { | 114 | const candidate: CandidateToDuplicate = { |
98 | redundancy: redundancyConfig, | 115 | redundancy: redundancyConfig, |
99 | video: null, | 116 | video: null, |
100 | files: [], | 117 | files: [], |
@@ -140,7 +157,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
140 | } | 157 | } |
141 | } | 158 | } |
142 | 159 | ||
143 | private findVideoToDuplicate (cache: VideosRedundancy) { | 160 | private findVideoToDuplicate (cache: VideosRedundancyStrategy) { |
144 | if (cache.strategy === 'most-views') { | 161 | if (cache.strategy === 'most-views') { |
145 | return VideoRedundancyModel.findMostViewToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR) | 162 | return VideoRedundancyModel.findMostViewToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR) |
146 | } | 163 | } |
@@ -187,13 +204,21 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
187 | } | 204 | } |
188 | } | 205 | } |
189 | 206 | ||
190 | private async createVideoFileRedundancy (redundancy: VideosRedundancy, video: MVideoAccountLight, fileArg: MVideoFile) { | 207 | private async createVideoFileRedundancy (redundancy: VideosRedundancyStrategy | null, video: MVideoAccountLight, fileArg: MVideoFile) { |
208 | let strategy = 'manual' | ||
209 | let expiresOn: Date = null | ||
210 | |||
211 | if (redundancy) { | ||
212 | strategy = redundancy.strategy | ||
213 | expiresOn = this.buildNewExpiration(redundancy.minLifetime) | ||
214 | } | ||
215 | |||
191 | const file = fileArg as MVideoFileVideo | 216 | const file = fileArg as MVideoFileVideo |
192 | file.Video = video | 217 | file.Video = video |
193 | 218 | ||
194 | const serverActor = await getServerActor() | 219 | const serverActor = await getServerActor() |
195 | 220 | ||
196 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, redundancy.strategy) | 221 | logger.info('Duplicating %s - %d in videos redundancy with "%s" strategy.', video.url, file.resolution, strategy) |
197 | 222 | ||
198 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() | 223 | const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() |
199 | const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) | 224 | const magnetUri = generateMagnetUri(video, file, baseUrlHttp, baseUrlWs) |
@@ -204,10 +229,10 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
204 | await move(tmpPath, destPath, { overwrite: true }) | 229 | await move(tmpPath, destPath, { overwrite: true }) |
205 | 230 | ||
206 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ | 231 | const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ |
207 | expiresOn: this.buildNewExpiration(redundancy.minLifetime), | 232 | expiresOn, |
208 | url: getVideoCacheFileActivityPubUrl(file), | 233 | url: getVideoCacheFileActivityPubUrl(file), |
209 | fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), | 234 | fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), |
210 | strategy: redundancy.strategy, | 235 | strategy, |
211 | videoFileId: file.id, | 236 | videoFileId: file.id, |
212 | actorId: serverActor.id | 237 | actorId: serverActor.id |
213 | }) | 238 | }) |
@@ -220,25 +245,33 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
220 | } | 245 | } |
221 | 246 | ||
222 | private async createStreamingPlaylistRedundancy ( | 247 | private async createStreamingPlaylistRedundancy ( |
223 | redundancy: VideosRedundancy, | 248 | redundancy: VideosRedundancyStrategy, |
224 | video: MVideoAccountLight, | 249 | video: MVideoAccountLight, |
225 | playlistArg: MStreamingPlaylist | 250 | playlistArg: MStreamingPlaylist |
226 | ) { | 251 | ) { |
252 | let strategy = 'manual' | ||
253 | let expiresOn: Date = null | ||
254 | |||
255 | if (redundancy) { | ||
256 | strategy = redundancy.strategy | ||
257 | expiresOn = this.buildNewExpiration(redundancy.minLifetime) | ||
258 | } | ||
259 | |||
227 | const playlist = playlistArg as MStreamingPlaylistVideo | 260 | const playlist = playlistArg as MStreamingPlaylistVideo |
228 | playlist.Video = video | 261 | playlist.Video = video |
229 | 262 | ||
230 | const serverActor = await getServerActor() | 263 | const serverActor = await getServerActor() |
231 | 264 | ||
232 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, redundancy.strategy) | 265 | logger.info('Duplicating %s streaming playlist in videos redundancy with "%s" strategy.', video.url, strategy) |
233 | 266 | ||
234 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) | 267 | const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) |
235 | await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) | 268 | await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) |
236 | 269 | ||
237 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ | 270 | const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ |
238 | expiresOn: this.buildNewExpiration(redundancy.minLifetime), | 271 | expiresOn, |
239 | url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), | 272 | url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), |
240 | fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), | 273 | fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), |
241 | strategy: redundancy.strategy, | 274 | strategy, |
242 | videoStreamingPlaylistId: playlist.id, | 275 | videoStreamingPlaylistId: playlist.id, |
243 | actorId: serverActor.id | 276 | actorId: serverActor.id |
244 | }) | 277 | }) |
diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index a99f71629..8dbd41771 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts | |||
@@ -69,7 +69,7 @@ function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile, | |||
69 | function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { | 69 | function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { |
70 | const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) | 70 | const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) |
71 | 71 | ||
72 | const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() | 72 | const thumbnail = existingThumbnail || new ThumbnailModel() |
73 | 73 | ||
74 | thumbnail.filename = filename | 74 | thumbnail.filename = filename |
75 | thumbnail.height = height | 75 | thumbnail.height = height |
@@ -142,18 +142,18 @@ function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, si | |||
142 | } | 142 | } |
143 | 143 | ||
144 | async function createThumbnailFromFunction (parameters: { | 144 | async function createThumbnailFromFunction (parameters: { |
145 | thumbnailCreator: () => Promise<any>, | 145 | thumbnailCreator: () => Promise<any> |
146 | filename: string, | 146 | filename: string |
147 | height: number, | 147 | height: number |
148 | width: number, | 148 | width: number |
149 | type: ThumbnailType, | 149 | type: ThumbnailType |
150 | automaticallyGenerated?: boolean, | 150 | automaticallyGenerated?: boolean |
151 | fileUrl?: string, | 151 | fileUrl?: string |
152 | existingThumbnail?: MThumbnail | 152 | existingThumbnail?: MThumbnail |
153 | }) { | 153 | }) { |
154 | const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters | 154 | const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters |
155 | 155 | ||
156 | const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() | 156 | const thumbnail = existingThumbnail || new ThumbnailModel() |
157 | 157 | ||
158 | thumbnail.filename = filename | 158 | thumbnail.filename = filename |
159 | thumbnail.height = height | 159 | thumbnail.height = height |
diff --git a/server/lib/user.ts b/server/lib/user.ts index c45438d95..88e60a7df 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts | |||
@@ -18,9 +18,9 @@ import { MUser, MUserDefault, MUserId } from '../typings/models/user' | |||
18 | type ChannelNames = { name: string, displayName: string } | 18 | type ChannelNames = { name: string, displayName: string } |
19 | 19 | ||
20 | async function createUserAccountAndChannelAndPlaylist (parameters: { | 20 | async function createUserAccountAndChannelAndPlaylist (parameters: { |
21 | userToCreate: MUser, | 21 | userToCreate: MUser |
22 | userDisplayName?: string, | 22 | userDisplayName?: string |
23 | channelNames?: ChannelNames, | 23 | channelNames?: ChannelNames |
24 | validateUser?: boolean | 24 | validateUser?: boolean |
25 | }): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { | 25 | }): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { |
26 | const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters | 26 | const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters |
@@ -63,11 +63,11 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { | |||
63 | } | 63 | } |
64 | 64 | ||
65 | async function createLocalAccountWithoutKeys (parameters: { | 65 | async function createLocalAccountWithoutKeys (parameters: { |
66 | name: string, | 66 | name: string |
67 | displayName?: string, | 67 | displayName?: string |
68 | userId: number | null, | 68 | userId: number | null |
69 | applicationId: number | null, | 69 | applicationId: number | null |
70 | t: Transaction | undefined, | 70 | t: Transaction | undefined |
71 | type?: ActivityPubActorType | 71 | type?: ActivityPubActorType |
72 | }) { | 72 | }) { |
73 | const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters | 73 | const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters |
diff --git a/server/lib/video-blacklist.ts b/server/lib/video-blacklist.ts index 1dd45b76d..3b90b1b94 100644 --- a/server/lib/video-blacklist.ts +++ b/server/lib/video-blacklist.ts | |||
@@ -9,15 +9,15 @@ import { Notifier } from './notifier' | |||
9 | import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' | 9 | import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' |
10 | 10 | ||
11 | async function autoBlacklistVideoIfNeeded (parameters: { | 11 | async function autoBlacklistVideoIfNeeded (parameters: { |
12 | video: MVideoWithBlacklistLight, | 12 | video: MVideoWithBlacklistLight |
13 | user?: MUser, | 13 | user?: MUser |
14 | isRemote: boolean, | 14 | isRemote: boolean |
15 | isNew: boolean, | 15 | isNew: boolean |
16 | notify?: boolean, | 16 | notify?: boolean |
17 | transaction?: Transaction | 17 | transaction?: Transaction |
18 | }) { | 18 | }) { |
19 | const { video, user, isRemote, isNew, notify = true, transaction } = parameters | 19 | const { video, user, isRemote, isNew, notify = true, transaction } = parameters |
20 | const doAutoBlacklist = await Hooks.wrapPromiseFun( | 20 | const doAutoBlacklist = await Hooks.wrapFun( |
21 | autoBlacklistNeeded, | 21 | autoBlacklistNeeded, |
22 | { video, user, isRemote, isNew }, | 22 | { video, user, isRemote, isNew }, |
23 | 'filter:video.auto-blacklist.result' | 23 | 'filter:video.auto-blacklist.result' |
@@ -49,10 +49,10 @@ async function autoBlacklistVideoIfNeeded (parameters: { | |||
49 | return true | 49 | return true |
50 | } | 50 | } |
51 | 51 | ||
52 | async function autoBlacklistNeeded (parameters: { | 52 | function autoBlacklistNeeded (parameters: { |
53 | video: MVideoWithBlacklistLight, | 53 | video: MVideoWithBlacklistLight |
54 | isRemote: boolean, | 54 | isRemote: boolean |
55 | isNew: boolean, | 55 | isNew: boolean |
56 | user?: MUser | 56 | user?: MUser |
57 | }) { | 57 | }) { |
58 | const { user, video, isRemote, isNew } = parameters | 58 | const { user, video, isRemote, isNew } = parameters |
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index 41eab456b..14829c9d6 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts | |||
@@ -6,8 +6,7 @@ import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUr | |||
6 | import { VideoModel } from '../models/video/video' | 6 | import { VideoModel } from '../models/video/video' |
7 | import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' | 7 | import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' |
8 | 8 | ||
9 | type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & | 9 | type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T } |
10 | { Account?: T } | ||
11 | 10 | ||
12 | async function createLocalVideoChannel <T extends MAccountId> ( | 11 | async function createLocalVideoChannel <T extends MAccountId> ( |
13 | videoChannelInfo: VideoChannelCreate, | 12 | videoChannelInfo: VideoChannelCreate, |
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index b8074e6d2..fe83d23e7 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts | |||
@@ -7,9 +7,9 @@ import { sendCreateVideoComment } from './activitypub/send' | |||
7 | import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' | 7 | import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' |
8 | 8 | ||
9 | async function createVideoComment (obj: { | 9 | async function createVideoComment (obj: { |
10 | text: string, | 10 | text: string |
11 | inReplyToComment: MComment | null, | 11 | inReplyToComment: MComment | null |
12 | video: MVideoFullLight, | 12 | video: MVideoFullLight |
13 | account: MAccountDefault | 13 | account: MAccountDefault |
14 | }, t: Sequelize.Transaction) { | 14 | }, t: Sequelize.Transaction) { |
15 | let originCommentId: number | null = null | 15 | let originCommentId: number | null = null |
diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index c6d8466ac..ab7d04d25 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts | |||
@@ -1,10 +1,12 @@ | |||
1 | import { NextFunction, Request, Response } from 'express' | 1 | import { NextFunction, Request, Response } from 'express' |
2 | import { ActivityPubSignature } from '../../shared' | 2 | import { ActivityDelete, ActivityPubSignature } from '../../shared' |
3 | import { logger } from '../helpers/logger' | 3 | import { logger } from '../helpers/logger' |
4 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' | 4 | import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' |
5 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' | 5 | import { ACCEPT_HEADERS, ACTIVITY_PUB, HTTP_SIGNATURE } from '../initializers/constants' |
6 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' | 6 | import { getOrCreateActorAndServerAndModel } from '../lib/activitypub' |
7 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' | 7 | import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger' |
8 | import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' | ||
9 | import { getAPId } from '@server/helpers/activitypub' | ||
8 | 10 | ||
9 | async function checkSignature (req: Request, res: Response, next: NextFunction) { | 11 | async function checkSignature (req: Request, res: Response, next: NextFunction) { |
10 | try { | 12 | try { |
@@ -15,7 +17,7 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
15 | 17 | ||
16 | // Forwarded activity | 18 | // Forwarded activity |
17 | const bodyActor = req.body.actor | 19 | const bodyActor = req.body.actor |
18 | const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor | 20 | const bodyActorId = getAPId(bodyActor) |
19 | if (bodyActorId && bodyActorId !== actor.url) { | 21 | if (bodyActorId && bodyActorId !== actor.url) { |
20 | const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) | 22 | const jsonLDSignatureChecked = await checkJsonLDSignature(req, res) |
21 | if (jsonLDSignatureChecked !== true) return | 23 | if (jsonLDSignatureChecked !== true) return |
@@ -23,7 +25,13 @@ async function checkSignature (req: Request, res: Response, next: NextFunction) | |||
23 | 25 | ||
24 | return next() | 26 | return next() |
25 | } catch (err) { | 27 | } catch (err) { |
26 | logger.error('Error in ActivityPub signature checker.', err) | 28 | const activity: ActivityDelete = req.body |
29 | if (isActorDeleteActivityValid(activity) && activity.object === activity.actor) { | ||
30 | logger.debug('Handling signature error on actor delete activity', { err }) | ||
31 | return res.sendStatus(204) | ||
32 | } | ||
33 | |||
34 | logger.warn('Error in ActivityPub signature checker.', { err }) | ||
27 | return res.sendStatus(403) | 35 | return res.sendStatus(403) |
28 | } | 36 | } |
29 | } | 37 | } |
diff --git a/server/middlewares/csp.ts b/server/middlewares/csp.ts index d11d70790..f5de69603 100644 --- a/server/middlewares/csp.ts +++ b/server/middlewares/csp.ts | |||
@@ -3,20 +3,20 @@ import { CONFIG } from '../initializers/config' | |||
3 | 3 | ||
4 | const baseDirectives = Object.assign({}, | 4 | const baseDirectives = Object.assign({}, |
5 | { | 5 | { |
6 | defaultSrc: ["'none'"], // by default, not specifying default-src = '*' | 6 | defaultSrc: [ '\'none\'' ], // by default, not specifying default-src = '*' |
7 | connectSrc: ['*', 'data:'], | 7 | connectSrc: [ '*', 'data:' ], |
8 | mediaSrc: ["'self'", 'https:', 'blob:'], | 8 | mediaSrc: [ '\'self\'', 'https:', 'blob:' ], |
9 | fontSrc: ["'self'", 'data:'], | 9 | fontSrc: [ '\'self\'', 'data:' ], |
10 | imgSrc: ["'self'", 'data:', 'blob:'], | 10 | imgSrc: [ '\'self\'', 'data:', 'blob:' ], |
11 | scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'", 'blob:'], | 11 | scriptSrc: [ '\'self\' \'unsafe-inline\' \'unsafe-eval\'', 'blob:' ], |
12 | styleSrc: ["'self' 'unsafe-inline'"], | 12 | styleSrc: [ '\'self\' \'unsafe-inline\'' ], |
13 | objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it | 13 | objectSrc: [ '\'none\'' ], // only define to allow plugins, else let defaultSrc 'none' block it |
14 | formAction: ["'self'"], | 14 | formAction: [ '\'self\'' ], |
15 | frameAncestors: ["'none'"], | 15 | frameAncestors: [ '\'none\'' ], |
16 | baseUri: ["'self'"], | 16 | baseUri: [ '\'self\'' ], |
17 | manifestSrc: ["'self'"], | 17 | manifestSrc: [ '\'self\'' ], |
18 | frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed | 18 | frameSrc: [ '\'self\'' ], // instead of deprecated child-src / self because of test-embed |
19 | workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src | 19 | workerSrc: [ '\'self\'', 'blob:' ] // instead of deprecated child-src |
20 | }, | 20 | }, |
21 | CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, | 21 | CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {}, |
22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} | 22 | CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {} |
@@ -29,7 +29,7 @@ const baseCSP = helmet.contentSecurityPolicy({ | |||
29 | }) | 29 | }) |
30 | 30 | ||
31 | const embedCSP = helmet.contentSecurityPolicy({ | 31 | const embedCSP = helmet.contentSecurityPolicy({ |
32 | directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }), | 32 | directives: Object.assign({}, baseDirectives, { frameAncestors: [ '*' ] }), |
33 | browserSniff: false, // assumes a modern browser, but allows CDN in front | 33 | browserSniff: false, // assumes a modern browser, but allows CDN in front |
34 | reportOnly: CONFIG.CSP.REPORT_ONLY | 34 | reportOnly: CONFIG.CSP.REPORT_ONLY |
35 | }) | 35 | }) |
diff --git a/server/middlewares/dnt.ts b/server/middlewares/dnt.ts index 607def855..dd88005dd 100644 --- a/server/middlewares/dnt.ts +++ b/server/middlewares/dnt.ts | |||
@@ -1,6 +1,3 @@ | |||
1 | import * as ipaddr from 'ipaddr.js' | ||
2 | import { format } from 'util' | ||
3 | |||
4 | const advertiseDoNotTrack = (_, res, next) => { | 1 | const advertiseDoNotTrack = (_, res, next) => { |
5 | res.setHeader('Tk', 'N') | 2 | res.setHeader('Tk', 'N') |
6 | return next() | 3 | return next() |
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 749f5cccd..9eef03bb4 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts | |||
@@ -51,6 +51,7 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) { | |||
51 | 51 | ||
52 | return next() | 52 | return next() |
53 | }) | 53 | }) |
54 | .catch(err => logger.error('Cannot get access token.', { err })) | ||
54 | } | 55 | } |
55 | 56 | ||
56 | function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { | 57 | function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) { |
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index 8c27e8237..fcbb2902c 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts | |||
@@ -1,20 +1,14 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { SortType } from '../models/utils' | 2 | import { SortType } from '../models/utils' |
3 | 3 | ||
4 | function setDefaultSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 4 | const setDefaultSort = setDefaultSortFactory('-createdAt') |
5 | if (!req.query.sort) req.query.sort = '-createdAt' | ||
6 | |||
7 | return next() | ||
8 | } | ||
9 | 5 | ||
10 | function setDefaultSearchSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 6 | const setDefaultVideoRedundanciesSort = setDefaultSortFactory('name') |
11 | if (!req.query.sort) req.query.sort = '-match' | ||
12 | 7 | ||
13 | return next() | 8 | const setDefaultSearchSort = setDefaultSortFactory('-match') |
14 | } | ||
15 | 9 | ||
16 | function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 10 | function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { |
17 | let newSort: SortType = { sortModel: undefined, sortValue: '' } | 11 | const newSort: SortType = { sortModel: undefined, sortValue: '' } |
18 | 12 | ||
19 | if (!req.query.sort) req.query.sort = '-createdAt' | 13 | if (!req.query.sort) req.query.sort = '-createdAt' |
20 | 14 | ||
@@ -39,5 +33,16 @@ function setBlacklistSort (req: express.Request, res: express.Response, next: ex | |||
39 | export { | 33 | export { |
40 | setDefaultSort, | 34 | setDefaultSort, |
41 | setDefaultSearchSort, | 35 | setDefaultSearchSort, |
36 | setDefaultVideoRedundanciesSort, | ||
42 | setBlacklistSort | 37 | setBlacklistSort |
43 | } | 38 | } |
39 | |||
40 | // --------------------------------------------------------------------------- | ||
41 | |||
42 | function setDefaultSortFactory (sort: string) { | ||
43 | return (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
44 | if (!req.query.sort) req.query.sort = sort | ||
45 | |||
46 | return next() | ||
47 | } | ||
48 | } | ||
diff --git a/server/middlewares/validators/avatar.ts b/server/middlewares/validators/avatar.ts index 8623d07e8..2acb97483 100644 --- a/server/middlewares/validators/avatar.ts +++ b/server/middlewares/validators/avatar.ts | |||
@@ -8,8 +8,8 @@ import { cleanUpReqFiles } from '../../helpers/express-utils' | |||
8 | 8 | ||
9 | const updateAvatarValidator = [ | 9 | const updateAvatarValidator = [ |
10 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( | 10 | body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage( |
11 | 'This file is not supported or too large. Please, make sure it is of the following type : ' | 11 | 'This file is not supported or too large. Please, make sure it is of the following type : ' + |
12 | + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') | 12 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ') |
13 | ), | 13 | ), |
14 | 14 | ||
15 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 15 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index 2d1f61947..dfa549e76 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -3,10 +3,10 @@ import { body } from 'express-validator' | |||
3 | import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' | 3 | import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' | 5 | import { CustomConfig } from '../../../shared/models/server/custom-config.model' |
6 | import { Emailer } from '../../lib/emailer' | ||
7 | import { areValidationErrors } from './utils' | 6 | import { areValidationErrors } from './utils' |
8 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' | 7 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' |
9 | import { isThemeRegistered } from '../../lib/plugins/theme-utils' | 8 | import { isThemeRegistered } from '../../lib/plugins/theme-utils' |
9 | import { isEmailEnabled } from '@server/initializers/config' | ||
10 | 10 | ||
11 | const customConfigUpdateValidator = [ | 11 | const customConfigUpdateValidator = [ |
12 | body('instance.name').exists().withMessage('Should have a valid instance name'), | 12 | body('instance.name').exists().withMessage('Should have a valid instance name'), |
@@ -55,7 +55,7 @@ const customConfigUpdateValidator = [ | |||
55 | 55 | ||
56 | body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), | 56 | body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'), |
57 | 57 | ||
58 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 58 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
59 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) | 59 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) |
60 | 60 | ||
61 | if (areValidationErrors(req, res)) return | 61 | if (areValidationErrors(req, res)) return |
@@ -73,7 +73,7 @@ export { | |||
73 | } | 73 | } |
74 | 74 | ||
75 | function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { | 75 | function checkInvalidConfigIfEmailDisabled (customConfig: CustomConfig, res: express.Response) { |
76 | if (Emailer.isEnabled()) return true | 76 | if (isEmailEnabled()) return true |
77 | 77 | ||
78 | if (customConfig.signup.requiresEmailVerification === true) { | 78 | if (customConfig.signup.requiresEmailVerification === true) { |
79 | res.status(400) | 79 | res.status(400) |
diff --git a/server/middlewares/validators/feeds.ts b/server/middlewares/validators/feeds.ts index 29f6c87be..f34c2b174 100644 --- a/server/middlewares/validators/feeds.ts +++ b/server/middlewares/validators/feeds.ts | |||
@@ -22,13 +22,13 @@ function setFeedFormatContentType (req: express.Request, res: express.Response, | |||
22 | 22 | ||
23 | let acceptableContentTypes: string[] | 23 | let acceptableContentTypes: string[] |
24 | if (format === 'atom' || format === 'atom1') { | 24 | if (format === 'atom' || format === 'atom1') { |
25 | acceptableContentTypes = ['application/atom+xml', 'application/xml', 'text/xml'] | 25 | acceptableContentTypes = [ 'application/atom+xml', 'application/xml', 'text/xml' ] |
26 | } else if (format === 'json' || format === 'json1') { | 26 | } else if (format === 'json' || format === 'json1') { |
27 | acceptableContentTypes = ['application/json'] | 27 | acceptableContentTypes = [ 'application/json' ] |
28 | } else if (format === 'rss' || format === 'rss2') { | 28 | } else if (format === 'rss' || format === 'rss2') { |
29 | acceptableContentTypes = ['application/rss+xml', 'application/xml', 'text/xml'] | 29 | acceptableContentTypes = [ 'application/rss+xml', 'application/xml', 'text/xml' ] |
30 | } else { | 30 | } else { |
31 | acceptableContentTypes = ['application/xml', 'text/xml'] | 31 | acceptableContentTypes = [ 'application/xml', 'text/xml' ] |
32 | } | 32 | } |
33 | 33 | ||
34 | if (req.accepts(acceptableContentTypes)) { | 34 | if (req.accepts(acceptableContentTypes)) { |
diff --git a/server/middlewares/validators/redundancy.ts b/server/middlewares/validators/redundancy.ts index 8098e3a44..8cd3bc33d 100644 --- a/server/middlewares/validators/redundancy.ts +++ b/server/middlewares/validators/redundancy.ts | |||
@@ -1,12 +1,13 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { exists, isBooleanValid, isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' | 3 | import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' | 6 | import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' |
7 | import { isHostValid } from '../../helpers/custom-validators/servers' | 7 | import { isHostValid } from '../../helpers/custom-validators/servers' |
8 | import { ServerModel } from '../../models/server/server' | 8 | import { ServerModel } from '../../models/server/server' |
9 | import { doesVideoExist } from '../../helpers/middlewares' | 9 | import { doesVideoExist } from '../../helpers/middlewares' |
10 | import { isVideoRedundancyTarget } from '@server/helpers/custom-validators/video-redundancies' | ||
10 | 11 | ||
11 | const videoFileRedundancyGetValidator = [ | 12 | const videoFileRedundancyGetValidator = [ |
12 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | 13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), |
@@ -101,10 +102,77 @@ const updateServerRedundancyValidator = [ | |||
101 | } | 102 | } |
102 | ] | 103 | ] |
103 | 104 | ||
105 | const listVideoRedundanciesValidator = [ | ||
106 | query('target') | ||
107 | .custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'), | ||
108 | |||
109 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
110 | logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query }) | ||
111 | |||
112 | if (areValidationErrors(req, res)) return | ||
113 | |||
114 | return next() | ||
115 | } | ||
116 | ] | ||
117 | |||
118 | const addVideoRedundancyValidator = [ | ||
119 | body('videoId') | ||
120 | .custom(isIdValid) | ||
121 | .withMessage('Should have a valid video id'), | ||
122 | |||
123 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
124 | logger.debug('Checking addVideoRedundancyValidator parameters', { parameters: req.query }) | ||
125 | |||
126 | if (areValidationErrors(req, res)) return | ||
127 | |||
128 | if (!await doesVideoExist(req.body.videoId, res, 'only-video')) return | ||
129 | |||
130 | if (res.locals.onlyVideo.remote === false) { | ||
131 | return res.status(400) | ||
132 | .json({ error: 'Cannot create a redundancy on a local video' }) | ||
133 | .end() | ||
134 | } | ||
135 | |||
136 | const alreadyExists = await VideoRedundancyModel.isLocalByVideoUUIDExists(res.locals.onlyVideo.uuid) | ||
137 | if (alreadyExists) { | ||
138 | return res.status(409) | ||
139 | .json({ error: 'This video is already duplicated by your instance.' }) | ||
140 | } | ||
141 | |||
142 | return next() | ||
143 | } | ||
144 | ] | ||
145 | |||
146 | const removeVideoRedundancyValidator = [ | ||
147 | param('redundancyId') | ||
148 | .custom(isIdValid) | ||
149 | .withMessage('Should have a valid redundancy id'), | ||
150 | |||
151 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
152 | logger.debug('Checking removeVideoRedundancyValidator parameters', { parameters: req.query }) | ||
153 | |||
154 | if (areValidationErrors(req, res)) return | ||
155 | |||
156 | const redundancy = await VideoRedundancyModel.loadByIdWithVideo(parseInt(req.params.redundancyId, 10)) | ||
157 | if (!redundancy) { | ||
158 | return res.status(404) | ||
159 | .json({ error: 'Video redundancy not found' }) | ||
160 | .end() | ||
161 | } | ||
162 | |||
163 | res.locals.videoRedundancy = redundancy | ||
164 | |||
165 | return next() | ||
166 | } | ||
167 | ] | ||
168 | |||
104 | // --------------------------------------------------------------------------- | 169 | // --------------------------------------------------------------------------- |
105 | 170 | ||
106 | export { | 171 | export { |
107 | videoFileRedundancyGetValidator, | 172 | videoFileRedundancyGetValidator, |
108 | videoPlaylistRedundancyGetValidator, | 173 | videoPlaylistRedundancyGetValidator, |
109 | updateServerRedundancyValidator | 174 | updateServerRedundancyValidator, |
175 | listVideoRedundanciesValidator, | ||
176 | addVideoRedundancyValidator, | ||
177 | removeVideoRedundancyValidator | ||
110 | } | 178 | } |
diff --git a/server/middlewares/validators/server.ts b/server/middlewares/validators/server.ts index f6812647b..6158c3363 100644 --- a/server/middlewares/validators/server.ts +++ b/server/middlewares/validators/server.ts | |||
@@ -5,9 +5,8 @@ import { isHostValid, isValidContactBody } from '../../helpers/custom-validators | |||
5 | import { ServerModel } from '../../models/server/server' | 5 | import { ServerModel } from '../../models/server/server' |
6 | import { body } from 'express-validator' | 6 | import { body } from 'express-validator' |
7 | import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' | 7 | import { isUserDisplayNameValid } from '../../helpers/custom-validators/users' |
8 | import { Emailer } from '../../lib/emailer' | ||
9 | import { Redis } from '../../lib/redis' | 8 | import { Redis } from '../../lib/redis' |
10 | import { CONFIG } from '../../initializers/config' | 9 | import { CONFIG, isEmailEnabled } from '../../initializers/config' |
11 | 10 | ||
12 | const serverGetValidator = [ | 11 | const serverGetValidator = [ |
13 | body('host').custom(isHostValid).withMessage('Should have a valid host'), | 12 | body('host').custom(isHostValid).withMessage('Should have a valid host'), |
@@ -50,7 +49,7 @@ const contactAdministratorValidator = [ | |||
50 | .end() | 49 | .end() |
51 | } | 50 | } |
52 | 51 | ||
53 | if (Emailer.isEnabled() === false) { | 52 | if (isEmailEnabled() === false) { |
54 | return res | 53 | return res |
55 | .status(409) | 54 | .status(409) |
56 | .send({ error: 'Emailer is not enabled on this instance.' }) | 55 | .send({ error: 'Emailer is not enabled on this instance.' }) |
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index c75e701d6..b76dab722 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -23,6 +23,7 @@ const SORTABLE_USER_NOTIFICATIONS_COLUMNS = createSortableColumns(SORTABLE_COLUM | |||
23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) | 23 | const SORTABLE_VIDEO_PLAYLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_PLAYLISTS) |
24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) | 24 | const SORTABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PLUGINS) |
25 | const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) | 25 | const SORTABLE_AVAILABLE_PLUGINS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.AVAILABLE_PLUGINS) |
26 | const SORTABLE_VIDEO_REDUNDANCIES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_REDUNDANCIES) | ||
26 | 27 | ||
27 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 28 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
28 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) | 29 | const accountsSortValidator = checkSort(SORTABLE_ACCOUNTS_COLUMNS) |
@@ -45,6 +46,7 @@ const userNotificationsSortValidator = checkSort(SORTABLE_USER_NOTIFICATIONS_COL | |||
45 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) | 46 | const videoPlaylistsSortValidator = checkSort(SORTABLE_VIDEO_PLAYLISTS_COLUMNS) |
46 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) | 47 | const pluginsSortValidator = checkSort(SORTABLE_PLUGINS_COLUMNS) |
47 | const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) | 48 | const availablePluginsSortValidator = checkSort(SORTABLE_AVAILABLE_PLUGINS_COLUMNS) |
49 | const videoRedundanciesSortValidator = checkSort(SORTABLE_VIDEO_REDUNDANCIES_COLUMNS) | ||
48 | 50 | ||
49 | // --------------------------------------------------------------------------- | 51 | // --------------------------------------------------------------------------- |
50 | 52 | ||
@@ -69,5 +71,6 @@ export { | |||
69 | serversBlocklistSortValidator, | 71 | serversBlocklistSortValidator, |
70 | userNotificationsSortValidator, | 72 | userNotificationsSortValidator, |
71 | videoPlaylistsSortValidator, | 73 | videoPlaylistsSortValidator, |
74 | videoRedundanciesSortValidator, | ||
72 | pluginsSortValidator | 75 | pluginsSortValidator |
73 | } | 76 | } |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index c78c67a8c..adc67a046 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -14,6 +14,7 @@ import { | |||
14 | isUserDisplayNameValid, | 14 | isUserDisplayNameValid, |
15 | isUserNSFWPolicyValid, | 15 | isUserNSFWPolicyValid, |
16 | isUserPasswordValid, | 16 | isUserPasswordValid, |
17 | isUserPasswordValidOrEmpty, | ||
17 | isUserRoleValid, | 18 | isUserRoleValid, |
18 | isUserUsernameValid, | 19 | isUserUsernameValid, |
19 | isUserVideoLanguages, | 20 | isUserVideoLanguages, |
@@ -36,11 +37,10 @@ import { doesVideoExist } from '../../helpers/middlewares' | |||
36 | import { UserRole } from '../../../shared/models/users' | 37 | import { UserRole } from '../../../shared/models/users' |
37 | import { MUserDefault } from '@server/typings/models' | 38 | import { MUserDefault } from '@server/typings/models' |
38 | import { Hooks } from '@server/lib/plugins/hooks' | 39 | import { Hooks } from '@server/lib/plugins/hooks' |
39 | import { isLocalVideoAccepted } from '@server/lib/moderation' | ||
40 | 40 | ||
41 | const usersAddValidator = [ | 41 | const usersAddValidator = [ |
42 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), | 42 | body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'), |
43 | body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'), | 43 | body('password').custom(isUserPasswordValidOrEmpty).withMessage('Should have a valid password'), |
44 | body('email').isEmail().withMessage('Should have a valid email'), | 44 | body('email').isEmail().withMessage('Should have a valid email'), |
45 | body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), | 45 | body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), |
46 | body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), | 46 | body('videoQuotaDaily').custom(isUserVideoQuotaDailyValid).withMessage('Should have a valid daily user quota'), |
@@ -149,7 +149,7 @@ const usersBlockingValidator = [ | |||
149 | ] | 149 | ] |
150 | 150 | ||
151 | const deleteMeValidator = [ | 151 | const deleteMeValidator = [ |
152 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 152 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
153 | const user = res.locals.oauth.token.User | 153 | const user = res.locals.oauth.token.User |
154 | if (user.username === 'root') { | 154 | if (user.username === 'root') { |
155 | return res.status(400) | 155 | return res.status(400) |
@@ -303,7 +303,7 @@ const ensureUserRegistrationAllowed = [ | |||
303 | ] | 303 | ] |
304 | 304 | ||
305 | const ensureUserRegistrationAllowedForIP = [ | 305 | const ensureUserRegistrationAllowedForIP = [ |
306 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 306 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
307 | const allowed = isSignupAllowedForCurrentIP(req.ip) | 307 | const allowed = isSignupAllowedForCurrentIP(req.ip) |
308 | 308 | ||
309 | if (allowed === false) { | 309 | if (allowed === false) { |
@@ -410,7 +410,7 @@ const userAutocompleteValidator = [ | |||
410 | ] | 410 | ] |
411 | 411 | ||
412 | const ensureAuthUserOwnsAccountValidator = [ | 412 | const ensureAuthUserOwnsAccountValidator = [ |
413 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 413 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
414 | const user = res.locals.oauth.token.User | 414 | const user = res.locals.oauth.token.User |
415 | 415 | ||
416 | if (res.locals.account.id !== user.Account.id) { | 416 | if (res.locals.account.id !== user.Account.id) { |
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts index 7b0cd6f66..872d9c2ab 100644 --- a/server/middlewares/validators/videos/video-captions.ts +++ b/server/middlewares/validators/videos/video-captions.ts | |||
@@ -13,10 +13,12 @@ const addVideoCaptionValidator = [ | |||
13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), | 13 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), |
14 | param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), | 14 | param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), |
15 | body('captionfile') | 15 | body('captionfile') |
16 | .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')).withMessage( | 16 | .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')) |
17 | `This caption file is not supported or too large. Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` | 17 | .withMessage( |
18 | + Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') | 18 | 'This caption file is not supported or too large. ' + |
19 | ), | 19 | `Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` + |
20 | Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ') | ||
21 | ), | ||
20 | 22 | ||
21 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 23 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
22 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) | 24 | logger.debug('Checking addVideoCaption parameters', { parameters: req.body }) |
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts index 77c5f940d..da2fafb10 100644 --- a/server/middlewares/validators/videos/video-comments.ts +++ b/server/middlewares/validators/videos/video-comments.ts | |||
@@ -50,7 +50,7 @@ const addVideoCommentThreadValidator = [ | |||
50 | if (areValidationErrors(req, res)) return | 50 | if (areValidationErrors(req, res)) return |
51 | if (!await doesVideoExist(req.params.videoId, res)) return | 51 | if (!await doesVideoExist(req.params.videoId, res)) return |
52 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return | 52 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return |
53 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return | 53 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return |
54 | 54 | ||
55 | return next() | 55 | return next() |
56 | } | 56 | } |
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index 318dad100..5dc5db533 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts | |||
@@ -22,10 +22,11 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ | |||
22 | .optional() | 22 | .optional() |
23 | .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), | 23 | .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'), |
24 | body('torrentfile') | 24 | body('torrentfile') |
25 | .custom((value, { req }) => isVideoImportTorrentFile(req.files)).withMessage( | 25 | .custom((value, { req }) => isVideoImportTorrentFile(req.files)) |
26 | 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' | 26 | .withMessage( |
27 | + CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') | 27 | 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' + |
28 | ), | 28 | CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ') |
29 | ), | ||
29 | body('name') | 30 | body('name') |
30 | .optional() | 31 | .optional() |
31 | .custom(isVideoNameValid).withMessage('Should have a valid name'), | 32 | .custom(isVideoNameValid).withMessage('Should have a valid name'), |
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts index 1d67e8666..6b15c5464 100644 --- a/server/middlewares/validators/videos/video-playlists.ts +++ b/server/middlewares/validators/videos/video-playlists.ts | |||
@@ -384,10 +384,11 @@ export { | |||
384 | function getCommonPlaylistEditAttributes () { | 384 | function getCommonPlaylistEditAttributes () { |
385 | return [ | 385 | return [ |
386 | body('thumbnailfile') | 386 | body('thumbnailfile') |
387 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 387 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')) |
388 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' | 388 | .withMessage( |
389 | + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') | 389 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' + |
390 | ), | 390 | CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ') |
391 | ), | ||
391 | 392 | ||
392 | body('description') | 393 | body('description') |
393 | .optional() | 394 | .optional() |
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts index 4021cfecc..cbc144f69 100644 --- a/server/middlewares/validators/videos/video-rates.ts +++ b/server/middlewares/validators/videos/video-rates.ts | |||
@@ -24,7 +24,7 @@ const videoUpdateRateValidator = [ | |||
24 | } | 24 | } |
25 | ] | 25 | ] |
26 | 26 | ||
27 | const getAccountVideoRateValidator = function (rateType: VideoRateType) { | 27 | const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) { |
28 | return [ | 28 | return [ |
29 | param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), | 29 | param('name').custom(isAccountNameValid).withMessage('Should have a valid account name'), |
30 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), | 30 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), |
@@ -51,7 +51,7 @@ const getAccountVideoRateValidator = function (rateType: VideoRateType) { | |||
51 | const videoRatingValidator = [ | 51 | const videoRatingValidator = [ |
52 | query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), | 52 | query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'), |
53 | 53 | ||
54 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 54 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
55 | logger.debug('Checking rating parameter', { parameters: req.params }) | 55 | logger.debug('Checking rating parameter', { parameters: req.params }) |
56 | 56 | ||
57 | if (areValidationErrors(req, res)) return | 57 | if (areValidationErrors(req, res)) return |
@@ -64,6 +64,6 @@ const videoRatingValidator = [ | |||
64 | 64 | ||
65 | export { | 65 | export { |
66 | videoUpdateRateValidator, | 66 | videoUpdateRateValidator, |
67 | getAccountVideoRateValidator, | 67 | getAccountVideoRateValidatorFactory, |
68 | videoRatingValidator | 68 | videoRatingValidator |
69 | } | 69 | } |
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts index 6733d9dec..a027c4840 100644 --- a/server/middlewares/validators/videos/videos.ts +++ b/server/middlewares/validators/videos/videos.ts | |||
@@ -49,8 +49,8 @@ import { getVideoWithAttributes } from '../../../helpers/video' | |||
49 | const videosAddValidator = getCommonVideoEditAttributes().concat([ | 49 | const videosAddValidator = getCommonVideoEditAttributes().concat([ |
50 | body('videofile') | 50 | body('videofile') |
51 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( | 51 | .custom((value, { req }) => isVideoFile(req.files)).withMessage( |
52 | 'This file is not supported or too large. Please, make sure it is of the following type: ' | 52 | 'This file is not supported or too large. Please, make sure it is of the following type: ' + |
53 | + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') | 53 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') |
54 | ), | 54 | ), |
55 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), | 55 | body('name').custom(isVideoNameValid).withMessage('Should have a valid name'), |
56 | body('channelId') | 56 | body('channelId') |
@@ -147,7 +147,10 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R | |||
147 | }) | 147 | }) |
148 | } | 148 | } |
149 | 149 | ||
150 | const videosCustomGetValidator = (fetchType: 'all' | 'only-video' | 'only-video-with-rights', authenticateInQuery = false) => { | 150 | const videosCustomGetValidator = ( |
151 | fetchType: 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes', | ||
152 | authenticateInQuery = false | ||
153 | ) => { | ||
151 | return [ | 154 | return [ |
152 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), | 155 | param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), |
153 | 156 | ||
@@ -157,6 +160,9 @@ const videosCustomGetValidator = (fetchType: 'all' | 'only-video' | 'only-video- | |||
157 | if (areValidationErrors(req, res)) return | 160 | if (areValidationErrors(req, res)) return |
158 | if (!await doesVideoExist(req.params.id, res, fetchType)) return | 161 | if (!await doesVideoExist(req.params.id, res, fetchType)) return |
159 | 162 | ||
163 | // Controllers does not need to check video rights | ||
164 | if (fetchType === 'only-immutable-attributes') return next() | ||
165 | |||
160 | const video = getVideoWithAttributes(res) | 166 | const video = getVideoWithAttributes(res) |
161 | const videoAll = video as MVideoFullLight | 167 | const videoAll = video as MVideoFullLight |
162 | 168 | ||
@@ -245,19 +251,15 @@ const videosTerminateChangeOwnershipValidator = [ | |||
245 | // Check if the user who did the request is able to change the ownership of the video | 251 | // Check if the user who did the request is able to change the ownership of the video |
246 | if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return | 252 | if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return |
247 | 253 | ||
248 | return next() | ||
249 | }, | ||
250 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
251 | const videoChangeOwnership = res.locals.videoChangeOwnership | 254 | const videoChangeOwnership = res.locals.videoChangeOwnership |
252 | 255 | ||
253 | if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) { | 256 | if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) { |
254 | return next() | ||
255 | } else { | ||
256 | res.status(403) | 257 | res.status(403) |
257 | .json({ error: 'Ownership already accepted or refused' }) | 258 | .json({ error: 'Ownership already accepted or refused' }) |
258 | |||
259 | return | 259 | return |
260 | } | 260 | } |
261 | |||
262 | return next() | ||
261 | } | 263 | } |
262 | ] | 264 | ] |
263 | 265 | ||
@@ -284,14 +286,14 @@ function getCommonVideoEditAttributes () { | |||
284 | return [ | 286 | return [ |
285 | body('thumbnailfile') | 287 | body('thumbnailfile') |
286 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( | 288 | .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage( |
287 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' | 289 | 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' + |
288 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 290 | CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
289 | ), | 291 | ), |
290 | body('previewfile') | 292 | body('previewfile') |
291 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( | 293 | .custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage( |
292 | 'This preview file is not supported or too large. Please, make sure it is of the following type: ' | 294 | 'This preview file is not supported or too large. Please, make sure it is of the following type: ' + |
293 | + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') | 295 | CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ') |
294 | ), | 296 | ), |
295 | 297 | ||
296 | body('category') | 298 | body('category') |
297 | .optional() | 299 | .optional() |
diff --git a/server/middlewares/validators/webfinger.ts b/server/middlewares/validators/webfinger.ts index d50e6527f..5fe864f8b 100644 --- a/server/middlewares/validators/webfinger.ts +++ b/server/middlewares/validators/webfinger.ts | |||
@@ -18,15 +18,14 @@ const webfingerValidator = [ | |||
18 | const nameWithHost = getHostWithPort(req.query.resource.substr(5)) | 18 | const nameWithHost = getHostWithPort(req.query.resource.substr(5)) |
19 | const [ name ] = nameWithHost.split('@') | 19 | const [ name ] = nameWithHost.split('@') |
20 | 20 | ||
21 | // FIXME: we don't need the full actor | 21 | const actor = await ActorModel.loadLocalUrlByName(name) |
22 | const actor = await ActorModel.loadLocalByName(name) | ||
23 | if (!actor) { | 22 | if (!actor) { |
24 | return res.status(404) | 23 | return res.status(404) |
25 | .send({ error: 'Actor not found' }) | 24 | .send({ error: 'Actor not found' }) |
26 | .end() | 25 | .end() |
27 | } | 26 | } |
28 | 27 | ||
29 | res.locals.actorFull = actor | 28 | res.locals.actorUrl = actor |
30 | return next() | 29 | return next() |
31 | } | 30 | } |
32 | ] | 31 | ] |
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts index 6ebe32556..e2f66d733 100644 --- a/server/models/account/account-blocklist.ts +++ b/server/models/account/account-blocklist.ts | |||
@@ -80,7 +80,7 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> { | |||
80 | attributes: [ 'accountId', 'id' ], | 80 | attributes: [ 'accountId', 'id' ], |
81 | where: { | 81 | where: { |
82 | accountId: { | 82 | accountId: { |
83 | [Op.in]: accountIds // FIXME: sequelize ANY seems broken | 83 | [Op.in]: accountIds |
84 | }, | 84 | }, |
85 | targetAccountId | 85 | targetAccountId |
86 | }, | 86 | }, |
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index c593595b2..8aeb486d1 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts | |||
@@ -99,7 +99,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
99 | static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> { | 99 | static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> { |
100 | const options: FindOptions = { | 100 | const options: FindOptions = { |
101 | where: { | 101 | where: { |
102 | [ Op.or]: [ | 102 | [Op.or]: [ |
103 | { | 103 | { |
104 | accountId, | 104 | accountId, |
105 | videoId | 105 | videoId |
@@ -116,10 +116,10 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
116 | } | 116 | } |
117 | 117 | ||
118 | static listByAccountForApi (options: { | 118 | static listByAccountForApi (options: { |
119 | start: number, | 119 | start: number |
120 | count: number, | 120 | count: number |
121 | sort: string, | 121 | sort: string |
122 | type?: string, | 122 | type?: string |
123 | accountId: number | 123 | accountId: number |
124 | }) { | 124 | }) { |
125 | const query: FindOptions = { | 125 | const query: FindOptions = { |
@@ -135,7 +135,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> { | |||
135 | required: true, | 135 | required: true, |
136 | include: [ | 136 | include: [ |
137 | { | 137 | { |
138 | model: VideoChannelModel.scope({ method: [VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }), | 138 | model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }), |
139 | required: true | 139 | required: true |
140 | } | 140 | } |
141 | ] | 141 | ] |
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 8a0ffeb63..a0081f259 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -32,8 +32,9 @@ import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequ | |||
32 | import { AccountBlocklistModel } from './account-blocklist' | 32 | import { AccountBlocklistModel } from './account-blocklist' |
33 | import { ServerBlocklistModel } from '../server/server-blocklist' | 33 | import { ServerBlocklistModel } from '../server/server-blocklist' |
34 | import { ActorFollowModel } from '../activitypub/actor-follow' | 34 | import { ActorFollowModel } from '../activitypub/actor-follow' |
35 | import { MAccountActor, MAccountDefault, MAccountSummaryFormattable, MAccountFormattable, MAccountAP } from '../../typings/models' | 35 | import { MAccountActor, MAccountAP, MAccountDefault, MAccountFormattable, MAccountSummaryFormattable } from '../../typings/models' |
36 | import * as Bluebird from 'bluebird' | 36 | import * as Bluebird from 'bluebird' |
37 | import { ModelCache } from '@server/models/model-cache' | ||
37 | 38 | ||
38 | export enum ScopeNames { | 39 | export enum ScopeNames { |
39 | SUMMARY = 'SUMMARY' | 40 | SUMMARY = 'SUMMARY' |
@@ -53,7 +54,7 @@ export type SummaryOptions = { | |||
53 | ] | 54 | ] |
54 | })) | 55 | })) |
55 | @Scopes(() => ({ | 56 | @Scopes(() => ({ |
56 | [ ScopeNames.SUMMARY ]: (options: SummaryOptions = {}) => { | 57 | [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { |
57 | const whereActor = options.whereActor || undefined | 58 | const whereActor = options.whereActor || undefined |
58 | 59 | ||
59 | const serverInclude: IncludeOptions = { | 60 | const serverInclude: IncludeOptions = { |
@@ -218,8 +219,6 @@ export class AccountModel extends Model<AccountModel> { | |||
218 | }) | 219 | }) |
219 | BlockedAccounts: AccountBlocklistModel[] | 220 | BlockedAccounts: AccountBlocklistModel[] |
220 | 221 | ||
221 | private static cache: { [ id: string ]: any } = {} | ||
222 | |||
223 | @BeforeDestroy | 222 | @BeforeDestroy |
224 | static async sendDeleteIfOwned (instance: AccountModel, options) { | 223 | static async sendDeleteIfOwned (instance: AccountModel, options) { |
225 | if (!instance.Actor) { | 224 | if (!instance.Actor) { |
@@ -247,45 +246,43 @@ export class AccountModel extends Model<AccountModel> { | |||
247 | } | 246 | } |
248 | 247 | ||
249 | static loadLocalByName (name: string): Bluebird<MAccountDefault> { | 248 | static loadLocalByName (name: string): Bluebird<MAccountDefault> { |
250 | // The server actor never change, so we can easily cache it | 249 | const fun = () => { |
251 | if (name === SERVER_ACTOR_NAME && AccountModel.cache[name]) { | 250 | const query = { |
252 | return Bluebird.resolve(AccountModel.cache[name]) | 251 | where: { |
253 | } | 252 | [Op.or]: [ |
254 | 253 | { | |
255 | const query = { | 254 | userId: { |
256 | where: { | 255 | [Op.ne]: null |
257 | [ Op.or ]: [ | 256 | } |
258 | { | 257 | }, |
259 | userId: { | 258 | { |
260 | [ Op.ne ]: null | 259 | applicationId: { |
260 | [Op.ne]: null | ||
261 | } | ||
261 | } | 262 | } |
262 | }, | 263 | ] |
264 | }, | ||
265 | include: [ | ||
263 | { | 266 | { |
264 | applicationId: { | 267 | model: ActorModel, |
265 | [ Op.ne ]: null | 268 | required: true, |
269 | where: { | ||
270 | preferredUsername: name | ||
266 | } | 271 | } |
267 | } | 272 | } |
268 | ] | 273 | ] |
269 | }, | 274 | } |
270 | include: [ | ||
271 | { | ||
272 | model: ActorModel, | ||
273 | required: true, | ||
274 | where: { | ||
275 | preferredUsername: name | ||
276 | } | ||
277 | } | ||
278 | ] | ||
279 | } | ||
280 | 275 | ||
281 | return AccountModel.findOne(query) | 276 | return AccountModel.findOne(query) |
282 | .then(account => { | 277 | } |
283 | if (name === SERVER_ACTOR_NAME) { | ||
284 | AccountModel.cache[name] = account | ||
285 | } | ||
286 | 278 | ||
287 | return account | 279 | return ModelCache.Instance.doCache({ |
288 | }) | 280 | cacheType: 'local-account-name', |
281 | key: name, | ||
282 | fun, | ||
283 | // The server actor never change, so we can easily cache it | ||
284 | whitelist: () => name === SERVER_ACTOR_NAME | ||
285 | }) | ||
289 | } | 286 | } |
290 | 287 | ||
291 | static loadByNameAndHost (name: string, host: string): Bluebird<MAccountDefault> { | 288 | static loadByNameAndHost (name: string, host: string): Bluebird<MAccountDefault> { |
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts index a05f30175..5a725187a 100644 --- a/server/models/account/user-notification.ts +++ b/server/models/account/user-notification.ts | |||
@@ -363,7 +363,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
363 | where: { | 363 | where: { |
364 | userId, | 364 | userId, |
365 | id: { | 365 | id: { |
366 | [Op.in]: notificationIds // FIXME: sequelize ANY seems broken | 366 | [Op.in]: notificationIds |
367 | } | 367 | } |
368 | } | 368 | } |
369 | } | 369 | } |
@@ -379,7 +379,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> { | |||
379 | 379 | ||
380 | toFormattedJSON (this: UserNotificationModelForApi): UserNotification { | 380 | toFormattedJSON (this: UserNotificationModelForApi): UserNotification { |
381 | const video = this.Video | 381 | const video = this.Video |
382 | ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) }) | 382 | ? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) }) |
383 | : undefined | 383 | : undefined |
384 | 384 | ||
385 | const videoImport = this.VideoImport ? { | 385 | const videoImport = this.VideoImport ? { |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 4c2c5e278..777f09666 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { FindOptions, literal, Op, QueryTypes, where, fn, col } from 'sequelize' | 1 | import { FindOptions, literal, Op, QueryTypes, where, fn, col, WhereOptions } from 'sequelize' |
2 | import { | 2 | import { |
3 | AfterDestroy, | 3 | AfterDestroy, |
4 | AfterUpdate, | 4 | AfterUpdate, |
@@ -49,7 +49,7 @@ import { VideoPlaylistModel } from '../video/video-playlist' | |||
49 | import { AccountModel } from './account' | 49 | import { AccountModel } from './account' |
50 | import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' | 50 | import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' |
51 | import { values } from 'lodash' | 51 | import { values } from 'lodash' |
52 | import { DEFAULT_THEME_NAME, DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' | 52 | import { DEFAULT_USER_THEME_NAME, NSFW_POLICY_TYPES } from '../../initializers/constants' |
53 | import { clearCacheByUserId } from '../../lib/oauth-model' | 53 | import { clearCacheByUserId } from '../../lib/oauth-model' |
54 | import { UserNotificationSettingModel } from './user-notification-setting' | 54 | import { UserNotificationSettingModel } from './user-notification-setting' |
55 | import { VideoModel } from '../video/video' | 55 | import { VideoModel } from '../video/video' |
@@ -101,7 +101,7 @@ enum ScopeNames { | |||
101 | required: true, | 101 | required: true, |
102 | where: { | 102 | where: { |
103 | type: { | 103 | type: { |
104 | [ Op.ne ]: VideoPlaylistType.REGULAR | 104 | [Op.ne]: VideoPlaylistType.REGULAR |
105 | } | 105 | } |
106 | } | 106 | } |
107 | } | 107 | } |
@@ -186,7 +186,10 @@ export class UserModel extends Model<UserModel> { | |||
186 | 186 | ||
187 | @AllowNull(false) | 187 | @AllowNull(false) |
188 | @Default(true) | 188 | @Default(true) |
189 | @Is('UserAutoPlayNextVideoPlaylist', value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean')) | 189 | @Is( |
190 | 'UserAutoPlayNextVideoPlaylist', | ||
191 | value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean') | ||
192 | ) | ||
190 | @Column | 193 | @Column |
191 | autoPlayNextVideoPlaylist: boolean | 194 | autoPlayNextVideoPlaylist: boolean |
192 | 195 | ||
@@ -230,7 +233,7 @@ export class UserModel extends Model<UserModel> { | |||
230 | videoQuotaDaily: number | 233 | videoQuotaDaily: number |
231 | 234 | ||
232 | @AllowNull(false) | 235 | @AllowNull(false) |
233 | @Default(DEFAULT_THEME_NAME) | 236 | @Default(DEFAULT_USER_THEME_NAME) |
234 | @Is('UserTheme', value => throwIfNotValid(value, isThemeNameValid, 'theme')) | 237 | @Is('UserTheme', value => throwIfNotValid(value, isThemeNameValid, 'theme')) |
235 | @Column | 238 | @Column |
236 | theme: string | 239 | theme: string |
@@ -308,7 +311,8 @@ export class UserModel extends Model<UserModel> { | |||
308 | } | 311 | } |
309 | 312 | ||
310 | static listForApi (start: number, count: number, sort: string, search?: string) { | 313 | static listForApi (start: number, count: number, sort: string, search?: string) { |
311 | let where = undefined | 314 | let where: WhereOptions |
315 | |||
312 | if (search) { | 316 | if (search) { |
313 | where = { | 317 | where = { |
314 | [Op.or]: [ | 318 | [Op.or]: [ |
@@ -319,7 +323,7 @@ export class UserModel extends Model<UserModel> { | |||
319 | }, | 323 | }, |
320 | { | 324 | { |
321 | username: { | 325 | username: { |
322 | [ Op.iLike ]: '%' + search + '%' | 326 | [Op.iLike]: '%' + search + '%' |
323 | } | 327 | } |
324 | } | 328 | } |
325 | ] | 329 | ] |
@@ -332,14 +336,14 @@ export class UserModel extends Model<UserModel> { | |||
332 | [ | 336 | [ |
333 | literal( | 337 | literal( |
334 | '(' + | 338 | '(' + |
335 | 'SELECT COALESCE(SUM("size"), 0) ' + | 339 | 'SELECT COALESCE(SUM("size"), 0) ' + |
336 | 'FROM (' + | 340 | 'FROM (' + |
337 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + | 341 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + |
338 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + | 342 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + |
339 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 343 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
340 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + | 344 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + |
341 | 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' + | 345 | 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' + |
342 | ') t' + | 346 | ') t' + |
343 | ')' | 347 | ')' |
344 | ), | 348 | ), |
345 | 'videoQuotaUsed' | 349 | 'videoQuotaUsed' |
@@ -353,18 +357,18 @@ export class UserModel extends Model<UserModel> { | |||
353 | } | 357 | } |
354 | 358 | ||
355 | return UserModel.findAndCountAll(query) | 359 | return UserModel.findAndCountAll(query) |
356 | .then(({ rows, count }) => { | 360 | .then(({ rows, count }) => { |
357 | return { | 361 | return { |
358 | data: rows, | 362 | data: rows, |
359 | total: count | 363 | total: count |
360 | } | 364 | } |
361 | }) | 365 | }) |
362 | } | 366 | } |
363 | 367 | ||
364 | static listWithRight (right: UserRight): Bluebird<MUserDefault[]> { | 368 | static listWithRight (right: UserRight): Bluebird<MUserDefault[]> { |
365 | const roles = Object.keys(USER_ROLE_LABELS) | 369 | const roles = Object.keys(USER_ROLE_LABELS) |
366 | .map(k => parseInt(k, 10) as UserRole) | 370 | .map(k => parseInt(k, 10) as UserRole) |
367 | .filter(role => hasUserRight(role, right)) | 371 | .filter(role => hasUserRight(role, right)) |
368 | 372 | ||
369 | const query = { | 373 | const query = { |
370 | where: { | 374 | where: { |
@@ -390,7 +394,7 @@ export class UserModel extends Model<UserModel> { | |||
390 | required: true, | 394 | required: true, |
391 | include: [ | 395 | include: [ |
392 | { | 396 | { |
393 | attributes: [ ], | 397 | attributes: [], |
394 | model: ActorModel.unscoped(), | 398 | model: ActorModel.unscoped(), |
395 | required: true, | 399 | required: true, |
396 | where: { | 400 | where: { |
@@ -398,7 +402,7 @@ export class UserModel extends Model<UserModel> { | |||
398 | }, | 402 | }, |
399 | include: [ | 403 | include: [ |
400 | { | 404 | { |
401 | attributes: [ ], | 405 | attributes: [], |
402 | as: 'ActorFollowings', | 406 | as: 'ActorFollowings', |
403 | model: ActorFollowModel.unscoped(), | 407 | model: ActorFollowModel.unscoped(), |
404 | required: true, | 408 | required: true, |
@@ -433,7 +437,7 @@ export class UserModel extends Model<UserModel> { | |||
433 | static loadByUsername (username: string): Bluebird<MUserDefault> { | 437 | static loadByUsername (username: string): Bluebird<MUserDefault> { |
434 | const query = { | 438 | const query = { |
435 | where: { | 439 | where: { |
436 | username: { [ Op.iLike ]: username } | 440 | username: { [Op.iLike]: username } |
437 | } | 441 | } |
438 | } | 442 | } |
439 | 443 | ||
@@ -443,7 +447,7 @@ export class UserModel extends Model<UserModel> { | |||
443 | static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> { | 447 | static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> { |
444 | const query = { | 448 | const query = { |
445 | where: { | 449 | where: { |
446 | username: { [ Op.iLike ]: username } | 450 | username: { [Op.iLike]: username } |
447 | } | 451 | } |
448 | } | 452 | } |
449 | 453 | ||
@@ -465,7 +469,7 @@ export class UserModel extends Model<UserModel> { | |||
465 | 469 | ||
466 | const query = { | 470 | const query = { |
467 | where: { | 471 | where: { |
468 | [ Op.or ]: [ | 472 | [Op.or]: [ |
469 | where(fn('lower', col('username')), fn('lower', username)), | 473 | where(fn('lower', col('username')), fn('lower', username)), |
470 | 474 | ||
471 | { email } | 475 | { email } |
@@ -592,7 +596,7 @@ export class UserModel extends Model<UserModel> { | |||
592 | const query = { | 596 | const query = { |
593 | where: { | 597 | where: { |
594 | username: { | 598 | username: { |
595 | [ Op.like ]: `%${search}%` | 599 | [Op.like]: `%${search}%` |
596 | } | 600 | } |
597 | }, | 601 | }, |
598 | limit: 10 | 602 | limit: 10 |
@@ -652,7 +656,7 @@ export class UserModel extends Model<UserModel> { | |||
652 | videoLanguages: this.videoLanguages, | 656 | videoLanguages: this.videoLanguages, |
653 | 657 | ||
654 | role: this.role, | 658 | role: this.role, |
655 | roleLabel: USER_ROLE_LABELS[ this.role ], | 659 | roleLabel: USER_ROLE_LABELS[this.role], |
656 | 660 | ||
657 | videoQuota: this.videoQuota, | 661 | videoQuota: this.videoQuota, |
658 | videoQuotaDaily: this.videoQuotaDaily, | 662 | videoQuotaDaily: this.videoQuotaDaily, |
@@ -686,13 +690,13 @@ export class UserModel extends Model<UserModel> { | |||
686 | 690 | ||
687 | if (Array.isArray(this.Account.VideoChannels) === true) { | 691 | if (Array.isArray(this.Account.VideoChannels) === true) { |
688 | json.videoChannels = this.Account.VideoChannels | 692 | json.videoChannels = this.Account.VideoChannels |
689 | .map(c => c.toFormattedJSON()) | 693 | .map(c => c.toFormattedJSON()) |
690 | .sort((v1, v2) => { | 694 | .sort((v1, v2) => { |
691 | if (v1.createdAt < v2.createdAt) return -1 | 695 | if (v1.createdAt < v2.createdAt) return -1 |
692 | if (v1.createdAt === v2.createdAt) return 0 | 696 | if (v1.createdAt === v2.createdAt) return 0 |
693 | 697 | ||
694 | return 1 | 698 | return 1 |
695 | }) | 699 | }) |
696 | } | 700 | } |
697 | 701 | ||
698 | return json | 702 | return json |
@@ -702,7 +706,7 @@ export class UserModel extends Model<UserModel> { | |||
702 | const formatted = this.toFormattedJSON() | 706 | const formatted = this.toFormattedJSON() |
703 | 707 | ||
704 | const specialPlaylists = this.Account.VideoPlaylists | 708 | const specialPlaylists = this.Account.VideoPlaylists |
705 | .map(p => ({ id: p.id, name: p.name, type: p.type })) | 709 | .map(p => ({ id: p.id, name: p.name, type: p.type })) |
706 | 710 | ||
707 | return Object.assign(formatted, { specialPlaylists }) | 711 | return Object.assign(formatted, { specialPlaylists }) |
708 | } | 712 | } |
@@ -729,12 +733,12 @@ export class UserModel extends Model<UserModel> { | |||
729 | 733 | ||
730 | return 'SELECT SUM("size") AS "total" ' + | 734 | return 'SELECT SUM("size") AS "total" ' + |
731 | 'FROM (' + | 735 | 'FROM (' + |
732 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + | 736 | 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' + |
733 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + | 737 | 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' + |
734 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 738 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
735 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + | 739 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + |
736 | 'WHERE "account"."userId" = $userId ' + andWhere + | 740 | 'WHERE "account"."userId" = $userId ' + andWhere + |
737 | 'GROUP BY "video"."id"' + | 741 | 'GROUP BY "video"."id"' + |
738 | ') t' | 742 | ') t' |
739 | } | 743 | } |
740 | 744 | ||
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index f21d2b8a2..27643704e 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { values, difference } from 'lodash' | 2 | import { difference, values } from 'lodash' |
3 | import { | 3 | import { |
4 | AfterCreate, | 4 | AfterCreate, |
5 | AfterDestroy, | 5 | AfterDestroy, |
@@ -23,7 +23,7 @@ import { logger } from '../../helpers/logger' | |||
23 | import { getServerActor } from '../../helpers/utils' | 23 | import { getServerActor } from '../../helpers/utils' |
24 | import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' | 24 | import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' |
25 | import { ServerModel } from '../server/server' | 25 | import { ServerModel } from '../server/server' |
26 | import { createSafeIn, getSort, getFollowsSort } from '../utils' | 26 | import { createSafeIn, getFollowsSort, getSort } from '../utils' |
27 | import { ActorModel, unusedActorAttributesForAPI } from './actor' | 27 | import { ActorModel, unusedActorAttributesForAPI } from './actor' |
28 | import { VideoChannelModel } from '../video/video-channel' | 28 | import { VideoChannelModel } from '../video/video-channel' |
29 | import { AccountModel } from '../account/account' | 29 | import { AccountModel } from '../account/account' |
@@ -36,7 +36,6 @@ import { | |||
36 | MActorFollowSubscriptions | 36 | MActorFollowSubscriptions |
37 | } from '@server/typings/models' | 37 | } from '@server/typings/models' |
38 | import { ActivityPubActorType } from '@shared/models' | 38 | import { ActivityPubActorType } from '@shared/models' |
39 | import { afterCommitIfTransaction } from '@server/helpers/database-utils' | ||
40 | 39 | ||
41 | @Table({ | 40 | @Table({ |
42 | tableName: 'actorFollow', | 41 | tableName: 'actorFollow', |
@@ -226,7 +225,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
226 | 225 | ||
227 | return ActorFollowModel.findOne(query) | 226 | return ActorFollowModel.findOne(query) |
228 | .then(result => { | 227 | .then(result => { |
229 | if (result && result.ActorFollowing.VideoChannel) { | 228 | if (result?.ActorFollowing.VideoChannel) { |
230 | result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing | 229 | result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing |
231 | } | 230 | } |
232 | 231 | ||
@@ -239,24 +238,24 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
239 | .map(t => { | 238 | .map(t => { |
240 | if (t.host) { | 239 | if (t.host) { |
241 | return { | 240 | return { |
242 | [ Op.and ]: [ | 241 | [Op.and]: [ |
243 | { | 242 | { |
244 | '$preferredUsername$': t.name | 243 | $preferredUsername$: t.name |
245 | }, | 244 | }, |
246 | { | 245 | { |
247 | '$host$': t.host | 246 | $host$: t.host |
248 | } | 247 | } |
249 | ] | 248 | ] |
250 | } | 249 | } |
251 | } | 250 | } |
252 | 251 | ||
253 | return { | 252 | return { |
254 | [ Op.and ]: [ | 253 | [Op.and]: [ |
255 | { | 254 | { |
256 | '$preferredUsername$': t.name | 255 | $preferredUsername$: t.name |
257 | }, | 256 | }, |
258 | { | 257 | { |
259 | '$serverId$': null | 258 | $serverId$: null |
260 | } | 259 | } |
261 | ] | 260 | ] |
262 | } | 261 | } |
@@ -265,9 +264,9 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
265 | const query = { | 264 | const query = { |
266 | attributes: [], | 265 | attributes: [], |
267 | where: { | 266 | where: { |
268 | [ Op.and ]: [ | 267 | [Op.and]: [ |
269 | { | 268 | { |
270 | [ Op.or ]: whereTab | 269 | [Op.or]: whereTab |
271 | }, | 270 | }, |
272 | { | 271 | { |
273 | actorId | 272 | actorId |
@@ -295,12 +294,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
295 | } | 294 | } |
296 | 295 | ||
297 | static listFollowingForApi (options: { | 296 | static listFollowingForApi (options: { |
298 | id: number, | 297 | id: number |
299 | start: number, | 298 | start: number |
300 | count: number, | 299 | count: number |
301 | sort: string, | 300 | sort: string |
302 | state?: FollowState, | 301 | state?: FollowState |
303 | actorType?: ActivityPubActorType, | 302 | actorType?: ActivityPubActorType |
304 | search?: string | 303 | search?: string |
305 | }) { | 304 | }) { |
306 | const { id, start, count, sort, search, state, actorType } = options | 305 | const { id, start, count, sort, search, state, actorType } = options |
@@ -312,7 +311,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
312 | if (search) { | 311 | if (search) { |
313 | Object.assign(followingServerWhere, { | 312 | Object.assign(followingServerWhere, { |
314 | host: { | 313 | host: { |
315 | [ Op.iLike ]: '%' + search + '%' | 314 | [Op.iLike]: '%' + search + '%' |
316 | } | 315 | } |
317 | }) | 316 | }) |
318 | } | 317 | } |
@@ -362,12 +361,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
362 | } | 361 | } |
363 | 362 | ||
364 | static listFollowersForApi (options: { | 363 | static listFollowersForApi (options: { |
365 | actorId: number, | 364 | actorId: number |
366 | start: number, | 365 | start: number |
367 | count: number, | 366 | count: number |
368 | sort: string, | 367 | sort: string |
369 | state?: FollowState, | 368 | state?: FollowState |
370 | actorType?: ActivityPubActorType, | 369 | actorType?: ActivityPubActorType |
371 | search?: string | 370 | search?: string |
372 | }) { | 371 | }) { |
373 | const { actorId, start, count, sort, search, state, actorType } = options | 372 | const { actorId, start, count, sort, search, state, actorType } = options |
@@ -379,7 +378,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
379 | if (search) { | 378 | if (search) { |
380 | Object.assign(followerServerWhere, { | 379 | Object.assign(followerServerWhere, { |
381 | host: { | 380 | host: { |
382 | [ Op.iLike ]: '%' + search + '%' | 381 | [Op.iLike]: '%' + search + '%' |
383 | } | 382 | } |
384 | }) | 383 | }) |
385 | } | 384 | } |
@@ -631,7 +630,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
631 | 630 | ||
632 | const tasks: Bluebird<any>[] = [] | 631 | const tasks: Bluebird<any>[] = [] |
633 | 632 | ||
634 | for (let selection of selections) { | 633 | for (const selection of selections) { |
635 | let query = 'SELECT ' + selection + ' FROM "actor" ' + | 634 | let query = 'SELECT ' + selection + ' FROM "actor" ' + |
636 | 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' + | 635 | 'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' + |
637 | 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' + | 636 | 'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' + |
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts index 007647ced..e547d2c0c 100644 --- a/server/models/activitypub/actor.ts +++ b/server/models/activitypub/actor.ts | |||
@@ -16,7 +16,7 @@ import { | |||
16 | Table, | 16 | Table, |
17 | UpdatedAt | 17 | UpdatedAt |
18 | } from 'sequelize-typescript' | 18 | } from 'sequelize-typescript' |
19 | import { ActivityPubActorType } from '../../../shared/models/activitypub' | 19 | import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub' |
20 | import { Avatar } from '../../../shared/models/avatars/avatar.model' | 20 | import { Avatar } from '../../../shared/models/avatars/avatar.model' |
21 | import { activityPubContextify } from '../../helpers/activitypub' | 21 | import { activityPubContextify } from '../../helpers/activitypub' |
22 | import { | 22 | import { |
@@ -43,11 +43,12 @@ import { | |||
43 | MActorFull, | 43 | MActorFull, |
44 | MActorHost, | 44 | MActorHost, |
45 | MActorServer, | 45 | MActorServer, |
46 | MActorSummaryFormattable, | 46 | MActorSummaryFormattable, MActorUrl, |
47 | MActorWithInboxes | 47 | MActorWithInboxes |
48 | } from '../../typings/models' | 48 | } from '../../typings/models' |
49 | import * as Bluebird from 'bluebird' | 49 | import * as Bluebird from 'bluebird' |
50 | import { Op, Transaction, literal } from 'sequelize' | 50 | import { Op, Transaction, literal } from 'sequelize' |
51 | import { ModelCache } from '@server/models/model-cache' | ||
51 | 52 | ||
52 | enum ScopeNames { | 53 | enum ScopeNames { |
53 | FULL = 'FULL' | 54 | FULL = 'FULL' |
@@ -276,8 +277,6 @@ export class ActorModel extends Model<ActorModel> { | |||
276 | }) | 277 | }) |
277 | VideoChannel: VideoChannelModel | 278 | VideoChannel: VideoChannelModel |
278 | 279 | ||
279 | private static cache: { [ id: string ]: any } = {} | ||
280 | |||
281 | static load (id: number): Bluebird<MActor> { | 280 | static load (id: number): Bluebird<MActor> { |
282 | return ActorModel.unscoped().findByPk(id) | 281 | return ActorModel.unscoped().findByPk(id) |
283 | } | 282 | } |
@@ -334,7 +333,7 @@ export class ActorModel extends Model<ActorModel> { | |||
334 | const query = { | 333 | const query = { |
335 | where: { | 334 | where: { |
336 | followersUrl: { | 335 | followersUrl: { |
337 | [ Op.in ]: followersUrls | 336 | [Op.in]: followersUrls |
338 | } | 337 | } |
339 | }, | 338 | }, |
340 | transaction | 339 | transaction |
@@ -344,28 +343,50 @@ export class ActorModel extends Model<ActorModel> { | |||
344 | } | 343 | } |
345 | 344 | ||
346 | static loadLocalByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorFull> { | 345 | static loadLocalByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorFull> { |
347 | // The server actor never change, so we can easily cache it | 346 | const fun = () => { |
348 | if (preferredUsername === SERVER_ACTOR_NAME && ActorModel.cache[preferredUsername]) { | 347 | const query = { |
349 | return Bluebird.resolve(ActorModel.cache[preferredUsername]) | 348 | where: { |
350 | } | 349 | preferredUsername, |
350 | serverId: null | ||
351 | }, | ||
352 | transaction | ||
353 | } | ||
351 | 354 | ||
352 | const query = { | 355 | return ActorModel.scope(ScopeNames.FULL) |
353 | where: { | 356 | .findOne(query) |
354 | preferredUsername, | ||
355 | serverId: null | ||
356 | }, | ||
357 | transaction | ||
358 | } | 357 | } |
359 | 358 | ||
360 | return ActorModel.scope(ScopeNames.FULL) | 359 | return ModelCache.Instance.doCache({ |
361 | .findOne(query) | 360 | cacheType: 'local-actor-name', |
362 | .then(actor => { | 361 | key: preferredUsername, |
363 | if (preferredUsername === SERVER_ACTOR_NAME) { | 362 | // The server actor never change, so we can easily cache it |
364 | ActorModel.cache[ preferredUsername ] = actor | 363 | whitelist: () => preferredUsername === SERVER_ACTOR_NAME, |
365 | } | 364 | fun |
365 | }) | ||
366 | } | ||
366 | 367 | ||
367 | return actor | 368 | static loadLocalUrlByName (preferredUsername: string, transaction?: Transaction): Bluebird<MActorUrl> { |
368 | }) | 369 | const fun = () => { |
370 | const query = { | ||
371 | attributes: [ 'url' ], | ||
372 | where: { | ||
373 | preferredUsername, | ||
374 | serverId: null | ||
375 | }, | ||
376 | transaction | ||
377 | } | ||
378 | |||
379 | return ActorModel.unscoped() | ||
380 | .findOne(query) | ||
381 | } | ||
382 | |||
383 | return ModelCache.Instance.doCache({ | ||
384 | cacheType: 'local-actor-name', | ||
385 | key: preferredUsername, | ||
386 | // The server actor never change, so we can easily cache it | ||
387 | whitelist: () => preferredUsername === SERVER_ACTOR_NAME, | ||
388 | fun | ||
389 | }) | ||
369 | } | 390 | } |
370 | 391 | ||
371 | static loadByNameAndHost (preferredUsername: string, host: string): Bluebird<MActorFull> { | 392 | static loadByNameAndHost (preferredUsername: string, host: string): Bluebird<MActorFull> { |
@@ -441,6 +462,36 @@ export class ActorModel extends Model<ActorModel> { | |||
441 | }, { where, transaction }) | 462 | }, { where, transaction }) |
442 | } | 463 | } |
443 | 464 | ||
465 | static loadAccountActorByVideoId (videoId: number): Bluebird<MActor> { | ||
466 | const query = { | ||
467 | include: [ | ||
468 | { | ||
469 | attributes: [ 'id' ], | ||
470 | model: AccountModel.unscoped(), | ||
471 | required: true, | ||
472 | include: [ | ||
473 | { | ||
474 | attributes: [ 'id', 'accountId' ], | ||
475 | model: VideoChannelModel.unscoped(), | ||
476 | required: true, | ||
477 | include: [ | ||
478 | { | ||
479 | attributes: [ 'id', 'channelId' ], | ||
480 | model: VideoModel.unscoped(), | ||
481 | where: { | ||
482 | id: videoId | ||
483 | } | ||
484 | } | ||
485 | ] | ||
486 | } | ||
487 | ] | ||
488 | } | ||
489 | ] | ||
490 | } | ||
491 | |||
492 | return ActorModel.unscoped().findOne(query) | ||
493 | } | ||
494 | |||
444 | getSharedInbox (this: MActorWithInboxes) { | 495 | getSharedInbox (this: MActorWithInboxes) { |
445 | return this.sharedInboxUrl || this.inboxUrl | 496 | return this.sharedInboxUrl || this.inboxUrl |
446 | } | 497 | } |
@@ -473,9 +524,11 @@ export class ActorModel extends Model<ActorModel> { | |||
473 | } | 524 | } |
474 | 525 | ||
475 | toActivityPubObject (this: MActorAP, name: string) { | 526 | toActivityPubObject (this: MActorAP, name: string) { |
476 | let icon = undefined | 527 | let icon: ActivityIconObject |
528 | |||
477 | if (this.avatarId) { | 529 | if (this.avatarId) { |
478 | const extension = extname(this.Avatar.filename) | 530 | const extension = extname(this.Avatar.filename) |
531 | |||
479 | icon = { | 532 | icon = { |
480 | type: 'Image', | 533 | type: 'Image', |
481 | mediaType: extension === '.png' ? 'image/png' : 'image/jpeg', | 534 | mediaType: extension === '.png' ? 'image/png' : 'image/jpeg', |
diff --git a/server/models/model-cache.ts b/server/models/model-cache.ts new file mode 100644 index 000000000..a87f99aa2 --- /dev/null +++ b/server/models/model-cache.ts | |||
@@ -0,0 +1,91 @@ | |||
1 | import { Model } from 'sequelize-typescript' | ||
2 | import * as Bluebird from 'bluebird' | ||
3 | import { logger } from '@server/helpers/logger' | ||
4 | |||
5 | type ModelCacheType = | ||
6 | 'local-account-name' | ||
7 | | 'local-actor-name' | ||
8 | | 'local-actor-url' | ||
9 | | 'load-video-immutable-id' | ||
10 | | 'load-video-immutable-url' | ||
11 | |||
12 | type DeleteKey = | ||
13 | 'video' | ||
14 | |||
15 | class ModelCache { | ||
16 | |||
17 | private static instance: ModelCache | ||
18 | |||
19 | private readonly localCache: { [id in ModelCacheType]: Map<string, any> } = { | ||
20 | 'local-account-name': new Map(), | ||
21 | 'local-actor-name': new Map(), | ||
22 | 'local-actor-url': new Map(), | ||
23 | 'load-video-immutable-id': new Map(), | ||
24 | 'load-video-immutable-url': new Map() | ||
25 | } | ||
26 | |||
27 | private readonly deleteIds: { | ||
28 | [deleteKey in DeleteKey]: Map<number, { cacheType: ModelCacheType, key: string }[]> | ||
29 | } = { | ||
30 | video: new Map() | ||
31 | } | ||
32 | |||
33 | private constructor () { | ||
34 | } | ||
35 | |||
36 | static get Instance () { | ||
37 | return this.instance || (this.instance = new this()) | ||
38 | } | ||
39 | |||
40 | doCache<T extends Model> (options: { | ||
41 | cacheType: ModelCacheType | ||
42 | key: string | ||
43 | fun: () => Bluebird<T> | ||
44 | whitelist?: () => boolean | ||
45 | deleteKey?: DeleteKey | ||
46 | }) { | ||
47 | const { cacheType, key, fun, whitelist, deleteKey } = options | ||
48 | |||
49 | if (whitelist && whitelist() !== true) return fun() | ||
50 | |||
51 | const cache = this.localCache[cacheType] | ||
52 | |||
53 | if (cache.has(key)) { | ||
54 | logger.debug('Model cache hit for %s -> %s.', cacheType, key) | ||
55 | return Bluebird.resolve<T>(cache.get(key)) | ||
56 | } | ||
57 | |||
58 | return fun().then(m => { | ||
59 | if (!m) return m | ||
60 | |||
61 | if (!whitelist || whitelist()) cache.set(key, m) | ||
62 | |||
63 | if (deleteKey) { | ||
64 | const map = this.deleteIds[deleteKey] | ||
65 | if (!map.has(m.id)) map.set(m.id, []) | ||
66 | |||
67 | const a = map.get(m.id) | ||
68 | a.push({ cacheType, key }) | ||
69 | } | ||
70 | |||
71 | return m | ||
72 | }) | ||
73 | } | ||
74 | |||
75 | invalidateCache (deleteKey: DeleteKey, modelId: number) { | ||
76 | const map = this.deleteIds[deleteKey] | ||
77 | |||
78 | if (!map.has(modelId)) return | ||
79 | |||
80 | for (const toDelete of map.get(modelId)) { | ||
81 | logger.debug('Removing %s -> %d of model cache %s -> %s.', deleteKey, modelId, toDelete.cacheType, toDelete.key) | ||
82 | this.localCache[toDelete.cacheType].delete(toDelete.key) | ||
83 | } | ||
84 | |||
85 | map.delete(modelId) | ||
86 | } | ||
87 | } | ||
88 | |||
89 | export { | ||
90 | ModelCache | ||
91 | } | ||
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index b680be237..d2101ce86 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts | |||
@@ -23,10 +23,10 @@ import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token' | |||
23 | 23 | ||
24 | export type OAuthTokenInfo = { | 24 | export type OAuthTokenInfo = { |
25 | refreshToken: string | 25 | refreshToken: string |
26 | refreshTokenExpiresAt: Date, | 26 | refreshTokenExpiresAt: Date |
27 | client: { | 27 | client: { |
28 | id: number | 28 | id: number |
29 | }, | 29 | } |
30 | user: { | 30 | user: { |
31 | id: number | 31 | id: number |
32 | } | 32 | } |
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts index 8c9a7eabf..1b63d3818 100644 --- a/server/models/redundancy/video-redundancy.ts +++ b/server/models/redundancy/video-redundancy.ts | |||
@@ -13,13 +13,13 @@ import { | |||
13 | UpdatedAt | 13 | UpdatedAt |
14 | } from 'sequelize-typescript' | 14 | } from 'sequelize-typescript' |
15 | import { ActorModel } from '../activitypub/actor' | 15 | import { ActorModel } from '../activitypub/actor' |
16 | import { getVideoSort, parseAggregateResult, throwIfNotValid } from '../utils' | 16 | import { getSort, getVideoSort, parseAggregateResult, throwIfNotValid } from '../utils' |
17 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 17 | import { isActivityPubUrlValid, isUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
18 | import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../initializers/constants' | 18 | import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../initializers/constants' |
19 | import { VideoFileModel } from '../video/video-file' | 19 | import { VideoFileModel } from '../video/video-file' |
20 | import { getServerActor } from '../../helpers/utils' | 20 | import { getServerActor } from '../../helpers/utils' |
21 | import { VideoModel } from '../video/video' | 21 | import { VideoModel } from '../video/video' |
22 | import { VideoRedundancyStrategy } from '../../../shared/models/redundancy' | 22 | import { VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../shared/models/redundancy' |
23 | import { logger } from '../../helpers/logger' | 23 | import { logger } from '../../helpers/logger' |
24 | import { CacheFileObject, VideoPrivacy } from '../../../shared' | 24 | import { CacheFileObject, VideoPrivacy } from '../../../shared' |
25 | import { VideoChannelModel } from '../video/video-channel' | 25 | import { VideoChannelModel } from '../video/video-channel' |
@@ -27,17 +27,23 @@ import { ServerModel } from '../server/server' | |||
27 | import { sample } from 'lodash' | 27 | import { sample } from 'lodash' |
28 | import { isTestInstance } from '../../helpers/core-utils' | 28 | import { isTestInstance } from '../../helpers/core-utils' |
29 | import * as Bluebird from 'bluebird' | 29 | import * as Bluebird from 'bluebird' |
30 | import { col, FindOptions, fn, literal, Op, Transaction } from 'sequelize' | 30 | import { col, FindOptions, fn, literal, Op, Transaction, WhereOptions } from 'sequelize' |
31 | import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist' | 31 | import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist' |
32 | import { CONFIG } from '../../initializers/config' | 32 | import { CONFIG } from '../../initializers/config' |
33 | import { MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/typings/models' | 33 | import { MVideoForRedundancyAPI, MVideoRedundancy, MVideoRedundancyAP, MVideoRedundancyVideo } from '@server/typings/models' |
34 | import { VideoRedundanciesTarget } from '@shared/models/redundancy/video-redundancies-filters.model' | ||
35 | import { | ||
36 | FileRedundancyInformation, | ||
37 | StreamingPlaylistRedundancyInformation, | ||
38 | VideoRedundancy | ||
39 | } from '@shared/models/redundancy/video-redundancy.model' | ||
34 | 40 | ||
35 | export enum ScopeNames { | 41 | export enum ScopeNames { |
36 | WITH_VIDEO = 'WITH_VIDEO' | 42 | WITH_VIDEO = 'WITH_VIDEO' |
37 | } | 43 | } |
38 | 44 | ||
39 | @Scopes(() => ({ | 45 | @Scopes(() => ({ |
40 | [ ScopeNames.WITH_VIDEO ]: { | 46 | [ScopeNames.WITH_VIDEO]: { |
41 | include: [ | 47 | include: [ |
42 | { | 48 | { |
43 | model: VideoFileModel, | 49 | model: VideoFileModel, |
@@ -86,7 +92,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
86 | @UpdatedAt | 92 | @UpdatedAt |
87 | updatedAt: Date | 93 | updatedAt: Date |
88 | 94 | ||
89 | @AllowNull(false) | 95 | @AllowNull(true) |
90 | @Column | 96 | @Column |
91 | expiresOn: Date | 97 | expiresOn: Date |
92 | 98 | ||
@@ -161,7 +167,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
161 | logger.info('Removing duplicated video streaming playlist %s.', videoUUID) | 167 | logger.info('Removing duplicated video streaming playlist %s.', videoUUID) |
162 | 168 | ||
163 | videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true) | 169 | videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true) |
164 | .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err })) | 170 | .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err })) |
165 | } | 171 | } |
166 | 172 | ||
167 | return undefined | 173 | return undefined |
@@ -193,6 +199,15 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
193 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) | 199 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) |
194 | } | 200 | } |
195 | 201 | ||
202 | static loadByIdWithVideo (id: number, transaction?: Transaction): Bluebird<MVideoRedundancyVideo> { | ||
203 | const query = { | ||
204 | where: { id }, | ||
205 | transaction | ||
206 | } | ||
207 | |||
208 | return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) | ||
209 | } | ||
210 | |||
196 | static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoRedundancy> { | 211 | static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoRedundancy> { |
197 | const query = { | 212 | const query = { |
198 | where: { | 213 | where: { |
@@ -215,12 +230,12 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
215 | }, | 230 | }, |
216 | include: [ | 231 | include: [ |
217 | { | 232 | { |
218 | attributes: [ ], | 233 | attributes: [], |
219 | model: VideoFileModel, | 234 | model: VideoFileModel, |
220 | required: true, | 235 | required: true, |
221 | include: [ | 236 | include: [ |
222 | { | 237 | { |
223 | attributes: [ ], | 238 | attributes: [], |
224 | model: VideoModel, | 239 | model: VideoModel, |
225 | required: true, | 240 | required: true, |
226 | where: { | 241 | where: { |
@@ -233,7 +248,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
233 | } | 248 | } |
234 | 249 | ||
235 | return VideoRedundancyModel.findOne(query) | 250 | return VideoRedundancyModel.findOne(query) |
236 | .then(r => !!r) | 251 | .then(r => !!r) |
237 | } | 252 | } |
238 | 253 | ||
239 | static async getVideoSample (p: Bluebird<VideoModel[]>) { | 254 | static async getVideoSample (p: Bluebird<VideoModel[]>) { |
@@ -295,7 +310,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
295 | where: { | 310 | where: { |
296 | privacy: VideoPrivacy.PUBLIC, | 311 | privacy: VideoPrivacy.PUBLIC, |
297 | views: { | 312 | views: { |
298 | [ Op.gte ]: minViews | 313 | [Op.gte]: minViews |
299 | } | 314 | } |
300 | }, | 315 | }, |
301 | include: [ | 316 | include: [ |
@@ -318,7 +333,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
318 | actorId: actor.id, | 333 | actorId: actor.id, |
319 | strategy, | 334 | strategy, |
320 | createdAt: { | 335 | createdAt: { |
321 | [ Op.lt ]: expiredDate | 336 | [Op.lt]: expiredDate |
322 | } | 337 | } |
323 | } | 338 | } |
324 | } | 339 | } |
@@ -377,7 +392,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
377 | where: { | 392 | where: { |
378 | actorId: actor.id, | 393 | actorId: actor.id, |
379 | expiresOn: { | 394 | expiresOn: { |
380 | [ Op.lt ]: new Date() | 395 | [Op.lt]: new Date() |
381 | } | 396 | } |
382 | } | 397 | } |
383 | } | 398 | } |
@@ -394,7 +409,8 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
394 | [Op.ne]: actor.id | 409 | [Op.ne]: actor.id |
395 | }, | 410 | }, |
396 | expiresOn: { | 411 | expiresOn: { |
397 | [ Op.lt ]: new Date() | 412 | [Op.lt]: new Date(), |
413 | [Op.ne]: null | ||
398 | } | 414 | } |
399 | } | 415 | } |
400 | } | 416 | } |
@@ -447,7 +463,112 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
447 | return VideoRedundancyModel.findAll(query) | 463 | return VideoRedundancyModel.findAll(query) |
448 | } | 464 | } |
449 | 465 | ||
450 | static async getStats (strategy: VideoRedundancyStrategy) { | 466 | static listForApi (options: { |
467 | start: number | ||
468 | count: number | ||
469 | sort: string | ||
470 | target: VideoRedundanciesTarget | ||
471 | strategy?: string | ||
472 | }) { | ||
473 | const { start, count, sort, target, strategy } = options | ||
474 | const redundancyWhere: WhereOptions = {} | ||
475 | const videosWhere: WhereOptions = {} | ||
476 | let redundancySqlSuffix = '' | ||
477 | |||
478 | if (target === 'my-videos') { | ||
479 | Object.assign(videosWhere, { remote: false }) | ||
480 | } else if (target === 'remote-videos') { | ||
481 | Object.assign(videosWhere, { remote: true }) | ||
482 | Object.assign(redundancyWhere, { strategy: { [Op.ne]: null } }) | ||
483 | redundancySqlSuffix = ' AND "videoRedundancy"."strategy" IS NOT NULL' | ||
484 | } | ||
485 | |||
486 | if (strategy) { | ||
487 | Object.assign(redundancyWhere, { strategy: strategy }) | ||
488 | } | ||
489 | |||
490 | const videoFilterWhere = { | ||
491 | [Op.and]: [ | ||
492 | { | ||
493 | [Op.or]: [ | ||
494 | { | ||
495 | id: { | ||
496 | [Op.in]: literal( | ||
497 | '(' + | ||
498 | 'SELECT "videoId" FROM "videoFile" ' + | ||
499 | 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoFileId" = "videoFile".id' + | ||
500 | redundancySqlSuffix + | ||
501 | ')' | ||
502 | ) | ||
503 | } | ||
504 | }, | ||
505 | { | ||
506 | id: { | ||
507 | [Op.in]: literal( | ||
508 | '(' + | ||
509 | 'select "videoId" FROM "videoStreamingPlaylist" ' + | ||
510 | 'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id' + | ||
511 | redundancySqlSuffix + | ||
512 | ')' | ||
513 | ) | ||
514 | } | ||
515 | } | ||
516 | ] | ||
517 | }, | ||
518 | |||
519 | videosWhere | ||
520 | ] | ||
521 | } | ||
522 | |||
523 | // /!\ On video model /!\ | ||
524 | const findOptions = { | ||
525 | offset: start, | ||
526 | limit: count, | ||
527 | order: getSort(sort), | ||
528 | include: [ | ||
529 | { | ||
530 | required: false, | ||
531 | model: VideoFileModel.unscoped(), | ||
532 | include: [ | ||
533 | { | ||
534 | model: VideoRedundancyModel.unscoped(), | ||
535 | required: false, | ||
536 | where: redundancyWhere | ||
537 | } | ||
538 | ] | ||
539 | }, | ||
540 | { | ||
541 | required: false, | ||
542 | model: VideoStreamingPlaylistModel.unscoped(), | ||
543 | include: [ | ||
544 | { | ||
545 | model: VideoRedundancyModel.unscoped(), | ||
546 | required: false, | ||
547 | where: redundancyWhere | ||
548 | }, | ||
549 | { | ||
550 | model: VideoFileModel.unscoped(), | ||
551 | required: false | ||
552 | } | ||
553 | ] | ||
554 | } | ||
555 | ], | ||
556 | where: videoFilterWhere | ||
557 | } | ||
558 | |||
559 | // /!\ On video model /!\ | ||
560 | const countOptions = { | ||
561 | where: videoFilterWhere | ||
562 | } | ||
563 | |||
564 | return Promise.all([ | ||
565 | VideoModel.findAll(findOptions), | ||
566 | |||
567 | VideoModel.count(countOptions) | ||
568 | ]).then(([ data, total ]) => ({ total, data })) | ||
569 | } | ||
570 | |||
571 | static async getStats (strategy: VideoRedundancyStrategyWithManual) { | ||
451 | const actor = await getServerActor() | 572 | const actor = await getServerActor() |
452 | 573 | ||
453 | const query: FindOptions = { | 574 | const query: FindOptions = { |
@@ -471,11 +592,58 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
471 | } | 592 | } |
472 | 593 | ||
473 | return VideoRedundancyModel.findOne(query) | 594 | return VideoRedundancyModel.findOne(query) |
474 | .then((r: any) => ({ | 595 | .then((r: any) => ({ |
475 | totalUsed: parseAggregateResult(r.totalUsed), | 596 | totalUsed: parseAggregateResult(r.totalUsed), |
476 | totalVideos: r.totalVideos, | 597 | totalVideos: r.totalVideos, |
477 | totalVideoFiles: r.totalVideoFiles | 598 | totalVideoFiles: r.totalVideoFiles |
478 | })) | 599 | })) |
600 | } | ||
601 | |||
602 | static toFormattedJSONStatic (video: MVideoForRedundancyAPI): VideoRedundancy { | ||
603 | const filesRedundancies: FileRedundancyInformation[] = [] | ||
604 | const streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = [] | ||
605 | |||
606 | for (const file of video.VideoFiles) { | ||
607 | for (const redundancy of file.RedundancyVideos) { | ||
608 | filesRedundancies.push({ | ||
609 | id: redundancy.id, | ||
610 | fileUrl: redundancy.fileUrl, | ||
611 | strategy: redundancy.strategy, | ||
612 | createdAt: redundancy.createdAt, | ||
613 | updatedAt: redundancy.updatedAt, | ||
614 | expiresOn: redundancy.expiresOn, | ||
615 | size: file.size | ||
616 | }) | ||
617 | } | ||
618 | } | ||
619 | |||
620 | for (const playlist of video.VideoStreamingPlaylists) { | ||
621 | const size = playlist.VideoFiles.reduce((a, b) => a + b.size, 0) | ||
622 | |||
623 | for (const redundancy of playlist.RedundancyVideos) { | ||
624 | streamingPlaylistsRedundancies.push({ | ||
625 | id: redundancy.id, | ||
626 | fileUrl: redundancy.fileUrl, | ||
627 | strategy: redundancy.strategy, | ||
628 | createdAt: redundancy.createdAt, | ||
629 | updatedAt: redundancy.updatedAt, | ||
630 | expiresOn: redundancy.expiresOn, | ||
631 | size | ||
632 | }) | ||
633 | } | ||
634 | } | ||
635 | |||
636 | return { | ||
637 | id: video.id, | ||
638 | name: video.name, | ||
639 | url: video.url, | ||
640 | uuid: video.uuid, | ||
641 | |||
642 | redundancies: { | ||
643 | files: filesRedundancies, | ||
644 | streamingPlaylists: streamingPlaylistsRedundancies | ||
645 | } | ||
646 | } | ||
479 | } | 647 | } |
480 | 648 | ||
481 | getVideo () { | 649 | getVideo () { |
@@ -494,7 +662,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
494 | id: this.url, | 662 | id: this.url, |
495 | type: 'CacheFile' as 'CacheFile', | 663 | type: 'CacheFile' as 'CacheFile', |
496 | object: this.VideoStreamingPlaylist.Video.url, | 664 | object: this.VideoStreamingPlaylist.Video.url, |
497 | expires: this.expiresOn.toISOString(), | 665 | expires: this.expiresOn ? this.expiresOn.toISOString() : null, |
498 | url: { | 666 | url: { |
499 | type: 'Link', | 667 | type: 'Link', |
500 | mediaType: 'application/x-mpegURL', | 668 | mediaType: 'application/x-mpegURL', |
@@ -507,10 +675,10 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
507 | id: this.url, | 675 | id: this.url, |
508 | type: 'CacheFile' as 'CacheFile', | 676 | type: 'CacheFile' as 'CacheFile', |
509 | object: this.VideoFile.Video.url, | 677 | object: this.VideoFile.Video.url, |
510 | expires: this.expiresOn.toISOString(), | 678 | expires: this.expiresOn ? this.expiresOn.toISOString() : null, |
511 | url: { | 679 | url: { |
512 | type: 'Link', | 680 | type: 'Link', |
513 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ this.VideoFile.extname ] as any, | 681 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[this.VideoFile.extname] as any, |
514 | href: this.fileUrl, | 682 | href: this.fileUrl, |
515 | height: this.VideoFile.resolution, | 683 | height: this.VideoFile.resolution, |
516 | size: this.VideoFile.size, | 684 | size: this.VideoFile.size, |
@@ -525,7 +693,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
525 | 693 | ||
526 | const notIn = literal( | 694 | const notIn = literal( |
527 | '(' + | 695 | '(' + |
528 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` + | 696 | `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` + |
529 | ')' | 697 | ')' |
530 | ) | 698 | ) |
531 | 699 | ||
@@ -535,7 +703,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> { | |||
535 | required: true, | 703 | required: true, |
536 | where: { | 704 | where: { |
537 | id: { | 705 | id: { |
538 | [ Op.notIn ]: notIn | 706 | [Op.notIn]: notIn |
539 | } | 707 | } |
540 | } | 708 | } |
541 | } | 709 | } |
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts index d094da1f5..95774a467 100644 --- a/server/models/server/plugin.ts +++ b/server/models/server/plugin.ts | |||
@@ -189,10 +189,10 @@ export class PluginModel extends Model<PluginModel> { | |||
189 | } | 189 | } |
190 | 190 | ||
191 | static listForApi (options: { | 191 | static listForApi (options: { |
192 | pluginType?: PluginType, | 192 | pluginType?: PluginType |
193 | uninstalled?: boolean, | 193 | uninstalled?: boolean |
194 | start: number, | 194 | start: number |
195 | count: number, | 195 | count: number |
196 | sort: string | 196 | sort: string |
197 | }) { | 197 | }) { |
198 | const { uninstalled = false } = options | 198 | const { uninstalled = false } = options |
diff --git a/server/models/server/server-blocklist.ts b/server/models/server/server-blocklist.ts index b88df4fd5..883ae47ab 100644 --- a/server/models/server/server-blocklist.ts +++ b/server/models/server/server-blocklist.ts | |||
@@ -81,7 +81,7 @@ export class ServerBlocklistModel extends Model<ServerBlocklistModel> { | |||
81 | attributes: [ 'accountId', 'id' ], | 81 | attributes: [ 'accountId', 'id' ], |
82 | where: { | 82 | where: { |
83 | accountId: { | 83 | accountId: { |
84 | [Op.in]: accountIds // FIXME: sequelize ANY seems broken | 84 | [Op.in]: accountIds |
85 | }, | 85 | }, |
86 | targetServerId | 86 | targetServerId |
87 | }, | 87 | }, |
diff --git a/server/models/utils.ts b/server/models/utils.ts index f89b80011..f7afb8d4b 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -67,7 +67,7 @@ function getVideoSort (value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): Or | |||
67 | function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { | 67 | function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] { |
68 | const [ firstSort ] = getSort(value) | 68 | const [ firstSort ] = getSort(value) |
69 | 69 | ||
70 | if (model) return [ [ literal(`"${model}.${firstSort[ 0 ]}" ${firstSort[ 1 ]}`) ], lastSort ] as any[] // FIXME: typings | 70 | if (model) return [ [ literal(`"${model}.${firstSort[0]}" ${firstSort[1]}`) ], lastSort ] as any[] // FIXME: typings |
71 | return [ firstSort, lastSort ] | 71 | return [ firstSort, lastSort ] |
72 | } | 72 | } |
73 | 73 | ||
@@ -139,7 +139,7 @@ function buildServerIdsFollowedBy (actorId: any) { | |||
139 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + | 139 | 'SELECT "actor"."serverId" FROM "actorFollow" ' + |
140 | 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' + | 140 | 'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' + |
141 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + | 141 | 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + |
142 | ')' | 142 | ')' |
143 | } | 143 | } |
144 | 144 | ||
145 | function buildWhereIdOrUUID (id: number | string) { | 145 | function buildWhereIdOrUUID (id: number | string) { |
diff --git a/server/models/video/thumbnail.ts b/server/models/video/thumbnail.ts index 3b011b1d2..e396784d2 100644 --- a/server/models/video/thumbnail.ts +++ b/server/models/video/thumbnail.ts | |||
@@ -19,6 +19,8 @@ import { CONFIG } from '../../initializers/config' | |||
19 | import { VideoModel } from './video' | 19 | import { VideoModel } from './video' |
20 | import { VideoPlaylistModel } from './video-playlist' | 20 | import { VideoPlaylistModel } from './video-playlist' |
21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 21 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
22 | import { MVideoAccountLight } from '@server/typings/models' | ||
23 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
22 | 24 | ||
23 | @Table({ | 25 | @Table({ |
24 | tableName: 'thumbnail', | 26 | tableName: 'thumbnail', |
@@ -90,7 +92,7 @@ export class ThumbnailModel extends Model<ThumbnailModel> { | |||
90 | @UpdatedAt | 92 | @UpdatedAt |
91 | updatedAt: Date | 93 | updatedAt: Date |
92 | 94 | ||
93 | private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { | 95 | private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = { |
94 | [ThumbnailType.MINIATURE]: { | 96 | [ThumbnailType.MINIATURE]: { |
95 | label: 'miniature', | 97 | label: 'miniature', |
96 | directory: CONFIG.STORAGE.THUMBNAILS_DIR, | 98 | directory: CONFIG.STORAGE.THUMBNAILS_DIR, |
@@ -126,11 +128,14 @@ export class ThumbnailModel extends Model<ThumbnailModel> { | |||
126 | return videoUUID + '.jpg' | 128 | return videoUUID + '.jpg' |
127 | } | 129 | } |
128 | 130 | ||
129 | getFileUrl (isLocal: boolean) { | 131 | getFileUrl (video: MVideoAccountLight) { |
130 | if (isLocal === false) return this.fileUrl | 132 | const staticPath = ThumbnailModel.types[this.type].staticPath + this.filename |
131 | 133 | ||
132 | const staticPath = ThumbnailModel.types[this.type].staticPath | 134 | if (video.isOwned()) return WEBSERVER.URL + staticPath |
133 | return WEBSERVER.URL + staticPath + this.filename | 135 | if (this.fileUrl) return this.fileUrl |
136 | |||
137 | // Fallback if we don't have a file URL | ||
138 | return buildRemoteVideoBaseUrl(video, staticPath) | ||
134 | } | 139 | } |
135 | 140 | ||
136 | getPath () { | 141 | getPath () { |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index 3636db18d..da8c1577c 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -87,9 +87,9 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
87 | } | 87 | } |
88 | 88 | ||
89 | static listForApi (parameters: { | 89 | static listForApi (parameters: { |
90 | start: number, | 90 | start: number |
91 | count: number, | 91 | count: number |
92 | sort: string, | 92 | sort: string |
93 | serverAccountId: number | 93 | serverAccountId: number |
94 | user?: MUserAccountId | 94 | user?: MUserAccountId |
95 | }) { | 95 | }) { |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index eeb2a4afd..59d3e1050 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -5,6 +5,7 @@ import { | |||
5 | BelongsTo, | 5 | BelongsTo, |
6 | Column, | 6 | Column, |
7 | CreatedAt, | 7 | CreatedAt, |
8 | DataType, | ||
8 | ForeignKey, | 9 | ForeignKey, |
9 | Is, | 10 | Is, |
10 | Model, | 11 | Model, |
@@ -16,13 +17,14 @@ import { buildWhereIdOrUUID, throwIfNotValid } from '../utils' | |||
16 | import { VideoModel } from './video' | 17 | import { VideoModel } from './video' |
17 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' | 18 | import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions' |
18 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' | 19 | import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model' |
19 | import { LAZY_STATIC_PATHS, VIDEO_LANGUAGES } from '../../initializers/constants' | 20 | import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants' |
20 | import { join } from 'path' | 21 | import { join } from 'path' |
21 | import { logger } from '../../helpers/logger' | 22 | import { logger } from '../../helpers/logger' |
22 | import { remove } from 'fs-extra' | 23 | import { remove } from 'fs-extra' |
23 | import { CONFIG } from '../../initializers/config' | 24 | import { CONFIG } from '../../initializers/config' |
24 | import * as Bluebird from 'bluebird' | 25 | import * as Bluebird from 'bluebird' |
25 | import { MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' | 26 | import { MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' |
27 | import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' | ||
26 | 28 | ||
27 | export enum ScopeNames { | 29 | export enum ScopeNames { |
28 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' | 30 | WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' |
@@ -64,6 +66,10 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
64 | @Column | 66 | @Column |
65 | language: string | 67 | language: string |
66 | 68 | ||
69 | @AllowNull(true) | ||
70 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.COMMONS.URL.max)) | ||
71 | fileUrl: string | ||
72 | |||
67 | @ForeignKey(() => VideoModel) | 73 | @ForeignKey(() => VideoModel) |
68 | @Column | 74 | @Column |
69 | videoId: number | 75 | videoId: number |
@@ -114,13 +120,14 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
114 | return VideoCaptionModel.findOne(query) | 120 | return VideoCaptionModel.findOne(query) |
115 | } | 121 | } |
116 | 122 | ||
117 | static insertOrReplaceLanguage (videoId: number, language: string, transaction: Transaction) { | 123 | static insertOrReplaceLanguage (videoId: number, language: string, fileUrl: string, transaction: Transaction) { |
118 | const values = { | 124 | const values = { |
119 | videoId, | 125 | videoId, |
120 | language | 126 | language, |
127 | fileUrl | ||
121 | } | 128 | } |
122 | 129 | ||
123 | return (VideoCaptionModel.upsert<VideoCaptionModel>(values, { transaction, returning: true }) as any) // FIXME: typings | 130 | return VideoCaptionModel.upsert(values, { transaction, returning: true }) |
124 | .then(([ caption ]) => caption) | 131 | .then(([ caption ]) => caption) |
125 | } | 132 | } |
126 | 133 | ||
@@ -175,4 +182,14 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
175 | removeCaptionFile (this: MVideoCaptionFormattable) { | 182 | removeCaptionFile (this: MVideoCaptionFormattable) { |
176 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) | 183 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) |
177 | } | 184 | } |
185 | |||
186 | getFileUrl (video: MVideoAccountLight) { | ||
187 | if (!this.Video) this.Video = video as VideoModel | ||
188 | |||
189 | if (video.isOwned()) return WEBSERVER.URL + this.getCaptionStaticPath() | ||
190 | if (this.fileUrl) return this.fileUrl | ||
191 | |||
192 | // Fallback if we don't have a file URL | ||
193 | return buildRemoteVideoBaseUrl(video, this.getCaptionStaticPath()) | ||
194 | } | ||
178 | } | 195 | } |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index e10adcb3a..835216671 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -30,7 +30,7 @@ import { buildServerIdsFollowedBy, buildTrigramSearchIndex, createSimilarityAttr | |||
30 | import { VideoModel } from './video' | 30 | import { VideoModel } from './video' |
31 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' | 31 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' |
32 | import { ServerModel } from '../server/server' | 32 | import { ServerModel } from '../server/server' |
33 | import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' | 33 | import { FindOptions, Op } from 'sequelize' |
34 | import { AvatarModel } from '../avatar/avatar' | 34 | import { AvatarModel } from '../avatar/avatar' |
35 | import { VideoPlaylistModel } from './video-playlist' | 35 | import { VideoPlaylistModel } from './video-playlist' |
36 | import * as Bluebird from 'bluebird' | 36 | import * as Bluebird from 'bluebird' |
@@ -43,18 +43,6 @@ import { | |||
43 | MChannelSummaryFormattable | 43 | MChannelSummaryFormattable |
44 | } from '../../typings/models/video' | 44 | } from '../../typings/models/video' |
45 | 45 | ||
46 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | ||
47 | const indexes: ModelIndexesOptions[] = [ | ||
48 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), | ||
49 | |||
50 | { | ||
51 | fields: [ 'accountId' ] | ||
52 | }, | ||
53 | { | ||
54 | fields: [ 'actorId' ] | ||
55 | } | ||
56 | ] | ||
57 | |||
58 | export enum ScopeNames { | 46 | export enum ScopeNames { |
59 | FOR_API = 'FOR_API', | 47 | FOR_API = 'FOR_API', |
60 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 48 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
@@ -133,7 +121,7 @@ export type SummaryOptions = { | |||
133 | }, | 121 | }, |
134 | { | 122 | { |
135 | serverId: { | 123 | serverId: { |
136 | [ Op.in ]: Sequelize.literal(inQueryInstanceFollow) | 124 | [Op.in]: Sequelize.literal(inQueryInstanceFollow) |
137 | } | 125 | } |
138 | } | 126 | } |
139 | ] | 127 | ] |
@@ -176,7 +164,16 @@ export type SummaryOptions = { | |||
176 | })) | 164 | })) |
177 | @Table({ | 165 | @Table({ |
178 | tableName: 'videoChannel', | 166 | tableName: 'videoChannel', |
179 | indexes | 167 | indexes: [ |
168 | buildTrigramSearchIndex('video_channel_name_trigram', 'name'), | ||
169 | |||
170 | { | ||
171 | fields: [ 'accountId' ] | ||
172 | }, | ||
173 | { | ||
174 | fields: [ 'actorId' ] | ||
175 | } | ||
176 | ] | ||
180 | }) | 177 | }) |
181 | export class VideoChannelModel extends Model<VideoChannelModel> { | 178 | export class VideoChannelModel extends Model<VideoChannelModel> { |
182 | 179 | ||
@@ -351,9 +348,9 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
351 | } | 348 | } |
352 | 349 | ||
353 | static listByAccount (options: { | 350 | static listByAccount (options: { |
354 | accountId: number, | 351 | accountId: number |
355 | start: number, | 352 | start: number |
356 | count: number, | 353 | count: number |
357 | sort: string | 354 | sort: string |
358 | }) { | 355 | }) { |
359 | const query = { | 356 | const query = { |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index fb4d16b4d..b33c33d5e 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -257,10 +257,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
257 | } | 257 | } |
258 | 258 | ||
259 | static async listThreadsForApi (parameters: { | 259 | static async listThreadsForApi (parameters: { |
260 | videoId: number, | 260 | videoId: number |
261 | start: number, | 261 | start: number |
262 | count: number, | 262 | count: number |
263 | sort: string, | 263 | sort: string |
264 | user?: MUserAccountId | 264 | user?: MUserAccountId |
265 | }) { | 265 | }) { |
266 | const { videoId, start, count, sort, user } = parameters | 266 | const { videoId, start, count, sort, user } = parameters |
@@ -300,8 +300,8 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
300 | } | 300 | } |
301 | 301 | ||
302 | static async listThreadCommentsForApi (parameters: { | 302 | static async listThreadCommentsForApi (parameters: { |
303 | videoId: number, | 303 | videoId: number |
304 | threadId: number, | 304 | threadId: number |
305 | user?: MUserAccountId | 305 | user?: MUserAccountId |
306 | }) { | 306 | }) { |
307 | const { videoId, threadId, user } = parameters | 307 | const { videoId, threadId, user } = parameters |
@@ -314,7 +314,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
314 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, | 314 | order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order, |
315 | where: { | 315 | where: { |
316 | videoId, | 316 | videoId, |
317 | [ Op.or ]: [ | 317 | [Op.or]: [ |
318 | { id: threadId }, | 318 | { id: threadId }, |
319 | { originCommentId: threadId } | 319 | { originCommentId: threadId } |
320 | ], | 320 | ], |
@@ -346,7 +346,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
346 | order: [ [ 'createdAt', order ] ] as Order, | 346 | order: [ [ 'createdAt', order ] ] as Order, |
347 | where: { | 347 | where: { |
348 | id: { | 348 | id: { |
349 | [ Op.in ]: Sequelize.literal('(' + | 349 | [Op.in]: Sequelize.literal('(' + |
350 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + | 350 | 'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' + |
351 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + | 351 | `SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` + |
352 | 'UNION ' + | 352 | 'UNION ' + |
@@ -355,7 +355,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
355 | ') ' + | 355 | ') ' + |
356 | 'SELECT id FROM children' + | 356 | 'SELECT id FROM children' + |
357 | ')'), | 357 | ')'), |
358 | [ Op.ne ]: comment.id | 358 | [Op.ne]: comment.id |
359 | } | 359 | } |
360 | }, | 360 | }, |
361 | transaction: t | 361 | transaction: t |
@@ -461,7 +461,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
461 | } | 461 | } |
462 | 462 | ||
463 | isDeleted () { | 463 | isDeleted () { |
464 | return null !== this.deletedAt | 464 | return this.deletedAt !== null |
465 | } | 465 | } |
466 | 466 | ||
467 | extractMentions () { | 467 | extractMentions () { |
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index 67395e5c0..1fa66fd63 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts | |||
@@ -27,12 +27,13 @@ import { generateMagnetUri } from '@server/helpers/webtorrent' | |||
27 | export type VideoFormattingJSONOptions = { | 27 | export type VideoFormattingJSONOptions = { |
28 | completeDescription?: boolean | 28 | completeDescription?: boolean |
29 | additionalAttributes: { | 29 | additionalAttributes: { |
30 | state?: boolean, | 30 | state?: boolean |
31 | waitTranscoding?: boolean, | 31 | waitTranscoding?: boolean |
32 | scheduledUpdate?: boolean, | 32 | scheduledUpdate?: boolean |
33 | blacklistInfo?: boolean | 33 | blacklistInfo?: boolean |
34 | } | 34 | } |
35 | } | 35 | } |
36 | |||
36 | function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { | 37 | function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { |
37 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined | 38 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined |
38 | 39 | ||
@@ -181,12 +182,10 @@ function videoFilesModelToFormattedJSON ( | |||
181 | ): VideoFile[] { | 182 | ): VideoFile[] { |
182 | return videoFiles | 183 | return videoFiles |
183 | .map(videoFile => { | 184 | .map(videoFile => { |
184 | let resolutionLabel = videoFile.resolution + 'p' | ||
185 | |||
186 | return { | 185 | return { |
187 | resolution: { | 186 | resolution: { |
188 | id: videoFile.resolution, | 187 | id: videoFile.resolution, |
189 | label: resolutionLabel | 188 | label: videoFile.resolution + 'p' |
190 | }, | 189 | }, |
191 | magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), | 190 | magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs), |
192 | size: videoFile.size, | 191 | size: videoFile.size, |
@@ -214,7 +213,7 @@ function addVideoFilesInAPAcc ( | |||
214 | for (const file of files) { | 213 | for (const file of files) { |
215 | acc.push({ | 214 | acc.push({ |
216 | type: 'Link', | 215 | type: 'Link', |
217 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ file.extname ] as any, | 216 | mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] as any, |
218 | href: model.getVideoFileUrl(file, baseUrlHttp), | 217 | href: model.getVideoFileUrl(file, baseUrlHttp), |
219 | height: file.resolution, | 218 | height: file.resolution, |
220 | size: file.size, | 219 | size: file.size, |
@@ -282,10 +281,8 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
282 | addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) | 281 | addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || []) |
283 | 282 | ||
284 | for (const playlist of (video.VideoStreamingPlaylists || [])) { | 283 | for (const playlist of (video.VideoStreamingPlaylists || [])) { |
285 | let tag: ActivityTagObject[] | 284 | const tag = playlist.p2pMediaLoaderInfohashes |
286 | 285 | .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) as ActivityTagObject[] | |
287 | tag = playlist.p2pMediaLoaderInfohashes | ||
288 | .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) | ||
289 | tag.push({ | 286 | tag.push({ |
290 | type: 'Link', | 287 | type: 'Link', |
291 | name: 'sha256', | 288 | name: 'sha256', |
@@ -308,11 +305,12 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
308 | for (const caption of video.VideoCaptions) { | 305 | for (const caption of video.VideoCaptions) { |
309 | subtitleLanguage.push({ | 306 | subtitleLanguage.push({ |
310 | identifier: caption.language, | 307 | identifier: caption.language, |
311 | name: VideoCaptionModel.getLanguageLabel(caption.language) | 308 | name: VideoCaptionModel.getLanguageLabel(caption.language), |
309 | url: caption.getFileUrl(video) | ||
312 | }) | 310 | }) |
313 | } | 311 | } |
314 | 312 | ||
315 | const miniature = video.getMiniature() | 313 | const icons = [ video.getMiniature(), video.getPreview() ] |
316 | 314 | ||
317 | return { | 315 | return { |
318 | type: 'Video' as 'Video', | 316 | type: 'Video' as 'Video', |
@@ -337,13 +335,13 @@ function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject { | |||
337 | content: video.getTruncatedDescription(), | 335 | content: video.getTruncatedDescription(), |
338 | support: video.support, | 336 | support: video.support, |
339 | subtitleLanguage, | 337 | subtitleLanguage, |
340 | icon: { | 338 | icon: icons.map(i => ({ |
341 | type: 'Image', | 339 | type: 'Image', |
342 | url: miniature.getFileUrl(video.isOwned()), | 340 | url: i.getFileUrl(video), |
343 | mediaType: 'image/jpeg', | 341 | mediaType: 'image/jpeg', |
344 | width: miniature.width, | 342 | width: i.width, |
345 | height: miniature.height | 343 | height: i.height |
346 | }, | 344 | })), |
347 | url, | 345 | url, |
348 | likes: getVideoLikesActivityPubUrl(video), | 346 | likes: getVideoLikesActivityPubUrl(video), |
349 | dislikes: getVideoDislikesActivityPubUrl(video), | 347 | dislikes: getVideoDislikesActivityPubUrl(video), |
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index f2d71357f..4ba16f5fd 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -120,10 +120,10 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
120 | } | 120 | } |
121 | 121 | ||
122 | static listForApi (options: { | 122 | static listForApi (options: { |
123 | start: number, | 123 | start: number |
124 | count: number, | 124 | count: number |
125 | videoPlaylistId: number, | 125 | videoPlaylistId: number |
126 | serverAccount: AccountModel, | 126 | serverAccount: AccountModel |
127 | user?: MUserAccountId | 127 | user?: MUserAccountId |
128 | }) { | 128 | }) { |
129 | const accountIds = [ options.serverAccount.id ] | 129 | const accountIds = [ options.serverAccount.id ] |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index bcdda36e5..4ca17ebec 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -68,12 +68,12 @@ type AvailableForListOptions = { | |||
68 | type?: VideoPlaylistType | 68 | type?: VideoPlaylistType |
69 | accountId?: number | 69 | accountId?: number |
70 | videoChannelId?: number | 70 | videoChannelId?: number |
71 | listMyPlaylists?: boolean, | 71 | listMyPlaylists?: boolean |
72 | search?: string | 72 | search?: string |
73 | } | 73 | } |
74 | 74 | ||
75 | @Scopes(() => ({ | 75 | @Scopes(() => ({ |
76 | [ ScopeNames.WITH_THUMBNAIL ]: { | 76 | [ScopeNames.WITH_THUMBNAIL]: { |
77 | include: [ | 77 | include: [ |
78 | { | 78 | { |
79 | model: ThumbnailModel, | 79 | model: ThumbnailModel, |
@@ -81,7 +81,7 @@ type AvailableForListOptions = { | |||
81 | } | 81 | } |
82 | ] | 82 | ] |
83 | }, | 83 | }, |
84 | [ ScopeNames.WITH_VIDEOS_LENGTH ]: { | 84 | [ScopeNames.WITH_VIDEOS_LENGTH]: { |
85 | attributes: { | 85 | attributes: { |
86 | include: [ | 86 | include: [ |
87 | [ | 87 | [ |
@@ -91,7 +91,7 @@ type AvailableForListOptions = { | |||
91 | ] | 91 | ] |
92 | } | 92 | } |
93 | } as FindOptions, | 93 | } as FindOptions, |
94 | [ ScopeNames.WITH_ACCOUNT ]: { | 94 | [ScopeNames.WITH_ACCOUNT]: { |
95 | include: [ | 95 | include: [ |
96 | { | 96 | { |
97 | model: AccountModel, | 97 | model: AccountModel, |
@@ -99,7 +99,7 @@ type AvailableForListOptions = { | |||
99 | } | 99 | } |
100 | ] | 100 | ] |
101 | }, | 101 | }, |
102 | [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: { | 102 | [ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY]: { |
103 | include: [ | 103 | include: [ |
104 | { | 104 | { |
105 | model: AccountModel.scope(AccountScopeNames.SUMMARY), | 105 | model: AccountModel.scope(AccountScopeNames.SUMMARY), |
@@ -111,7 +111,7 @@ type AvailableForListOptions = { | |||
111 | } | 111 | } |
112 | ] | 112 | ] |
113 | }, | 113 | }, |
114 | [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL ]: { | 114 | [ScopeNames.WITH_ACCOUNT_AND_CHANNEL]: { |
115 | include: [ | 115 | include: [ |
116 | { | 116 | { |
117 | model: AccountModel, | 117 | model: AccountModel, |
@@ -123,7 +123,7 @@ type AvailableForListOptions = { | |||
123 | } | 123 | } |
124 | ] | 124 | ] |
125 | }, | 125 | }, |
126 | [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => { | 126 | [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { |
127 | 127 | ||
128 | let whereActor: WhereOptions = {} | 128 | let whereActor: WhereOptions = {} |
129 | 129 | ||
@@ -138,13 +138,13 @@ type AvailableForListOptions = { | |||
138 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) | 138 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId) |
139 | 139 | ||
140 | whereActor = { | 140 | whereActor = { |
141 | [ Op.or ]: [ | 141 | [Op.or]: [ |
142 | { | 142 | { |
143 | serverId: null | 143 | serverId: null |
144 | }, | 144 | }, |
145 | { | 145 | { |
146 | serverId: { | 146 | serverId: { |
147 | [ Op.in ]: literal(inQueryInstanceFollow) | 147 | [Op.in]: literal(inQueryInstanceFollow) |
148 | } | 148 | } |
149 | } | 149 | } |
150 | ] | 150 | ] |
@@ -172,7 +172,7 @@ type AvailableForListOptions = { | |||
172 | if (options.search) { | 172 | if (options.search) { |
173 | whereAnd.push({ | 173 | whereAnd.push({ |
174 | name: { | 174 | name: { |
175 | [ Op.iLike ]: '%' + options.search + '%' | 175 | [Op.iLike]: '%' + options.search + '%' |
176 | } | 176 | } |
177 | }) | 177 | }) |
178 | } | 178 | } |
@@ -299,13 +299,13 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
299 | 299 | ||
300 | static listForApi (options: { | 300 | static listForApi (options: { |
301 | followerActorId: number | 301 | followerActorId: number |
302 | start: number, | 302 | start: number |
303 | count: number, | 303 | count: number |
304 | sort: string, | 304 | sort: string |
305 | type?: VideoPlaylistType, | 305 | type?: VideoPlaylistType |
306 | accountId?: number, | 306 | accountId?: number |
307 | videoChannelId?: number, | 307 | videoChannelId?: number |
308 | listMyPlaylists?: boolean, | 308 | listMyPlaylists?: boolean |
309 | search?: string | 309 | search?: string |
310 | }) { | 310 | }) { |
311 | const query = { | 311 | const query = { |
@@ -369,7 +369,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
369 | model: VideoPlaylistElementModel.unscoped(), | 369 | model: VideoPlaylistElementModel.unscoped(), |
370 | where: { | 370 | where: { |
371 | videoId: { | 371 | videoId: { |
372 | [Op.in]: videoIds // FIXME: sequelize ANY seems broken | 372 | [Op.in]: videoIds |
373 | } | 373 | } |
374 | }, | 374 | }, |
375 | required: true | 375 | required: true |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index eacffe186..bd4ca63ea 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1,18 +1,7 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { maxBy, minBy } from 'lodash' | 2 | import { maxBy, minBy } from 'lodash' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { | 4 | import { CountOptions, FindOptions, IncludeOptions, Op, QueryTypes, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize' |
5 | CountOptions, | ||
6 | FindOptions, | ||
7 | IncludeOptions, | ||
8 | ModelIndexesOptions, | ||
9 | Op, | ||
10 | QueryTypes, | ||
11 | ScopeOptions, | ||
12 | Sequelize, | ||
13 | Transaction, | ||
14 | WhereOptions | ||
15 | } from 'sequelize' | ||
16 | import { | 5 | import { |
17 | AllowNull, | 6 | AllowNull, |
18 | BeforeDestroy, | 7 | BeforeDestroy, |
@@ -131,87 +120,19 @@ import { | |||
131 | MVideoFormattableDetails, | 120 | MVideoFormattableDetails, |
132 | MVideoForUser, | 121 | MVideoForUser, |
133 | MVideoFullLight, | 122 | MVideoFullLight, |
134 | MVideoIdThumbnail, | 123 | MVideoIdThumbnail, MVideoImmutable, |
135 | MVideoThumbnail, | 124 | MVideoThumbnail, |
136 | MVideoThumbnailBlacklist, | 125 | MVideoThumbnailBlacklist, |
137 | MVideoWithAllFiles, | 126 | MVideoWithAllFiles, |
138 | MVideoWithFile, | 127 | MVideoWithFile, |
139 | MVideoWithRights, | 128 | MVideoWithRights |
140 | MStreamingPlaylistFiles | ||
141 | } from '../../typings/models' | 129 | } from '../../typings/models' |
142 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' | 130 | import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' |
143 | import { MThumbnail } from '../../typings/models/video/thumbnail' | 131 | import { MThumbnail } from '../../typings/models/video/thumbnail' |
144 | import { VideoFile } from '@shared/models/videos/video-file.model' | 132 | import { VideoFile } from '@shared/models/videos/video-file.model' |
145 | import { getHLSDirectory, getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' | 133 | import { getHLSDirectory, getTorrentFileName, getTorrentFilePath, getVideoFilename, getVideoFilePath } from '@server/lib/video-paths' |
146 | import validator from 'validator' | 134 | import validator from 'validator' |
147 | 135 | import { ModelCache } from '@server/models/model-cache' | |
148 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | ||
149 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ | ||
150 | buildTrigramSearchIndex('video_name_trigram', 'name'), | ||
151 | |||
152 | { fields: [ 'createdAt' ] }, | ||
153 | { | ||
154 | fields: [ | ||
155 | { name: 'publishedAt', order: 'DESC' }, | ||
156 | { name: 'id', order: 'ASC' } | ||
157 | ] | ||
158 | }, | ||
159 | { fields: [ 'duration' ] }, | ||
160 | { fields: [ 'views' ] }, | ||
161 | { fields: [ 'channelId' ] }, | ||
162 | { | ||
163 | fields: [ 'originallyPublishedAt' ], | ||
164 | where: { | ||
165 | originallyPublishedAt: { | ||
166 | [Op.ne]: null | ||
167 | } | ||
168 | } | ||
169 | }, | ||
170 | { | ||
171 | fields: [ 'category' ], // We don't care videos with an unknown category | ||
172 | where: { | ||
173 | category: { | ||
174 | [Op.ne]: null | ||
175 | } | ||
176 | } | ||
177 | }, | ||
178 | { | ||
179 | fields: [ 'licence' ], // We don't care videos with an unknown licence | ||
180 | where: { | ||
181 | licence: { | ||
182 | [Op.ne]: null | ||
183 | } | ||
184 | } | ||
185 | }, | ||
186 | { | ||
187 | fields: [ 'language' ], // We don't care videos with an unknown language | ||
188 | where: { | ||
189 | language: { | ||
190 | [Op.ne]: null | ||
191 | } | ||
192 | } | ||
193 | }, | ||
194 | { | ||
195 | fields: [ 'nsfw' ], // Most of the videos are not NSFW | ||
196 | where: { | ||
197 | nsfw: true | ||
198 | } | ||
199 | }, | ||
200 | { | ||
201 | fields: [ 'remote' ], // Only index local videos | ||
202 | where: { | ||
203 | remote: false | ||
204 | } | ||
205 | }, | ||
206 | { | ||
207 | fields: [ 'uuid' ], | ||
208 | unique: true | ||
209 | }, | ||
210 | { | ||
211 | fields: [ 'url' ], | ||
212 | unique: true | ||
213 | } | ||
214 | ] | ||
215 | 136 | ||
216 | export enum ScopeNames { | 137 | export enum ScopeNames { |
217 | AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS', | 138 | AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS', |
@@ -224,6 +145,7 @@ export enum ScopeNames { | |||
224 | WITH_USER_HISTORY = 'WITH_USER_HISTORY', | 145 | WITH_USER_HISTORY = 'WITH_USER_HISTORY', |
225 | WITH_STREAMING_PLAYLISTS = 'WITH_STREAMING_PLAYLISTS', | 146 | WITH_STREAMING_PLAYLISTS = 'WITH_STREAMING_PLAYLISTS', |
226 | WITH_USER_ID = 'WITH_USER_ID', | 147 | WITH_USER_ID = 'WITH_USER_ID', |
148 | WITH_IMMUTABLE_ATTRIBUTES = 'WITH_IMMUTABLE_ATTRIBUTES', | ||
227 | WITH_THUMBNAILS = 'WITH_THUMBNAILS' | 149 | WITH_THUMBNAILS = 'WITH_THUMBNAILS' |
228 | } | 150 | } |
229 | 151 | ||
@@ -267,7 +189,10 @@ export type AvailableForListIDsOptions = { | |||
267 | } | 189 | } |
268 | 190 | ||
269 | @Scopes(() => ({ | 191 | @Scopes(() => ({ |
270 | [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { | 192 | [ScopeNames.WITH_IMMUTABLE_ATTRIBUTES]: { |
193 | attributes: [ 'id', 'url', 'uuid', 'remote' ] | ||
194 | }, | ||
195 | [ScopeNames.FOR_API]: (options: ForAPIOptions) => { | ||
271 | const query: FindOptions = { | 196 | const query: FindOptions = { |
272 | include: [ | 197 | include: [ |
273 | { | 198 | { |
@@ -292,7 +217,7 @@ export type AvailableForListIDsOptions = { | |||
292 | if (options.ids) { | 217 | if (options.ids) { |
293 | query.where = { | 218 | query.where = { |
294 | id: { | 219 | id: { |
295 | [ Op.in ]: options.ids // FIXME: sequelize ANY seems broken | 220 | [Op.in]: options.ids |
296 | } | 221 | } |
297 | } | 222 | } |
298 | } | 223 | } |
@@ -316,7 +241,7 @@ export type AvailableForListIDsOptions = { | |||
316 | 241 | ||
317 | return query | 242 | return query |
318 | }, | 243 | }, |
319 | [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { | 244 | [ScopeNames.AVAILABLE_FOR_LIST_IDS]: (options: AvailableForListIDsOptions) => { |
320 | const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : [] | 245 | const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : [] |
321 | 246 | ||
322 | const query: FindOptions = { | 247 | const query: FindOptions = { |
@@ -327,11 +252,11 @@ export type AvailableForListIDsOptions = { | |||
327 | const attributesType = options.attributesType || 'id' | 252 | const attributesType = options.attributesType || 'id' |
328 | 253 | ||
329 | if (attributesType === 'id') query.attributes = [ 'id' ] | 254 | if (attributesType === 'id') query.attributes = [ 'id' ] |
330 | else if (attributesType === 'none') query.attributes = [ ] | 255 | else if (attributesType === 'none') query.attributes = [] |
331 | 256 | ||
332 | whereAnd.push({ | 257 | whereAnd.push({ |
333 | id: { | 258 | id: { |
334 | [ Op.notIn ]: Sequelize.literal( | 259 | [Op.notIn]: Sequelize.literal( |
335 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' | 260 | '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")' |
336 | ) | 261 | ) |
337 | } | 262 | } |
@@ -340,7 +265,7 @@ export type AvailableForListIDsOptions = { | |||
340 | if (options.serverAccountId) { | 265 | if (options.serverAccountId) { |
341 | whereAnd.push({ | 266 | whereAnd.push({ |
342 | channelId: { | 267 | channelId: { |
343 | [ Op.notIn ]: Sequelize.literal( | 268 | [Op.notIn]: Sequelize.literal( |
344 | '(' + | 269 | '(' + |
345 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + | 270 | 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' + |
346 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + | 271 | buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) + |
@@ -353,15 +278,14 @@ export type AvailableForListIDsOptions = { | |||
353 | 278 | ||
354 | // Only list public/published videos | 279 | // Only list public/published videos |
355 | if (!options.filter || options.filter !== 'all-local') { | 280 | if (!options.filter || options.filter !== 'all-local') { |
356 | |||
357 | const publishWhere = { | 281 | const publishWhere = { |
358 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding | 282 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding |
359 | [ Op.or ]: [ | 283 | [Op.or]: [ |
360 | { | 284 | { |
361 | state: VideoState.PUBLISHED | 285 | state: VideoState.PUBLISHED |
362 | }, | 286 | }, |
363 | { | 287 | { |
364 | [ Op.and ]: { | 288 | [Op.and]: { |
365 | state: VideoState.TO_TRANSCODE, | 289 | state: VideoState.TO_TRANSCODE, |
366 | waitTranscoding: false | 290 | waitTranscoding: false |
367 | } | 291 | } |
@@ -448,7 +372,7 @@ export type AvailableForListIDsOptions = { | |||
448 | [Op.or]: [ | 372 | [Op.or]: [ |
449 | { | 373 | { |
450 | id: { | 374 | id: { |
451 | [ Op.in ]: Sequelize.literal( | 375 | [Op.in]: Sequelize.literal( |
452 | '(' + | 376 | '(' + |
453 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + | 377 | 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + |
454 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 378 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
@@ -459,7 +383,7 @@ export type AvailableForListIDsOptions = { | |||
459 | }, | 383 | }, |
460 | { | 384 | { |
461 | id: { | 385 | id: { |
462 | [ Op.in ]: Sequelize.literal( | 386 | [Op.in]: Sequelize.literal( |
463 | '(' + | 387 | '(' + |
464 | 'SELECT "video"."id" AS "id" FROM "video" ' + | 388 | 'SELECT "video"."id" AS "id" FROM "video" ' + |
465 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | 389 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + |
@@ -479,7 +403,7 @@ export type AvailableForListIDsOptions = { | |||
479 | if (options.withFiles === true) { | 403 | if (options.withFiles === true) { |
480 | whereAnd.push({ | 404 | whereAnd.push({ |
481 | id: { | 405 | id: { |
482 | [ Op.in ]: Sequelize.literal( | 406 | [Op.in]: Sequelize.literal( |
483 | '(SELECT "videoId" FROM "videoFile")' | 407 | '(SELECT "videoId" FROM "videoFile")' |
484 | ) | 408 | ) |
485 | } | 409 | } |
@@ -493,7 +417,7 @@ export type AvailableForListIDsOptions = { | |||
493 | 417 | ||
494 | whereAnd.push({ | 418 | whereAnd.push({ |
495 | id: { | 419 | id: { |
496 | [ Op.in ]: Sequelize.literal( | 420 | [Op.in]: Sequelize.literal( |
497 | '(' + | 421 | '(' + |
498 | 'SELECT "videoId" FROM "videoTag" ' + | 422 | 'SELECT "videoId" FROM "videoTag" ' + |
499 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 423 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -509,7 +433,7 @@ export type AvailableForListIDsOptions = { | |||
509 | 433 | ||
510 | whereAnd.push({ | 434 | whereAnd.push({ |
511 | id: { | 435 | id: { |
512 | [ Op.in ]: Sequelize.literal( | 436 | [Op.in]: Sequelize.literal( |
513 | '(' + | 437 | '(' + |
514 | 'SELECT "videoId" FROM "videoTag" ' + | 438 | 'SELECT "videoId" FROM "videoTag" ' + |
515 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 439 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
@@ -529,7 +453,7 @@ export type AvailableForListIDsOptions = { | |||
529 | if (options.categoryOneOf) { | 453 | if (options.categoryOneOf) { |
530 | whereAnd.push({ | 454 | whereAnd.push({ |
531 | category: { | 455 | category: { |
532 | [ Op.or ]: options.categoryOneOf | 456 | [Op.or]: options.categoryOneOf |
533 | } | 457 | } |
534 | }) | 458 | }) |
535 | } | 459 | } |
@@ -537,7 +461,7 @@ export type AvailableForListIDsOptions = { | |||
537 | if (options.licenceOneOf) { | 461 | if (options.licenceOneOf) { |
538 | whereAnd.push({ | 462 | whereAnd.push({ |
539 | licence: { | 463 | licence: { |
540 | [ Op.or ]: options.licenceOneOf | 464 | [Op.or]: options.licenceOneOf |
541 | } | 465 | } |
542 | }) | 466 | }) |
543 | } | 467 | } |
@@ -552,12 +476,12 @@ export type AvailableForListIDsOptions = { | |||
552 | [Op.or]: [ | 476 | [Op.or]: [ |
553 | { | 477 | { |
554 | language: { | 478 | language: { |
555 | [ Op.or ]: videoLanguages | 479 | [Op.or]: videoLanguages |
556 | } | 480 | } |
557 | }, | 481 | }, |
558 | { | 482 | { |
559 | id: { | 483 | id: { |
560 | [ Op.in ]: Sequelize.literal( | 484 | [Op.in]: Sequelize.literal( |
561 | '(' + | 485 | '(' + |
562 | 'SELECT "videoId" FROM "videoCaption" ' + | 486 | 'SELECT "videoId" FROM "videoCaption" ' + |
563 | 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' + | 487 | 'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' + |
@@ -591,12 +515,12 @@ export type AvailableForListIDsOptions = { | |||
591 | } | 515 | } |
592 | 516 | ||
593 | query.where = { | 517 | query.where = { |
594 | [ Op.and ]: whereAnd | 518 | [Op.and]: whereAnd |
595 | } | 519 | } |
596 | 520 | ||
597 | return query | 521 | return query |
598 | }, | 522 | }, |
599 | [ ScopeNames.WITH_THUMBNAILS ]: { | 523 | [ScopeNames.WITH_THUMBNAILS]: { |
600 | include: [ | 524 | include: [ |
601 | { | 525 | { |
602 | model: ThumbnailModel, | 526 | model: ThumbnailModel, |
@@ -604,7 +528,7 @@ export type AvailableForListIDsOptions = { | |||
604 | } | 528 | } |
605 | ] | 529 | ] |
606 | }, | 530 | }, |
607 | [ ScopeNames.WITH_USER_ID ]: { | 531 | [ScopeNames.WITH_USER_ID]: { |
608 | include: [ | 532 | include: [ |
609 | { | 533 | { |
610 | attributes: [ 'accountId' ], | 534 | attributes: [ 'accountId' ], |
@@ -620,7 +544,7 @@ export type AvailableForListIDsOptions = { | |||
620 | } | 544 | } |
621 | ] | 545 | ] |
622 | }, | 546 | }, |
623 | [ ScopeNames.WITH_ACCOUNT_DETAILS ]: { | 547 | [ScopeNames.WITH_ACCOUNT_DETAILS]: { |
624 | include: [ | 548 | include: [ |
625 | { | 549 | { |
626 | model: VideoChannelModel.unscoped(), | 550 | model: VideoChannelModel.unscoped(), |
@@ -672,10 +596,10 @@ export type AvailableForListIDsOptions = { | |||
672 | } | 596 | } |
673 | ] | 597 | ] |
674 | }, | 598 | }, |
675 | [ ScopeNames.WITH_TAGS ]: { | 599 | [ScopeNames.WITH_TAGS]: { |
676 | include: [ TagModel ] | 600 | include: [ TagModel ] |
677 | }, | 601 | }, |
678 | [ ScopeNames.WITH_BLACKLISTED ]: { | 602 | [ScopeNames.WITH_BLACKLISTED]: { |
679 | include: [ | 603 | include: [ |
680 | { | 604 | { |
681 | attributes: [ 'id', 'reason', 'unfederated' ], | 605 | attributes: [ 'id', 'reason', 'unfederated' ], |
@@ -684,7 +608,7 @@ export type AvailableForListIDsOptions = { | |||
684 | } | 608 | } |
685 | ] | 609 | ] |
686 | }, | 610 | }, |
687 | [ ScopeNames.WITH_WEBTORRENT_FILES ]: (withRedundancies = false) => { | 611 | [ScopeNames.WITH_WEBTORRENT_FILES]: (withRedundancies = false) => { |
688 | let subInclude: any[] = [] | 612 | let subInclude: any[] = [] |
689 | 613 | ||
690 | if (withRedundancies === true) { | 614 | if (withRedundancies === true) { |
@@ -708,7 +632,7 @@ export type AvailableForListIDsOptions = { | |||
708 | ] | 632 | ] |
709 | } | 633 | } |
710 | }, | 634 | }, |
711 | [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => { | 635 | [ScopeNames.WITH_STREAMING_PLAYLISTS]: (withRedundancies = false) => { |
712 | const subInclude: IncludeOptions[] = [ | 636 | const subInclude: IncludeOptions[] = [ |
713 | { | 637 | { |
714 | model: VideoFileModel.unscoped(), | 638 | model: VideoFileModel.unscoped(), |
@@ -735,7 +659,7 @@ export type AvailableForListIDsOptions = { | |||
735 | ] | 659 | ] |
736 | } | 660 | } |
737 | }, | 661 | }, |
738 | [ ScopeNames.WITH_SCHEDULED_UPDATE ]: { | 662 | [ScopeNames.WITH_SCHEDULED_UPDATE]: { |
739 | include: [ | 663 | include: [ |
740 | { | 664 | { |
741 | model: ScheduleVideoUpdateModel.unscoped(), | 665 | model: ScheduleVideoUpdateModel.unscoped(), |
@@ -743,7 +667,7 @@ export type AvailableForListIDsOptions = { | |||
743 | } | 667 | } |
744 | ] | 668 | ] |
745 | }, | 669 | }, |
746 | [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => { | 670 | [ScopeNames.WITH_USER_HISTORY]: (userId: number) => { |
747 | return { | 671 | return { |
748 | include: [ | 672 | include: [ |
749 | { | 673 | { |
@@ -760,7 +684,72 @@ export type AvailableForListIDsOptions = { | |||
760 | })) | 684 | })) |
761 | @Table({ | 685 | @Table({ |
762 | tableName: 'video', | 686 | tableName: 'video', |
763 | indexes | 687 | indexes: [ |
688 | buildTrigramSearchIndex('video_name_trigram', 'name'), | ||
689 | |||
690 | { fields: [ 'createdAt' ] }, | ||
691 | { | ||
692 | fields: [ | ||
693 | { name: 'publishedAt', order: 'DESC' }, | ||
694 | { name: 'id', order: 'ASC' } | ||
695 | ] | ||
696 | }, | ||
697 | { fields: [ 'duration' ] }, | ||
698 | { fields: [ 'views' ] }, | ||
699 | { fields: [ 'channelId' ] }, | ||
700 | { | ||
701 | fields: [ 'originallyPublishedAt' ], | ||
702 | where: { | ||
703 | originallyPublishedAt: { | ||
704 | [Op.ne]: null | ||
705 | } | ||
706 | } | ||
707 | }, | ||
708 | { | ||
709 | fields: [ 'category' ], // We don't care videos with an unknown category | ||
710 | where: { | ||
711 | category: { | ||
712 | [Op.ne]: null | ||
713 | } | ||
714 | } | ||
715 | }, | ||
716 | { | ||
717 | fields: [ 'licence' ], // We don't care videos with an unknown licence | ||
718 | where: { | ||
719 | licence: { | ||
720 | [Op.ne]: null | ||
721 | } | ||
722 | } | ||
723 | }, | ||
724 | { | ||
725 | fields: [ 'language' ], // We don't care videos with an unknown language | ||
726 | where: { | ||
727 | language: { | ||
728 | [Op.ne]: null | ||
729 | } | ||
730 | } | ||
731 | }, | ||
732 | { | ||
733 | fields: [ 'nsfw' ], // Most of the videos are not NSFW | ||
734 | where: { | ||
735 | nsfw: true | ||
736 | } | ||
737 | }, | ||
738 | { | ||
739 | fields: [ 'remote' ], // Only index local videos | ||
740 | where: { | ||
741 | remote: false | ||
742 | } | ||
743 | }, | ||
744 | { | ||
745 | fields: [ 'uuid' ], | ||
746 | unique: true | ||
747 | }, | ||
748 | { | ||
749 | fields: [ 'url' ], | ||
750 | unique: true | ||
751 | } | ||
752 | ] | ||
764 | }) | 753 | }) |
765 | export class VideoModel extends Model<VideoModel> { | 754 | export class VideoModel extends Model<VideoModel> { |
766 | 755 | ||
@@ -1031,7 +1020,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1031 | }, | 1020 | }, |
1032 | onDelete: 'cascade', | 1021 | onDelete: 'cascade', |
1033 | hooks: true, | 1022 | hooks: true, |
1034 | [ 'separate' as any ]: true | 1023 | ['separate' as any]: true |
1035 | }) | 1024 | }) |
1036 | VideoCaptions: VideoCaptionModel[] | 1025 | VideoCaptions: VideoCaptionModel[] |
1037 | 1026 | ||
@@ -1090,6 +1079,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1090 | return undefined | 1079 | return undefined |
1091 | } | 1080 | } |
1092 | 1081 | ||
1082 | @BeforeDestroy | ||
1083 | static invalidateCache (instance: VideoModel) { | ||
1084 | ModelCache.Instance.invalidateCache('video', instance.id) | ||
1085 | } | ||
1086 | |||
1093 | static listLocal (): Bluebird<MVideoWithAllFiles[]> { | 1087 | static listLocal (): Bluebird<MVideoWithAllFiles[]> { |
1094 | const query = { | 1088 | const query = { |
1095 | where: { | 1089 | where: { |
@@ -1127,16 +1121,16 @@ export class VideoModel extends Model<VideoModel> { | |||
1127 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings | 1121 | order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings |
1128 | where: { | 1122 | where: { |
1129 | id: { | 1123 | id: { |
1130 | [ Op.in ]: Sequelize.literal('(' + rawQuery + ')') | 1124 | [Op.in]: Sequelize.literal('(' + rawQuery + ')') |
1131 | }, | 1125 | }, |
1132 | [ Op.or ]: [ | 1126 | [Op.or]: [ |
1133 | { privacy: VideoPrivacy.PUBLIC }, | 1127 | { privacy: VideoPrivacy.PUBLIC }, |
1134 | { privacy: VideoPrivacy.UNLISTED } | 1128 | { privacy: VideoPrivacy.UNLISTED } |
1135 | ] | 1129 | ] |
1136 | }, | 1130 | }, |
1137 | include: [ | 1131 | include: [ |
1138 | { | 1132 | { |
1139 | attributes: [ 'language' ], | 1133 | attributes: [ 'language', 'fileUrl' ], |
1140 | model: VideoCaptionModel.unscoped(), | 1134 | model: VideoCaptionModel.unscoped(), |
1141 | required: false | 1135 | required: false |
1142 | }, | 1136 | }, |
@@ -1146,10 +1140,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1146 | required: false, | 1140 | required: false, |
1147 | // We only want videos shared by this actor | 1141 | // We only want videos shared by this actor |
1148 | where: { | 1142 | where: { |
1149 | [ Op.and ]: [ | 1143 | [Op.and]: [ |
1150 | { | 1144 | { |
1151 | id: { | 1145 | id: { |
1152 | [ Op.not ]: null | 1146 | [Op.not]: null |
1153 | } | 1147 | } |
1154 | }, | 1148 | }, |
1155 | { | 1149 | { |
@@ -1199,8 +1193,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1199 | // totals: totalVideos + totalVideoShares | 1193 | // totals: totalVideos + totalVideoShares |
1200 | let totalVideos = 0 | 1194 | let totalVideos = 0 |
1201 | let totalVideoShares = 0 | 1195 | let totalVideoShares = 0 |
1202 | if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10) | 1196 | if (totals[0]) totalVideos = parseInt(totals[0].total, 10) |
1203 | if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10) | 1197 | if (totals[1]) totalVideoShares = parseInt(totals[1].total, 10) |
1204 | 1198 | ||
1205 | const total = totalVideos + totalVideoShares | 1199 | const total = totalVideos + totalVideoShares |
1206 | return { | 1200 | return { |
@@ -1243,7 +1237,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1243 | baseQuery = Object.assign(baseQuery, { | 1237 | baseQuery = Object.assign(baseQuery, { |
1244 | where: { | 1238 | where: { |
1245 | name: { | 1239 | name: { |
1246 | [ Op.iLike ]: '%' + search + '%' | 1240 | [Op.iLike]: '%' + search + '%' |
1247 | } | 1241 | } |
1248 | } | 1242 | } |
1249 | }) | 1243 | }) |
@@ -1273,25 +1267,25 @@ export class VideoModel extends Model<VideoModel> { | |||
1273 | } | 1267 | } |
1274 | 1268 | ||
1275 | static async listForApi (options: { | 1269 | static async listForApi (options: { |
1276 | start: number, | 1270 | start: number |
1277 | count: number, | 1271 | count: number |
1278 | sort: string, | 1272 | sort: string |
1279 | nsfw: boolean, | 1273 | nsfw: boolean |
1280 | includeLocalVideos: boolean, | 1274 | includeLocalVideos: boolean |
1281 | withFiles: boolean, | 1275 | withFiles: boolean |
1282 | categoryOneOf?: number[], | 1276 | categoryOneOf?: number[] |
1283 | licenceOneOf?: number[], | 1277 | licenceOneOf?: number[] |
1284 | languageOneOf?: string[], | 1278 | languageOneOf?: string[] |
1285 | tagsOneOf?: string[], | 1279 | tagsOneOf?: string[] |
1286 | tagsAllOf?: string[], | 1280 | tagsAllOf?: string[] |
1287 | filter?: VideoFilter, | 1281 | filter?: VideoFilter |
1288 | accountId?: number, | 1282 | accountId?: number |
1289 | videoChannelId?: number, | 1283 | videoChannelId?: number |
1290 | followerActorId?: number | 1284 | followerActorId?: number |
1291 | videoPlaylistId?: number, | 1285 | videoPlaylistId?: number |
1292 | trendingDays?: number, | 1286 | trendingDays?: number |
1293 | user?: MUserAccountId, | 1287 | user?: MUserAccountId |
1294 | historyOfUser?: MUserId, | 1288 | historyOfUser?: MUserId |
1295 | countVideos?: boolean | 1289 | countVideos?: boolean |
1296 | }) { | 1290 | }) { |
1297 | if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { | 1291 | if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { |
@@ -1357,7 +1351,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1357 | tagsAllOf?: string[] | 1351 | tagsAllOf?: string[] |
1358 | durationMin?: number // seconds | 1352 | durationMin?: number // seconds |
1359 | durationMax?: number // seconds | 1353 | durationMax?: number // seconds |
1360 | user?: MUserAccountId, | 1354 | user?: MUserAccountId |
1361 | filter?: VideoFilter | 1355 | filter?: VideoFilter |
1362 | }) { | 1356 | }) { |
1363 | const whereAnd = [] | 1357 | const whereAnd = [] |
@@ -1365,8 +1359,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1365 | if (options.startDate || options.endDate) { | 1359 | if (options.startDate || options.endDate) { |
1366 | const publishedAtRange = {} | 1360 | const publishedAtRange = {} |
1367 | 1361 | ||
1368 | if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate | 1362 | if (options.startDate) publishedAtRange[Op.gte] = options.startDate |
1369 | if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate | 1363 | if (options.endDate) publishedAtRange[Op.lte] = options.endDate |
1370 | 1364 | ||
1371 | whereAnd.push({ publishedAt: publishedAtRange }) | 1365 | whereAnd.push({ publishedAt: publishedAtRange }) |
1372 | } | 1366 | } |
@@ -1374,8 +1368,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1374 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { | 1368 | if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) { |
1375 | const originallyPublishedAtRange = {} | 1369 | const originallyPublishedAtRange = {} |
1376 | 1370 | ||
1377 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate | 1371 | if (options.originallyPublishedStartDate) originallyPublishedAtRange[Op.gte] = options.originallyPublishedStartDate |
1378 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate | 1372 | if (options.originallyPublishedEndDate) originallyPublishedAtRange[Op.lte] = options.originallyPublishedEndDate |
1379 | 1373 | ||
1380 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) | 1374 | whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange }) |
1381 | } | 1375 | } |
@@ -1383,8 +1377,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1383 | if (options.durationMin || options.durationMax) { | 1377 | if (options.durationMin || options.durationMax) { |
1384 | const durationRange = {} | 1378 | const durationRange = {} |
1385 | 1379 | ||
1386 | if (options.durationMin) durationRange[ Op.gte ] = options.durationMin | 1380 | if (options.durationMin) durationRange[Op.gte] = options.durationMin |
1387 | if (options.durationMax) durationRange[ Op.lte ] = options.durationMax | 1381 | if (options.durationMax) durationRange[Op.lte] = options.durationMax |
1388 | 1382 | ||
1389 | whereAnd.push({ duration: durationRange }) | 1383 | whereAnd.push({ duration: durationRange }) |
1390 | } | 1384 | } |
@@ -1395,7 +1389,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1395 | if (options.search) { | 1389 | if (options.search) { |
1396 | const trigramSearch = { | 1390 | const trigramSearch = { |
1397 | id: { | 1391 | id: { |
1398 | [ Op.in ]: Sequelize.literal( | 1392 | [Op.in]: Sequelize.literal( |
1399 | '(' + | 1393 | '(' + |
1400 | 'SELECT "video"."id" FROM "video" ' + | 1394 | 'SELECT "video"."id" FROM "video" ' + |
1401 | 'WHERE ' + | 1395 | 'WHERE ' + |
@@ -1484,6 +1478,24 @@ export class VideoModel extends Model<VideoModel> { | |||
1484 | ]).findOne(options) | 1478 | ]).findOne(options) |
1485 | } | 1479 | } |
1486 | 1480 | ||
1481 | static loadImmutableAttributes (id: number | string, t?: Transaction): Bluebird<MVideoImmutable> { | ||
1482 | const fun = () => { | ||
1483 | const query = { | ||
1484 | where: buildWhereIdOrUUID(id), | ||
1485 | transaction: t | ||
1486 | } | ||
1487 | |||
1488 | return VideoModel.scope(ScopeNames.WITH_IMMUTABLE_ATTRIBUTES).findOne(query) | ||
1489 | } | ||
1490 | |||
1491 | return ModelCache.Instance.doCache({ | ||
1492 | cacheType: 'load-video-immutable-id', | ||
1493 | key: '' + id, | ||
1494 | deleteKey: 'video', | ||
1495 | fun | ||
1496 | }) | ||
1497 | } | ||
1498 | |||
1487 | static loadWithRights (id: number | string, t?: Transaction): Bluebird<MVideoWithRights> { | 1499 | static loadWithRights (id: number | string, t?: Transaction): Bluebird<MVideoWithRights> { |
1488 | const where = buildWhereIdOrUUID(id) | 1500 | const where = buildWhereIdOrUUID(id) |
1489 | const options = { | 1501 | const options = { |
@@ -1547,6 +1559,26 @@ export class VideoModel extends Model<VideoModel> { | |||
1547 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) | 1559 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) |
1548 | } | 1560 | } |
1549 | 1561 | ||
1562 | static loadByUrlImmutableAttributes (url: string, transaction?: Transaction): Bluebird<MVideoImmutable> { | ||
1563 | const fun = () => { | ||
1564 | const query: FindOptions = { | ||
1565 | where: { | ||
1566 | url | ||
1567 | }, | ||
1568 | transaction | ||
1569 | } | ||
1570 | |||
1571 | return VideoModel.scope(ScopeNames.WITH_IMMUTABLE_ATTRIBUTES).findOne(query) | ||
1572 | } | ||
1573 | |||
1574 | return ModelCache.Instance.doCache({ | ||
1575 | cacheType: 'load-video-immutable-url', | ||
1576 | key: url, | ||
1577 | deleteKey: 'video', | ||
1578 | fun | ||
1579 | }) | ||
1580 | } | ||
1581 | |||
1550 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Bluebird<MVideoAccountLightBlacklistAllFiles> { | 1582 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Bluebird<MVideoAccountLightBlacklistAllFiles> { |
1551 | const query: FindOptions = { | 1583 | const query: FindOptions = { |
1552 | where: { | 1584 | where: { |
@@ -1593,8 +1625,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1593 | } | 1625 | } |
1594 | 1626 | ||
1595 | static loadForGetAPI (parameters: { | 1627 | static loadForGetAPI (parameters: { |
1596 | id: number | string, | 1628 | id: number | string |
1597 | t?: Transaction, | 1629 | t?: Transaction |
1598 | userId?: number | 1630 | userId?: number |
1599 | }): Bluebird<MVideoDetails> { | 1631 | }): Bluebird<MVideoDetails> { |
1600 | const { id, t, userId } = parameters | 1632 | const { id, t, userId } = parameters |
@@ -1660,9 +1692,9 @@ export class VideoModel extends Model<VideoModel> { | |||
1660 | static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) { | 1692 | static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) { |
1661 | // Instances only share videos | 1693 | // Instances only share videos |
1662 | const query = 'SELECT 1 FROM "videoShare" ' + | 1694 | const query = 'SELECT 1 FROM "videoShare" ' + |
1663 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + | 1695 | 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + |
1664 | 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' + | 1696 | 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' + |
1665 | 'LIMIT 1' | 1697 | 'LIMIT 1' |
1666 | 1698 | ||
1667 | const options = { | 1699 | const options = { |
1668 | type: QueryTypes.SELECT as QueryTypes.SELECT, | 1700 | type: QueryTypes.SELECT as QueryTypes.SELECT, |
@@ -1694,7 +1726,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1694 | } | 1726 | } |
1695 | 1727 | ||
1696 | return VideoModel.findAll(query) | 1728 | return VideoModel.findAll(query) |
1697 | .then(videos => videos.map(v => v.id)) | 1729 | .then(videos => videos.map(v => v.id)) |
1698 | } | 1730 | } |
1699 | 1731 | ||
1700 | // threshold corresponds to how many video the field should have to be returned | 1732 | // threshold corresponds to how many video the field should have to be returned |
@@ -1714,14 +1746,14 @@ export class VideoModel extends Model<VideoModel> { | |||
1714 | limit: count, | 1746 | limit: count, |
1715 | group: field, | 1747 | group: field, |
1716 | having: Sequelize.where( | 1748 | having: Sequelize.where( |
1717 | Sequelize.fn('COUNT', Sequelize.col(field)), { [ Op.gte ]: threshold } | 1749 | Sequelize.fn('COUNT', Sequelize.col(field)), { [Op.gte]: threshold } |
1718 | ), | 1750 | ), |
1719 | order: [ (this.sequelize as any).random() ] | 1751 | order: [ (this.sequelize as any).random() ] |
1720 | } | 1752 | } |
1721 | 1753 | ||
1722 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) | 1754 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) |
1723 | .findAll(query) | 1755 | .findAll(query) |
1724 | .then(rows => rows.map(r => r[ field ])) | 1756 | .then(rows => rows.map(r => r[field])) |
1725 | } | 1757 | } |
1726 | 1758 | ||
1727 | static buildTrendingQuery (trendingDays: number) { | 1759 | static buildTrendingQuery (trendingDays: number) { |
@@ -1732,7 +1764,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1732 | required: false, | 1764 | required: false, |
1733 | where: { | 1765 | where: { |
1734 | startDate: { | 1766 | startDate: { |
1735 | [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) | 1767 | [Op.gte]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays) |
1736 | } | 1768 | } |
1737 | } | 1769 | } |
1738 | } | 1770 | } |
@@ -1815,23 +1847,23 @@ export class VideoModel extends Model<VideoModel> { | |||
1815 | } | 1847 | } |
1816 | 1848 | ||
1817 | static getCategoryLabel (id: number) { | 1849 | static getCategoryLabel (id: number) { |
1818 | return VIDEO_CATEGORIES[ id ] || 'Misc' | 1850 | return VIDEO_CATEGORIES[id] || 'Misc' |
1819 | } | 1851 | } |
1820 | 1852 | ||
1821 | static getLicenceLabel (id: number) { | 1853 | static getLicenceLabel (id: number) { |
1822 | return VIDEO_LICENCES[ id ] || 'Unknown' | 1854 | return VIDEO_LICENCES[id] || 'Unknown' |
1823 | } | 1855 | } |
1824 | 1856 | ||
1825 | static getLanguageLabel (id: string) { | 1857 | static getLanguageLabel (id: string) { |
1826 | return VIDEO_LANGUAGES[ id ] || 'Unknown' | 1858 | return VIDEO_LANGUAGES[id] || 'Unknown' |
1827 | } | 1859 | } |
1828 | 1860 | ||
1829 | static getPrivacyLabel (id: number) { | 1861 | static getPrivacyLabel (id: number) { |
1830 | return VIDEO_PRIVACIES[ id ] || 'Unknown' | 1862 | return VIDEO_PRIVACIES[id] || 'Unknown' |
1831 | } | 1863 | } |
1832 | 1864 | ||
1833 | static getStateLabel (id: number) { | 1865 | static getStateLabel (id: number) { |
1834 | return VIDEO_STATES[ id ] || 'Unknown' | 1866 | return VIDEO_STATES[id] || 'Unknown' |
1835 | } | 1867 | } |
1836 | 1868 | ||
1837 | isBlacklisted () { | 1869 | isBlacklisted () { |
@@ -1843,7 +1875,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1843 | this.VideoChannel.Account.isBlocked() | 1875 | this.VideoChannel.Account.isBlocked() |
1844 | } | 1876 | } |
1845 | 1877 | ||
1846 | getQualityFileBy <T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { | 1878 | getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) { |
1847 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { | 1879 | if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) { |
1848 | const file = fun(this.VideoFiles, file => file.resolution) | 1880 | const file = fun(this.VideoFiles, file => file.resolution) |
1849 | 1881 | ||
@@ -1861,15 +1893,15 @@ export class VideoModel extends Model<VideoModel> { | |||
1861 | return undefined | 1893 | return undefined |
1862 | } | 1894 | } |
1863 | 1895 | ||
1864 | getMaxQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { | 1896 | getMaxQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { |
1865 | return this.getQualityFileBy(maxBy) | 1897 | return this.getQualityFileBy(maxBy) |
1866 | } | 1898 | } |
1867 | 1899 | ||
1868 | getMinQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { | 1900 | getMinQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo { |
1869 | return this.getQualityFileBy(minBy) | 1901 | return this.getQualityFileBy(minBy) |
1870 | } | 1902 | } |
1871 | 1903 | ||
1872 | getWebTorrentFile <T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { | 1904 | getWebTorrentFile<T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo { |
1873 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1905 | if (Array.isArray(this.VideoFiles) === false) return undefined |
1874 | 1906 | ||
1875 | const file = this.VideoFiles.find(f => f.resolution === resolution) | 1907 | const file = this.VideoFiles.find(f => f.resolution === resolution) |
@@ -1905,6 +1937,10 @@ export class VideoModel extends Model<VideoModel> { | |||
1905 | return this.uuid + '.jpg' | 1937 | return this.uuid + '.jpg' |
1906 | } | 1938 | } |
1907 | 1939 | ||
1940 | hasPreview () { | ||
1941 | return !!this.getPreview() | ||
1942 | } | ||
1943 | |||
1908 | getPreview () { | 1944 | getPreview () { |
1909 | if (Array.isArray(this.Thumbnails) === false) return undefined | 1945 | if (Array.isArray(this.Thumbnails) === false) return undefined |
1910 | 1946 | ||
@@ -1992,8 +2028,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1992 | } | 2028 | } |
1993 | 2029 | ||
1994 | this.VideoStreamingPlaylists = this.VideoStreamingPlaylists | 2030 | this.VideoStreamingPlaylists = this.VideoStreamingPlaylists |
1995 | .filter(s => s.type !== VideoStreamingPlaylistType.HLS) | 2031 | .filter(s => s.type !== VideoStreamingPlaylistType.HLS) |
1996 | .concat(toAdd) | 2032 | .concat(toAdd) |
1997 | } | 2033 | } |
1998 | 2034 | ||
1999 | removeFile (videoFile: MVideoFile, isRedundancy = false) { | 2035 | removeFile (videoFile: MVideoFile, isRedundancy = false) { |
@@ -2014,7 +2050,7 @@ export class VideoModel extends Model<VideoModel> { | |||
2014 | await remove(directoryPath) | 2050 | await remove(directoryPath) |
2015 | 2051 | ||
2016 | if (isRedundancy !== true) { | 2052 | if (isRedundancy !== true) { |
2017 | let streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo | 2053 | const streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo |
2018 | streamingPlaylistWithFiles.Video = this | 2054 | streamingPlaylistWithFiles.Video = this |
2019 | 2055 | ||
2020 | if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) { | 2056 | if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) { |
diff --git a/server/tests/api/activitypub/client.ts b/server/tests/api/activitypub/client.ts index 34c6be49b..d16f05108 100644 --- a/server/tests/api/activitypub/client.ts +++ b/server/tests/api/activitypub/client.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -6,8 +6,6 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | doubleFollow, | 7 | doubleFollow, |
8 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
9 | flushTests, | ||
10 | killallServers, | ||
11 | makeActivityPubGetRequest, | 9 | makeActivityPubGetRequest, |
12 | ServerInfo, | 10 | ServerInfo, |
13 | setAccessTokensToServers, | 11 | setAccessTokensToServers, |
diff --git a/server/tests/api/activitypub/fetch.ts b/server/tests/api/activitypub/fetch.ts index 3d54c2042..35fd94eed 100644 --- a/server/tests/api/activitypub/fetch.ts +++ b/server/tests/api/activitypub/fetch.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -8,9 +8,7 @@ import { | |||
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | getVideosListSort, | 11 | getVideosListSort, |
13 | killallServers, | ||
14 | ServerInfo, | 12 | ServerInfo, |
15 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
16 | setActorField, | 14 | setActorField, |
diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts index 8c00ba3d6..60d95b823 100644 --- a/server/tests/api/activitypub/helpers.ts +++ b/server/tests/api/activitypub/helpers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
diff --git a/server/tests/api/activitypub/refresher.ts b/server/tests/api/activitypub/refresher.ts index aa4bc6c0f..232c5d823 100644 --- a/server/tests/api/activitypub/refresher.ts +++ b/server/tests/api/activitypub/refresher.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -43,32 +43,32 @@ describe('Test AP refresher', function () { | |||
43 | await setDefaultVideoChannel(servers) | 43 | await setDefaultVideoChannel(servers) |
44 | 44 | ||
45 | { | 45 | { |
46 | videoUUID1 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video1' })).uuid | 46 | videoUUID1 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video1' })).uuid |
47 | videoUUID2 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video2' })).uuid | 47 | videoUUID2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video2' })).uuid |
48 | videoUUID3 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video3' })).uuid | 48 | videoUUID3 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video3' })).uuid |
49 | } | 49 | } |
50 | 50 | ||
51 | { | 51 | { |
52 | const a1 = await generateUserAccessToken(servers[ 1 ], 'user1') | 52 | const a1 = await generateUserAccessToken(servers[1], 'user1') |
53 | await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' }) | 53 | await uploadVideo(servers[1].url, a1, { name: 'video4' }) |
54 | 54 | ||
55 | const a2 = await generateUserAccessToken(servers[ 1 ], 'user2') | 55 | const a2 = await generateUserAccessToken(servers[1], 'user2') |
56 | await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' }) | 56 | await uploadVideo(servers[1].url, a2, { name: 'video5' }) |
57 | } | 57 | } |
58 | 58 | ||
59 | { | 59 | { |
60 | const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } | 60 | const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } |
61 | const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) | 61 | const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) |
62 | playlistUUID1 = res.body.videoPlaylist.uuid | 62 | playlistUUID1 = res.body.videoPlaylist.uuid |
63 | } | 63 | } |
64 | 64 | ||
65 | { | 65 | { |
66 | const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id } | 66 | const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id } |
67 | const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs }) | 67 | const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs }) |
68 | playlistUUID2 = res.body.videoPlaylist.uuid | 68 | playlistUUID2 = res.body.videoPlaylist.uuid |
69 | } | 69 | } |
70 | 70 | ||
71 | await doubleFollow(servers[ 0 ], servers[ 1 ]) | 71 | await doubleFollow(servers[0], servers[1]) |
72 | }) | 72 | }) |
73 | 73 | ||
74 | describe('Videos refresher', function () { | 74 | describe('Videos refresher', function () { |
@@ -79,34 +79,34 @@ describe('Test AP refresher', function () { | |||
79 | await wait(10000) | 79 | await wait(10000) |
80 | 80 | ||
81 | // Change UUID so the remote server returns a 404 | 81 | // Change UUID so the remote server returns a 404 |
82 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') | 82 | await setVideoField(servers[1].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f') |
83 | 83 | ||
84 | await getVideo(servers[ 0 ].url, videoUUID1) | 84 | await getVideo(servers[0].url, videoUUID1) |
85 | await getVideo(servers[ 0 ].url, videoUUID2) | 85 | await getVideo(servers[0].url, videoUUID2) |
86 | 86 | ||
87 | await waitJobs(servers) | 87 | await waitJobs(servers) |
88 | 88 | ||
89 | await getVideo(servers[ 0 ].url, videoUUID1, 404) | 89 | await getVideo(servers[0].url, videoUUID1, 404) |
90 | await getVideo(servers[ 0 ].url, videoUUID2, 200) | 90 | await getVideo(servers[0].url, videoUUID2, 200) |
91 | }) | 91 | }) |
92 | 92 | ||
93 | it('Should not update a remote video if the remote instance is down', async function () { | 93 | it('Should not update a remote video if the remote instance is down', async function () { |
94 | this.timeout(70000) | 94 | this.timeout(70000) |
95 | 95 | ||
96 | killallServers([ servers[ 1 ] ]) | 96 | killallServers([ servers[1] ]) |
97 | 97 | ||
98 | await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') | 98 | await setVideoField(servers[1].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e') |
99 | 99 | ||
100 | // Video will need a refresh | 100 | // Video will need a refresh |
101 | await wait(10000) | 101 | await wait(10000) |
102 | 102 | ||
103 | await getVideo(servers[ 0 ].url, videoUUID3) | 103 | await getVideo(servers[0].url, videoUUID3) |
104 | // The refresh should fail | 104 | // The refresh should fail |
105 | await waitJobs([ servers[ 0 ] ]) | 105 | await waitJobs([ servers[0] ]) |
106 | 106 | ||
107 | await reRunServer(servers[ 1 ]) | 107 | await reRunServer(servers[1]) |
108 | 108 | ||
109 | await getVideo(servers[ 0 ].url, videoUUID3, 200) | 109 | await getVideo(servers[0].url, videoUUID3, 200) |
110 | }) | 110 | }) |
111 | }) | 111 | }) |
112 | 112 | ||
@@ -118,16 +118,16 @@ describe('Test AP refresher', function () { | |||
118 | await wait(10000) | 118 | await wait(10000) |
119 | 119 | ||
120 | // Change actor name so the remote server returns a 404 | 120 | // Change actor name so the remote server returns a 404 |
121 | const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2' | 121 | const to = 'http://localhost:' + servers[1].port + '/accounts/user2' |
122 | await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto') | 122 | await setActorField(servers[1].internalServerNumber, to, 'preferredUsername', 'toto') |
123 | 123 | ||
124 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port) | 124 | await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port) |
125 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port) | 125 | await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port) |
126 | 126 | ||
127 | await waitJobs(servers) | 127 | await waitJobs(servers) |
128 | 128 | ||
129 | await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200) | 129 | await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, 200) |
130 | await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404) | 130 | await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, 404) |
131 | }) | 131 | }) |
132 | }) | 132 | }) |
133 | 133 | ||
@@ -139,15 +139,15 @@ describe('Test AP refresher', function () { | |||
139 | await wait(10000) | 139 | await wait(10000) |
140 | 140 | ||
141 | // Change UUID so the remote server returns a 404 | 141 | // Change UUID so the remote server returns a 404 |
142 | await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') | 142 | await setPlaylistField(servers[1].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e') |
143 | 143 | ||
144 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1) | 144 | await getVideoPlaylist(servers[0].url, playlistUUID1) |
145 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2) | 145 | await getVideoPlaylist(servers[0].url, playlistUUID2) |
146 | 146 | ||
147 | await waitJobs(servers) | 147 | await waitJobs(servers) |
148 | 148 | ||
149 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID1, 200) | 149 | await getVideoPlaylist(servers[0].url, playlistUUID1, 200) |
150 | await getVideoPlaylist(servers[ 0 ].url, playlistUUID2, 404) | 150 | await getVideoPlaylist(servers[0].url, playlistUUID2, 404) |
151 | }) | 151 | }) |
152 | }) | 152 | }) |
153 | 153 | ||
diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index dc960c5c3..7e58bf065 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts | |||
@@ -1,15 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { cleanupTests, closeAllSequelize, flushAndRunMultipleServers, ServerInfo, setActorField } from '../../../../shared/extra-utils' |
6 | cleanupTests, | ||
7 | closeAllSequelize, | ||
8 | flushAndRunMultipleServers, | ||
9 | killallServers, | ||
10 | ServerInfo, | ||
11 | setActorField | ||
12 | } from '../../../../shared/extra-utils' | ||
13 | import { HTTP_SIGNATURE } from '../../../initializers/constants' | 6 | import { HTTP_SIGNATURE } from '../../../initializers/constants' |
14 | import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' | 7 | import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils' |
15 | import * as chai from 'chai' | 8 | import * as chai from 'chai' |
@@ -33,7 +26,7 @@ function getAnnounceWithoutContext (server2: ServerInfo) { | |||
33 | if (Array.isArray(json[key])) { | 26 | if (Array.isArray(json[key])) { |
34 | result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) | 27 | result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`)) |
35 | } else { | 28 | } else { |
36 | result[ key ] = json[ key ].replace(':9002', `:${server2.port}`) | 29 | result[key] = json[key].replace(':9002', `:${server2.port}`) |
37 | } | 30 | } |
38 | } | 31 | } |
39 | 32 | ||
diff --git a/server/tests/api/check-params/accounts.ts b/server/tests/api/check-params/accounts.ts index 4f79685bd..c29af7cd7 100644 --- a/server/tests/api/check-params/accounts.ts +++ b/server/tests/api/check-params/accounts.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/blocklist.ts b/server/tests/api/check-params/blocklist.ts index 0661676ce..fb459f756 100644 --- a/server/tests/api/check-params/blocklist.ts +++ b/server/tests/api/check-params/blocklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 443fbcb60..f1a79806b 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/check-params/contact-form.ts b/server/tests/api/check-params/contact-form.ts index b3051945e..b2126b9b0 100644 --- a/server/tests/api/check-params/contact-form.ts +++ b/server/tests/api/check-params/contact-form.ts | |||
@@ -1,22 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { cleanupTests, flushAndRunServer, immutableAssign, killallServers, reRunServer, ServerInfo } from '../../../../shared/extra-utils' |
6 | flushTests, | ||
7 | immutableAssign, | ||
8 | killallServers, | ||
9 | reRunServer, | ||
10 | flushAndRunServer, | ||
11 | ServerInfo, | ||
12 | setAccessTokensToServers, cleanupTests | ||
13 | } from '../../../../shared/extra-utils' | ||
14 | import { | ||
15 | checkBadCountPagination, | ||
16 | checkBadSortPagination, | ||
17 | checkBadStartPagination | ||
18 | } from '../../../../shared/extra-utils/requests/check-api-params' | ||
19 | import { getAccount } from '../../../../shared/extra-utils/users/accounts' | ||
20 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' | 6 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' |
21 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 7 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
22 | 8 | ||
diff --git a/server/tests/api/check-params/debug.ts b/server/tests/api/check-params/debug.ts index 8dad26723..5fac73485 100644 --- a/server/tests/api/check-params/debug.ts +++ b/server/tests/api/check-params/debug.ts | |||
@@ -1,15 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, cleanupTests | 11 | userLogin |
13 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
14 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' | 13 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' |
15 | 14 | ||
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts index be2a603a3..2c2224a45 100644 --- a/server/tests/api/check-params/follows.ts +++ b/server/tests/api/check-params/follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/jobs.ts b/server/tests/api/check-params/jobs.ts index 22e237964..8f4af8d16 100644 --- a/server/tests/api/check-params/jobs.ts +++ b/server/tests/api/check-params/jobs.ts | |||
@@ -1,16 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, | 11 | userLogin |
13 | cleanupTests | ||
14 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
15 | import { | 13 | import { |
16 | checkBadCountPagination, | 14 | checkBadCountPagination, |
diff --git a/server/tests/api/check-params/logs.ts b/server/tests/api/check-params/logs.ts index f9d96bcc0..719da54e6 100644 --- a/server/tests/api/check-params/logs.ts +++ b/server/tests/api/check-params/logs.ts | |||
@@ -1,16 +1,14 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | cleanupTests, | ||
6 | createUser, | 7 | createUser, |
7 | flushTests, | ||
8 | killallServers, | ||
9 | flushAndRunServer, | 8 | flushAndRunServer, |
10 | ServerInfo, | 9 | ServerInfo, |
11 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
12 | userLogin, | 11 | userLogin |
13 | cleanupTests | ||
14 | } from '../../../../shared/extra-utils' | 12 | } from '../../../../shared/extra-utils' |
15 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' | 13 | import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests' |
16 | 14 | ||
diff --git a/server/tests/api/check-params/plugins.ts b/server/tests/api/check-params/plugins.ts index 9553bce17..cf80b35c2 100644 --- a/server/tests/api/check-params/plugins.ts +++ b/server/tests/api/check-params/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts index 6471da840..b2370a094 100644 --- a/server/tests/api/check-params/redundancy.ts +++ b/server/tests/api/check-params/redundancy.ts | |||
@@ -1,23 +1,27 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
5 | import { | 5 | import { |
6 | checkBadCountPagination, | ||
7 | checkBadSortPagination, | ||
8 | checkBadStartPagination, | ||
6 | cleanupTests, | 9 | cleanupTests, |
7 | createUser, | 10 | createUser, |
8 | doubleFollow, | 11 | doubleFollow, |
9 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, makeDeleteRequest, |
10 | flushTests, | 13 | makeGetRequest, makePostBodyRequest, |
11 | killallServers, | ||
12 | makePutBodyRequest, | 14 | makePutBodyRequest, |
13 | ServerInfo, | 15 | ServerInfo, |
14 | setAccessTokensToServers, | 16 | setAccessTokensToServers, uploadVideoAndGetId, |
15 | userLogin | 17 | userLogin, waitJobs |
16 | } from '../../../../shared/extra-utils' | 18 | } from '../../../../shared/extra-utils' |
17 | 19 | ||
18 | describe('Test server redundancy API validators', function () { | 20 | describe('Test server redundancy API validators', function () { |
19 | let servers: ServerInfo[] | 21 | let servers: ServerInfo[] |
20 | let userAccessToken = null | 22 | let userAccessToken = null |
23 | let videoIdLocal: number | ||
24 | let videoIdRemote: number | ||
21 | 25 | ||
22 | // --------------------------------------------------------------- | 26 | // --------------------------------------------------------------- |
23 | 27 | ||
@@ -34,11 +38,136 @@ describe('Test server redundancy API validators', function () { | |||
34 | password: 'password' | 38 | password: 'password' |
35 | } | 39 | } |
36 | 40 | ||
37 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 41 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
38 | userAccessToken = await userLogin(servers[0], user) | 42 | userAccessToken = await userLogin(servers[0], user) |
43 | |||
44 | videoIdLocal = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })).id | ||
45 | videoIdRemote = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video' })).id | ||
46 | |||
47 | await waitJobs(servers) | ||
48 | }) | ||
49 | |||
50 | describe('When listing redundancies', function () { | ||
51 | const path = '/api/v1/server/redundancy/videos' | ||
52 | |||
53 | let url: string | ||
54 | let token: string | ||
55 | |||
56 | before(function () { | ||
57 | url = servers[0].url | ||
58 | token = servers[0].accessToken | ||
59 | }) | ||
60 | |||
61 | it('Should fail with an invalid token', async function () { | ||
62 | await makeGetRequest({ url, path, token: 'fake_token', statusCodeExpected: 401 }) | ||
63 | }) | ||
64 | |||
65 | it('Should fail if the user is not an administrator', async function () { | ||
66 | await makeGetRequest({ url, path, token: userAccessToken, statusCodeExpected: 403 }) | ||
67 | }) | ||
68 | |||
69 | it('Should fail with a bad start pagination', async function () { | ||
70 | await checkBadStartPagination(url, path, servers[0].accessToken) | ||
71 | }) | ||
72 | |||
73 | it('Should fail with a bad count pagination', async function () { | ||
74 | await checkBadCountPagination(url, path, servers[0].accessToken) | ||
75 | }) | ||
76 | |||
77 | it('Should fail with an incorrect sort', async function () { | ||
78 | await checkBadSortPagination(url, path, servers[0].accessToken) | ||
79 | }) | ||
80 | |||
81 | it('Should fail with a bad target', async function () { | ||
82 | await makeGetRequest({ url, path, token, query: { target: 'bad target' } }) | ||
83 | }) | ||
84 | |||
85 | it('Should fail without target', async function () { | ||
86 | await makeGetRequest({ url, path, token }) | ||
87 | }) | ||
88 | |||
89 | it('Should succeed with the correct params', async function () { | ||
90 | await makeGetRequest({ url, path, token, query: { target: 'my-videos' }, statusCodeExpected: 200 }) | ||
91 | }) | ||
92 | }) | ||
93 | |||
94 | describe('When manually adding a redundancy', function () { | ||
95 | const path = '/api/v1/server/redundancy/videos' | ||
96 | |||
97 | let url: string | ||
98 | let token: string | ||
99 | |||
100 | before(function () { | ||
101 | url = servers[0].url | ||
102 | token = servers[0].accessToken | ||
103 | }) | ||
104 | |||
105 | it('Should fail with an invalid token', async function () { | ||
106 | await makePostBodyRequest({ url, path, token: 'fake_token', statusCodeExpected: 401 }) | ||
107 | }) | ||
108 | |||
109 | it('Should fail if the user is not an administrator', async function () { | ||
110 | await makePostBodyRequest({ url, path, token: userAccessToken, statusCodeExpected: 403 }) | ||
111 | }) | ||
112 | |||
113 | it('Should fail without a video id', async function () { | ||
114 | await makePostBodyRequest({ url, path, token }) | ||
115 | }) | ||
116 | |||
117 | it('Should fail with an incorrect video id', async function () { | ||
118 | await makePostBodyRequest({ url, path, token, fields: { videoId: 'peertube' } }) | ||
119 | }) | ||
120 | |||
121 | it('Should fail with a not found video id', async function () { | ||
122 | await makePostBodyRequest({ url, path, token, fields: { videoId: 6565 }, statusCodeExpected: 404 }) | ||
123 | }) | ||
124 | |||
125 | it('Should fail with a local a video id', async function () { | ||
126 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdLocal } }) | ||
127 | }) | ||
128 | |||
129 | it('Should succeed with the correct params', async function () { | ||
130 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: 204 }) | ||
131 | }) | ||
132 | |||
133 | it('Should fail if the video is already duplicated', async function () { | ||
134 | this.timeout(30000) | ||
135 | |||
136 | await waitJobs(servers) | ||
137 | |||
138 | await makePostBodyRequest({ url, path, token, fields: { videoId: videoIdRemote }, statusCodeExpected: 409 }) | ||
139 | }) | ||
140 | }) | ||
141 | |||
142 | describe('When manually removing a redundancy', function () { | ||
143 | const path = '/api/v1/server/redundancy/videos/' | ||
144 | |||
145 | let url: string | ||
146 | let token: string | ||
147 | |||
148 | before(function () { | ||
149 | url = servers[0].url | ||
150 | token = servers[0].accessToken | ||
151 | }) | ||
152 | |||
153 | it('Should fail with an invalid token', async function () { | ||
154 | await makeDeleteRequest({ url, path: path + '1', token: 'fake_token', statusCodeExpected: 401 }) | ||
155 | }) | ||
156 | |||
157 | it('Should fail if the user is not an administrator', async function () { | ||
158 | await makeDeleteRequest({ url, path: path + '1', token: userAccessToken, statusCodeExpected: 403 }) | ||
159 | }) | ||
160 | |||
161 | it('Should fail with an incorrect video id', async function () { | ||
162 | await makeDeleteRequest({ url, path: path + 'toto', token }) | ||
163 | }) | ||
164 | |||
165 | it('Should fail with a not found video redundancy', async function () { | ||
166 | await makeDeleteRequest({ url, path: path + '454545', token, statusCodeExpected: 404 }) | ||
167 | }) | ||
39 | }) | 168 | }) |
40 | 169 | ||
41 | describe('When updating redundancy', function () { | 170 | describe('When updating server redundancy', function () { |
42 | const path = '/api/v1/server/redundancy' | 171 | const path = '/api/v1/server/redundancy' |
43 | 172 | ||
44 | it('Should fail with an invalid token', async function () { | 173 | it('Should fail with an invalid token', async function () { |
diff --git a/server/tests/api/check-params/search.ts b/server/tests/api/check-params/search.ts index 8ad9d98bf..f8d0cd4ec 100644 --- a/server/tests/api/check-params/search.ts +++ b/server/tests/api/check-params/search.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/services.ts b/server/tests/api/check-params/services.ts index d15753aed..457adfaab 100644 --- a/server/tests/api/check-params/services.ts +++ b/server/tests/api/check-params/services.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/user-notifications.ts b/server/tests/api/check-params/user-notifications.ts index 3b06be7ef..2048fa667 100644 --- a/server/tests/api/check-params/user-notifications.ts +++ b/server/tests/api/check-params/user-notifications.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as io from 'socket.io-client' | 4 | import * as io from 'socket.io-client' |
diff --git a/server/tests/api/check-params/user-subscriptions.ts b/server/tests/api/check-params/user-subscriptions.ts index fa36c4078..1edba4d64 100644 --- a/server/tests/api/check-params/user-subscriptions.ts +++ b/server/tests/api/check-params/user-subscriptions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index 5d5af284c..4d597f0a3 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -16,12 +16,14 @@ import { | |||
16 | getMyUserVideoRating, | 16 | getMyUserVideoRating, |
17 | getUsersList, | 17 | getUsersList, |
18 | immutableAssign, | 18 | immutableAssign, |
19 | killallServers, | ||
19 | makeGetRequest, | 20 | makeGetRequest, |
20 | makePostBodyRequest, | 21 | makePostBodyRequest, |
21 | makePutBodyRequest, | 22 | makePutBodyRequest, |
22 | makeUploadRequest, | 23 | makeUploadRequest, |
23 | registerUser, | 24 | registerUser, |
24 | removeUser, | 25 | removeUser, |
26 | reRunServer, | ||
25 | ServerInfo, | 27 | ServerInfo, |
26 | setAccessTokensToServers, | 28 | setAccessTokensToServers, |
27 | unblockUser, | 29 | unblockUser, |
@@ -39,6 +41,7 @@ import { VideoPrivacy } from '../../../../shared/models/videos' | |||
39 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 41 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
40 | import { expect } from 'chai' | 42 | import { expect } from 'chai' |
41 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 43 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
44 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | ||
42 | 45 | ||
43 | describe('Test users API validators', function () { | 46 | describe('Test users API validators', function () { |
44 | const path = '/api/v1/users/' | 47 | const path = '/api/v1/users/' |
@@ -50,6 +53,9 @@ describe('Test users API validators', function () { | |||
50 | let serverWithRegistrationDisabled: ServerInfo | 53 | let serverWithRegistrationDisabled: ServerInfo |
51 | let userAccessToken = '' | 54 | let userAccessToken = '' |
52 | let moderatorAccessToken = '' | 55 | let moderatorAccessToken = '' |
56 | let emailPort: number | ||
57 | let overrideConfig: Object | ||
58 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
53 | let channelId: number | 59 | let channelId: number |
54 | 60 | ||
55 | // --------------------------------------------------------------- | 61 | // --------------------------------------------------------------- |
@@ -57,9 +63,14 @@ describe('Test users API validators', function () { | |||
57 | before(async function () { | 63 | before(async function () { |
58 | this.timeout(30000) | 64 | this.timeout(30000) |
59 | 65 | ||
66 | const emails: object[] = [] | ||
67 | emailPort = await MockSmtpServer.Instance.collectEmails(emails) | ||
68 | |||
69 | overrideConfig = { signup: { limit: 8 } } | ||
70 | |||
60 | { | 71 | { |
61 | const res = await Promise.all([ | 72 | const res = await Promise.all([ |
62 | flushAndRunServer(1, { signup: { limit: 7 } }), | 73 | flushAndRunServer(1, overrideConfig), |
63 | flushAndRunServer(2) | 74 | flushAndRunServer(2) |
64 | ]) | 75 | ]) |
65 | 76 | ||
@@ -120,7 +131,7 @@ describe('Test users API validators', function () { | |||
120 | 131 | ||
121 | { | 132 | { |
122 | const res = await getMyUserInformation(server.url, server.accessToken) | 133 | const res = await getMyUserInformation(server.url, server.accessToken) |
123 | channelId = res.body.videoChannels[ 0 ].id | 134 | channelId = res.body.videoChannels[0].id |
124 | } | 135 | } |
125 | 136 | ||
126 | { | 137 | { |
@@ -228,6 +239,40 @@ describe('Test users API validators', function () { | |||
228 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | 239 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) |
229 | }) | 240 | }) |
230 | 241 | ||
242 | it('Should fail with empty password and no smtp configured', async function () { | ||
243 | const fields = immutableAssign(baseCorrectParams, { password: '' }) | ||
244 | |||
245 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
246 | }) | ||
247 | |||
248 | it('Should succeed with no password on a server with smtp enabled', async function () { | ||
249 | this.timeout(10000) | ||
250 | |||
251 | killallServers([ server ]) | ||
252 | |||
253 | const config = immutableAssign(overrideConfig, { | ||
254 | smtp: { | ||
255 | hostname: 'localhost', | ||
256 | port: emailPort | ||
257 | } | ||
258 | }) | ||
259 | await reRunServer(server, config) | ||
260 | |||
261 | const fields = immutableAssign(baseCorrectParams, { | ||
262 | password: '', | ||
263 | username: 'create_password', | ||
264 | email: 'create_password@example.com' | ||
265 | }) | ||
266 | |||
267 | await makePostBodyRequest({ | ||
268 | url: server.url, | ||
269 | path: path, | ||
270 | token: server.accessToken, | ||
271 | fields, | ||
272 | statusCodeExpected: 200 | ||
273 | }) | ||
274 | }) | ||
275 | |||
231 | it('Should fail with invalid admin flags', async function () { | 276 | it('Should fail with invalid admin flags', async function () { |
232 | const fields = immutableAssign(baseCorrectParams, { adminFlags: 'toto' }) | 277 | const fields = immutableAssign(baseCorrectParams, { adminFlags: 'toto' }) |
233 | 278 | ||
@@ -529,7 +574,7 @@ describe('Test users API validators', function () { | |||
529 | it('Should fail without an incorrect input file', async function () { | 574 | it('Should fail without an incorrect input file', async function () { |
530 | const fields = {} | 575 | const fields = {} |
531 | const attaches = { | 576 | const attaches = { |
532 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') | 577 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
533 | } | 578 | } |
534 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | 579 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) |
535 | }) | 580 | }) |
@@ -537,7 +582,7 @@ describe('Test users API validators', function () { | |||
537 | it('Should fail with a big file', async function () { | 582 | it('Should fail with a big file', async function () { |
538 | const fields = {} | 583 | const fields = {} |
539 | const attaches = { | 584 | const attaches = { |
540 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 585 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
541 | } | 586 | } |
542 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) | 587 | await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches }) |
543 | }) | 588 | }) |
@@ -545,7 +590,7 @@ describe('Test users API validators', function () { | |||
545 | it('Should fail with an unauthenticated user', async function () { | 590 | it('Should fail with an unauthenticated user', async function () { |
546 | const fields = {} | 591 | const fields = {} |
547 | const attaches = { | 592 | const attaches = { |
548 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 593 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
549 | } | 594 | } |
550 | await makeUploadRequest({ | 595 | await makeUploadRequest({ |
551 | url: server.url, | 596 | url: server.url, |
@@ -559,7 +604,7 @@ describe('Test users API validators', function () { | |||
559 | it('Should succeed with the correct params', async function () { | 604 | it('Should succeed with the correct params', async function () { |
560 | const fields = {} | 605 | const fields = {} |
561 | const attaches = { | 606 | const attaches = { |
562 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 607 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
563 | } | 608 | } |
564 | await makeUploadRequest({ | 609 | await makeUploadRequest({ |
565 | url: server.url, | 610 | url: server.url, |
@@ -1101,6 +1146,8 @@ describe('Test users API validators', function () { | |||
1101 | }) | 1146 | }) |
1102 | 1147 | ||
1103 | after(async function () { | 1148 | after(async function () { |
1149 | MockSmtpServer.Instance.kill() | ||
1150 | |||
1104 | await cleanupTests([ server, serverWithRegistrationDisabled ]) | 1151 | await cleanupTests([ server, serverWithRegistrationDisabled ]) |
1105 | }) | 1152 | }) |
1106 | }) | 1153 | }) |
diff --git a/server/tests/api/check-params/video-abuses.ts b/server/tests/api/check-params/video-abuses.ts index bf29f8d4d..bea2177f3 100644 --- a/server/tests/api/check-params/video-abuses.ts +++ b/server/tests/api/check-params/video-abuses.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -126,6 +126,7 @@ describe('Test video abuses API validators', function () { | |||
126 | 126 | ||
127 | describe('When updating a video abuse', function () { | 127 | describe('When updating a video abuse', function () { |
128 | const basePath = '/api/v1/videos/' | 128 | const basePath = '/api/v1/videos/' |
129 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
129 | let path: string | 130 | let path: string |
130 | 131 | ||
131 | before(() => { | 132 | before(() => { |
@@ -163,6 +164,7 @@ describe('Test video abuses API validators', function () { | |||
163 | 164 | ||
164 | describe('When deleting a video abuse', function () { | 165 | describe('When deleting a video abuse', function () { |
165 | const basePath = '/api/v1/videos/' | 166 | const basePath = '/api/v1/videos/' |
167 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
166 | let path: string | 168 | let path: string |
167 | 169 | ||
168 | before(() => { | 170 | before(() => { |
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts index 6466888fb..145f43980 100644 --- a/server/tests/api/check-params/video-blacklist.ts +++ b/server/tests/api/check-params/video-blacklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | 4 | ||
@@ -7,25 +7,24 @@ import { | |||
7 | createUser, | 7 | createUser, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | flushTests, | ||
11 | getBlacklistedVideosList, | 10 | getBlacklistedVideosList, |
12 | getVideo, | 11 | getVideo, |
13 | getVideoWithToken, | 12 | getVideoWithToken, |
14 | killallServers, | ||
15 | makePostBodyRequest, | 13 | makePostBodyRequest, |
16 | makePutBodyRequest, | 14 | makePutBodyRequest, |
17 | removeVideoFromBlacklist, | 15 | removeVideoFromBlacklist, |
18 | ServerInfo, | 16 | ServerInfo, |
19 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
20 | uploadVideo, | 18 | uploadVideo, |
21 | userLogin, waitJobs | 19 | userLogin, |
20 | waitJobs | ||
22 | } from '../../../../shared/extra-utils' | 21 | } from '../../../../shared/extra-utils' |
23 | import { | 22 | import { |
24 | checkBadCountPagination, | 23 | checkBadCountPagination, |
25 | checkBadSortPagination, | 24 | checkBadSortPagination, |
26 | checkBadStartPagination | 25 | checkBadStartPagination |
27 | } from '../../../../shared/extra-utils/requests/check-api-params' | 26 | } from '../../../../shared/extra-utils/requests/check-api-params' |
28 | import { VideoDetails, VideoBlacklistType } from '../../../../shared/models/videos' | 27 | import { VideoBlacklistType, VideoDetails } from '../../../../shared/models/videos' |
29 | import { expect } from 'chai' | 28 | import { expect } from 'chai' |
30 | 29 | ||
31 | describe('Test video blacklist API validators', function () { | 30 | describe('Test video blacklist API validators', function () { |
@@ -48,14 +47,14 @@ describe('Test video blacklist API validators', function () { | |||
48 | { | 47 | { |
49 | const username = 'user1' | 48 | const username = 'user1' |
50 | const password = 'my super password' | 49 | const password = 'my super password' |
51 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) | 50 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password }) |
52 | userAccessToken1 = await userLogin(servers[0], { username, password }) | 51 | userAccessToken1 = await userLogin(servers[0], { username, password }) |
53 | } | 52 | } |
54 | 53 | ||
55 | { | 54 | { |
56 | const username = 'user2' | 55 | const username = 'user2' |
57 | const password = 'my super password' | 56 | const password = 'my super password' |
58 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password }) | 57 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password }) |
59 | userAccessToken2 = await userLogin(servers[0], { username, password }) | 58 | userAccessToken2 = await userLogin(servers[0], { username, password }) |
60 | } | 59 | } |
61 | 60 | ||
@@ -120,7 +119,7 @@ describe('Test video blacklist API validators', function () { | |||
120 | 119 | ||
121 | it('Should succeed with the correct params', async function () { | 120 | it('Should succeed with the correct params', async function () { |
122 | const path = basePath + servers[0].video.uuid + '/blacklist' | 121 | const path = basePath + servers[0].video.uuid + '/blacklist' |
123 | const fields = { } | 122 | const fields = {} |
124 | 123 | ||
125 | await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 }) | 124 | await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 }) |
126 | }) | 125 | }) |
diff --git a/server/tests/api/check-params/video-captions.ts b/server/tests/api/check-params/video-captions.ts index 6ddc20d69..a5f5c3322 100644 --- a/server/tests/api/check-params/video-captions.ts +++ b/server/tests/api/check-params/video-captions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -50,7 +50,7 @@ describe('Test video captions API validator', function () { | |||
50 | describe('When adding video caption', function () { | 50 | describe('When adding video caption', function () { |
51 | const fields = { } | 51 | const fields = { } |
52 | const attaches = { | 52 | const attaches = { |
53 | 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') | 53 | captionfile: join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt') |
54 | } | 54 | } |
55 | 55 | ||
56 | it('Should fail without a valid uuid', async function () { | 56 | it('Should fail without a valid uuid', async function () { |
diff --git a/server/tests/api/check-params/video-channels.ts b/server/tests/api/check-params/video-channels.ts index de88298d1..2795ad7d5 100644 --- a/server/tests/api/check-params/video-channels.ts +++ b/server/tests/api/check-params/video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
@@ -243,7 +243,7 @@ describe('Test video channels API validator', function () { | |||
243 | it('Should fail with an incorrect input file', async function () { | 243 | it('Should fail with an incorrect input file', async function () { |
244 | const fields = {} | 244 | const fields = {} |
245 | const attaches = { | 245 | const attaches = { |
246 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') | 246 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4') |
247 | } | 247 | } |
248 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) | 248 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) |
249 | }) | 249 | }) |
@@ -251,7 +251,7 @@ describe('Test video channels API validator', function () { | |||
251 | it('Should fail with a big file', async function () { | 251 | it('Should fail with a big file', async function () { |
252 | const fields = {} | 252 | const fields = {} |
253 | const attaches = { | 253 | const attaches = { |
254 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 254 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
255 | } | 255 | } |
256 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) | 256 | await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches }) |
257 | }) | 257 | }) |
@@ -259,7 +259,7 @@ describe('Test video channels API validator', function () { | |||
259 | it('Should fail with an unauthenticated user', async function () { | 259 | it('Should fail with an unauthenticated user', async function () { |
260 | const fields = {} | 260 | const fields = {} |
261 | const attaches = { | 261 | const attaches = { |
262 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 262 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
263 | } | 263 | } |
264 | await makeUploadRequest({ | 264 | await makeUploadRequest({ |
265 | url: server.url, | 265 | url: server.url, |
@@ -273,7 +273,7 @@ describe('Test video channels API validator', function () { | |||
273 | it('Should succeed with the correct params', async function () { | 273 | it('Should succeed with the correct params', async function () { |
274 | const fields = {} | 274 | const fields = {} |
275 | const attaches = { | 275 | const attaches = { |
276 | 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 276 | avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
277 | } | 277 | } |
278 | await makeUploadRequest({ | 278 | await makeUploadRequest({ |
279 | url: server.url, | 279 | url: server.url, |
@@ -324,7 +324,7 @@ describe('Test video channels API validator', function () { | |||
324 | }) | 324 | }) |
325 | 325 | ||
326 | it('Should fail with an unknown video channel id', async function () { | 326 | it('Should fail with an unknown video channel id', async function () { |
327 | await deleteVideoChannel(server.url, server.accessToken,'super_channel2', 404) | 327 | await deleteVideoChannel(server.url, server.accessToken, 'super_channel2', 404) |
328 | }) | 328 | }) |
329 | 329 | ||
330 | it('Should succeed with the correct parameters', async function () { | 330 | it('Should succeed with the correct parameters', async function () { |
diff --git a/server/tests/api/check-params/video-comments.ts b/server/tests/api/check-params/video-comments.ts index 5cf90bacc..e67cc01fa 100644 --- a/server/tests/api/check-params/video-comments.ts +++ b/server/tests/api/check-params/video-comments.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts index 231d5cc85..dbea39c48 100644 --- a/server/tests/api/check-params/video-imports.ts +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -29,6 +29,7 @@ describe('Test video imports API validator', function () { | |||
29 | const path = '/api/v1/videos/imports' | 29 | const path = '/api/v1/videos/imports' |
30 | let server: ServerInfo | 30 | let server: ServerInfo |
31 | let userAccessToken = '' | 31 | let userAccessToken = '' |
32 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
32 | let accountName: string | 33 | let accountName: string |
33 | let channelId: number | 34 | let channelId: number |
34 | 35 | ||
@@ -48,7 +49,7 @@ describe('Test video imports API validator', function () { | |||
48 | 49 | ||
49 | { | 50 | { |
50 | const res = await getMyUserInformation(server.url, server.accessToken) | 51 | const res = await getMyUserInformation(server.url, server.accessToken) |
51 | channelId = res.body.videoChannels[ 0 ].id | 52 | channelId = res.body.videoChannels[0].id |
52 | accountName = res.body.account.name + '@' + res.body.account.host | 53 | accountName = res.body.account.name + '@' + res.body.account.host |
53 | } | 54 | } |
54 | }) | 55 | }) |
@@ -196,7 +197,7 @@ describe('Test video imports API validator', function () { | |||
196 | it('Should fail with an incorrect thumbnail file', async function () { | 197 | it('Should fail with an incorrect thumbnail file', async function () { |
197 | const fields = baseCorrectParams | 198 | const fields = baseCorrectParams |
198 | const attaches = { | 199 | const attaches = { |
199 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 200 | thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
200 | } | 201 | } |
201 | 202 | ||
202 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 203 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -205,7 +206,7 @@ describe('Test video imports API validator', function () { | |||
205 | it('Should fail with a big thumbnail file', async function () { | 206 | it('Should fail with a big thumbnail file', async function () { |
206 | const fields = baseCorrectParams | 207 | const fields = baseCorrectParams |
207 | const attaches = { | 208 | const attaches = { |
208 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 209 | thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
209 | } | 210 | } |
210 | 211 | ||
211 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 212 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -214,7 +215,7 @@ describe('Test video imports API validator', function () { | |||
214 | it('Should fail with an incorrect preview file', async function () { | 215 | it('Should fail with an incorrect preview file', async function () { |
215 | const fields = baseCorrectParams | 216 | const fields = baseCorrectParams |
216 | const attaches = { | 217 | const attaches = { |
217 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | 218 | previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png') |
218 | } | 219 | } |
219 | 220 | ||
220 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 221 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -223,7 +224,7 @@ describe('Test video imports API validator', function () { | |||
223 | it('Should fail with a big preview file', async function () { | 224 | it('Should fail with a big preview file', async function () { |
224 | const fields = baseCorrectParams | 225 | const fields = baseCorrectParams |
225 | const attaches = { | 226 | const attaches = { |
226 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 227 | previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
227 | } | 228 | } |
228 | 229 | ||
229 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 230 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -232,7 +233,7 @@ describe('Test video imports API validator', function () { | |||
232 | it('Should fail with an invalid torrent file', async function () { | 233 | it('Should fail with an invalid torrent file', async function () { |
233 | const fields = omit(baseCorrectParams, 'targetUrl') | 234 | const fields = omit(baseCorrectParams, 'targetUrl') |
234 | const attaches = { | 235 | const attaches = { |
235 | 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | 236 | torrentfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') |
236 | } | 237 | } |
237 | 238 | ||
238 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | 239 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) |
@@ -303,7 +304,7 @@ describe('Test video imports API validator', function () { | |||
303 | 304 | ||
304 | fields = omit(fields, 'magnetUri') | 305 | fields = omit(fields, 'magnetUri') |
305 | const attaches = { | 306 | const attaches = { |
306 | 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') | 307 | torrentfile: join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent') |
307 | } | 308 | } |
308 | 309 | ||
309 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 }) | 310 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 }) |
diff --git a/server/tests/api/check-params/video-playlists.ts b/server/tests/api/check-params/video-playlists.ts index df158f3b1..0410e737a 100644 --- a/server/tests/api/check-params/video-playlists.ts +++ b/server/tests/api/check-params/video-playlists.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
@@ -36,6 +36,7 @@ describe('Test video playlists API validator', function () { | |||
36 | let privatePlaylistUUID: string | 36 | let privatePlaylistUUID: string |
37 | let watchLaterPlaylistId: number | 37 | let watchLaterPlaylistId: number |
38 | let videoId: number | 38 | let videoId: number |
39 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
39 | let videoId2: number | 40 | let videoId2: number |
40 | let playlistElementId: number | 41 | let playlistElementId: number |
41 | 42 | ||
@@ -449,7 +450,7 @@ describe('Test video playlists API validator', function () { | |||
449 | videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id | 450 | videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id |
450 | videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id | 451 | videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id |
451 | 452 | ||
452 | for (let id of [ videoId3, videoId4 ]) { | 453 | for (const id of [ videoId3, videoId4 ]) { |
453 | await addVideoInPlaylist({ | 454 | await addVideoInPlaylist({ |
454 | url: server.url, | 455 | url: server.url, |
455 | token: server.accessToken, | 456 | token: server.accessToken, |
@@ -476,7 +477,7 @@ describe('Test video playlists API validator', function () { | |||
476 | } | 477 | } |
477 | 478 | ||
478 | { | 479 | { |
479 | const params = getBase({}, { playlistId: 42, expectedStatus: 404 }) | 480 | const params = getBase({}, { playlistId: 42, expectedStatus: 404 }) |
480 | await reorderVideosPlaylist(params) | 481 | await reorderVideosPlaylist(params) |
481 | } | 482 | } |
482 | }) | 483 | }) |
diff --git a/server/tests/api/check-params/videos-filter.ts b/server/tests/api/check-params/videos-filter.ts index 811756745..ec8654db2 100644 --- a/server/tests/api/check-params/videos-filter.ts +++ b/server/tests/api/check-params/videos-filter.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
5 | cleanupTests, | 5 | cleanupTests, |
6 | createUser, | 6 | createUser, |
7 | createVideoPlaylist, | ||
8 | flushAndRunServer, | 7 | flushAndRunServer, |
9 | makeGetRequest, | 8 | makeGetRequest, |
10 | ServerInfo, | 9 | ServerInfo, |
@@ -13,7 +12,6 @@ import { | |||
13 | userLogin | 12 | userLogin |
14 | } from '../../../../shared/extra-utils' | 13 | } from '../../../../shared/extra-utils' |
15 | import { UserRole } from '../../../../shared/models/users' | 14 | import { UserRole } from '../../../../shared/models/users' |
16 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | ||
17 | 15 | ||
18 | async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) { | 16 | async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) { |
19 | const paths = [ | 17 | const paths = [ |
@@ -77,7 +75,7 @@ describe('Test videos filters', function () { | |||
77 | }) | 75 | }) |
78 | 76 | ||
79 | it('Should succeed with a good filter', async function () { | 77 | it('Should succeed with a good filter', async function () { |
80 | await testEndpoints(server, server.accessToken,'local', 200) | 78 | await testEndpoints(server, server.accessToken, 'local', 200) |
81 | }) | 79 | }) |
82 | 80 | ||
83 | it('Should fail to list all-local with a simple user', async function () { | 81 | it('Should fail to list all-local with a simple user', async function () { |
diff --git a/server/tests/api/check-params/videos-history.ts b/server/tests/api/check-params/videos-history.ts index 3739e3fad..941f62654 100644 --- a/server/tests/api/check-params/videos-history.ts +++ b/server/tests/api/check-params/videos-history.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | 3 | import 'mocha' |
5 | import { | 4 | import { |
6 | checkBadCountPagination, | 5 | checkBadCountPagination, |
@@ -15,12 +14,10 @@ import { | |||
15 | uploadVideo | 14 | uploadVideo |
16 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
17 | 16 | ||
18 | const expect = chai.expect | ||
19 | |||
20 | describe('Test videos history API validator', function () { | 17 | describe('Test videos history API validator', function () { |
18 | const myHistoryPath = '/api/v1/users/me/history/videos' | ||
19 | const myHistoryRemove = myHistoryPath + '/remove' | ||
21 | let watchingPath: string | 20 | let watchingPath: string |
22 | let myHistoryPath = '/api/v1/users/me/history/videos' | ||
23 | let myHistoryRemove = myHistoryPath + '/remove' | ||
24 | let server: ServerInfo | 21 | let server: ServerInfo |
25 | 22 | ||
26 | // --------------------------------------------------------------- | 23 | // --------------------------------------------------------------- |
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 16ef1c505..0d4665954 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { omit } from 'lodash' | 4 | import { omit } from 'lodash' |
@@ -56,8 +56,8 @@ describe('Test videos API validator', function () { | |||
56 | 56 | ||
57 | { | 57 | { |
58 | const res = await getMyUserInformation(server.url, server.accessToken) | 58 | const res = await getMyUserInformation(server.url, server.accessToken) |
59 | channelId = res.body.videoChannels[ 0 ].id | 59 | channelId = res.body.videoChannels[0].id |
60 | channelName = res.body.videoChannels[ 0 ].name | 60 | channelName = res.body.videoChannels[0].name |
61 | accountName = res.body.account.name + '@' + res.body.account.host | 61 | accountName = res.body.account.name + '@' + res.body.account.host |
62 | } | 62 | } |
63 | }) | 63 | }) |
@@ -182,7 +182,7 @@ describe('Test videos API validator', function () { | |||
182 | describe('When adding a video', function () { | 182 | describe('When adding a video', function () { |
183 | let baseCorrectParams | 183 | let baseCorrectParams |
184 | const baseCorrectAttaches = { | 184 | const baseCorrectAttaches = { |
185 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') | 185 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm') |
186 | } | 186 | } |
187 | 187 | ||
188 | before(function () { | 188 | before(function () { |
@@ -330,7 +330,7 @@ describe('Test videos API validator', function () { | |||
330 | }) | 330 | }) |
331 | 331 | ||
332 | it('Should fail with a bad originally published at attribute', async function () { | 332 | it('Should fail with a bad originally published at attribute', async function () { |
333 | const fields = immutableAssign(baseCorrectParams, { 'originallyPublishedAt': 'toto' }) | 333 | const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' }) |
334 | const attaches = baseCorrectAttaches | 334 | const attaches = baseCorrectAttaches |
335 | 335 | ||
336 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 336 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -345,12 +345,12 @@ describe('Test videos API validator', function () { | |||
345 | it('Should fail with an incorrect input file', async function () { | 345 | it('Should fail with an incorrect input file', async function () { |
346 | const fields = baseCorrectParams | 346 | const fields = baseCorrectParams |
347 | let attaches = { | 347 | let attaches = { |
348 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') | 348 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm') |
349 | } | 349 | } |
350 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 350 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
351 | 351 | ||
352 | attaches = { | 352 | attaches = { |
353 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') | 353 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv') |
354 | } | 354 | } |
355 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 355 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
356 | }) | 356 | }) |
@@ -358,8 +358,8 @@ describe('Test videos API validator', function () { | |||
358 | it('Should fail with an incorrect thumbnail file', async function () { | 358 | it('Should fail with an incorrect thumbnail file', async function () { |
359 | const fields = baseCorrectParams | 359 | const fields = baseCorrectParams |
360 | const attaches = { | 360 | const attaches = { |
361 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), | 361 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), |
362 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 362 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
363 | } | 363 | } |
364 | 364 | ||
365 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 365 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -368,8 +368,8 @@ describe('Test videos API validator', function () { | |||
368 | it('Should fail with a big thumbnail file', async function () { | 368 | it('Should fail with a big thumbnail file', async function () { |
369 | const fields = baseCorrectParams | 369 | const fields = baseCorrectParams |
370 | const attaches = { | 370 | const attaches = { |
371 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), | 371 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), |
372 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 372 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
373 | } | 373 | } |
374 | 374 | ||
375 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 375 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -378,8 +378,8 @@ describe('Test videos API validator', function () { | |||
378 | it('Should fail with an incorrect preview file', async function () { | 378 | it('Should fail with an incorrect preview file', async function () { |
379 | const fields = baseCorrectParams | 379 | const fields = baseCorrectParams |
380 | const attaches = { | 380 | const attaches = { |
381 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), | 381 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'), |
382 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 382 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
383 | } | 383 | } |
384 | 384 | ||
385 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 385 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -388,8 +388,8 @@ describe('Test videos API validator', function () { | |||
388 | it('Should fail with a big preview file', async function () { | 388 | it('Should fail with a big preview file', async function () { |
389 | const fields = baseCorrectParams | 389 | const fields = baseCorrectParams |
390 | const attaches = { | 390 | const attaches = { |
391 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), | 391 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'), |
392 | 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') | 392 | videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4') |
393 | } | 393 | } |
394 | 394 | ||
395 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) | 395 | await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches }) |
@@ -566,7 +566,7 @@ describe('Test videos API validator', function () { | |||
566 | it('Should fail with an incorrect thumbnail file', async function () { | 566 | it('Should fail with an incorrect thumbnail file', async function () { |
567 | const fields = baseCorrectParams | 567 | const fields = baseCorrectParams |
568 | const attaches = { | 568 | const attaches = { |
569 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') | 569 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png') |
570 | } | 570 | } |
571 | 571 | ||
572 | await makeUploadRequest({ | 572 | await makeUploadRequest({ |
@@ -582,7 +582,7 @@ describe('Test videos API validator', function () { | |||
582 | it('Should fail with a big thumbnail file', async function () { | 582 | it('Should fail with a big thumbnail file', async function () { |
583 | const fields = baseCorrectParams | 583 | const fields = baseCorrectParams |
584 | const attaches = { | 584 | const attaches = { |
585 | 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') | 585 | thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') |
586 | } | 586 | } |
587 | 587 | ||
588 | await makeUploadRequest({ | 588 | await makeUploadRequest({ |
@@ -598,7 +598,7 @@ describe('Test videos API validator', function () { | |||
598 | it('Should fail with an incorrect preview file', async function () { | 598 | it('Should fail with an incorrect preview file', async function () { |
599 | const fields = baseCorrectParams | 599 | const fields = baseCorrectParams |
600 | const attaches = { | 600 | const attaches = { |
601 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png') | 601 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png') |
602 | } | 602 | } |
603 | 603 | ||
604 | await makeUploadRequest({ | 604 | await makeUploadRequest({ |
@@ -614,7 +614,7 @@ describe('Test videos API validator', function () { | |||
614 | it('Should fail with a big preview file', async function () { | 614 | it('Should fail with a big preview file', async function () { |
615 | const fields = baseCorrectParams | 615 | const fields = baseCorrectParams |
616 | const attaches = { | 616 | const attaches = { |
617 | 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') | 617 | previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png') |
618 | } | 618 | } |
619 | 619 | ||
620 | await makeUploadRequest({ | 620 | await makeUploadRequest({ |
diff --git a/server/tests/api/notifications/user-notifications.ts b/server/tests/api/notifications/user-notifications.ts index 15a34f5aa..2a632e16f 100644 --- a/server/tests/api/notifications/user-notifications.ts +++ b/server/tests/api/notifications/user-notifications.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -74,7 +74,7 @@ async function uploadVideoByRemoteAccount (servers: ServerInfo[], additionalPara | |||
74 | const name = 'remote video ' + uuidv4() | 74 | const name = 'remote video ' + uuidv4() |
75 | 75 | ||
76 | const data = Object.assign({ name }, additionalParams) | 76 | const data = Object.assign({ name }, additionalParams) |
77 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data) | 77 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, data) |
78 | 78 | ||
79 | await waitJobs(servers) | 79 | await waitJobs(servers) |
80 | 80 | ||
@@ -85,7 +85,7 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam | |||
85 | const name = 'local video ' + uuidv4() | 85 | const name = 'local video ' + uuidv4() |
86 | 86 | ||
87 | const data = Object.assign({ name }, additionalParams) | 87 | const data = Object.assign({ name }, additionalParams) |
88 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data) | 88 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, data) |
89 | 89 | ||
90 | await waitJobs(servers) | 90 | await waitJobs(servers) |
91 | 91 | ||
@@ -95,9 +95,9 @@ async function uploadVideoByLocalAccount (servers: ServerInfo[], additionalParam | |||
95 | describe('Test users notifications', function () { | 95 | describe('Test users notifications', function () { |
96 | let servers: ServerInfo[] = [] | 96 | let servers: ServerInfo[] = [] |
97 | let userAccessToken: string | 97 | let userAccessToken: string |
98 | let userNotifications: UserNotification[] = [] | 98 | const userNotifications: UserNotification[] = [] |
99 | let adminNotifications: UserNotification[] = [] | 99 | const adminNotifications: UserNotification[] = [] |
100 | let adminNotificationsServer2: UserNotification[] = [] | 100 | const adminNotificationsServer2: UserNotification[] = [] |
101 | const emails: object[] = [] | 101 | const emails: object[] = [] |
102 | let channelId: number | 102 | let channelId: number |
103 | 103 | ||
@@ -142,8 +142,8 @@ describe('Test users notifications', function () { | |||
142 | password: 'super password' | 142 | password: 'super password' |
143 | } | 143 | } |
144 | await createUser({ | 144 | await createUser({ |
145 | url: servers[ 0 ].url, | 145 | url: servers[0].url, |
146 | accessToken: servers[ 0 ].accessToken, | 146 | accessToken: servers[0].accessToken, |
147 | username: user.username, | 147 | username: user.username, |
148 | password: user.password, | 148 | password: user.password, |
149 | videoQuota: 10 * 1000 * 1000 | 149 | videoQuota: 10 * 1000 * 1000 |
@@ -155,15 +155,15 @@ describe('Test users notifications', function () { | |||
155 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) | 155 | await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings) |
156 | 156 | ||
157 | { | 157 | { |
158 | const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken) | 158 | const socket = getUserNotificationSocket(servers[0].url, userAccessToken) |
159 | socket.on('new-notification', n => userNotifications.push(n)) | 159 | socket.on('new-notification', n => userNotifications.push(n)) |
160 | } | 160 | } |
161 | { | 161 | { |
162 | const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken) | 162 | const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken) |
163 | socket.on('new-notification', n => adminNotifications.push(n)) | 163 | socket.on('new-notification', n => adminNotifications.push(n)) |
164 | } | 164 | } |
165 | { | 165 | { |
166 | const socket = getUserNotificationSocket(servers[ 1 ].url, servers[1].accessToken) | 166 | const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken) |
167 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) | 167 | socket.on('new-notification', n => adminNotificationsServer2.push(n)) |
168 | } | 168 | } |
169 | 169 | ||
@@ -190,7 +190,7 @@ describe('Test users notifications', function () { | |||
190 | 190 | ||
191 | await uploadVideoByLocalAccount(servers) | 191 | await uploadVideoByLocalAccount(servers) |
192 | 192 | ||
193 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | 193 | const notification = await getLastNotification(servers[0].url, userAccessToken) |
194 | expect(notification).to.be.undefined | 194 | expect(notification).to.be.undefined |
195 | 195 | ||
196 | expect(emails).to.have.lengthOf(0) | 196 | expect(emails).to.have.lengthOf(0) |
@@ -221,7 +221,7 @@ describe('Test users notifications', function () { | |||
221 | this.timeout(20000) | 221 | this.timeout(20000) |
222 | 222 | ||
223 | // In 2 seconds | 223 | // In 2 seconds |
224 | let updateAt = new Date(new Date().getTime() + 2000) | 224 | const updateAt = new Date(new Date().getTime() + 2000) |
225 | 225 | ||
226 | const data = { | 226 | const data = { |
227 | privacy: VideoPrivacy.PRIVATE, | 227 | privacy: VideoPrivacy.PRIVATE, |
@@ -240,7 +240,7 @@ describe('Test users notifications', function () { | |||
240 | this.timeout(50000) | 240 | this.timeout(50000) |
241 | 241 | ||
242 | // In 2 seconds | 242 | // In 2 seconds |
243 | let updateAt = new Date(new Date().getTime() + 2000) | 243 | const updateAt = new Date(new Date().getTime() + 2000) |
244 | 244 | ||
245 | const data = { | 245 | const data = { |
246 | privacy: VideoPrivacy.PRIVATE, | 246 | privacy: VideoPrivacy.PRIVATE, |
@@ -259,7 +259,7 @@ describe('Test users notifications', function () { | |||
259 | it('Should not send a notification before the video is published', async function () { | 259 | it('Should not send a notification before the video is published', async function () { |
260 | this.timeout(20000) | 260 | this.timeout(20000) |
261 | 261 | ||
262 | let updateAt = new Date(new Date().getTime() + 1000000) | 262 | const updateAt = new Date(new Date().getTime() + 1000000) |
263 | 263 | ||
264 | const data = { | 264 | const data = { |
265 | privacy: VideoPrivacy.PRIVATE, | 265 | privacy: VideoPrivacy.PRIVATE, |
@@ -386,7 +386,7 @@ describe('Test users notifications', function () { | |||
386 | it('Should not send a new comment notification if the account is muted', async function () { | 386 | it('Should not send a new comment notification if the account is muted', async function () { |
387 | this.timeout(10000) | 387 | this.timeout(10000) |
388 | 388 | ||
389 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 389 | await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root') |
390 | 390 | ||
391 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) | 391 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' }) |
392 | const uuid = resVideo.body.video.uuid | 392 | const uuid = resVideo.body.video.uuid |
@@ -397,7 +397,7 @@ describe('Test users notifications', function () { | |||
397 | await wait(500) | 397 | await wait(500) |
398 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') | 398 | await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence') |
399 | 399 | ||
400 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 400 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root') |
401 | }) | 401 | }) |
402 | 402 | ||
403 | it('Should send a new comment notification after a local comment on my video', async function () { | 403 | it('Should send a new comment notification after a local comment on my video', async function () { |
@@ -456,9 +456,9 @@ describe('Test users notifications', function () { | |||
456 | await waitJobs(servers) | 456 | await waitJobs(servers) |
457 | 457 | ||
458 | { | 458 | { |
459 | const resThread = await addVideoCommentThread(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, 'comment') | 459 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'comment') |
460 | const threadId = resThread.body.comment.id | 460 | const threadId = resThread.body.comment.id |
461 | await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, threadId, 'reply') | 461 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, threadId, 'reply') |
462 | } | 462 | } |
463 | 463 | ||
464 | await waitJobs(servers) | 464 | await waitJobs(servers) |
@@ -530,7 +530,7 @@ describe('Test users notifications', function () { | |||
530 | it('Should not send a new mention notification if the account is muted', async function () { | 530 | it('Should not send a new mention notification if the account is muted', async function () { |
531 | this.timeout(10000) | 531 | this.timeout(10000) |
532 | 532 | ||
533 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 533 | await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root') |
534 | 534 | ||
535 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) | 535 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) |
536 | const uuid = resVideo.body.video.uuid | 536 | const uuid = resVideo.body.video.uuid |
@@ -541,7 +541,7 @@ describe('Test users notifications', function () { | |||
541 | await wait(500) | 541 | await wait(500) |
542 | await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence') | 542 | await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence') |
543 | 543 | ||
544 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 544 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root') |
545 | }) | 545 | }) |
546 | 546 | ||
547 | it('Should not send a new mention notification if the remote account mention a local account', async function () { | 547 | it('Should not send a new mention notification if the remote account mention a local account', async function () { |
@@ -585,7 +585,7 @@ describe('Test users notifications', function () { | |||
585 | 585 | ||
586 | await waitJobs(servers) | 586 | await waitJobs(servers) |
587 | 587 | ||
588 | const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1` | 588 | const text1 = `hello @user_1@localhost:${servers[0].port} 1` |
589 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) | 589 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1) |
590 | const server2ThreadId = resThread.body.comment.id | 590 | const server2ThreadId = resThread.body.comment.id |
591 | 591 | ||
@@ -596,7 +596,7 @@ describe('Test users notifications', function () { | |||
596 | const server1ThreadId = resThread2.body.data[0].id | 596 | const server1ThreadId = resThread2.body.data[0].id |
597 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') | 597 | await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence') |
598 | 598 | ||
599 | const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}` | 599 | const text2 = `@user_1@localhost:${servers[0].port} hello 2 @root@localhost:${servers[0].port}` |
600 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) | 600 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2) |
601 | 601 | ||
602 | await waitJobs(servers) | 602 | await waitJobs(servers) |
@@ -611,7 +611,7 @@ describe('Test users notifications', function () { | |||
611 | }) | 611 | }) |
612 | }) | 612 | }) |
613 | 613 | ||
614 | describe('Video abuse for moderators notification' , function () { | 614 | describe('Video abuse for moderators notification', function () { |
615 | let baseParams: CheckerBaseParams | 615 | let baseParams: CheckerBaseParams |
616 | 616 | ||
617 | before(() => { | 617 | before(() => { |
@@ -722,7 +722,7 @@ describe('Test users notifications', function () { | |||
722 | await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) | 722 | await uploadVideoByRemoteAccount(servers, { waitTranscoding: false }) |
723 | await waitJobs(servers) | 723 | await waitJobs(servers) |
724 | 724 | ||
725 | const notification = await getLastNotification(servers[ 0 ].url, userAccessToken) | 725 | const notification = await getLastNotification(servers[0].url, userAccessToken) |
726 | if (notification) { | 726 | if (notification) { |
727 | expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) | 727 | expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED) |
728 | } | 728 | } |
@@ -769,7 +769,7 @@ describe('Test users notifications', function () { | |||
769 | this.timeout(70000) | 769 | this.timeout(70000) |
770 | 770 | ||
771 | // In 2 seconds | 771 | // In 2 seconds |
772 | let updateAt = new Date(new Date().getTime() + 2000) | 772 | const updateAt = new Date(new Date().getTime() + 2000) |
773 | 773 | ||
774 | const data = { | 774 | const data = { |
775 | privacy: VideoPrivacy.PRIVATE, | 775 | privacy: VideoPrivacy.PRIVATE, |
@@ -787,7 +787,7 @@ describe('Test users notifications', function () { | |||
787 | it('Should not send a notification before the video is published', async function () { | 787 | it('Should not send a notification before the video is published', async function () { |
788 | this.timeout(20000) | 788 | this.timeout(20000) |
789 | 789 | ||
790 | let updateAt = new Date(new Date().getTime() + 1000000) | 790 | const updateAt = new Date(new Date().getTime() + 1000000) |
791 | 791 | ||
792 | const data = { | 792 | const data = { |
793 | privacy: VideoPrivacy.PRIVATE, | 793 | privacy: VideoPrivacy.PRIVATE, |
@@ -970,8 +970,8 @@ describe('Test users notifications', function () { | |||
970 | 970 | ||
971 | describe('New actor follow', function () { | 971 | describe('New actor follow', function () { |
972 | let baseParams: CheckerBaseParams | 972 | let baseParams: CheckerBaseParams |
973 | let myChannelName = 'super channel name' | 973 | const myChannelName = 'super channel name' |
974 | let myUserName = 'super user name' | 974 | const myUserName = 'super user name' |
975 | 975 | ||
976 | before(async () => { | 976 | before(async () => { |
977 | baseParams = { | 977 | baseParams = { |
@@ -1143,7 +1143,7 @@ describe('Test users notifications', function () { | |||
1143 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { | 1143 | it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () { |
1144 | this.timeout(20000) | 1144 | this.timeout(20000) |
1145 | 1145 | ||
1146 | let updateAt = new Date(new Date().getTime() + 1000000) | 1146 | const updateAt = new Date(new Date().getTime() + 1000000) |
1147 | 1147 | ||
1148 | const name = 'video with auto-blacklist and future schedule ' + uuidv4() | 1148 | const name = 'video with auto-blacklist and future schedule ' + uuidv4() |
1149 | 1149 | ||
@@ -1176,7 +1176,7 @@ describe('Test users notifications', function () { | |||
1176 | this.timeout(20000) | 1176 | this.timeout(20000) |
1177 | 1177 | ||
1178 | // In 2 seconds | 1178 | // In 2 seconds |
1179 | let updateAt = new Date(new Date().getTime() + 2000) | 1179 | const updateAt = new Date(new Date().getTime() + 2000) |
1180 | 1180 | ||
1181 | const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() | 1181 | const name = 'video with schedule done and still auto-blacklisted ' + uuidv4() |
1182 | 1182 | ||
@@ -1221,26 +1221,26 @@ describe('Test users notifications', function () { | |||
1221 | 1221 | ||
1222 | describe('Mark as read', function () { | 1222 | describe('Mark as read', function () { |
1223 | it('Should mark as read some notifications', async function () { | 1223 | it('Should mark as read some notifications', async function () { |
1224 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 2, 3) | 1224 | const res = await getUserNotifications(servers[0].url, userAccessToken, 2, 3) |
1225 | const ids = res.body.data.map(n => n.id) | 1225 | const ids = res.body.data.map(n => n.id) |
1226 | 1226 | ||
1227 | await markAsReadNotifications(servers[ 0 ].url, userAccessToken, ids) | 1227 | await markAsReadNotifications(servers[0].url, userAccessToken, ids) |
1228 | }) | 1228 | }) |
1229 | 1229 | ||
1230 | it('Should have the notifications marked as read', async function () { | 1230 | it('Should have the notifications marked as read', async function () { |
1231 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10) | 1231 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10) |
1232 | 1232 | ||
1233 | const notifications = res.body.data as UserNotification[] | 1233 | const notifications = res.body.data as UserNotification[] |
1234 | expect(notifications[ 0 ].read).to.be.false | 1234 | expect(notifications[0].read).to.be.false |
1235 | expect(notifications[ 1 ].read).to.be.false | 1235 | expect(notifications[1].read).to.be.false |
1236 | expect(notifications[ 2 ].read).to.be.true | 1236 | expect(notifications[2].read).to.be.true |
1237 | expect(notifications[ 3 ].read).to.be.true | 1237 | expect(notifications[3].read).to.be.true |
1238 | expect(notifications[ 4 ].read).to.be.true | 1238 | expect(notifications[4].read).to.be.true |
1239 | expect(notifications[ 5 ].read).to.be.false | 1239 | expect(notifications[5].read).to.be.false |
1240 | }) | 1240 | }) |
1241 | 1241 | ||
1242 | it('Should only list read notifications', async function () { | 1242 | it('Should only list read notifications', async function () { |
1243 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, false) | 1243 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, false) |
1244 | 1244 | ||
1245 | const notifications = res.body.data as UserNotification[] | 1245 | const notifications = res.body.data as UserNotification[] |
1246 | for (const notification of notifications) { | 1246 | for (const notification of notifications) { |
@@ -1249,7 +1249,7 @@ describe('Test users notifications', function () { | |||
1249 | }) | 1249 | }) |
1250 | 1250 | ||
1251 | it('Should only list unread notifications', async function () { | 1251 | it('Should only list unread notifications', async function () { |
1252 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) | 1252 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true) |
1253 | 1253 | ||
1254 | const notifications = res.body.data as UserNotification[] | 1254 | const notifications = res.body.data as UserNotification[] |
1255 | for (const notification of notifications) { | 1255 | for (const notification of notifications) { |
@@ -1258,9 +1258,9 @@ describe('Test users notifications', function () { | |||
1258 | }) | 1258 | }) |
1259 | 1259 | ||
1260 | it('Should mark as read all notifications', async function () { | 1260 | it('Should mark as read all notifications', async function () { |
1261 | await markAsReadAllNotifications(servers[ 0 ].url, userAccessToken) | 1261 | await markAsReadAllNotifications(servers[0].url, userAccessToken) |
1262 | 1262 | ||
1263 | const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true) | 1263 | const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true) |
1264 | 1264 | ||
1265 | expect(res.body.total).to.equal(0) | 1265 | expect(res.body.total).to.equal(0) |
1266 | expect(res.body.data).to.have.lengthOf(0) | 1266 | expect(res.body.data).to.have.lengthOf(0) |
diff --git a/server/tests/api/redundancy/index.ts b/server/tests/api/redundancy/index.ts index 8e69b95a6..5359055b0 100644 --- a/server/tests/api/redundancy/index.ts +++ b/server/tests/api/redundancy/index.ts | |||
@@ -1 +1,2 @@ | |||
1 | import './redundancy' | 1 | import './redundancy' |
2 | import './manage-redundancy' | ||
diff --git a/server/tests/api/redundancy/manage-redundancy.ts b/server/tests/api/redundancy/manage-redundancy.ts new file mode 100644 index 000000000..4253124c8 --- /dev/null +++ b/server/tests/api/redundancy/manage-redundancy.ts | |||
@@ -0,0 +1,373 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | ||
5 | import { | ||
6 | cleanupTests, | ||
7 | doubleFollow, | ||
8 | flushAndRunMultipleServers, | ||
9 | getLocalIdByUUID, | ||
10 | ServerInfo, | ||
11 | setAccessTokensToServers, | ||
12 | uploadVideo, | ||
13 | uploadVideoAndGetId, | ||
14 | waitUntilLog | ||
15 | } from '../../../../shared/extra-utils' | ||
16 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | ||
17 | import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy, updateRedundancy } from '@shared/extra-utils/server/redundancy' | ||
18 | import { VideoPrivacy, VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
19 | |||
20 | const expect = chai.expect | ||
21 | |||
22 | describe('Test manage videos redundancy', function () { | ||
23 | const targets: VideoRedundanciesTarget[] = [ 'my-videos', 'remote-videos' ] | ||
24 | |||
25 | let servers: ServerInfo[] | ||
26 | let video1Server2UUID: string | ||
27 | let video2Server2UUID: string | ||
28 | let redundanciesToRemove: number[] = [] | ||
29 | |||
30 | before(async function () { | ||
31 | this.timeout(120000) | ||
32 | |||
33 | const config = { | ||
34 | transcoding: { | ||
35 | hls: { | ||
36 | enabled: true | ||
37 | } | ||
38 | }, | ||
39 | redundancy: { | ||
40 | videos: { | ||
41 | check_interval: '1 second', | ||
42 | strategies: [ | ||
43 | { | ||
44 | strategy: 'recently-added', | ||
45 | min_lifetime: '1 hour', | ||
46 | size: '10MB', | ||
47 | min_views: 0 | ||
48 | } | ||
49 | ] | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | servers = await flushAndRunMultipleServers(3, config) | ||
54 | |||
55 | // Get the access tokens | ||
56 | await setAccessTokensToServers(servers) | ||
57 | |||
58 | { | ||
59 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' }) | ||
60 | video1Server2UUID = res.body.video.uuid | ||
61 | } | ||
62 | |||
63 | { | ||
64 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' }) | ||
65 | video2Server2UUID = res.body.video.uuid | ||
66 | } | ||
67 | |||
68 | await waitJobs(servers) | ||
69 | |||
70 | // Server 1 and server 2 follow each other | ||
71 | await doubleFollow(servers[0], servers[1]) | ||
72 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true) | ||
73 | |||
74 | await waitJobs(servers) | ||
75 | }) | ||
76 | |||
77 | it('Should not have redundancies on server 3', async function () { | ||
78 | for (const target of targets) { | ||
79 | const res = await listVideoRedundancies({ | ||
80 | url: servers[2].url, | ||
81 | accessToken: servers[2].accessToken, | ||
82 | target | ||
83 | }) | ||
84 | |||
85 | expect(res.body.total).to.equal(0) | ||
86 | expect(res.body.data).to.have.lengthOf(0) | ||
87 | } | ||
88 | }) | ||
89 | |||
90 | it('Should not have "remote-videos" redundancies on server 2', async function () { | ||
91 | this.timeout(120000) | ||
92 | |||
93 | await waitJobs(servers) | ||
94 | await waitUntilLog(servers[0], 'Duplicated ', 10) | ||
95 | await waitJobs(servers) | ||
96 | |||
97 | const res = await listVideoRedundancies({ | ||
98 | url: servers[1].url, | ||
99 | accessToken: servers[1].accessToken, | ||
100 | target: 'remote-videos' | ||
101 | }) | ||
102 | |||
103 | expect(res.body.total).to.equal(0) | ||
104 | expect(res.body.data).to.have.lengthOf(0) | ||
105 | }) | ||
106 | |||
107 | it('Should have "my-videos" redundancies on server 2', async function () { | ||
108 | this.timeout(120000) | ||
109 | |||
110 | const res = await listVideoRedundancies({ | ||
111 | url: servers[1].url, | ||
112 | accessToken: servers[1].accessToken, | ||
113 | target: 'my-videos' | ||
114 | }) | ||
115 | |||
116 | expect(res.body.total).to.equal(2) | ||
117 | |||
118 | const videos = res.body.data as VideoRedundancy[] | ||
119 | expect(videos).to.have.lengthOf(2) | ||
120 | |||
121 | const videos1 = videos.find(v => v.uuid === video1Server2UUID) | ||
122 | const videos2 = videos.find(v => v.uuid === video2Server2UUID) | ||
123 | |||
124 | expect(videos1.name).to.equal('video 1 server 2') | ||
125 | expect(videos2.name).to.equal('video 2 server 2') | ||
126 | |||
127 | expect(videos1.redundancies.files).to.have.lengthOf(4) | ||
128 | expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
129 | |||
130 | const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) | ||
131 | |||
132 | for (const r of redundancies) { | ||
133 | expect(r.strategy).to.be.null | ||
134 | expect(r.fileUrl).to.exist | ||
135 | expect(r.createdAt).to.exist | ||
136 | expect(r.updatedAt).to.exist | ||
137 | expect(r.expiresOn).to.exist | ||
138 | } | ||
139 | }) | ||
140 | |||
141 | it('Should not have "my-videos" redundancies on server 1', async function () { | ||
142 | const res = await listVideoRedundancies({ | ||
143 | url: servers[0].url, | ||
144 | accessToken: servers[0].accessToken, | ||
145 | target: 'my-videos' | ||
146 | }) | ||
147 | |||
148 | expect(res.body.total).to.equal(0) | ||
149 | expect(res.body.data).to.have.lengthOf(0) | ||
150 | }) | ||
151 | |||
152 | it('Should have "remote-videos" redundancies on server 1', async function () { | ||
153 | this.timeout(120000) | ||
154 | |||
155 | const res = await listVideoRedundancies({ | ||
156 | url: servers[0].url, | ||
157 | accessToken: servers[0].accessToken, | ||
158 | target: 'remote-videos' | ||
159 | }) | ||
160 | |||
161 | expect(res.body.total).to.equal(2) | ||
162 | |||
163 | const videos = res.body.data as VideoRedundancy[] | ||
164 | expect(videos).to.have.lengthOf(2) | ||
165 | |||
166 | const videos1 = videos.find(v => v.uuid === video1Server2UUID) | ||
167 | const videos2 = videos.find(v => v.uuid === video2Server2UUID) | ||
168 | |||
169 | expect(videos1.name).to.equal('video 1 server 2') | ||
170 | expect(videos2.name).to.equal('video 2 server 2') | ||
171 | |||
172 | expect(videos1.redundancies.files).to.have.lengthOf(4) | ||
173 | expect(videos1.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
174 | |||
175 | const redundancies = videos1.redundancies.files.concat(videos1.redundancies.streamingPlaylists) | ||
176 | |||
177 | for (const r of redundancies) { | ||
178 | expect(r.strategy).to.equal('recently-added') | ||
179 | expect(r.fileUrl).to.exist | ||
180 | expect(r.createdAt).to.exist | ||
181 | expect(r.updatedAt).to.exist | ||
182 | expect(r.expiresOn).to.exist | ||
183 | } | ||
184 | }) | ||
185 | |||
186 | it('Should correctly paginate and sort results', async function () { | ||
187 | { | ||
188 | const res = await listVideoRedundancies({ | ||
189 | url: servers[0].url, | ||
190 | accessToken: servers[0].accessToken, | ||
191 | target: 'remote-videos', | ||
192 | sort: 'name', | ||
193 | start: 0, | ||
194 | count: 2 | ||
195 | }) | ||
196 | |||
197 | const videos = res.body.data | ||
198 | expect(videos[0].name).to.equal('video 1 server 2') | ||
199 | expect(videos[1].name).to.equal('video 2 server 2') | ||
200 | } | ||
201 | |||
202 | { | ||
203 | const res = await listVideoRedundancies({ | ||
204 | url: servers[0].url, | ||
205 | accessToken: servers[0].accessToken, | ||
206 | target: 'remote-videos', | ||
207 | sort: '-name', | ||
208 | start: 0, | ||
209 | count: 2 | ||
210 | }) | ||
211 | |||
212 | const videos = res.body.data | ||
213 | expect(videos[0].name).to.equal('video 2 server 2') | ||
214 | expect(videos[1].name).to.equal('video 1 server 2') | ||
215 | } | ||
216 | |||
217 | { | ||
218 | const res = await listVideoRedundancies({ | ||
219 | url: servers[0].url, | ||
220 | accessToken: servers[0].accessToken, | ||
221 | target: 'remote-videos', | ||
222 | sort: '-name', | ||
223 | start: 1, | ||
224 | count: 1 | ||
225 | }) | ||
226 | |||
227 | const videos = res.body.data | ||
228 | expect(videos[0].name).to.equal('video 1 server 2') | ||
229 | } | ||
230 | }) | ||
231 | |||
232 | it('Should manually add a redundancy and list it', async function () { | ||
233 | this.timeout(120000) | ||
234 | |||
235 | const uuid = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid | ||
236 | await waitJobs(servers) | ||
237 | const videoId = await getLocalIdByUUID(servers[0].url, uuid) | ||
238 | |||
239 | await addVideoRedundancy({ | ||
240 | url: servers[0].url, | ||
241 | accessToken: servers[0].accessToken, | ||
242 | videoId | ||
243 | }) | ||
244 | |||
245 | await waitJobs(servers) | ||
246 | await waitUntilLog(servers[0], 'Duplicated ', 15) | ||
247 | await waitJobs(servers) | ||
248 | |||
249 | { | ||
250 | const res = await listVideoRedundancies({ | ||
251 | url: servers[0].url, | ||
252 | accessToken: servers[0].accessToken, | ||
253 | target: 'remote-videos', | ||
254 | sort: '-name', | ||
255 | start: 0, | ||
256 | count: 5 | ||
257 | }) | ||
258 | |||
259 | const videos = res.body.data | ||
260 | expect(videos[0].name).to.equal('video 3 server 2') | ||
261 | |||
262 | const video = videos[0] | ||
263 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
264 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
265 | |||
266 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
267 | |||
268 | for (const r of redundancies) { | ||
269 | redundanciesToRemove.push(r.id) | ||
270 | |||
271 | expect(r.strategy).to.equal('manual') | ||
272 | expect(r.fileUrl).to.exist | ||
273 | expect(r.createdAt).to.exist | ||
274 | expect(r.updatedAt).to.exist | ||
275 | expect(r.expiresOn).to.be.null | ||
276 | } | ||
277 | } | ||
278 | |||
279 | const res = await listVideoRedundancies({ | ||
280 | url: servers[1].url, | ||
281 | accessToken: servers[1].accessToken, | ||
282 | target: 'my-videos', | ||
283 | sort: '-name', | ||
284 | start: 0, | ||
285 | count: 5 | ||
286 | }) | ||
287 | |||
288 | const videos = res.body.data | ||
289 | expect(videos[0].name).to.equal('video 3 server 2') | ||
290 | |||
291 | const video = videos[0] | ||
292 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
293 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
294 | |||
295 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
296 | |||
297 | for (const r of redundancies) { | ||
298 | expect(r.strategy).to.be.null | ||
299 | expect(r.fileUrl).to.exist | ||
300 | expect(r.createdAt).to.exist | ||
301 | expect(r.updatedAt).to.exist | ||
302 | expect(r.expiresOn).to.be.null | ||
303 | } | ||
304 | }) | ||
305 | |||
306 | it('Should manually remove a redundancy and remove it from the list', async function () { | ||
307 | this.timeout(120000) | ||
308 | |||
309 | for (const redundancyId of redundanciesToRemove) { | ||
310 | await removeVideoRedundancy({ | ||
311 | url: servers[0].url, | ||
312 | accessToken: servers[0].accessToken, | ||
313 | redundancyId | ||
314 | }) | ||
315 | } | ||
316 | |||
317 | { | ||
318 | const res = await listVideoRedundancies({ | ||
319 | url: servers[0].url, | ||
320 | accessToken: servers[0].accessToken, | ||
321 | target: 'remote-videos', | ||
322 | sort: '-name', | ||
323 | start: 0, | ||
324 | count: 5 | ||
325 | }) | ||
326 | |||
327 | const videos = res.body.data | ||
328 | expect(videos).to.have.lengthOf(2) | ||
329 | |||
330 | expect(videos[0].name).to.equal('video 2 server 2') | ||
331 | |||
332 | redundanciesToRemove = [] | ||
333 | const video = videos[0] | ||
334 | expect(video.redundancies.files).to.have.lengthOf(4) | ||
335 | expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1) | ||
336 | |||
337 | const redundancies = video.redundancies.files.concat(video.redundancies.streamingPlaylists) | ||
338 | |||
339 | for (const r of redundancies) { | ||
340 | redundanciesToRemove.push(r.id) | ||
341 | } | ||
342 | } | ||
343 | }) | ||
344 | |||
345 | it('Should remove another (auto) redundancy', async function () { | ||
346 | { | ||
347 | for (const redundancyId of redundanciesToRemove) { | ||
348 | await removeVideoRedundancy({ | ||
349 | url: servers[0].url, | ||
350 | accessToken: servers[0].accessToken, | ||
351 | redundancyId | ||
352 | }) | ||
353 | } | ||
354 | |||
355 | const res = await listVideoRedundancies({ | ||
356 | url: servers[0].url, | ||
357 | accessToken: servers[0].accessToken, | ||
358 | target: 'remote-videos', | ||
359 | sort: '-name', | ||
360 | start: 0, | ||
361 | count: 5 | ||
362 | }) | ||
363 | |||
364 | const videos = res.body.data | ||
365 | expect(videos[0].name).to.equal('video 1 server 2') | ||
366 | expect(videos).to.have.lengthOf(1) | ||
367 | } | ||
368 | }) | ||
369 | |||
370 | after(async function () { | ||
371 | await cleanupTests(servers) | ||
372 | }) | ||
373 | }) | ||
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts index 1cdf93aa1..c5037a541 100644 --- a/server/tests/api/redundancy/redundancy.ts +++ b/server/tests/api/redundancy/redundancy.ts | |||
@@ -1,11 +1,12 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { VideoDetails } from '../../../../shared/models/videos' | 5 | import { VideoDetails } from '../../../../shared/models/videos' |
6 | import { | 6 | import { |
7 | checkSegmentHash, | 7 | checkSegmentHash, |
8 | checkVideoFilesWereRemoved, cleanupTests, | 8 | checkVideoFilesWereRemoved, |
9 | cleanupTests, | ||
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
11 | getFollowingListPaginationAndSort, | 12 | getFollowingListPaginationAndSort, |
@@ -28,11 +29,16 @@ import { | |||
28 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 29 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
29 | 30 | ||
30 | import * as magnetUtil from 'magnet-uri' | 31 | import * as magnetUtil from 'magnet-uri' |
31 | import { updateRedundancy } from '../../../../shared/extra-utils/server/redundancy' | 32 | import { |
33 | addVideoRedundancy, | ||
34 | listVideoRedundancies, | ||
35 | removeVideoRedundancy, | ||
36 | updateRedundancy | ||
37 | } from '../../../../shared/extra-utils/server/redundancy' | ||
32 | import { ActorFollow } from '../../../../shared/models/actors' | 38 | import { ActorFollow } from '../../../../shared/models/actors' |
33 | import { readdir } from 'fs-extra' | 39 | import { readdir } from 'fs-extra' |
34 | import { join } from 'path' | 40 | import { join } from 'path' |
35 | import { VideoRedundancyStrategy } from '../../../../shared/models/redundancy' | 41 | import { VideoRedundancy, VideoRedundancyStrategy, VideoRedundancyStrategyWithManual } from '../../../../shared/models/redundancy' |
36 | import { getStats } from '../../../../shared/extra-utils/server/stats' | 42 | import { getStats } from '../../../../shared/extra-utils/server/stats' |
37 | import { ServerStats } from '../../../../shared/models/server/server-stats.model' | 43 | import { ServerStats } from '../../../../shared/models/server/server-stats.model' |
38 | 44 | ||
@@ -40,6 +46,7 @@ const expect = chai.expect | |||
40 | 46 | ||
41 | let servers: ServerInfo[] = [] | 47 | let servers: ServerInfo[] = [] |
42 | let video1Server2UUID: string | 48 | let video1Server2UUID: string |
49 | let video1Server2Id: number | ||
43 | 50 | ||
44 | function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[], server: ServerInfo) { | 51 | function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: number } }, baseWebseeds: string[], server: ServerInfo) { |
45 | const parsed = magnetUtil.decode(file.magnetUri) | 52 | const parsed = magnetUtil.decode(file.magnetUri) |
@@ -52,7 +59,19 @@ function checkMagnetWebseeds (file: { magnetUri: string, resolution: { id: numbe | |||
52 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) | 59 | expect(parsed.urlList).to.have.lengthOf(baseWebseeds.length) |
53 | } | 60 | } |
54 | 61 | ||
55 | async function flushAndRunServers (strategy: VideoRedundancyStrategy, additionalParams: any = {}) { | 62 | async function flushAndRunServers (strategy: VideoRedundancyStrategy | null, additionalParams: any = {}) { |
63 | const strategies: any[] = [] | ||
64 | |||
65 | if (strategy !== null) { | ||
66 | strategies.push( | ||
67 | immutableAssign({ | ||
68 | min_lifetime: '1 hour', | ||
69 | strategy: strategy, | ||
70 | size: '400KB' | ||
71 | }, additionalParams) | ||
72 | ) | ||
73 | } | ||
74 | |||
56 | const config = { | 75 | const config = { |
57 | transcoding: { | 76 | transcoding: { |
58 | hls: { | 77 | hls: { |
@@ -62,36 +81,32 @@ async function flushAndRunServers (strategy: VideoRedundancyStrategy, additional | |||
62 | redundancy: { | 81 | redundancy: { |
63 | videos: { | 82 | videos: { |
64 | check_interval: '5 seconds', | 83 | check_interval: '5 seconds', |
65 | strategies: [ | 84 | strategies |
66 | immutableAssign({ | ||
67 | min_lifetime: '1 hour', | ||
68 | strategy: strategy, | ||
69 | size: '400KB' | ||
70 | }, additionalParams) | ||
71 | ] | ||
72 | } | 85 | } |
73 | } | 86 | } |
74 | } | 87 | } |
88 | |||
75 | servers = await flushAndRunMultipleServers(3, config) | 89 | servers = await flushAndRunMultipleServers(3, config) |
76 | 90 | ||
77 | // Get the access tokens | 91 | // Get the access tokens |
78 | await setAccessTokensToServers(servers) | 92 | await setAccessTokensToServers(servers) |
79 | 93 | ||
80 | { | 94 | { |
81 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' }) | 95 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' }) |
82 | video1Server2UUID = res.body.video.uuid | 96 | video1Server2UUID = res.body.video.uuid |
97 | video1Server2Id = res.body.video.id | ||
83 | 98 | ||
84 | await viewVideo(servers[ 1 ].url, video1Server2UUID) | 99 | await viewVideo(servers[1].url, video1Server2UUID) |
85 | } | 100 | } |
86 | 101 | ||
87 | await waitJobs(servers) | 102 | await waitJobs(servers) |
88 | 103 | ||
89 | // Server 1 and server 2 follow each other | 104 | // Server 1 and server 2 follow each other |
90 | await doubleFollow(servers[ 0 ], servers[ 1 ]) | 105 | await doubleFollow(servers[0], servers[1]) |
91 | // Server 1 and server 3 follow each other | 106 | // Server 1 and server 3 follow each other |
92 | await doubleFollow(servers[ 0 ], servers[ 2 ]) | 107 | await doubleFollow(servers[0], servers[2]) |
93 | // Server 2 and server 3 follow each other | 108 | // Server 2 and server 3 follow each other |
94 | await doubleFollow(servers[ 1 ], servers[ 2 ]) | 109 | await doubleFollow(servers[1], servers[2]) |
95 | 110 | ||
96 | await waitJobs(servers) | 111 | await waitJobs(servers) |
97 | } | 112 | } |
@@ -100,7 +115,7 @@ async function check1WebSeed (videoUUID?: string) { | |||
100 | if (!videoUUID) videoUUID = video1Server2UUID | 115 | if (!videoUUID) videoUUID = video1Server2UUID |
101 | 116 | ||
102 | const webseeds = [ | 117 | const webseeds = [ |
103 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` | 118 | `http://localhost:${servers[1].port}/static/webseed/${videoUUID}` |
104 | ] | 119 | ] |
105 | 120 | ||
106 | for (const server of servers) { | 121 | for (const server of servers) { |
@@ -118,8 +133,8 @@ async function check2Webseeds (videoUUID?: string) { | |||
118 | if (!videoUUID) videoUUID = video1Server2UUID | 133 | if (!videoUUID) videoUUID = video1Server2UUID |
119 | 134 | ||
120 | const webseeds = [ | 135 | const webseeds = [ |
121 | `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`, | 136 | `http://localhost:${servers[0].port}/static/redundancy/${videoUUID}`, |
122 | `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}` | 137 | `http://localhost:${servers[1].port}/static/webseed/${videoUUID}` |
123 | ] | 138 | ] |
124 | 139 | ||
125 | for (const server of servers) { | 140 | for (const server of servers) { |
@@ -216,41 +231,50 @@ async function check1PlaylistRedundancies (videoUUID?: string) { | |||
216 | } | 231 | } |
217 | } | 232 | } |
218 | 233 | ||
219 | async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategy) { | 234 | async function checkStatsGlobal (strategy: VideoRedundancyStrategyWithManual) { |
235 | let totalSize: number = null | ||
236 | let statsLength = 1 | ||
237 | |||
238 | if (strategy !== 'manual') { | ||
239 | totalSize = 409600 | ||
240 | statsLength = 2 | ||
241 | } | ||
242 | |||
220 | const res = await getStats(servers[0].url) | 243 | const res = await getStats(servers[0].url) |
221 | const data: ServerStats = res.body | 244 | const data: ServerStats = res.body |
222 | 245 | ||
223 | expect(data.videosRedundancy).to.have.lengthOf(1) | 246 | expect(data.videosRedundancy).to.have.lengthOf(statsLength) |
224 | const stat = data.videosRedundancy[0] | ||
225 | 247 | ||
248 | const stat = data.videosRedundancy[0] | ||
226 | expect(stat.strategy).to.equal(strategy) | 249 | expect(stat.strategy).to.equal(strategy) |
227 | expect(stat.totalSize).to.equal(409600) | 250 | expect(stat.totalSize).to.equal(totalSize) |
251 | |||
252 | return stat | ||
253 | } | ||
254 | |||
255 | async function checkStatsWith2Webseed (strategy: VideoRedundancyStrategyWithManual) { | ||
256 | const stat = await checkStatsGlobal(strategy) | ||
257 | |||
228 | expect(stat.totalUsed).to.be.at.least(1).and.below(409601) | 258 | expect(stat.totalUsed).to.be.at.least(1).and.below(409601) |
229 | expect(stat.totalVideoFiles).to.equal(4) | 259 | expect(stat.totalVideoFiles).to.equal(4) |
230 | expect(stat.totalVideos).to.equal(1) | 260 | expect(stat.totalVideos).to.equal(1) |
231 | } | 261 | } |
232 | 262 | ||
233 | async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) { | 263 | async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategyWithManual) { |
234 | const res = await getStats(servers[0].url) | 264 | const stat = await checkStatsGlobal(strategy) |
235 | const data: ServerStats = res.body | ||
236 | 265 | ||
237 | expect(data.videosRedundancy).to.have.lengthOf(1) | ||
238 | |||
239 | const stat = data.videosRedundancy[0] | ||
240 | expect(stat.strategy).to.equal(strategy) | ||
241 | expect(stat.totalSize).to.equal(409600) | ||
242 | expect(stat.totalUsed).to.equal(0) | 266 | expect(stat.totalUsed).to.equal(0) |
243 | expect(stat.totalVideoFiles).to.equal(0) | 267 | expect(stat.totalVideoFiles).to.equal(0) |
244 | expect(stat.totalVideos).to.equal(0) | 268 | expect(stat.totalVideos).to.equal(0) |
245 | } | 269 | } |
246 | 270 | ||
247 | async function enableRedundancyOnServer1 () { | 271 | async function enableRedundancyOnServer1 () { |
248 | await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) | 272 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true) |
249 | 273 | ||
250 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) | 274 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) |
251 | const follows: ActorFollow[] = res.body.data | 275 | const follows: ActorFollow[] = res.body.data |
252 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) | 276 | const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`) |
253 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) | 277 | const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`) |
254 | 278 | ||
255 | expect(server3).to.not.be.undefined | 279 | expect(server3).to.not.be.undefined |
256 | expect(server3.following.hostRedundancyAllowed).to.be.false | 280 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -260,12 +284,12 @@ async function enableRedundancyOnServer1 () { | |||
260 | } | 284 | } |
261 | 285 | ||
262 | async function disableRedundancyOnServer1 () { | 286 | async function disableRedundancyOnServer1 () { |
263 | await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) | 287 | await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false) |
264 | 288 | ||
265 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' }) | 289 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' }) |
266 | const follows: ActorFollow[] = res.body.data | 290 | const follows: ActorFollow[] = res.body.data |
267 | const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) | 291 | const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`) |
268 | const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) | 292 | const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`) |
269 | 293 | ||
270 | expect(server3).to.not.be.undefined | 294 | expect(server3).to.not.be.undefined |
271 | expect(server3.following.hostRedundancyAllowed).to.be.false | 295 | expect(server3.following.hostRedundancyAllowed).to.be.false |
@@ -410,8 +434,8 @@ describe('Test videos redundancy', function () { | |||
410 | it('Should view 2 times the first video to have > min_views config', async function () { | 434 | it('Should view 2 times the first video to have > min_views config', async function () { |
411 | this.timeout(80000) | 435 | this.timeout(80000) |
412 | 436 | ||
413 | await viewVideo(servers[ 0 ].url, video1Server2UUID) | 437 | await viewVideo(servers[0].url, video1Server2UUID) |
414 | await viewVideo(servers[ 2 ].url, video1Server2UUID) | 438 | await viewVideo(servers[2].url, video1Server2UUID) |
415 | 439 | ||
416 | await wait(10000) | 440 | await wait(10000) |
417 | await waitJobs(servers) | 441 | await waitJobs(servers) |
@@ -446,6 +470,74 @@ describe('Test videos redundancy', function () { | |||
446 | }) | 470 | }) |
447 | }) | 471 | }) |
448 | 472 | ||
473 | describe('With manual strategy', function () { | ||
474 | before(function () { | ||
475 | this.timeout(120000) | ||
476 | |||
477 | return flushAndRunServers(null) | ||
478 | }) | ||
479 | |||
480 | it('Should have 1 webseed on the first video', async function () { | ||
481 | await check1WebSeed() | ||
482 | await check0PlaylistRedundancies() | ||
483 | await checkStatsWith1Webseed('manual') | ||
484 | }) | ||
485 | |||
486 | it('Should create a redundancy on first video', async function () { | ||
487 | await addVideoRedundancy({ | ||
488 | url: servers[0].url, | ||
489 | accessToken: servers[0].accessToken, | ||
490 | videoId: video1Server2Id | ||
491 | }) | ||
492 | }) | ||
493 | |||
494 | it('Should have 2 webseeds on the first video', async function () { | ||
495 | this.timeout(80000) | ||
496 | |||
497 | await waitJobs(servers) | ||
498 | await waitUntilLog(servers[0], 'Duplicated ', 5) | ||
499 | await waitJobs(servers) | ||
500 | |||
501 | await check2Webseeds() | ||
502 | await check1PlaylistRedundancies() | ||
503 | await checkStatsWith2Webseed('manual') | ||
504 | }) | ||
505 | |||
506 | it('Should manually remove redundancies on server 1 and remove duplicated videos', async function () { | ||
507 | this.timeout(80000) | ||
508 | |||
509 | const res = await listVideoRedundancies({ | ||
510 | url: servers[0].url, | ||
511 | accessToken: servers[0].accessToken, | ||
512 | target: 'remote-videos' | ||
513 | }) | ||
514 | |||
515 | const videos = res.body.data as VideoRedundancy[] | ||
516 | expect(videos).to.have.lengthOf(1) | ||
517 | |||
518 | const video = videos[0] | ||
519 | for (const r of video.redundancies.files.concat(video.redundancies.streamingPlaylists)) { | ||
520 | await removeVideoRedundancy({ | ||
521 | url: servers[0].url, | ||
522 | accessToken: servers[0].accessToken, | ||
523 | redundancyId: r.id | ||
524 | }) | ||
525 | } | ||
526 | |||
527 | await waitJobs(servers) | ||
528 | await wait(5000) | ||
529 | |||
530 | await check1WebSeed() | ||
531 | await check0PlaylistRedundancies() | ||
532 | |||
533 | await checkVideoFilesWereRemoved(video1Server2UUID, servers[0].serverNumber, [ 'videos' ]) | ||
534 | }) | ||
535 | |||
536 | after(async function () { | ||
537 | await cleanupTests(servers) | ||
538 | }) | ||
539 | }) | ||
540 | |||
449 | describe('Test expiration', function () { | 541 | describe('Test expiration', function () { |
450 | const strategy = 'recently-added' | 542 | const strategy = 'recently-added' |
451 | 543 | ||
@@ -528,7 +620,7 @@ describe('Test videos redundancy', function () { | |||
528 | await check1PlaylistRedundancies() | 620 | await check1PlaylistRedundancies() |
529 | await checkStatsWith2Webseed(strategy) | 621 | await checkStatsWith2Webseed(strategy) |
530 | 622 | ||
531 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' }) | 623 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' }) |
532 | video2Server2UUID = res.body.video.uuid | 624 | video2Server2UUID = res.body.video.uuid |
533 | }) | 625 | }) |
534 | 626 | ||
@@ -560,8 +652,8 @@ describe('Test videos redundancy', function () { | |||
560 | 652 | ||
561 | await waitJobs(servers) | 653 | await waitJobs(servers) |
562 | 654 | ||
563 | killallServers([ servers[ 0 ] ]) | 655 | killallServers([ servers[0] ]) |
564 | await reRunServer(servers[ 0 ], { | 656 | await reRunServer(servers[0], { |
565 | redundancy: { | 657 | redundancy: { |
566 | videos: { | 658 | videos: { |
567 | check_interval: '1 second', | 659 | check_interval: '1 second', |
diff --git a/server/tests/api/search/search-activitypub-video-channels.ts b/server/tests/api/search/search-activitypub-video-channels.ts index d5f0a5457..d7e3ed5be 100644 --- a/server/tests/api/search/search-activitypub-video-channels.ts +++ b/server/tests/api/search/search-activitypub-video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -39,7 +39,7 @@ describe('Test ActivityPub video channels search', function () { | |||
39 | await setAccessTokensToServers(servers) | 39 | await setAccessTokensToServers(servers) |
40 | 40 | ||
41 | { | 41 | { |
42 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'user1_server1', password: 'password' }) | 42 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user1_server1', password: 'password' }) |
43 | const channel = { | 43 | const channel = { |
44 | name: 'channel1_server1', | 44 | name: 'channel1_server1', |
45 | displayName: 'Channel 1 server 1' | 45 | displayName: 'Channel 1 server 1' |
@@ -49,7 +49,7 @@ describe('Test ActivityPub video channels search', function () { | |||
49 | 49 | ||
50 | { | 50 | { |
51 | const user = { username: 'user1_server2', password: 'password' } | 51 | const user = { username: 'user1_server2', password: 'password' } |
52 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 52 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
53 | userServer2Token = await userLogin(servers[1], user) | 53 | userServer2Token = await userLogin(servers[1], user) |
54 | 54 | ||
55 | const channel = { | 55 | const channel = { |
@@ -70,8 +70,8 @@ describe('Test ActivityPub video channels search', function () { | |||
70 | this.timeout(15000) | 70 | this.timeout(15000) |
71 | 71 | ||
72 | { | 72 | { |
73 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3' | 73 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server3' |
74 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 74 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
75 | 75 | ||
76 | expect(res.body.total).to.equal(0) | 76 | expect(res.body.total).to.equal(0) |
77 | expect(res.body.data).to.be.an('array') | 77 | expect(res.body.data).to.be.an('array') |
@@ -80,7 +80,7 @@ describe('Test ActivityPub video channels search', function () { | |||
80 | 80 | ||
81 | { | 81 | { |
82 | // Without token | 82 | // Without token |
83 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 83 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
84 | const res = await searchVideoChannel(servers[0].url, search) | 84 | const res = await searchVideoChannel(servers[0].url, search) |
85 | 85 | ||
86 | expect(res.body.total).to.equal(0) | 86 | expect(res.body.total).to.equal(0) |
@@ -91,35 +91,35 @@ describe('Test ActivityPub video channels search', function () { | |||
91 | 91 | ||
92 | it('Should search a local video channel', async function () { | 92 | it('Should search a local video channel', async function () { |
93 | const searches = [ | 93 | const searches = [ |
94 | 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1', | 94 | 'http://localhost:' + servers[0].port + '/video-channels/channel1_server1', |
95 | 'channel1_server1@localhost:' + servers[ 0 ].port | 95 | 'channel1_server1@localhost:' + servers[0].port |
96 | ] | 96 | ] |
97 | 97 | ||
98 | for (const search of searches) { | 98 | for (const search of searches) { |
99 | const res = await searchVideoChannel(servers[ 0 ].url, search) | 99 | const res = await searchVideoChannel(servers[0].url, search) |
100 | 100 | ||
101 | expect(res.body.total).to.equal(1) | 101 | expect(res.body.total).to.equal(1) |
102 | expect(res.body.data).to.be.an('array') | 102 | expect(res.body.data).to.be.an('array') |
103 | expect(res.body.data).to.have.lengthOf(1) | 103 | expect(res.body.data).to.have.lengthOf(1) |
104 | expect(res.body.data[ 0 ].name).to.equal('channel1_server1') | 104 | expect(res.body.data[0].name).to.equal('channel1_server1') |
105 | expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 1') | 105 | expect(res.body.data[0].displayName).to.equal('Channel 1 server 1') |
106 | } | 106 | } |
107 | }) | 107 | }) |
108 | 108 | ||
109 | it('Should search a remote video channel with URL or handle', async function () { | 109 | it('Should search a remote video channel with URL or handle', async function () { |
110 | const searches = [ | 110 | const searches = [ |
111 | 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2', | 111 | 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2', |
112 | 'channel1_server2@localhost:' + servers[ 1 ].port | 112 | 'channel1_server2@localhost:' + servers[1].port |
113 | ] | 113 | ] |
114 | 114 | ||
115 | for (const search of searches) { | 115 | for (const search of searches) { |
116 | const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 116 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
117 | 117 | ||
118 | expect(res.body.total).to.equal(1) | 118 | expect(res.body.total).to.equal(1) |
119 | expect(res.body.data).to.be.an('array') | 119 | expect(res.body.data).to.be.an('array') |
120 | expect(res.body.data).to.have.lengthOf(1) | 120 | expect(res.body.data).to.have.lengthOf(1) |
121 | expect(res.body.data[ 0 ].name).to.equal('channel1_server2') | 121 | expect(res.body.data[0].name).to.equal('channel1_server2') |
122 | expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 2') | 122 | expect(res.body.data[0].displayName).to.equal('Channel 1 server 2') |
123 | } | 123 | } |
124 | }) | 124 | }) |
125 | 125 | ||
@@ -137,13 +137,13 @@ describe('Test ActivityPub video channels search', function () { | |||
137 | 137 | ||
138 | await waitJobs(servers) | 138 | await waitJobs(servers) |
139 | 139 | ||
140 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) | 140 | const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[1].port, 0, 5) |
141 | expect(res.body.total).to.equal(0) | 141 | expect(res.body.total).to.equal(0) |
142 | expect(res.body.data).to.have.lengthOf(0) | 142 | expect(res.body.data).to.have.lengthOf(0) |
143 | }) | 143 | }) |
144 | 144 | ||
145 | it('Should list video channel videos of server 2 with token', async function () { | 145 | it('Should list video channel videos of server 2 with token', async function () { |
146 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5) | 146 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[1].port, 0, 5) |
147 | 147 | ||
148 | expect(res.body.total).to.equal(1) | 148 | expect(res.body.total).to.equal(1) |
149 | expect(res.body.data[0].name).to.equal('video 1 server 2') | 149 | expect(res.body.data[0].name).to.equal('video 1 server 2') |
@@ -159,7 +159,7 @@ describe('Test ActivityPub video channels search', function () { | |||
159 | // Expire video channel | 159 | // Expire video channel |
160 | await wait(10000) | 160 | await wait(10000) |
161 | 161 | ||
162 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 162 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
163 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 163 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
164 | expect(res.body.total).to.equal(1) | 164 | expect(res.body.total).to.equal(1) |
165 | expect(res.body.data).to.have.lengthOf(1) | 165 | expect(res.body.data).to.have.lengthOf(1) |
@@ -182,12 +182,12 @@ describe('Test ActivityPub video channels search', function () { | |||
182 | // Expire video channel | 182 | // Expire video channel |
183 | await wait(10000) | 183 | await wait(10000) |
184 | 184 | ||
185 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 185 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
186 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 186 | await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
187 | 187 | ||
188 | await waitJobs(servers) | 188 | await waitJobs(servers) |
189 | 189 | ||
190 | const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port | 190 | const videoChannelName = 'channel1_server2@localhost:' + servers[1].port |
191 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') | 191 | const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt') |
192 | 192 | ||
193 | expect(res.body.total).to.equal(2) | 193 | expect(res.body.total).to.equal(2) |
@@ -204,7 +204,7 @@ describe('Test ActivityPub video channels search', function () { | |||
204 | // Expire video | 204 | // Expire video |
205 | await wait(10000) | 205 | await wait(10000) |
206 | 206 | ||
207 | const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2' | 207 | const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2' |
208 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) | 208 | const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken) |
209 | expect(res.body.total).to.equal(0) | 209 | expect(res.body.total).to.equal(0) |
210 | expect(res.body.data).to.have.lengthOf(0) | 210 | expect(res.body.data).to.have.lengthOf(0) |
diff --git a/server/tests/api/search/search-activitypub-videos.ts b/server/tests/api/search/search-activitypub-videos.ts index dbfefadda..c62dfca0d 100644 --- a/server/tests/api/search/search-activitypub-videos.ts +++ b/server/tests/api/search/search-activitypub-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -34,12 +34,12 @@ describe('Test ActivityPub videos search', function () { | |||
34 | await setAccessTokensToServers(servers) | 34 | await setAccessTokensToServers(servers) |
35 | 35 | ||
36 | { | 36 | { |
37 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1 on server 1' }) | 37 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1 on server 1' }) |
38 | videoServer1UUID = res.body.video.uuid | 38 | videoServer1UUID = res.body.video.uuid |
39 | } | 39 | } |
40 | 40 | ||
41 | { | 41 | { |
42 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 on server 2' }) | 42 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 on server 2' }) |
43 | videoServer2UUID = res.body.video.uuid | 43 | videoServer2UUID = res.body.video.uuid |
44 | } | 44 | } |
45 | 45 | ||
@@ -49,7 +49,7 @@ describe('Test ActivityPub videos search', function () { | |||
49 | it('Should not find a remote video', async function () { | 49 | it('Should not find a remote video', async function () { |
50 | { | 50 | { |
51 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' | 51 | const search = 'http://localhost:' + servers[1].port + '/videos/watch/43' |
52 | const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken) | 52 | const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken) |
53 | 53 | ||
54 | expect(res.body.total).to.equal(0) | 54 | expect(res.body.total).to.equal(0) |
55 | expect(res.body.data).to.be.an('array') | 55 | expect(res.body.data).to.be.an('array') |
diff --git a/server/tests/api/search/search-videos.ts b/server/tests/api/search/search-videos.ts index 7882d9373..4801fe04a 100644 --- a/server/tests/api/search/search-videos.ts +++ b/server/tests/api/search/search-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -78,7 +78,7 @@ describe('Test videos search', function () { | |||
78 | const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined }) | 78 | const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined }) |
79 | await uploadVideo(server.url, server.accessToken, attributes5) | 79 | await uploadVideo(server.url, server.accessToken, attributes5) |
80 | 80 | ||
81 | const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2 '] }) | 81 | const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] }) |
82 | await uploadVideo(server.url, server.accessToken, attributes6) | 82 | await uploadVideo(server.url, server.accessToken, attributes6) |
83 | 83 | ||
84 | const attributes7 = immutableAssign(attributes1, { | 84 | const attributes7 = immutableAssign(attributes1, { |
@@ -269,16 +269,16 @@ describe('Test videos search', function () { | |||
269 | { | 269 | { |
270 | const res = await advancedVideosSearch(server.url, query) | 270 | const res = await advancedVideosSearch(server.url, query) |
271 | expect(res.body.total).to.equal(2) | 271 | expect(res.body.total).to.equal(2) |
272 | expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') | 272 | expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3') |
273 | expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') | 273 | expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4') |
274 | } | 274 | } |
275 | 275 | ||
276 | { | 276 | { |
277 | const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] })) | 277 | const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] })) |
278 | expect(res.body.total).to.equal(3) | 278 | expect(res.body.total).to.equal(3) |
279 | expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3') | 279 | expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3') |
280 | expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4') | 280 | expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4') |
281 | expect(res.body.data[ 2 ].name).to.equal('1111 2222 3333 - 5') | 281 | expect(res.body.data[2].name).to.equal('1111 2222 3333 - 5') |
282 | } | 282 | } |
283 | 283 | ||
284 | { | 284 | { |
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts index a06f578fc..5f48dc0eb 100644 --- a/server/tests/api/server/auto-follows.ts +++ b/server/tests/api/server/auto-follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -59,9 +59,10 @@ async function server1Follows2 (servers: ServerInfo[]) { | |||
59 | 59 | ||
60 | async function resetFollows (servers: ServerInfo[]) { | 60 | async function resetFollows (servers: ServerInfo[]) { |
61 | try { | 61 | try { |
62 | await unfollow(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ]) | 62 | await unfollow(servers[0].url, servers[0].accessToken, servers[1]) |
63 | await unfollow(servers[ 1 ].url, servers[ 1 ].accessToken, servers[ 0 ]) | 63 | await unfollow(servers[1].url, servers[1].accessToken, servers[0]) |
64 | } catch { /* empty */ } | 64 | } catch { /* empty */ |
65 | } | ||
65 | 66 | ||
66 | await waitJobs(servers) | 67 | await waitJobs(servers) |
67 | 68 | ||
@@ -163,8 +164,8 @@ describe('Test auto follows', function () { | |||
163 | await wait(5000) | 164 | await wait(5000) |
164 | await waitJobs(servers) | 165 | await waitJobs(servers) |
165 | 166 | ||
166 | await checkFollow(servers[ 0 ], servers[ 1 ], false) | 167 | await checkFollow(servers[0], servers[1], false) |
167 | await checkFollow(servers[ 1 ], servers[ 0 ], false) | 168 | await checkFollow(servers[1], servers[0], false) |
168 | }) | 169 | }) |
169 | 170 | ||
170 | it('Should auto follow the index', async function () { | 171 | it('Should auto follow the index', async function () { |
@@ -187,7 +188,7 @@ describe('Test auto follows', function () { | |||
187 | await wait(5000) | 188 | await wait(5000) |
188 | await waitJobs(servers) | 189 | await waitJobs(servers) |
189 | 190 | ||
190 | await checkFollow(servers[ 0 ], servers[ 1 ], true) | 191 | await checkFollow(servers[0], servers[1], true) |
191 | 192 | ||
192 | await resetFollows(servers) | 193 | await resetFollows(servers) |
193 | }) | 194 | }) |
@@ -200,8 +201,8 @@ describe('Test auto follows', function () { | |||
200 | await wait(5000) | 201 | await wait(5000) |
201 | await waitJobs(servers) | 202 | await waitJobs(servers) |
202 | 203 | ||
203 | await checkFollow(servers[ 0 ], servers[ 1 ], false) | 204 | await checkFollow(servers[0], servers[1], false) |
204 | await checkFollow(servers[ 0 ], servers[ 2 ], true) | 205 | await checkFollow(servers[0], servers[2], true) |
205 | }) | 206 | }) |
206 | }) | 207 | }) |
207 | 208 | ||
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index cf99e5c0a..642525455 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -11,11 +11,14 @@ import { | |||
11 | getAbout, | 11 | getAbout, |
12 | getConfig, | 12 | getConfig, |
13 | getCustomConfig, | 13 | getCustomConfig, |
14 | killallServers, parallelTests, | 14 | killallServers, |
15 | parallelTests, | ||
15 | registerUser, | 16 | registerUser, |
16 | reRunServer, ServerInfo, | 17 | reRunServer, |
18 | ServerInfo, | ||
17 | setAccessTokensToServers, | 19 | setAccessTokensToServers, |
18 | updateCustomConfig, uploadVideo | 20 | updateCustomConfig, |
21 | uploadVideo | ||
19 | } from '../../../../shared/extra-utils' | 22 | } from '../../../../shared/extra-utils' |
20 | import { ServerConfig } from '../../../../shared/models' | 23 | import { ServerConfig } from '../../../../shared/models' |
21 | 24 | ||
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index e4e895acb..bd1b0e38a 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts | |||
@@ -1,16 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { cleanupTests, flushAndRunServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/extra-utils' |
6 | flushTests, | ||
7 | killallServers, | ||
8 | flushAndRunServer, | ||
9 | ServerInfo, | ||
10 | setAccessTokensToServers, | ||
11 | wait, | ||
12 | cleanupTests | ||
13 | } from '../../../../shared/extra-utils' | ||
14 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' | 6 | import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email' |
15 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 7 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
16 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' | 8 | import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form' |
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index c55a221f2..95b64a459 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -28,10 +28,12 @@ const expect = chai.expect | |||
28 | describe('Test emails', function () { | 28 | describe('Test emails', function () { |
29 | let server: ServerInfo | 29 | let server: ServerInfo |
30 | let userId: number | 30 | let userId: number |
31 | let userId2: number | ||
31 | let userAccessToken: string | 32 | let userAccessToken: string |
32 | let videoUUID: string | 33 | let videoUUID: string |
33 | let videoUserUUID: string | 34 | let videoUserUUID: string |
34 | let verificationString: string | 35 | let verificationString: string |
36 | let verificationString2: string | ||
35 | const emails: object[] = [] | 37 | const emails: object[] = [] |
36 | const user = { | 38 | const user = { |
37 | username: 'user_1', | 39 | username: 'user_1', |
@@ -122,6 +124,56 @@ describe('Test emails', function () { | |||
122 | }) | 124 | }) |
123 | }) | 125 | }) |
124 | 126 | ||
127 | describe('When creating a user without password', function () { | ||
128 | it('Should send a create password email', async function () { | ||
129 | this.timeout(10000) | ||
130 | |||
131 | await createUser({ | ||
132 | url: server.url, | ||
133 | accessToken: server.accessToken, | ||
134 | username: 'create_password', | ||
135 | password: '' | ||
136 | }) | ||
137 | |||
138 | await waitJobs(server) | ||
139 | expect(emails).to.have.lengthOf(2) | ||
140 | |||
141 | const email = emails[1] | ||
142 | |||
143 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | ||
144 | expect(email['from'][0]['address']).equal('test-admin@localhost') | ||
145 | expect(email['to'][0]['address']).equal('create_password@example.com') | ||
146 | expect(email['subject']).contains('account') | ||
147 | expect(email['subject']).contains('password') | ||
148 | |||
149 | const verificationStringMatches = /verificationString=([a-z0-9]+)/.exec(email['text']) | ||
150 | expect(verificationStringMatches).not.to.be.null | ||
151 | |||
152 | verificationString2 = verificationStringMatches[1] | ||
153 | expect(verificationString2).to.have.length.above(2) | ||
154 | |||
155 | const userIdMatches = /userId=([0-9]+)/.exec(email['text']) | ||
156 | expect(userIdMatches).not.to.be.null | ||
157 | |||
158 | userId2 = parseInt(userIdMatches[1], 10) | ||
159 | }) | ||
160 | |||
161 | it('Should not reset the password with an invalid verification string', async function () { | ||
162 | await resetPassword(server.url, userId2, verificationString2 + 'c', 'newly_created_password', 403) | ||
163 | }) | ||
164 | |||
165 | it('Should reset the password', async function () { | ||
166 | await resetPassword(server.url, userId2, verificationString2, 'newly_created_password') | ||
167 | }) | ||
168 | |||
169 | it('Should login with this new password', async function () { | ||
170 | await userLogin(server, { | ||
171 | username: 'create_password', | ||
172 | password: 'newly_created_password' | ||
173 | }) | ||
174 | }) | ||
175 | }) | ||
176 | |||
125 | describe('When creating a video abuse', function () { | 177 | describe('When creating a video abuse', function () { |
126 | it('Should send the notification email', async function () { | 178 | it('Should send the notification email', async function () { |
127 | this.timeout(10000) | 179 | this.timeout(10000) |
@@ -130,9 +182,9 @@ describe('Test emails', function () { | |||
130 | await reportVideoAbuse(server.url, server.accessToken, videoUUID, reason) | 182 | await reportVideoAbuse(server.url, server.accessToken, videoUUID, reason) |
131 | 183 | ||
132 | await waitJobs(server) | 184 | await waitJobs(server) |
133 | expect(emails).to.have.lengthOf(2) | 185 | expect(emails).to.have.lengthOf(3) |
134 | 186 | ||
135 | const email = emails[1] | 187 | const email = emails[2] |
136 | 188 | ||
137 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 189 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
138 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 190 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
@@ -151,9 +203,9 @@ describe('Test emails', function () { | |||
151 | await blockUser(server.url, userId, server.accessToken, 204, reason) | 203 | await blockUser(server.url, userId, server.accessToken, 204, reason) |
152 | 204 | ||
153 | await waitJobs(server) | 205 | await waitJobs(server) |
154 | expect(emails).to.have.lengthOf(3) | 206 | expect(emails).to.have.lengthOf(4) |
155 | 207 | ||
156 | const email = emails[2] | 208 | const email = emails[3] |
157 | 209 | ||
158 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 210 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
159 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 211 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
@@ -169,9 +221,9 @@ describe('Test emails', function () { | |||
169 | await unblockUser(server.url, userId, server.accessToken, 204) | 221 | await unblockUser(server.url, userId, server.accessToken, 204) |
170 | 222 | ||
171 | await waitJobs(server) | 223 | await waitJobs(server) |
172 | expect(emails).to.have.lengthOf(4) | 224 | expect(emails).to.have.lengthOf(5) |
173 | 225 | ||
174 | const email = emails[3] | 226 | const email = emails[4] |
175 | 227 | ||
176 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 228 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
177 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 229 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
@@ -189,9 +241,9 @@ describe('Test emails', function () { | |||
189 | await addVideoToBlacklist(server.url, server.accessToken, videoUserUUID, reason) | 241 | await addVideoToBlacklist(server.url, server.accessToken, videoUserUUID, reason) |
190 | 242 | ||
191 | await waitJobs(server) | 243 | await waitJobs(server) |
192 | expect(emails).to.have.lengthOf(5) | 244 | expect(emails).to.have.lengthOf(6) |
193 | 245 | ||
194 | const email = emails[4] | 246 | const email = emails[5] |
195 | 247 | ||
196 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 248 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
197 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 249 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
@@ -207,9 +259,9 @@ describe('Test emails', function () { | |||
207 | await removeVideoFromBlacklist(server.url, server.accessToken, videoUserUUID) | 259 | await removeVideoFromBlacklist(server.url, server.accessToken, videoUserUUID) |
208 | 260 | ||
209 | await waitJobs(server) | 261 | await waitJobs(server) |
210 | expect(emails).to.have.lengthOf(6) | 262 | expect(emails).to.have.lengthOf(7) |
211 | 263 | ||
212 | const email = emails[5] | 264 | const email = emails[6] |
213 | 265 | ||
214 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 266 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
215 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 267 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
@@ -227,9 +279,9 @@ describe('Test emails', function () { | |||
227 | await askSendVerifyEmail(server.url, 'user_1@example.com') | 279 | await askSendVerifyEmail(server.url, 'user_1@example.com') |
228 | 280 | ||
229 | await waitJobs(server) | 281 | await waitJobs(server) |
230 | expect(emails).to.have.lengthOf(7) | 282 | expect(emails).to.have.lengthOf(8) |
231 | 283 | ||
232 | const email = emails[6] | 284 | const email = emails[7] |
233 | 285 | ||
234 | expect(email['from'][0]['name']).equal('localhost:' + server.port) | 286 | expect(email['from'][0]['name']).equal('localhost:' + server.port) |
235 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 287 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
diff --git a/server/tests/api/server/follow-constraints.ts b/server/tests/api/server/follow-constraints.ts index 46663bf7c..a73440286 100644 --- a/server/tests/api/server/follow-constraints.ts +++ b/server/tests/api/server/follow-constraints.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -35,11 +35,11 @@ describe('Test follow constraints', function () { | |||
35 | await setAccessTokensToServers(servers) | 35 | await setAccessTokensToServers(servers) |
36 | 36 | ||
37 | { | 37 | { |
38 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video server 1' }) | 38 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video server 1' }) |
39 | video1UUID = res.body.video.uuid | 39 | video1UUID = res.body.video.uuid |
40 | } | 40 | } |
41 | { | 41 | { |
42 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video server 2' }) | 42 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video server 2' }) |
43 | video2UUID = res.body.video.uuid | 43 | video2UUID = res.body.video.uuid |
44 | } | 44 | } |
45 | 45 | ||
@@ -47,7 +47,7 @@ describe('Test follow constraints', function () { | |||
47 | username: 'user1', | 47 | username: 'user1', |
48 | password: 'super_password' | 48 | password: 'super_password' |
49 | } | 49 | } |
50 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 50 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
51 | userAccessToken = await userLogin(servers[0], user) | 51 | userAccessToken = await userLogin(servers[0], user) |
52 | 52 | ||
53 | await doubleFollow(servers[0], servers[1]) | 53 | await doubleFollow(servers[0], servers[1]) |
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts index 1984c9eb1..cee85cc4b 100644 --- a/server/tests/api/server/follows-moderation.ts +++ b/server/tests/api/server/follows-moderation.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -24,7 +24,7 @@ const expect = chai.expect | |||
24 | 24 | ||
25 | async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { | 25 | async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { |
26 | { | 26 | { |
27 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 27 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
28 | expect(res.body.total).to.equal(1) | 28 | expect(res.body.total).to.equal(1) |
29 | 29 | ||
30 | const follow = res.body.data[0] as ActorFollow | 30 | const follow = res.body.data[0] as ActorFollow |
@@ -34,7 +34,7 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
34 | } | 34 | } |
35 | 35 | ||
36 | { | 36 | { |
37 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 37 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
38 | expect(res.body.total).to.equal(1) | 38 | expect(res.body.total).to.equal(1) |
39 | 39 | ||
40 | const follow = res.body.data[0] as ActorFollow | 40 | const follow = res.body.data[0] as ActorFollow |
@@ -46,12 +46,12 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc | |||
46 | 46 | ||
47 | async function checkNoFollowers (servers: ServerInfo[]) { | 47 | async function checkNoFollowers (servers: ServerInfo[]) { |
48 | { | 48 | { |
49 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 49 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
50 | expect(res.body.total).to.equal(0) | 50 | expect(res.body.total).to.equal(0) |
51 | } | 51 | } |
52 | 52 | ||
53 | { | 53 | { |
54 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 54 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
55 | expect(res.body.total).to.equal(0) | 55 | expect(res.body.total).to.equal(0) |
56 | } | 56 | } |
57 | } | 57 | } |
@@ -164,17 +164,17 @@ describe('Test follows moderation', function () { | |||
164 | await waitJobs(servers) | 164 | await waitJobs(servers) |
165 | 165 | ||
166 | { | 166 | { |
167 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 167 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
168 | expect(res.body.total).to.equal(2) | 168 | expect(res.body.total).to.equal(2) |
169 | } | 169 | } |
170 | 170 | ||
171 | { | 171 | { |
172 | const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' }) | 172 | const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' }) |
173 | expect(res.body.total).to.equal(1) | 173 | expect(res.body.total).to.equal(1) |
174 | } | 174 | } |
175 | 175 | ||
176 | { | 176 | { |
177 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) | 177 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) |
178 | expect(res.body.total).to.equal(1) | 178 | expect(res.body.total).to.equal(1) |
179 | } | 179 | } |
180 | 180 | ||
@@ -184,7 +184,7 @@ describe('Test follows moderation', function () { | |||
184 | await checkServer1And2HasFollowers(servers) | 184 | await checkServer1And2HasFollowers(servers) |
185 | 185 | ||
186 | { | 186 | { |
187 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' }) | 187 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' }) |
188 | expect(res.body.total).to.equal(0) | 188 | expect(res.body.total).to.equal(0) |
189 | } | 189 | } |
190 | }) | 190 | }) |
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts index 4ffa9e791..b686af4e4 100644 --- a/server/tests/api/server/follows.ts +++ b/server/tests/api/server/follows.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -78,14 +78,14 @@ describe('Test follows', function () { | |||
78 | }) | 78 | }) |
79 | 79 | ||
80 | it('Should have 2 followings on server 1', async function () { | 80 | it('Should have 2 followings on server 1', async function () { |
81 | let res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 1, sort: 'createdAt' }) | 81 | let res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 1, sort: 'createdAt' }) |
82 | let follows = res.body.data | 82 | let follows = res.body.data |
83 | 83 | ||
84 | expect(res.body.total).to.equal(2) | 84 | expect(res.body.total).to.equal(2) |
85 | expect(follows).to.be.an('array') | 85 | expect(follows).to.be.an('array') |
86 | expect(follows.length).to.equal(1) | 86 | expect(follows.length).to.equal(1) |
87 | 87 | ||
88 | res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 1, count: 1, sort: 'createdAt' }) | 88 | res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 1, count: 1, sort: 'createdAt' }) |
89 | follows = follows.concat(res.body.data) | 89 | follows = follows.concat(res.body.data) |
90 | 90 | ||
91 | const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) | 91 | const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) |
@@ -101,7 +101,7 @@ describe('Test follows', function () { | |||
101 | const sort = 'createdAt' | 101 | const sort = 'createdAt' |
102 | const start = 0 | 102 | const start = 0 |
103 | const count = 1 | 103 | const count = 1 |
104 | const url = servers[ 0 ].url | 104 | const url = servers[0].url |
105 | 105 | ||
106 | { | 106 | { |
107 | const search = ':' + servers[1].port | 107 | const search = ':' + servers[1].port |
@@ -112,7 +112,7 @@ describe('Test follows', function () { | |||
112 | 112 | ||
113 | expect(res.body.total).to.equal(1) | 113 | expect(res.body.total).to.equal(1) |
114 | expect(follows.length).to.equal(1) | 114 | expect(follows.length).to.equal(1) |
115 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 1 ].port) | 115 | expect(follows[0].following.host).to.equal('localhost:' + servers[1].port) |
116 | } | 116 | } |
117 | 117 | ||
118 | { | 118 | { |
@@ -170,9 +170,9 @@ describe('Test follows', function () { | |||
170 | 170 | ||
171 | it('Should have 1 followers on server 2 and 3', async function () { | 171 | it('Should have 1 followers on server 2 and 3', async function () { |
172 | for (const server of [ servers[1], servers[2] ]) { | 172 | for (const server of [ servers[1], servers[2] ]) { |
173 | let res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) | 173 | const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' }) |
174 | 174 | ||
175 | let follows = res.body.data | 175 | const follows = res.body.data |
176 | expect(res.body.total).to.equal(1) | 176 | expect(res.body.total).to.equal(1) |
177 | expect(follows).to.be.an('array') | 177 | expect(follows).to.be.an('array') |
178 | expect(follows.length).to.equal(1) | 178 | expect(follows.length).to.equal(1) |
@@ -181,7 +181,7 @@ describe('Test follows', function () { | |||
181 | }) | 181 | }) |
182 | 182 | ||
183 | it('Should search/filter followers on server 2', async function () { | 183 | it('Should search/filter followers on server 2', async function () { |
184 | const url = servers[ 2 ].url | 184 | const url = servers[2].url |
185 | const start = 0 | 185 | const start = 0 |
186 | const count = 5 | 186 | const count = 5 |
187 | const sort = 'createdAt' | 187 | const sort = 'createdAt' |
@@ -195,7 +195,7 @@ describe('Test follows', function () { | |||
195 | 195 | ||
196 | expect(res.body.total).to.equal(1) | 196 | expect(res.body.total).to.equal(1) |
197 | expect(follows.length).to.equal(1) | 197 | expect(follows.length).to.equal(1) |
198 | expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 2 ].port) | 198 | expect(follows[0].following.host).to.equal('localhost:' + servers[2].port) |
199 | } | 199 | } |
200 | 200 | ||
201 | { | 201 | { |
@@ -241,7 +241,7 @@ describe('Test follows', function () { | |||
241 | }) | 241 | }) |
242 | 242 | ||
243 | it('Should have 0 followers on server 1', async function () { | 243 | it('Should have 0 followers on server 1', async function () { |
244 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' }) | 244 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' }) |
245 | const follows = res.body.data | 245 | const follows = res.body.data |
246 | 246 | ||
247 | expect(res.body.total).to.equal(0) | 247 | expect(res.body.total).to.equal(0) |
@@ -271,8 +271,8 @@ describe('Test follows', function () { | |||
271 | }) | 271 | }) |
272 | 272 | ||
273 | it('Should not follow server 3 on server 1 anymore', async function () { | 273 | it('Should not follow server 3 on server 1 anymore', async function () { |
274 | const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 274 | const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
275 | let follows = res.body.data | 275 | const follows = res.body.data |
276 | 276 | ||
277 | expect(res.body.total).to.equal(1) | 277 | expect(res.body.total).to.equal(1) |
278 | expect(follows).to.be.an('array') | 278 | expect(follows).to.be.an('array') |
@@ -282,9 +282,9 @@ describe('Test follows', function () { | |||
282 | }) | 282 | }) |
283 | 283 | ||
284 | it('Should not have server 1 as follower on server 3 anymore', async function () { | 284 | it('Should not have server 1 as follower on server 3 anymore', async function () { |
285 | const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 1, sort: 'createdAt' }) | 285 | const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 1, sort: 'createdAt' }) |
286 | 286 | ||
287 | let follows = res.body.data | 287 | const follows = res.body.data |
288 | expect(res.body.total).to.equal(0) | 288 | expect(res.body.total).to.equal(0) |
289 | expect(follows).to.be.an('array') | 289 | expect(follows).to.be.an('array') |
290 | expect(follows.length).to.equal(0) | 290 | expect(follows.length).to.equal(0) |
@@ -336,59 +336,59 @@ describe('Test follows', function () { | |||
336 | tags: [ 'tag1', 'tag2', 'tag3' ] | 336 | tags: [ 'tag1', 'tag2', 'tag3' ] |
337 | } | 337 | } |
338 | 338 | ||
339 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-2' }) | 339 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-2' }) |
340 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-3' }) | 340 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-3' }) |
341 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4Attributes) | 341 | await uploadVideo(servers[2].url, servers[2].accessToken, video4Attributes) |
342 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-5' }) | 342 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-5' }) |
343 | await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-6' }) | 343 | await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-6' }) |
344 | 344 | ||
345 | { | 345 | { |
346 | const user = { username: 'captain', password: 'password' } | 346 | const user = { username: 'captain', password: 'password' } |
347 | await createUser({ url: servers[ 2 ].url, accessToken: servers[ 2 ].accessToken, username: user.username, password: user.password }) | 347 | await createUser({ url: servers[2].url, accessToken: servers[2].accessToken, username: user.username, password: user.password }) |
348 | const userAccessToken = await userLogin(servers[ 2 ], user) | 348 | const userAccessToken = await userLogin(servers[2], user) |
349 | 349 | ||
350 | const resVideos = await getVideosList(servers[ 2 ].url) | 350 | const resVideos = await getVideosList(servers[2].url) |
351 | video4 = resVideos.body.data.find(v => v.name === 'server3-4') | 351 | video4 = resVideos.body.data.find(v => v.name === 'server3-4') |
352 | 352 | ||
353 | { | 353 | { |
354 | await rateVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, 'like') | 354 | await rateVideo(servers[2].url, servers[2].accessToken, video4.id, 'like') |
355 | await rateVideo(servers[ 2 ].url, userAccessToken, video4.id, 'dislike') | 355 | await rateVideo(servers[2].url, userAccessToken, video4.id, 'dislike') |
356 | } | 356 | } |
357 | 357 | ||
358 | { | 358 | { |
359 | { | 359 | { |
360 | const text = 'my super first comment' | 360 | const text = 'my super first comment' |
361 | const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) | 361 | const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text) |
362 | const threadId = res.body.comment.id | 362 | const threadId = res.body.comment.id |
363 | 363 | ||
364 | const text1 = 'my super answer to thread 1' | 364 | const text1 = 'my super answer to thread 1' |
365 | const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) | 365 | const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1) |
366 | const childCommentId = childCommentRes.body.comment.id | 366 | const childCommentId = childCommentRes.body.comment.id |
367 | 367 | ||
368 | const text2 = 'my super answer to answer of thread 1' | 368 | const text2 = 'my super answer to answer of thread 1' |
369 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text2) | 369 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text2) |
370 | 370 | ||
371 | const text3 = 'my second answer to thread 1' | 371 | const text3 = 'my second answer to thread 1' |
372 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text3) | 372 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text3) |
373 | } | 373 | } |
374 | 374 | ||
375 | { | 375 | { |
376 | const text = 'will be deleted' | 376 | const text = 'will be deleted' |
377 | const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text) | 377 | const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text) |
378 | const threadId = res.body.comment.id | 378 | const threadId = res.body.comment.id |
379 | 379 | ||
380 | const text1 = 'answer to deleted' | 380 | const text1 = 'answer to deleted' |
381 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1) | 381 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1) |
382 | 382 | ||
383 | const text2 = 'will also be deleted' | 383 | const text2 = 'will also be deleted' |
384 | const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text2) | 384 | const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text2) |
385 | const childCommentId = childCommentRes.body.comment.id | 385 | const childCommentId = childCommentRes.body.comment.id |
386 | 386 | ||
387 | const text3 = 'my second answer to deleted' | 387 | const text3 = 'my second answer to deleted' |
388 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text3) | 388 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text3) |
389 | 389 | ||
390 | await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId) | 390 | await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, threadId) |
391 | await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId) | 391 | await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, childCommentId) |
392 | } | 392 | } |
393 | } | 393 | } |
394 | 394 | ||
@@ -406,7 +406,7 @@ describe('Test follows', function () { | |||
406 | await waitJobs(servers) | 406 | await waitJobs(servers) |
407 | 407 | ||
408 | // Server 1 follows server 3 | 408 | // Server 1 follows server 3 |
409 | await follow(servers[ 0 ].url, [ servers[ 2 ].url ], servers[ 0 ].accessToken) | 409 | await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken) |
410 | 410 | ||
411 | await waitJobs(servers) | 411 | await waitJobs(servers) |
412 | }) | 412 | }) |
@@ -424,7 +424,7 @@ describe('Test follows', function () { | |||
424 | }) | 424 | }) |
425 | 425 | ||
426 | it('Should have propagated videos', async function () { | 426 | it('Should have propagated videos', async function () { |
427 | const res = await getVideosList(servers[ 0 ].url) | 427 | const res = await getVideosList(servers[0].url) |
428 | expect(res.body.total).to.equal(7) | 428 | expect(res.body.total).to.equal(7) |
429 | 429 | ||
430 | const video2 = res.body.data.find(v => v.name === 'server3-2') | 430 | const video2 = res.body.data.find(v => v.name === 'server3-2') |
@@ -470,7 +470,7 @@ describe('Test follows', function () { | |||
470 | } | 470 | } |
471 | ] | 471 | ] |
472 | } | 472 | } |
473 | await completeVideoCheck(servers[ 0 ].url, video4, checkAttributes) | 473 | await completeVideoCheck(servers[0].url, video4, checkAttributes) |
474 | }) | 474 | }) |
475 | 475 | ||
476 | it('Should have propagated comments', async function () { | 476 | it('Should have propagated comments', async function () { |
@@ -481,34 +481,34 @@ describe('Test follows', function () { | |||
481 | expect(res1.body.data).to.have.lengthOf(2) | 481 | expect(res1.body.data).to.have.lengthOf(2) |
482 | 482 | ||
483 | { | 483 | { |
484 | const comment: VideoComment = res1.body.data[ 0 ] | 484 | const comment: VideoComment = res1.body.data[0] |
485 | expect(comment.inReplyToCommentId).to.be.null | 485 | expect(comment.inReplyToCommentId).to.be.null |
486 | expect(comment.text).equal('my super first comment') | 486 | expect(comment.text).equal('my super first comment') |
487 | expect(comment.videoId).to.equal(video4.id) | 487 | expect(comment.videoId).to.equal(video4.id) |
488 | expect(comment.id).to.equal(comment.threadId) | 488 | expect(comment.id).to.equal(comment.threadId) |
489 | expect(comment.account.name).to.equal('root') | 489 | expect(comment.account.name).to.equal('root') |
490 | expect(comment.account.host).to.equal('localhost:' + servers[ 2 ].port) | 490 | expect(comment.account.host).to.equal('localhost:' + servers[2].port) |
491 | expect(comment.totalReplies).to.equal(3) | 491 | expect(comment.totalReplies).to.equal(3) |
492 | expect(dateIsValid(comment.createdAt as string)).to.be.true | 492 | expect(dateIsValid(comment.createdAt as string)).to.be.true |
493 | expect(dateIsValid(comment.updatedAt as string)).to.be.true | 493 | expect(dateIsValid(comment.updatedAt as string)).to.be.true |
494 | 494 | ||
495 | const threadId = comment.threadId | 495 | const threadId = comment.threadId |
496 | 496 | ||
497 | const res2 = await getVideoThreadComments(servers[ 0 ].url, video4.id, threadId) | 497 | const res2 = await getVideoThreadComments(servers[0].url, video4.id, threadId) |
498 | 498 | ||
499 | const tree: VideoCommentThreadTree = res2.body | 499 | const tree: VideoCommentThreadTree = res2.body |
500 | expect(tree.comment.text).equal('my super first comment') | 500 | expect(tree.comment.text).equal('my super first comment') |
501 | expect(tree.children).to.have.lengthOf(2) | 501 | expect(tree.children).to.have.lengthOf(2) |
502 | 502 | ||
503 | const firstChild = tree.children[ 0 ] | 503 | const firstChild = tree.children[0] |
504 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') | 504 | expect(firstChild.comment.text).to.equal('my super answer to thread 1') |
505 | expect(firstChild.children).to.have.lengthOf(1) | 505 | expect(firstChild.children).to.have.lengthOf(1) |
506 | 506 | ||
507 | const childOfFirstChild = firstChild.children[ 0 ] | 507 | const childOfFirstChild = firstChild.children[0] |
508 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') | 508 | expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1') |
509 | expect(childOfFirstChild.children).to.have.lengthOf(0) | 509 | expect(childOfFirstChild.children).to.have.lengthOf(0) |
510 | 510 | ||
511 | const secondChild = tree.children[ 1 ] | 511 | const secondChild = tree.children[1] |
512 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') | 512 | expect(secondChild.comment.text).to.equal('my second answer to thread 1') |
513 | expect(secondChild.children).to.have.lengthOf(0) | 513 | expect(secondChild.children).to.have.lengthOf(0) |
514 | } | 514 | } |
@@ -569,7 +569,7 @@ describe('Test follows', function () { | |||
569 | 569 | ||
570 | await waitJobs(servers) | 570 | await waitJobs(servers) |
571 | 571 | ||
572 | let res = await getVideosList(servers[ 0 ].url) | 572 | const res = await getVideosList(servers[0].url) |
573 | expect(res.body.total).to.equal(1) | 573 | expect(res.body.total).to.equal(1) |
574 | }) | 574 | }) |
575 | 575 | ||
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts index 7e36067f1..2cf6e15ad 100644 --- a/server/tests/api/server/handle-down.ts +++ b/server/tests/api/server/handle-down.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,6 +8,7 @@ import { VideoCommentThreadTree } from '../../../../shared/models/videos/video-c | |||
8 | 8 | ||
9 | import { | 9 | import { |
10 | cleanupTests, | 10 | cleanupTests, |
11 | closeAllSequelize, | ||
11 | completeVideoCheck, | 12 | completeVideoCheck, |
12 | flushAndRunMultipleServers, | 13 | flushAndRunMultipleServers, |
13 | getVideo, | 14 | getVideo, |
@@ -17,11 +18,12 @@ import { | |||
17 | reRunServer, | 18 | reRunServer, |
18 | ServerInfo, | 19 | ServerInfo, |
19 | setAccessTokensToServers, | 20 | setAccessTokensToServers, |
21 | setActorFollowScores, | ||
20 | unfollow, | 22 | unfollow, |
21 | updateVideo, | 23 | updateVideo, |
22 | uploadVideo, uploadVideoAndGetId, | 24 | uploadVideo, |
23 | wait, | 25 | uploadVideoAndGetId, |
24 | setActorFollowScores, closeAllSequelize | 26 | wait |
25 | } from '../../../../shared/extra-utils' | 27 | } from '../../../../shared/extra-utils' |
26 | import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' | 28 | import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows' |
27 | import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' | 29 | import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -44,7 +46,7 @@ describe('Test handle downs', function () { | |||
44 | let missedVideo2: Video | 46 | let missedVideo2: Video |
45 | let unlistedVideo: Video | 47 | let unlistedVideo: Video |
46 | 48 | ||
47 | let videoIdsServer1: number[] = [] | 49 | const videoIdsServer1: number[] = [] |
48 | 50 | ||
49 | const videoAttributes = { | 51 | const videoAttributes = { |
50 | name: 'my super name for server 1', | 52 | name: 'my super name for server 1', |
@@ -137,7 +139,7 @@ describe('Test handle downs', function () { | |||
137 | 139 | ||
138 | // Remove server 2 follower | 140 | // Remove server 2 follower |
139 | for (let i = 0; i < 10; i++) { | 141 | for (let i = 0; i < 10; i++) { |
140 | await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 142 | await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
141 | } | 143 | } |
142 | 144 | ||
143 | await waitJobs(servers[0]) | 145 | await waitJobs(servers[0]) |
@@ -145,14 +147,14 @@ describe('Test handle downs', function () { | |||
145 | // Kill server 3 | 147 | // Kill server 3 |
146 | killallServers([ servers[2] ]) | 148 | killallServers([ servers[2] ]) |
147 | 149 | ||
148 | const resLastVideo1 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 150 | const resLastVideo1 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
149 | missedVideo1 = resLastVideo1.body.video | 151 | missedVideo1 = resLastVideo1.body.video |
150 | 152 | ||
151 | const resLastVideo2 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 153 | const resLastVideo2 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
152 | missedVideo2 = resLastVideo2.body.video | 154 | missedVideo2 = resLastVideo2.body.video |
153 | 155 | ||
154 | // Unlisted video | 156 | // Unlisted video |
155 | let resVideo = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, unlistedVideoAttributes) | 157 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, unlistedVideoAttributes) |
156 | unlistedVideo = resVideo.body.video | 158 | unlistedVideo = resVideo.body.video |
157 | 159 | ||
158 | // Add comments to video 2 | 160 | // Add comments to video 2 |
@@ -174,7 +176,7 @@ describe('Test handle downs', function () { | |||
174 | await wait(11000) | 176 | await wait(11000) |
175 | 177 | ||
176 | // Only server 3 is still a follower of server 1 | 178 | // Only server 3 is still a follower of server 1 |
177 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 179 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
178 | expect(res.body.data).to.be.an('array') | 180 | expect(res.body.data).to.be.an('array') |
179 | expect(res.body.data).to.have.lengthOf(1) | 181 | expect(res.body.data).to.have.lengthOf(1) |
180 | expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) | 182 | expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) |
@@ -185,8 +187,8 @@ describe('Test handle downs', function () { | |||
185 | 187 | ||
186 | for (const state of states) { | 188 | for (const state of states) { |
187 | const res = await getJobsListPaginationAndSort({ | 189 | const res = await getJobsListPaginationAndSort({ |
188 | url: servers[ 0 ].url, | 190 | url: servers[0].url, |
189 | accessToken: servers[ 0 ].accessToken, | 191 | accessToken: servers[0].accessToken, |
190 | state: state, | 192 | state: state, |
191 | start: 0, | 193 | start: 0, |
192 | count: 50, | 194 | count: 50, |
@@ -209,7 +211,7 @@ describe('Test handle downs', function () { | |||
209 | 211 | ||
210 | await waitJobs(servers) | 212 | await waitJobs(servers) |
211 | 213 | ||
212 | const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' }) | 214 | const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' }) |
213 | expect(res.body.data).to.be.an('array') | 215 | expect(res.body.data).to.be.an('array') |
214 | expect(res.body.data).to.have.lengthOf(2) | 216 | expect(res.body.data).to.have.lengthOf(2) |
215 | }) | 217 | }) |
@@ -221,8 +223,8 @@ describe('Test handle downs', function () { | |||
221 | expect(res1.body.data).to.be.an('array') | 223 | expect(res1.body.data).to.be.an('array') |
222 | expect(res1.body.data).to.have.lengthOf(11) | 224 | expect(res1.body.data).to.have.lengthOf(11) |
223 | 225 | ||
224 | await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { }) | 226 | await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, {}) |
225 | await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { }) | 227 | await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, {}) |
226 | 228 | ||
227 | await waitJobs(servers) | 229 | await waitJobs(servers) |
228 | 230 | ||
@@ -313,14 +315,14 @@ describe('Test handle downs', function () { | |||
313 | this.timeout(120000) | 315 | this.timeout(120000) |
314 | 316 | ||
315 | for (let i = 0; i < 10; i++) { | 317 | for (let i = 0; i < 10; i++) { |
316 | const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid | 318 | const uuid = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video ' + i })).uuid |
317 | videoIdsServer1.push(uuid) | 319 | videoIdsServer1.push(uuid) |
318 | } | 320 | } |
319 | 321 | ||
320 | await waitJobs(servers) | 322 | await waitJobs(servers) |
321 | 323 | ||
322 | for (const id of videoIdsServer1) { | 324 | for (const id of videoIdsServer1) { |
323 | await getVideo(servers[ 1 ].url, id) | 325 | await getVideo(servers[1].url, id) |
324 | } | 326 | } |
325 | 327 | ||
326 | await waitJobs(servers) | 328 | await waitJobs(servers) |
diff --git a/server/tests/api/server/jobs.ts b/server/tests/api/server/jobs.ts index 58d8c8c10..19c8836b5 100644 --- a/server/tests/api/server/jobs.ts +++ b/server/tests/api/server/jobs.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 5 | import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
6 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' | 6 | import { doubleFollow } from '../../../../shared/extra-utils/server/follows' |
7 | import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' | 7 | import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs' |
8 | import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' | 8 | import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers' |
@@ -44,8 +44,8 @@ describe('Test jobs', function () { | |||
44 | it('Should list jobs with sort, pagination and job type', async function () { | 44 | it('Should list jobs with sort, pagination and job type', async function () { |
45 | { | 45 | { |
46 | const res = await getJobsListPaginationAndSort({ | 46 | const res = await getJobsListPaginationAndSort({ |
47 | url: servers[ 1 ].url, | 47 | url: servers[1].url, |
48 | accessToken: servers[ 1 ].accessToken, | 48 | accessToken: servers[1].accessToken, |
49 | state: 'completed', | 49 | state: 'completed', |
50 | start: 1, | 50 | start: 1, |
51 | count: 2, | 51 | count: 2, |
@@ -54,9 +54,9 @@ describe('Test jobs', function () { | |||
54 | expect(res.body.total).to.be.above(2) | 54 | expect(res.body.total).to.be.above(2) |
55 | expect(res.body.data).to.have.lengthOf(2) | 55 | expect(res.body.data).to.have.lengthOf(2) |
56 | 56 | ||
57 | let job: Job = res.body.data[ 0 ] | 57 | let job: Job = res.body.data[0] |
58 | // Skip repeat jobs | 58 | // Skip repeat jobs |
59 | if (job.type === 'videos-views') job = res.body.data[ 1 ] | 59 | if (job.type === 'videos-views') job = res.body.data[1] |
60 | 60 | ||
61 | expect(job.state).to.equal('completed') | 61 | expect(job.state).to.equal('completed') |
62 | expect(job.type.startsWith('activitypub-')).to.be.true | 62 | expect(job.type.startsWith('activitypub-')).to.be.true |
@@ -67,8 +67,8 @@ describe('Test jobs', function () { | |||
67 | 67 | ||
68 | { | 68 | { |
69 | const res = await getJobsListPaginationAndSort({ | 69 | const res = await getJobsListPaginationAndSort({ |
70 | url: servers[ 1 ].url, | 70 | url: servers[1].url, |
71 | accessToken: servers[ 1 ].accessToken, | 71 | accessToken: servers[1].accessToken, |
72 | state: 'completed', | 72 | state: 'completed', |
73 | start: 0, | 73 | start: 0, |
74 | count: 100, | 74 | count: 100, |
diff --git a/server/tests/api/server/logs.ts b/server/tests/api/server/logs.ts index d3c877408..b8714c7a1 100644 --- a/server/tests/api/server/logs.ts +++ b/server/tests/api/server/logs.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/server/no-client.ts b/server/tests/api/server/no-client.ts index 86edeb289..d0450aba0 100644 --- a/server/tests/api/server/no-client.ts +++ b/server/tests/api/server/no-client.ts | |||
@@ -9,7 +9,7 @@ describe('Start and stop server without web client routes', function () { | |||
9 | before(async function () { | 9 | before(async function () { |
10 | this.timeout(30000) | 10 | this.timeout(30000) |
11 | 11 | ||
12 | server = await flushAndRunServer(1, {}, ['--no-client']) | 12 | server = await flushAndRunServer(1, {}, [ '--no-client' ]) |
13 | }) | 13 | }) |
14 | 14 | ||
15 | it('Should fail getting the client', function () { | 15 | it('Should fail getting the client', function () { |
diff --git a/server/tests/api/server/plugins.ts b/server/tests/api/server/plugins.ts index b8a8a2fee..452d05012 100644 --- a/server/tests/api/server/plugins.ts +++ b/server/tests/api/server/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -6,19 +6,28 @@ import { | |||
6 | cleanupTests, | 6 | cleanupTests, |
7 | closeAllSequelize, | 7 | closeAllSequelize, |
8 | flushAndRunServer, | 8 | flushAndRunServer, |
9 | getConfig, getMyUserInformation, getPluginPackageJSON, | 9 | getConfig, |
10 | getMyUserInformation, | ||
10 | getPlugin, | 11 | getPlugin, |
12 | getPluginPackageJSON, | ||
11 | getPluginRegisteredSettings, | 13 | getPluginRegisteredSettings, |
12 | getPluginsCSS, | 14 | getPluginsCSS, |
13 | installPlugin, killallServers, | 15 | getPublicSettings, |
16 | installPlugin, | ||
17 | killallServers, | ||
14 | listAvailablePlugins, | 18 | listAvailablePlugins, |
15 | listPlugins, reRunServer, | 19 | listPlugins, |
20 | reRunServer, | ||
16 | ServerInfo, | 21 | ServerInfo, |
17 | setAccessTokensToServers, | 22 | setAccessTokensToServers, |
18 | setPluginVersion, uninstallPlugin, | 23 | setPluginVersion, |
19 | updateCustomSubConfig, updateMyUser, updatePluginPackageJSON, updatePlugin, | 24 | uninstallPlugin, |
25 | updateCustomSubConfig, | ||
26 | updateMyUser, | ||
27 | updatePlugin, | ||
28 | updatePluginPackageJSON, | ||
20 | updatePluginSettings, | 29 | updatePluginSettings, |
21 | wait, getPublicSettings | 30 | wait |
22 | } from '../../../../shared/extra-utils' | 31 | } from '../../../../shared/extra-utils' |
23 | import { PluginType } from '../../../../shared/models/plugins/plugin.type' | 32 | import { PluginType } from '../../../../shared/models/plugins/plugin.type' |
24 | import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' | 33 | import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model' |
@@ -88,7 +97,7 @@ describe('Test plugins', function () { | |||
88 | expect(res2.body.total).to.be.at.least(2) | 97 | expect(res2.body.total).to.be.at.least(2) |
89 | expect(data2).to.have.lengthOf(2) | 98 | expect(data2).to.have.lengthOf(2) |
90 | 99 | ||
91 | expect(data1[0].npmName).to.not.equal(data2[ 0 ].npmName) | 100 | expect(data1[0].npmName).to.not.equal(data2[0].npmName) |
92 | } | 101 | } |
93 | 102 | ||
94 | { | 103 | { |
diff --git a/server/tests/api/server/reverse-proxy.ts b/server/tests/api/server/reverse-proxy.ts index b6b33a884..d0d79c4f6 100644 --- a/server/tests/api/server/reverse-proxy.ts +++ b/server/tests/api/server/reverse-proxy.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts index a01cd4b38..c207bb5f0 100644 --- a/server/tests/api/server/stats.ts +++ b/server/tests/api/server/stats.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -9,13 +9,12 @@ import { | |||
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | follow, | 11 | follow, |
12 | killallServers, | ||
13 | ServerInfo, | 12 | ServerInfo, |
14 | uploadVideo, | 13 | uploadVideo, |
15 | viewVideo, | 14 | viewVideo, |
16 | wait | 15 | wait |
17 | } from '../../../../shared/extra-utils' | 16 | } from '../../../../shared/extra-utils' |
18 | import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
19 | import { getStats } from '../../../../shared/extra-utils/server/stats' | 18 | import { getStats } from '../../../../shared/extra-utils/server/stats' |
20 | import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' | 19 | import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments' |
21 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 20 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
@@ -36,7 +35,7 @@ describe('Test stats (excluding redundancy)', function () { | |||
36 | username: 'user1', | 35 | username: 'user1', |
37 | password: 'super_password' | 36 | password: 'super_password' |
38 | } | 37 | } |
39 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 38 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
40 | 39 | ||
41 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' }) | 40 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' }) |
42 | const videoUUID = resVideo.body.video.uuid | 41 | const videoUUID = resVideo.body.video.uuid |
diff --git a/server/tests/api/server/tracker.ts b/server/tests/api/server/tracker.ts index 9d7eec8ca..9d3a274d4 100644 --- a/server/tests/api/server/tracker.ts +++ b/server/tests/api/server/tracker.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */ |
2 | 2 | ||
3 | import * as magnetUtil from 'magnet-uri' | 3 | import * as magnetUtil from 'magnet-uri' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts index 05e58017a..21b9ae4f8 100644 --- a/server/tests/api/users/blocklist.ts +++ b/server/tests/api/users/blocklist.ts | |||
@@ -1,21 +1,20 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { AccountBlock, ServerBlock, UserNotificationType, Video } from '../../../../shared/index' | 5 | import { AccountBlock, ServerBlock, Video } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, deleteVideoComment, | 8 | createUser, |
9 | deleteVideoComment, | ||
9 | doubleFollow, | 10 | doubleFollow, |
10 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | killallServers, | ||
13 | ServerInfo, | 12 | ServerInfo, |
14 | uploadVideo, | 13 | uploadVideo, |
15 | userLogin | 14 | userLogin |
16 | } from '../../../../shared/extra-utils/index' | 15 | } from '../../../../shared/extra-utils/index' |
17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 16 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
18 | import { getVideosListWithToken, getVideosList } from '../../../../shared/extra-utils/videos/videos' | 17 | import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos' |
19 | import { | 18 | import { |
20 | addVideoCommentReply, | 19 | addVideoCommentReply, |
21 | addVideoCommentThread, | 20 | addVideoCommentThread, |
@@ -79,7 +78,7 @@ async function checkCommentNotification ( | |||
79 | const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) | 78 | const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) |
80 | const threadId = resComment.body.comment.id | 79 | const threadId = resComment.body.comment.id |
81 | 80 | ||
82 | await waitJobs([ mainServer, comment.server]) | 81 | await waitJobs([ mainServer, comment.server ]) |
83 | 82 | ||
84 | const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) | 83 | const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) |
85 | const commentNotifications = res.body.data | 84 | const commentNotifications = res.body.data |
@@ -90,7 +89,7 @@ async function checkCommentNotification ( | |||
90 | 89 | ||
91 | await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId) | 90 | await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId) |
92 | 91 | ||
93 | await waitJobs([ mainServer, comment.server]) | 92 | await waitJobs([ mainServer, comment.server ]) |
94 | } | 93 | } |
95 | 94 | ||
96 | describe('Test blocklist', function () { | 95 | describe('Test blocklist', function () { |
@@ -109,7 +108,7 @@ describe('Test blocklist', function () { | |||
109 | 108 | ||
110 | { | 109 | { |
111 | const user = { username: 'user1', password: 'password' } | 110 | const user = { username: 'user1', password: 'password' } |
112 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 111 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
113 | 112 | ||
114 | userToken1 = await userLogin(servers[0], user) | 113 | userToken1 = await userLogin(servers[0], user) |
115 | await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) | 114 | await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' }) |
@@ -117,14 +116,14 @@ describe('Test blocklist', function () { | |||
117 | 116 | ||
118 | { | 117 | { |
119 | const user = { username: 'moderator', password: 'password' } | 118 | const user = { username: 'moderator', password: 'password' } |
120 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 119 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
121 | 120 | ||
122 | userModeratorToken = await userLogin(servers[0], user) | 121 | userModeratorToken = await userLogin(servers[0], user) |
123 | } | 122 | } |
124 | 123 | ||
125 | { | 124 | { |
126 | const user = { username: 'user2', password: 'password' } | 125 | const user = { username: 'user2', password: 'password' } |
127 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 126 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
128 | 127 | ||
129 | userToken2 = await userLogin(servers[1], user) | 128 | userToken2 = await userLogin(servers[1], user) |
130 | await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) | 129 | await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' }) |
@@ -143,14 +142,14 @@ describe('Test blocklist', function () { | |||
143 | await doubleFollow(servers[0], servers[1]) | 142 | await doubleFollow(servers[0], servers[1]) |
144 | 143 | ||
145 | { | 144 | { |
146 | const resComment = await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, 'comment root 1') | 145 | const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1') |
147 | const resReply = await addVideoCommentReply(servers[ 0 ].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') | 146 | const resReply = await addVideoCommentReply(servers[0].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1') |
148 | await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') | 147 | await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1') |
149 | } | 148 | } |
150 | 149 | ||
151 | { | 150 | { |
152 | const resComment = await addVideoCommentThread(servers[ 0 ].url, userToken1, videoUUID1, 'comment user 1') | 151 | const resComment = await addVideoCommentThread(servers[0].url, userToken1, videoUUID1, 'comment user 1') |
153 | await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') | 152 | await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1') |
154 | } | 153 | } |
155 | 154 | ||
156 | await waitJobs(servers) | 155 | await waitJobs(servers) |
@@ -160,19 +159,19 @@ describe('Test blocklist', function () { | |||
160 | 159 | ||
161 | describe('When managing account blocklist', function () { | 160 | describe('When managing account blocklist', function () { |
162 | it('Should list all videos', function () { | 161 | it('Should list all videos', function () { |
163 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 162 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
164 | }) | 163 | }) |
165 | 164 | ||
166 | it('Should list the comments', function () { | 165 | it('Should list the comments', function () { |
167 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 166 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
168 | }) | 167 | }) |
169 | 168 | ||
170 | it('Should block a remote account', async function () { | 169 | it('Should block a remote account', async function () { |
171 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 170 | await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
172 | }) | 171 | }) |
173 | 172 | ||
174 | it('Should hide its videos', async function () { | 173 | it('Should hide its videos', async function () { |
175 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 174 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
176 | 175 | ||
177 | const videos: Video[] = res.body.data | 176 | const videos: Video[] = res.body.data |
178 | expect(videos).to.have.lengthOf(3) | 177 | expect(videos).to.have.lengthOf(3) |
@@ -182,11 +181,11 @@ describe('Test blocklist', function () { | |||
182 | }) | 181 | }) |
183 | 182 | ||
184 | it('Should block a local account', async function () { | 183 | it('Should block a local account', async function () { |
185 | await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 184 | await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
186 | }) | 185 | }) |
187 | 186 | ||
188 | it('Should hide its videos', async function () { | 187 | it('Should hide its videos', async function () { |
189 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 188 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
190 | 189 | ||
191 | const videos: Video[] = res.body.data | 190 | const videos: Video[] = res.body.data |
192 | expect(videos).to.have.lengthOf(2) | 191 | expect(videos).to.have.lengthOf(2) |
@@ -196,17 +195,17 @@ describe('Test blocklist', function () { | |||
196 | }) | 195 | }) |
197 | 196 | ||
198 | it('Should hide its comments', async function () { | 197 | it('Should hide its comments', async function () { |
199 | const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', servers[ 0 ].accessToken) | 198 | const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken) |
200 | 199 | ||
201 | const threads: VideoComment[] = resThreads.body.data | 200 | const threads: VideoComment[] = resThreads.body.data |
202 | expect(threads).to.have.lengthOf(1) | 201 | expect(threads).to.have.lengthOf(1) |
203 | expect(threads[ 0 ].totalReplies).to.equal(0) | 202 | expect(threads[0].totalReplies).to.equal(0) |
204 | 203 | ||
205 | const t = threads.find(t => t.text === 'comment user 1') | 204 | const t = threads.find(t => t.text === 'comment user 1') |
206 | expect(t).to.be.undefined | 205 | expect(t).to.be.undefined |
207 | 206 | ||
208 | for (const thread of threads) { | 207 | for (const thread of threads) { |
209 | const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, servers[ 0 ].accessToken) | 208 | const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, servers[0].accessToken) |
210 | 209 | ||
211 | const tree: VideoCommentThreadTree = res.body | 210 | const tree: VideoCommentThreadTree = res.body |
212 | expect(tree.children).to.have.lengthOf(0) | 211 | expect(tree.children).to.have.lengthOf(0) |
@@ -217,37 +216,37 @@ describe('Test blocklist', function () { | |||
217 | this.timeout(20000) | 216 | this.timeout(20000) |
218 | 217 | ||
219 | { | 218 | { |
220 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } | 219 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } |
221 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 220 | await checkCommentNotification(servers[0], comment, 'absence') |
222 | } | 221 | } |
223 | 222 | ||
224 | { | 223 | { |
225 | const comment = { | 224 | const comment = { |
226 | server: servers[ 0 ], | 225 | server: servers[0], |
227 | token: userToken1, | 226 | token: userToken1, |
228 | videoUUID: videoUUID2, | 227 | videoUUID: videoUUID2, |
229 | text: 'hello @root@localhost:' + servers[ 0 ].port | 228 | text: 'hello @root@localhost:' + servers[0].port |
230 | } | 229 | } |
231 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 230 | await checkCommentNotification(servers[0], comment, 'absence') |
232 | } | 231 | } |
233 | }) | 232 | }) |
234 | 233 | ||
235 | it('Should list all the videos with another user', async function () { | 234 | it('Should list all the videos with another user', async function () { |
236 | return checkAllVideos(servers[ 0 ].url, userToken1) | 235 | return checkAllVideos(servers[0].url, userToken1) |
237 | }) | 236 | }) |
238 | 237 | ||
239 | it('Should list all the comments with another user', async function () { | 238 | it('Should list all the comments with another user', async function () { |
240 | return checkAllComments(servers[ 0 ].url, userToken1, videoUUID1) | 239 | return checkAllComments(servers[0].url, userToken1, videoUUID1) |
241 | }) | 240 | }) |
242 | 241 | ||
243 | it('Should list blocked accounts', async function () { | 242 | it('Should list blocked accounts', async function () { |
244 | { | 243 | { |
245 | const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 244 | const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
246 | const blocks: AccountBlock[] = res.body.data | 245 | const blocks: AccountBlock[] = res.body.data |
247 | 246 | ||
248 | expect(res.body.total).to.equal(2) | 247 | expect(res.body.total).to.equal(2) |
249 | 248 | ||
250 | const block = blocks[ 0 ] | 249 | const block = blocks[0] |
251 | expect(block.byAccount.displayName).to.equal('root') | 250 | expect(block.byAccount.displayName).to.equal('root') |
252 | expect(block.byAccount.name).to.equal('root') | 251 | expect(block.byAccount.name).to.equal('root') |
253 | expect(block.blockedAccount.displayName).to.equal('user2') | 252 | expect(block.blockedAccount.displayName).to.equal('user2') |
@@ -256,12 +255,12 @@ describe('Test blocklist', function () { | |||
256 | } | 255 | } |
257 | 256 | ||
258 | { | 257 | { |
259 | const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') | 258 | const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt') |
260 | const blocks: AccountBlock[] = res.body.data | 259 | const blocks: AccountBlock[] = res.body.data |
261 | 260 | ||
262 | expect(res.body.total).to.equal(2) | 261 | expect(res.body.total).to.equal(2) |
263 | 262 | ||
264 | const block = blocks[ 0 ] | 263 | const block = blocks[0] |
265 | expect(block.byAccount.displayName).to.equal('root') | 264 | expect(block.byAccount.displayName).to.equal('root') |
266 | expect(block.byAccount.name).to.equal('root') | 265 | expect(block.byAccount.name).to.equal('root') |
267 | expect(block.blockedAccount.displayName).to.equal('user1') | 266 | expect(block.blockedAccount.displayName).to.equal('user1') |
@@ -271,11 +270,11 @@ describe('Test blocklist', function () { | |||
271 | }) | 270 | }) |
272 | 271 | ||
273 | it('Should unblock the remote account', async function () { | 272 | it('Should unblock the remote account', async function () { |
274 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 273 | await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
275 | }) | 274 | }) |
276 | 275 | ||
277 | it('Should display its videos', async function () { | 276 | it('Should display its videos', async function () { |
278 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 277 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
279 | 278 | ||
280 | const videos: Video[] = res.body.data | 279 | const videos: Video[] = res.body.data |
281 | expect(videos).to.have.lengthOf(3) | 280 | expect(videos).to.have.lengthOf(3) |
@@ -285,48 +284,48 @@ describe('Test blocklist', function () { | |||
285 | }) | 284 | }) |
286 | 285 | ||
287 | it('Should unblock the local account', async function () { | 286 | it('Should unblock the local account', async function () { |
288 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 287 | await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
289 | }) | 288 | }) |
290 | 289 | ||
291 | it('Should display its comments', function () { | 290 | it('Should display its comments', function () { |
292 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 291 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
293 | }) | 292 | }) |
294 | 293 | ||
295 | it('Should have a notification from a non blocked account', async function () { | 294 | it('Should have a notification from a non blocked account', async function () { |
296 | this.timeout(20000) | 295 | this.timeout(20000) |
297 | 296 | ||
298 | { | 297 | { |
299 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 298 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
300 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 299 | await checkCommentNotification(servers[0], comment, 'presence') |
301 | } | 300 | } |
302 | 301 | ||
303 | { | 302 | { |
304 | const comment = { | 303 | const comment = { |
305 | server: servers[ 0 ], | 304 | server: servers[0], |
306 | token: userToken1, | 305 | token: userToken1, |
307 | videoUUID: videoUUID2, | 306 | videoUUID: videoUUID2, |
308 | text: 'hello @root@localhost:' + servers[ 0 ].port | 307 | text: 'hello @root@localhost:' + servers[0].port |
309 | } | 308 | } |
310 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 309 | await checkCommentNotification(servers[0], comment, 'presence') |
311 | } | 310 | } |
312 | }) | 311 | }) |
313 | }) | 312 | }) |
314 | 313 | ||
315 | describe('When managing server blocklist', function () { | 314 | describe('When managing server blocklist', function () { |
316 | it('Should list all videos', function () { | 315 | it('Should list all videos', function () { |
317 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 316 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
318 | }) | 317 | }) |
319 | 318 | ||
320 | it('Should list the comments', function () { | 319 | it('Should list the comments', function () { |
321 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 320 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
322 | }) | 321 | }) |
323 | 322 | ||
324 | it('Should block a remote server', async function () { | 323 | it('Should block a remote server', async function () { |
325 | await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 324 | await addServerToAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
326 | }) | 325 | }) |
327 | 326 | ||
328 | it('Should hide its videos', async function () { | 327 | it('Should hide its videos', async function () { |
329 | const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken) | 328 | const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) |
330 | 329 | ||
331 | const videos: Video[] = res.body.data | 330 | const videos: Video[] = res.body.data |
332 | expect(videos).to.have.lengthOf(2) | 331 | expect(videos).to.have.lengthOf(2) |
@@ -339,81 +338,81 @@ describe('Test blocklist', function () { | |||
339 | }) | 338 | }) |
340 | 339 | ||
341 | it('Should list all the videos with another user', async function () { | 340 | it('Should list all the videos with another user', async function () { |
342 | return checkAllVideos(servers[ 0 ].url, userToken1) | 341 | return checkAllVideos(servers[0].url, userToken1) |
343 | }) | 342 | }) |
344 | 343 | ||
345 | it('Should hide its comments', async function () { | 344 | it('Should hide its comments', async function () { |
346 | this.timeout(10000) | 345 | this.timeout(10000) |
347 | 346 | ||
348 | const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') | 347 | const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2') |
349 | const threadId = resThreads.body.comment.id | 348 | const threadId = resThreads.body.comment.id |
350 | 349 | ||
351 | await waitJobs(servers) | 350 | await waitJobs(servers) |
352 | 351 | ||
353 | await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 352 | await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
354 | 353 | ||
355 | await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) | 354 | await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId) |
356 | }) | 355 | }) |
357 | 356 | ||
358 | it('Should not have notifications from blocked server', async function () { | 357 | it('Should not have notifications from blocked server', async function () { |
359 | this.timeout(20000) | 358 | this.timeout(20000) |
360 | 359 | ||
361 | { | 360 | { |
362 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } | 361 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } |
363 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 362 | await checkCommentNotification(servers[0], comment, 'absence') |
364 | } | 363 | } |
365 | 364 | ||
366 | { | 365 | { |
367 | const comment = { | 366 | const comment = { |
368 | server: servers[ 1 ], | 367 | server: servers[1], |
369 | token: userToken2, | 368 | token: userToken2, |
370 | videoUUID: videoUUID1, | 369 | videoUUID: videoUUID1, |
371 | text: 'hello @root@localhost:' + servers[ 0 ].port | 370 | text: 'hello @root@localhost:' + servers[0].port |
372 | } | 371 | } |
373 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 372 | await checkCommentNotification(servers[0], comment, 'absence') |
374 | } | 373 | } |
375 | }) | 374 | }) |
376 | 375 | ||
377 | it('Should list blocked servers', async function () { | 376 | it('Should list blocked servers', async function () { |
378 | const res = await getServerBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 377 | const res = await getServerBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
379 | const blocks: ServerBlock[] = res.body.data | 378 | const blocks: ServerBlock[] = res.body.data |
380 | 379 | ||
381 | expect(res.body.total).to.equal(1) | 380 | expect(res.body.total).to.equal(1) |
382 | 381 | ||
383 | const block = blocks[ 0 ] | 382 | const block = blocks[0] |
384 | expect(block.byAccount.displayName).to.equal('root') | 383 | expect(block.byAccount.displayName).to.equal('root') |
385 | expect(block.byAccount.name).to.equal('root') | 384 | expect(block.byAccount.name).to.equal('root') |
386 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 385 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
387 | }) | 386 | }) |
388 | 387 | ||
389 | it('Should unblock the remote server', async function () { | 388 | it('Should unblock the remote server', async function () { |
390 | await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 389 | await removeServerFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
391 | }) | 390 | }) |
392 | 391 | ||
393 | it('Should display its videos', function () { | 392 | it('Should display its videos', function () { |
394 | return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken) | 393 | return checkAllVideos(servers[0].url, servers[0].accessToken) |
395 | }) | 394 | }) |
396 | 395 | ||
397 | it('Should display its comments', function () { | 396 | it('Should display its comments', function () { |
398 | return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 397 | return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
399 | }) | 398 | }) |
400 | 399 | ||
401 | it('Should have notification from unblocked server', async function () { | 400 | it('Should have notification from unblocked server', async function () { |
402 | this.timeout(20000) | 401 | this.timeout(20000) |
403 | 402 | ||
404 | { | 403 | { |
405 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 404 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
406 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 405 | await checkCommentNotification(servers[0], comment, 'presence') |
407 | } | 406 | } |
408 | 407 | ||
409 | { | 408 | { |
410 | const comment = { | 409 | const comment = { |
411 | server: servers[ 1 ], | 410 | server: servers[1], |
412 | token: userToken2, | 411 | token: userToken2, |
413 | videoUUID: videoUUID1, | 412 | videoUUID: videoUUID1, |
414 | text: 'hello @root@localhost:' + servers[ 0 ].port | 413 | text: 'hello @root@localhost:' + servers[0].port |
415 | } | 414 | } |
416 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 415 | await checkCommentNotification(servers[0], comment, 'presence') |
417 | } | 416 | } |
418 | }) | 417 | }) |
419 | }) | 418 | }) |
@@ -423,24 +422,24 @@ describe('Test blocklist', function () { | |||
423 | 422 | ||
424 | describe('When managing account blocklist', function () { | 423 | describe('When managing account blocklist', function () { |
425 | it('Should list all videos', async function () { | 424 | it('Should list all videos', async function () { |
426 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 425 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
427 | await checkAllVideos(servers[ 0 ].url, token) | 426 | await checkAllVideos(servers[0].url, token) |
428 | } | 427 | } |
429 | }) | 428 | }) |
430 | 429 | ||
431 | it('Should list the comments', async function () { | 430 | it('Should list the comments', async function () { |
432 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 431 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
433 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 432 | await checkAllComments(servers[0].url, token, videoUUID1) |
434 | } | 433 | } |
435 | }) | 434 | }) |
436 | 435 | ||
437 | it('Should block a remote account', async function () { | 436 | it('Should block a remote account', async function () { |
438 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 437 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
439 | }) | 438 | }) |
440 | 439 | ||
441 | it('Should hide its videos', async function () { | 440 | it('Should hide its videos', async function () { |
442 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 441 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
443 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 442 | const res = await getVideosListWithToken(servers[0].url, token) |
444 | 443 | ||
445 | const videos: Video[] = res.body.data | 444 | const videos: Video[] = res.body.data |
446 | expect(videos).to.have.lengthOf(3) | 445 | expect(videos).to.have.lengthOf(3) |
@@ -451,12 +450,12 @@ describe('Test blocklist', function () { | |||
451 | }) | 450 | }) |
452 | 451 | ||
453 | it('Should block a local account', async function () { | 452 | it('Should block a local account', async function () { |
454 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 453 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
455 | }) | 454 | }) |
456 | 455 | ||
457 | it('Should hide its videos', async function () { | 456 | it('Should hide its videos', async function () { |
458 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 457 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
459 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 458 | const res = await getVideosListWithToken(servers[0].url, token) |
460 | 459 | ||
461 | const videos: Video[] = res.body.data | 460 | const videos: Video[] = res.body.data |
462 | expect(videos).to.have.lengthOf(2) | 461 | expect(videos).to.have.lengthOf(2) |
@@ -467,18 +466,18 @@ describe('Test blocklist', function () { | |||
467 | }) | 466 | }) |
468 | 467 | ||
469 | it('Should hide its comments', async function () { | 468 | it('Should hide its comments', async function () { |
470 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 469 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
471 | const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', token) | 470 | const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', token) |
472 | 471 | ||
473 | const threads: VideoComment[] = resThreads.body.data | 472 | const threads: VideoComment[] = resThreads.body.data |
474 | expect(threads).to.have.lengthOf(1) | 473 | expect(threads).to.have.lengthOf(1) |
475 | expect(threads[ 0 ].totalReplies).to.equal(0) | 474 | expect(threads[0].totalReplies).to.equal(0) |
476 | 475 | ||
477 | const t = threads.find(t => t.text === 'comment user 1') | 476 | const t = threads.find(t => t.text === 'comment user 1') |
478 | expect(t).to.be.undefined | 477 | expect(t).to.be.undefined |
479 | 478 | ||
480 | for (const thread of threads) { | 479 | for (const thread of threads) { |
481 | const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, token) | 480 | const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, token) |
482 | 481 | ||
483 | const tree: VideoCommentThreadTree = res.body | 482 | const tree: VideoCommentThreadTree = res.body |
484 | expect(tree.children).to.have.lengthOf(0) | 483 | expect(tree.children).to.have.lengthOf(0) |
@@ -490,29 +489,29 @@ describe('Test blocklist', function () { | |||
490 | this.timeout(20000) | 489 | this.timeout(20000) |
491 | 490 | ||
492 | { | 491 | { |
493 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } | 492 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' } |
494 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 493 | await checkCommentNotification(servers[0], comment, 'absence') |
495 | } | 494 | } |
496 | 495 | ||
497 | { | 496 | { |
498 | const comment = { | 497 | const comment = { |
499 | server: servers[ 1 ], | 498 | server: servers[1], |
500 | token: userToken2, | 499 | token: userToken2, |
501 | videoUUID: videoUUID1, | 500 | videoUUID: videoUUID1, |
502 | text: 'hello @root@localhost:' + servers[ 0 ].port | 501 | text: 'hello @root@localhost:' + servers[0].port |
503 | } | 502 | } |
504 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 503 | await checkCommentNotification(servers[0], comment, 'absence') |
505 | } | 504 | } |
506 | }) | 505 | }) |
507 | 506 | ||
508 | it('Should list blocked accounts', async function () { | 507 | it('Should list blocked accounts', async function () { |
509 | { | 508 | { |
510 | const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 509 | const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
511 | const blocks: AccountBlock[] = res.body.data | 510 | const blocks: AccountBlock[] = res.body.data |
512 | 511 | ||
513 | expect(res.body.total).to.equal(2) | 512 | expect(res.body.total).to.equal(2) |
514 | 513 | ||
515 | const block = blocks[ 0 ] | 514 | const block = blocks[0] |
516 | expect(block.byAccount.displayName).to.equal('peertube') | 515 | expect(block.byAccount.displayName).to.equal('peertube') |
517 | expect(block.byAccount.name).to.equal('peertube') | 516 | expect(block.byAccount.name).to.equal('peertube') |
518 | expect(block.blockedAccount.displayName).to.equal('user2') | 517 | expect(block.blockedAccount.displayName).to.equal('user2') |
@@ -521,12 +520,12 @@ describe('Test blocklist', function () { | |||
521 | } | 520 | } |
522 | 521 | ||
523 | { | 522 | { |
524 | const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt') | 523 | const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt') |
525 | const blocks: AccountBlock[] = res.body.data | 524 | const blocks: AccountBlock[] = res.body.data |
526 | 525 | ||
527 | expect(res.body.total).to.equal(2) | 526 | expect(res.body.total).to.equal(2) |
528 | 527 | ||
529 | const block = blocks[ 0 ] | 528 | const block = blocks[0] |
530 | expect(block.byAccount.displayName).to.equal('peertube') | 529 | expect(block.byAccount.displayName).to.equal('peertube') |
531 | expect(block.byAccount.name).to.equal('peertube') | 530 | expect(block.byAccount.name).to.equal('peertube') |
532 | expect(block.blockedAccount.displayName).to.equal('user1') | 531 | expect(block.blockedAccount.displayName).to.equal('user1') |
@@ -536,12 +535,12 @@ describe('Test blocklist', function () { | |||
536 | }) | 535 | }) |
537 | 536 | ||
538 | it('Should unblock the remote account', async function () { | 537 | it('Should unblock the remote account', async function () { |
539 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port) | 538 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) |
540 | }) | 539 | }) |
541 | 540 | ||
542 | it('Should display its videos', async function () { | 541 | it('Should display its videos', async function () { |
543 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 542 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
544 | const res = await getVideosListWithToken(servers[ 0 ].url, token) | 543 | const res = await getVideosListWithToken(servers[0].url, token) |
545 | 544 | ||
546 | const videos: Video[] = res.body.data | 545 | const videos: Video[] = res.body.data |
547 | expect(videos).to.have.lengthOf(3) | 546 | expect(videos).to.have.lengthOf(3) |
@@ -552,12 +551,12 @@ describe('Test blocklist', function () { | |||
552 | }) | 551 | }) |
553 | 552 | ||
554 | it('Should unblock the local account', async function () { | 553 | it('Should unblock the local account', async function () { |
555 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1') | 554 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user1') |
556 | }) | 555 | }) |
557 | 556 | ||
558 | it('Should display its comments', async function () { | 557 | it('Should display its comments', async function () { |
559 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 558 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
560 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 559 | await checkAllComments(servers[0].url, token, videoUUID1) |
561 | } | 560 | } |
562 | }) | 561 | }) |
563 | 562 | ||
@@ -565,43 +564,43 @@ describe('Test blocklist', function () { | |||
565 | this.timeout(20000) | 564 | this.timeout(20000) |
566 | 565 | ||
567 | { | 566 | { |
568 | const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } | 567 | const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' } |
569 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 568 | await checkCommentNotification(servers[0], comment, 'presence') |
570 | } | 569 | } |
571 | 570 | ||
572 | { | 571 | { |
573 | const comment = { | 572 | const comment = { |
574 | server: servers[ 1 ], | 573 | server: servers[1], |
575 | token: userToken2, | 574 | token: userToken2, |
576 | videoUUID: videoUUID1, | 575 | videoUUID: videoUUID1, |
577 | text: 'hello @root@localhost:' + servers[ 0 ].port | 576 | text: 'hello @root@localhost:' + servers[0].port |
578 | } | 577 | } |
579 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 578 | await checkCommentNotification(servers[0], comment, 'presence') |
580 | } | 579 | } |
581 | }) | 580 | }) |
582 | }) | 581 | }) |
583 | 582 | ||
584 | describe('When managing server blocklist', function () { | 583 | describe('When managing server blocklist', function () { |
585 | it('Should list all videos', async function () { | 584 | it('Should list all videos', async function () { |
586 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 585 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
587 | await checkAllVideos(servers[ 0 ].url, token) | 586 | await checkAllVideos(servers[0].url, token) |
588 | } | 587 | } |
589 | }) | 588 | }) |
590 | 589 | ||
591 | it('Should list the comments', async function () { | 590 | it('Should list the comments', async function () { |
592 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 591 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
593 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 592 | await checkAllComments(servers[0].url, token, videoUUID1) |
594 | } | 593 | } |
595 | }) | 594 | }) |
596 | 595 | ||
597 | it('Should block a remote server', async function () { | 596 | it('Should block a remote server', async function () { |
598 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 597 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
599 | }) | 598 | }) |
600 | 599 | ||
601 | it('Should hide its videos', async function () { | 600 | it('Should hide its videos', async function () { |
602 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 601 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
603 | const res1 = await getVideosList(servers[ 0 ].url) | 602 | const res1 = await getVideosList(servers[0].url) |
604 | const res2 = await getVideosListWithToken(servers[ 0 ].url, token) | 603 | const res2 = await getVideosListWithToken(servers[0].url, token) |
605 | 604 | ||
606 | for (const res of [ res1, res2 ]) { | 605 | for (const res of [ res1, res2 ]) { |
607 | const videos: Video[] = res.body.data | 606 | const videos: Video[] = res.body.data |
@@ -619,60 +618,60 @@ describe('Test blocklist', function () { | |||
619 | it('Should hide its comments', async function () { | 618 | it('Should hide its comments', async function () { |
620 | this.timeout(10000) | 619 | this.timeout(10000) |
621 | 620 | ||
622 | const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2') | 621 | const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2') |
623 | const threadId = resThreads.body.comment.id | 622 | const threadId = resThreads.body.comment.id |
624 | 623 | ||
625 | await waitJobs(servers) | 624 | await waitJobs(servers) |
626 | 625 | ||
627 | await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1) | 626 | await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1) |
628 | 627 | ||
629 | await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId) | 628 | await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId) |
630 | }) | 629 | }) |
631 | 630 | ||
632 | it('Should not have notification from blocked instances by instance', async function () { | 631 | it('Should not have notification from blocked instances by instance', async function () { |
633 | this.timeout(20000) | 632 | this.timeout(20000) |
634 | 633 | ||
635 | { | 634 | { |
636 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } | 635 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } |
637 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 636 | await checkCommentNotification(servers[0], comment, 'absence') |
638 | } | 637 | } |
639 | 638 | ||
640 | { | 639 | { |
641 | const comment = { | 640 | const comment = { |
642 | server: servers[ 1 ], | 641 | server: servers[1], |
643 | token: userToken2, | 642 | token: userToken2, |
644 | videoUUID: videoUUID1, | 643 | videoUUID: videoUUID1, |
645 | text: 'hello @root@localhost:' + servers[ 0 ].port | 644 | text: 'hello @root@localhost:' + servers[0].port |
646 | } | 645 | } |
647 | await checkCommentNotification(servers[ 0 ], comment, 'absence') | 646 | await checkCommentNotification(servers[0], comment, 'absence') |
648 | } | 647 | } |
649 | }) | 648 | }) |
650 | 649 | ||
651 | it('Should list blocked servers', async function () { | 650 | it('Should list blocked servers', async function () { |
652 | const res = await getServerBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt') | 651 | const res = await getServerBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') |
653 | const blocks: ServerBlock[] = res.body.data | 652 | const blocks: ServerBlock[] = res.body.data |
654 | 653 | ||
655 | expect(res.body.total).to.equal(1) | 654 | expect(res.body.total).to.equal(1) |
656 | 655 | ||
657 | const block = blocks[ 0 ] | 656 | const block = blocks[0] |
658 | expect(block.byAccount.displayName).to.equal('peertube') | 657 | expect(block.byAccount.displayName).to.equal('peertube') |
659 | expect(block.byAccount.name).to.equal('peertube') | 658 | expect(block.byAccount.name).to.equal('peertube') |
660 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) | 659 | expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port) |
661 | }) | 660 | }) |
662 | 661 | ||
663 | it('Should unblock the remote server', async function () { | 662 | it('Should unblock the remote server', async function () { |
664 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 663 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
665 | }) | 664 | }) |
666 | 665 | ||
667 | it('Should list all videos', async function () { | 666 | it('Should list all videos', async function () { |
668 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 667 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
669 | await checkAllVideos(servers[ 0 ].url, token) | 668 | await checkAllVideos(servers[0].url, token) |
670 | } | 669 | } |
671 | }) | 670 | }) |
672 | 671 | ||
673 | it('Should list the comments', async function () { | 672 | it('Should list the comments', async function () { |
674 | for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) { | 673 | for (const token of [ userModeratorToken, servers[0].accessToken ]) { |
675 | await checkAllComments(servers[ 0 ].url, token, videoUUID1) | 674 | await checkAllComments(servers[0].url, token, videoUUID1) |
676 | } | 675 | } |
677 | }) | 676 | }) |
678 | 677 | ||
@@ -680,18 +679,18 @@ describe('Test blocklist', function () { | |||
680 | this.timeout(20000) | 679 | this.timeout(20000) |
681 | 680 | ||
682 | { | 681 | { |
683 | const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } | 682 | const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } |
684 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 683 | await checkCommentNotification(servers[0], comment, 'presence') |
685 | } | 684 | } |
686 | 685 | ||
687 | { | 686 | { |
688 | const comment = { | 687 | const comment = { |
689 | server: servers[ 1 ], | 688 | server: servers[1], |
690 | token: userToken2, | 689 | token: userToken2, |
691 | videoUUID: videoUUID1, | 690 | videoUUID: videoUUID1, |
692 | text: 'hello @root@localhost:' + servers[ 0 ].port | 691 | text: 'hello @root@localhost:' + servers[0].port |
693 | } | 692 | } |
694 | await checkCommentNotification(servers[ 0 ], comment, 'presence') | 693 | await checkCommentNotification(servers[0], comment, 'presence') |
695 | } | 694 | } |
696 | }) | 695 | }) |
697 | }) | 696 | }) |
diff --git a/server/tests/api/users/user-subscriptions.ts b/server/tests/api/users/user-subscriptions.ts index 08017f89c..7d6b0c6a9 100644 --- a/server/tests/api/users/user-subscriptions.ts +++ b/server/tests/api/users/user-subscriptions.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -13,16 +13,17 @@ import { | |||
13 | updateVideo, | 13 | updateVideo, |
14 | userLogin | 14 | userLogin |
15 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
16 | import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index' | 16 | import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index' |
17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' | 17 | import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' |
18 | import { Video, VideoChannel } from '../../../../shared/models/videos' | 18 | import { Video, VideoChannel } from '../../../../shared/models/videos' |
19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
20 | import { | 20 | import { |
21 | addUserSubscription, | 21 | addUserSubscription, |
22 | areSubscriptionsExist, | ||
23 | getUserSubscription, | ||
22 | listUserSubscriptions, | 24 | listUserSubscriptions, |
23 | listUserSubscriptionVideos, | 25 | listUserSubscriptionVideos, |
24 | removeUserSubscription, | 26 | removeUserSubscription |
25 | getUserSubscription, areSubscriptionsExist | ||
26 | } from '../../../../shared/extra-utils/users/user-subscriptions' | 27 | } from '../../../../shared/extra-utils/users/user-subscriptions' |
27 | 28 | ||
28 | const expect = chai.expect | 29 | const expect = chai.expect |
@@ -116,7 +117,7 @@ describe('Test users subscriptions', function () { | |||
116 | 117 | ||
117 | it('Should get subscription', async function () { | 118 | it('Should get subscription', async function () { |
118 | { | 119 | { |
119 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port) | 120 | const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port) |
120 | const videoChannel: VideoChannel = res.body | 121 | const videoChannel: VideoChannel = res.body |
121 | 122 | ||
122 | expect(videoChannel.name).to.equal('user3_channel') | 123 | expect(videoChannel.name).to.equal('user3_channel') |
@@ -127,7 +128,7 @@ describe('Test users subscriptions', function () { | |||
127 | } | 128 | } |
128 | 129 | ||
129 | { | 130 | { |
130 | const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port) | 131 | const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port) |
131 | const videoChannel: VideoChannel = res.body | 132 | const videoChannel: VideoChannel = res.body |
132 | 133 | ||
133 | expect(videoChannel.name).to.equal('root_channel') | 134 | expect(videoChannel.name).to.equal('root_channel') |
@@ -146,7 +147,7 @@ describe('Test users subscriptions', function () { | |||
146 | 'user3_channel@localhost:' + servers[0].port | 147 | 'user3_channel@localhost:' + servers[0].port |
147 | ] | 148 | ] |
148 | 149 | ||
149 | const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris) | 150 | const res = await areSubscriptionsExist(servers[0].url, users[0].accessToken, uris) |
150 | const body = res.body | 151 | const body = res.body |
151 | 152 | ||
152 | expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true | 153 | expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true |
diff --git a/server/tests/api/users/users-multiple-servers.ts b/server/tests/api/users/users-multiple-servers.ts index 791418318..591ce4959 100644 --- a/server/tests/api/users/users-multiple-servers.ts +++ b/server/tests/api/users/users-multiple-servers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -57,17 +57,17 @@ describe('Test users with multiple servers', function () { | |||
57 | password: 'password' | 57 | password: 'password' |
58 | } | 58 | } |
59 | const res = await createUser({ | 59 | const res = await createUser({ |
60 | url: servers[ 0 ].url, | 60 | url: servers[0].url, |
61 | accessToken: servers[ 0 ].accessToken, | 61 | accessToken: servers[0].accessToken, |
62 | username: user.username, | 62 | username: user.username, |
63 | password: user.password | 63 | password: user.password |
64 | }) | 64 | }) |
65 | userId = res.body.user.id | 65 | userId = res.body.user.id |
66 | userAccessToken = await userLogin(servers[ 0 ], user) | 66 | userAccessToken = await userLogin(servers[0], user) |
67 | } | 67 | } |
68 | 68 | ||
69 | { | 69 | { |
70 | const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {}) | 70 | const resVideo = await uploadVideo(servers[0].url, userAccessToken, {}) |
71 | videoUUID = resVideo.body.video.uuid | 71 | videoUUID = resVideo.body.video.uuid |
72 | } | 72 | } |
73 | 73 | ||
@@ -86,7 +86,6 @@ describe('Test users with multiple servers', function () { | |||
86 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 86 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
87 | user = res.body | 87 | user = res.body |
88 | 88 | ||
89 | const account: Account = user.account | ||
90 | expect(user.account.displayName).to.equal('my super display name') | 89 | expect(user.account.displayName).to.equal('my super display name') |
91 | 90 | ||
92 | await waitJobs(servers) | 91 | await waitJobs(servers) |
diff --git a/server/tests/api/users/users-verification.ts b/server/tests/api/users/users-verification.ts index 7cd61f539..675ebf690 100644 --- a/server/tests/api/users/users-verification.ts +++ b/server/tests/api/users/users-verification.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 24203a731..502eac0bb 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index' | 5 | import { MyUser, User, UserRole, Video, VideoPlaylistType } from '../../../../shared/index' |
6 | import { | 6 | import { |
7 | blockUser, | 7 | blockUser, |
8 | cleanupTests, | 8 | cleanupTests, |
@@ -18,7 +18,8 @@ import { | |||
18 | getUsersList, | 18 | getUsersList, |
19 | getUsersListPaginationAndSort, | 19 | getUsersListPaginationAndSort, |
20 | getVideoChannel, | 20 | getVideoChannel, |
21 | getVideosList, installPlugin, | 21 | getVideosList, |
22 | installPlugin, | ||
22 | login, | 23 | login, |
23 | makePutBodyRequest, | 24 | makePutBodyRequest, |
24 | rateVideo, | 25 | rateVideo, |
@@ -121,13 +122,13 @@ describe('Test users', function () { | |||
121 | 122 | ||
122 | it('Should be able to login with an insensitive username', async function () { | 123 | it('Should be able to login with an insensitive username', async function () { |
123 | const user = { username: 'RoOt', password: server.user.password } | 124 | const user = { username: 'RoOt', password: server.user.password } |
124 | const res = await login(server.url, server.client, user, 200) | 125 | await login(server.url, server.client, user, 200) |
125 | 126 | ||
126 | const user2 = { username: 'rOoT', password: server.user.password } | 127 | const user2 = { username: 'rOoT', password: server.user.password } |
127 | const res2 = await login(server.url, server.client, user2, 200) | 128 | await login(server.url, server.client, user2, 200) |
128 | 129 | ||
129 | const user3 = { username: 'ROOt', password: server.user.password } | 130 | const user3 = { username: 'ROOt', password: server.user.password } |
130 | const res3 = await login(server.url, server.client, user3, 200) | 131 | await login(server.url, server.client, user3, 200) |
131 | }) | 132 | }) |
132 | }) | 133 | }) |
133 | 134 | ||
@@ -137,7 +138,7 @@ describe('Test users', function () { | |||
137 | const videoAttributes = {} | 138 | const videoAttributes = {} |
138 | await uploadVideo(server.url, accessToken, videoAttributes) | 139 | await uploadVideo(server.url, accessToken, videoAttributes) |
139 | const res = await getVideosList(server.url) | 140 | const res = await getVideosList(server.url) |
140 | const video = res.body.data[ 0 ] | 141 | const video = res.body.data[0] |
141 | 142 | ||
142 | expect(video.account.name).to.equal('root') | 143 | expect(video.account.name).to.equal('root') |
143 | videoId = video.id | 144 | videoId = video.id |
@@ -167,8 +168,8 @@ describe('Test users', function () { | |||
167 | const ratings = res.body | 168 | const ratings = res.body |
168 | 169 | ||
169 | expect(ratings.total).to.equal(1) | 170 | expect(ratings.total).to.equal(1) |
170 | expect(ratings.data[ 0 ].video.id).to.equal(videoId) | 171 | expect(ratings.data[0].video.id).to.equal(videoId) |
171 | expect(ratings.data[ 0 ].rating).to.equal('like') | 172 | expect(ratings.data[0].rating).to.equal('like') |
172 | }) | 173 | }) |
173 | 174 | ||
174 | it('Should retrieve ratings list by rating type', async function () { | 175 | it('Should retrieve ratings list by rating type', async function () { |
@@ -307,7 +308,7 @@ describe('Test users', function () { | |||
307 | const videos = res.body.data | 308 | const videos = res.body.data |
308 | expect(videos).to.have.lengthOf(1) | 309 | expect(videos).to.have.lengthOf(1) |
309 | 310 | ||
310 | const video: Video = videos[ 0 ] | 311 | const video: Video = videos[0] |
311 | expect(video.name).to.equal('super user video') | 312 | expect(video.name).to.equal('super user video') |
312 | expect(video.thumbnailPath).to.not.be.null | 313 | expect(video.thumbnailPath).to.not.be.null |
313 | expect(video.previewPath).to.not.be.null | 314 | expect(video.previewPath).to.not.be.null |
@@ -344,12 +345,12 @@ describe('Test users', function () { | |||
344 | expect(users).to.be.an('array') | 345 | expect(users).to.be.an('array') |
345 | expect(users.length).to.equal(2) | 346 | expect(users.length).to.equal(2) |
346 | 347 | ||
347 | const user = users[ 0 ] | 348 | const user = users[0] |
348 | expect(user.username).to.equal('user_1') | 349 | expect(user.username).to.equal('user_1') |
349 | expect(user.email).to.equal('user_1@example.com') | 350 | expect(user.email).to.equal('user_1@example.com') |
350 | expect(user.nsfwPolicy).to.equal('display') | 351 | expect(user.nsfwPolicy).to.equal('display') |
351 | 352 | ||
352 | const rootUser = users[ 1 ] | 353 | const rootUser = users[1] |
353 | expect(rootUser.username).to.equal('root') | 354 | expect(rootUser.username).to.equal('root') |
354 | expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 355 | expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
355 | expect(user.nsfwPolicy).to.equal('display') | 356 | expect(user.nsfwPolicy).to.equal('display') |
@@ -367,7 +368,7 @@ describe('Test users', function () { | |||
367 | expect(total).to.equal(2) | 368 | expect(total).to.equal(2) |
368 | expect(users.length).to.equal(1) | 369 | expect(users.length).to.equal(1) |
369 | 370 | ||
370 | const user = users[ 0 ] | 371 | const user = users[0] |
371 | expect(user.username).to.equal('root') | 372 | expect(user.username).to.equal('root') |
372 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') | 373 | expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com') |
373 | expect(user.roleLabel).to.equal('Administrator') | 374 | expect(user.roleLabel).to.equal('Administrator') |
@@ -383,7 +384,7 @@ describe('Test users', function () { | |||
383 | expect(total).to.equal(2) | 384 | expect(total).to.equal(2) |
384 | expect(users.length).to.equal(1) | 385 | expect(users.length).to.equal(1) |
385 | 386 | ||
386 | const user = users[ 0 ] | 387 | const user = users[0] |
387 | expect(user.username).to.equal('user_1') | 388 | expect(user.username).to.equal('user_1') |
388 | expect(user.email).to.equal('user_1@example.com') | 389 | expect(user.email).to.equal('user_1@example.com') |
389 | expect(user.nsfwPolicy).to.equal('display') | 390 | expect(user.nsfwPolicy).to.equal('display') |
@@ -398,7 +399,7 @@ describe('Test users', function () { | |||
398 | expect(total).to.equal(2) | 399 | expect(total).to.equal(2) |
399 | expect(users.length).to.equal(1) | 400 | expect(users.length).to.equal(1) |
400 | 401 | ||
401 | const user = users[ 0 ] | 402 | const user = users[0] |
402 | expect(user.username).to.equal('user_1') | 403 | expect(user.username).to.equal('user_1') |
403 | expect(user.email).to.equal('user_1@example.com') | 404 | expect(user.email).to.equal('user_1@example.com') |
404 | expect(user.nsfwPolicy).to.equal('display') | 405 | expect(user.nsfwPolicy).to.equal('display') |
@@ -413,13 +414,13 @@ describe('Test users', function () { | |||
413 | expect(total).to.equal(2) | 414 | expect(total).to.equal(2) |
414 | expect(users.length).to.equal(2) | 415 | expect(users.length).to.equal(2) |
415 | 416 | ||
416 | expect(users[ 0 ].username).to.equal('root') | 417 | expect(users[0].username).to.equal('root') |
417 | expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com') | 418 | expect(users[0].email).to.equal('admin' + server.internalServerNumber + '@example.com') |
418 | expect(users[ 0 ].nsfwPolicy).to.equal('display') | 419 | expect(users[0].nsfwPolicy).to.equal('display') |
419 | 420 | ||
420 | expect(users[ 1 ].username).to.equal('user_1') | 421 | expect(users[1].username).to.equal('user_1') |
421 | expect(users[ 1 ].email).to.equal('user_1@example.com') | 422 | expect(users[1].email).to.equal('user_1@example.com') |
422 | expect(users[ 1 ].nsfwPolicy).to.equal('display') | 423 | expect(users[1].nsfwPolicy).to.equal('display') |
423 | }) | 424 | }) |
424 | 425 | ||
425 | it('Should search user by username', async function () { | 426 | it('Should search user by username', async function () { |
@@ -429,7 +430,7 @@ describe('Test users', function () { | |||
429 | expect(res.body.total).to.equal(1) | 430 | expect(res.body.total).to.equal(1) |
430 | expect(users.length).to.equal(1) | 431 | expect(users.length).to.equal(1) |
431 | 432 | ||
432 | expect(users[ 0 ].username).to.equal('root') | 433 | expect(users[0].username).to.equal('root') |
433 | }) | 434 | }) |
434 | 435 | ||
435 | it('Should search user by email', async function () { | 436 | it('Should search user by email', async function () { |
@@ -440,8 +441,8 @@ describe('Test users', function () { | |||
440 | expect(res.body.total).to.equal(1) | 441 | expect(res.body.total).to.equal(1) |
441 | expect(users.length).to.equal(1) | 442 | expect(users.length).to.equal(1) |
442 | 443 | ||
443 | expect(users[ 0 ].username).to.equal('user_1') | 444 | expect(users[0].username).to.equal('user_1') |
444 | expect(users[ 0 ].email).to.equal('user_1@example.com') | 445 | expect(users[0].email).to.equal('user_1@example.com') |
445 | } | 446 | } |
446 | 447 | ||
447 | { | 448 | { |
@@ -451,8 +452,8 @@ describe('Test users', function () { | |||
451 | expect(res.body.total).to.equal(2) | 452 | expect(res.body.total).to.equal(2) |
452 | expect(users.length).to.equal(2) | 453 | expect(users.length).to.equal(2) |
453 | 454 | ||
454 | expect(users[ 0 ].username).to.equal('root') | 455 | expect(users[0].username).to.equal('root') |
455 | expect(users[ 1 ].username).to.equal('user_1') | 456 | expect(users[1].username).to.equal('user_1') |
456 | } | 457 | } |
457 | }) | 458 | }) |
458 | }) | 459 | }) |
@@ -691,7 +692,7 @@ describe('Test users', function () { | |||
691 | 692 | ||
692 | expect(res.body.total).to.equal(1) | 693 | expect(res.body.total).to.equal(1) |
693 | 694 | ||
694 | const video = res.body.data[ 0 ] | 695 | const video = res.body.data[0] |
695 | expect(video.account.name).to.equal('root') | 696 | expect(video.account.name).to.equal('root') |
696 | }) | 697 | }) |
697 | }) | 698 | }) |
diff --git a/server/tests/api/videos/audio-only.ts b/server/tests/api/videos/audio-only.ts index f12d730cc..ac7a0b89c 100644 --- a/server/tests/api/videos/audio-only.ts +++ b/server/tests/api/videos/audio-only.ts | |||
@@ -1,28 +1,21 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | checkDirectoryIsEmpty, | ||
7 | checkSegmentHash, | ||
8 | checkTmpIsEmpty, | ||
9 | cleanupTests, | 6 | cleanupTests, |
10 | doubleFollow, | 7 | doubleFollow, |
11 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
12 | getPlaylist, | 9 | getVideo, |
13 | getVideo, makeGetRequest, makeRawRequest, | 10 | root, |
14 | removeVideo, root, | ||
15 | ServerInfo, | 11 | ServerInfo, |
16 | setAccessTokensToServers, updateCustomSubConfig, | 12 | setAccessTokensToServers, |
17 | updateVideo, | ||
18 | uploadVideo, | 13 | uploadVideo, |
19 | waitJobs, webtorrentAdd | 14 | waitJobs |
20 | } from '../../../../shared/extra-utils' | 15 | } from '../../../../shared/extra-utils' |
21 | import { VideoDetails } from '../../../../shared/models/videos' | 16 | import { VideoDetails } from '../../../../shared/models/videos' |
22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | ||
23 | import { join } from 'path' | 17 | import { join } from 'path' |
24 | import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants' | 18 | import { audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils' |
25 | import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution, audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils' | ||
26 | 19 | ||
27 | const expect = chai.expect | 20 | const expect = chai.expect |
28 | 21 | ||
@@ -87,14 +80,14 @@ describe('Test audio only video transcoding', function () { | |||
87 | 80 | ||
88 | it('0p transcoded video should not have video', async function () { | 81 | it('0p transcoded video should not have video', async function () { |
89 | const paths = [ | 82 | const paths = [ |
90 | join(root(), 'test' + servers[ 0 ].internalServerNumber, 'videos', videoUUID + '-0.mp4'), | 83 | join(root(), 'test' + servers[0].internalServerNumber, 'videos', videoUUID + '-0.mp4'), |
91 | join(root(), 'test' + servers[ 0 ].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4') | 84 | join(root(), 'test' + servers[0].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4') |
92 | ] | 85 | ] |
93 | 86 | ||
94 | for (const path of paths) { | 87 | for (const path of paths) { |
95 | const { audioStream } = await audio.get(path) | 88 | const { audioStream } = await audio.get(path) |
96 | expect(audioStream[ 'codec_name' ]).to.be.equal('aac') | 89 | expect(audioStream['codec_name']).to.be.equal('aac') |
97 | expect(audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) | 90 | expect(audioStream['bit_rate']).to.be.at.most(384 * 8000) |
98 | 91 | ||
99 | const size = await getVideoStreamSize(path) | 92 | const size = await getVideoStreamSize(path) |
100 | expect(size.height).to.equal(0) | 93 | expect(size.height).to.equal(0) |
diff --git a/server/tests/api/videos/multiple-servers.ts b/server/tests/api/videos/multiple-servers.ts index fa3e250ec..e3029f1ae 100644 --- a/server/tests/api/videos/multiple-servers.ts +++ b/server/tests/api/videos/multiple-servers.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -63,9 +63,9 @@ describe('Test multiple servers', function () { | |||
63 | displayName: 'my channel', | 63 | displayName: 'my channel', |
64 | description: 'super channel' | 64 | description: 'super channel' |
65 | } | 65 | } |
66 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 66 | await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
67 | const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1) | 67 | const channelRes = await getVideoChannelsList(servers[0].url, 0, 1) |
68 | videoChannelId = channelRes.body.data[ 0 ].id | 68 | videoChannelId = channelRes.body.data[0].id |
69 | } | 69 | } |
70 | 70 | ||
71 | // Server 1 and server 2 follow each other | 71 | // Server 1 and server 2 follow each other |
@@ -163,7 +163,7 @@ describe('Test multiple servers', function () { | |||
163 | username: 'user1', | 163 | username: 'user1', |
164 | password: 'super_password' | 164 | password: 'super_password' |
165 | } | 165 | } |
166 | await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password }) | 166 | await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password }) |
167 | const userAccessToken = await userLogin(servers[1], user) | 167 | const userAccessToken = await userLogin(servers[1], user) |
168 | 168 | ||
169 | const videoAttributes = { | 169 | const videoAttributes = { |
@@ -762,12 +762,12 @@ describe('Test multiple servers', function () { | |||
762 | 762 | ||
763 | { | 763 | { |
764 | const text = 'my super first comment' | 764 | const text = 'my super first comment' |
765 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text) | 765 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, text) |
766 | } | 766 | } |
767 | 767 | ||
768 | { | 768 | { |
769 | const text = 'my super second comment' | 769 | const text = 'my super second comment' |
770 | await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text) | 770 | await addVideoCommentThread(servers[2].url, servers[2].accessToken, videoUUID, text) |
771 | } | 771 | } |
772 | 772 | ||
773 | await waitJobs(servers) | 773 | await waitJobs(servers) |
@@ -777,7 +777,7 @@ describe('Test multiple servers', function () { | |||
777 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id | 777 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id |
778 | 778 | ||
779 | const text = 'my super answer to thread 1' | 779 | const text = 'my super answer to thread 1' |
780 | await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text) | 780 | await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text) |
781 | } | 781 | } |
782 | 782 | ||
783 | await waitJobs(servers) | 783 | await waitJobs(servers) |
@@ -790,10 +790,10 @@ describe('Test multiple servers', function () { | |||
790 | const childCommentId = res2.body.children[0].comment.id | 790 | const childCommentId = res2.body.children[0].comment.id |
791 | 791 | ||
792 | const text3 = 'my second answer to thread 1' | 792 | const text3 = 'my second answer to thread 1' |
793 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3) | 793 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, threadId, text3) |
794 | 794 | ||
795 | const text2 = 'my super answer to answer of thread 1' | 795 | const text2 = 'my super answer to answer of thread 1' |
796 | await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2) | 796 | await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, childCommentId, text2) |
797 | } | 797 | } |
798 | 798 | ||
799 | await waitJobs(servers) | 799 | await waitJobs(servers) |
@@ -900,9 +900,9 @@ describe('Test multiple servers', function () { | |||
900 | it('Should delete the thread comments', async function () { | 900 | it('Should delete the thread comments', async function () { |
901 | this.timeout(10000) | 901 | this.timeout(10000) |
902 | 902 | ||
903 | const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) | 903 | const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5) |
904 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id | 904 | const threadId = res.body.data.find(c => c.text === 'my super first comment').id |
905 | await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) | 905 | await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId) |
906 | 906 | ||
907 | await waitJobs(servers) | 907 | await waitJobs(servers) |
908 | }) | 908 | }) |
@@ -945,9 +945,9 @@ describe('Test multiple servers', function () { | |||
945 | it('Should delete a remote thread by the origin server', async function () { | 945 | it('Should delete a remote thread by the origin server', async function () { |
946 | this.timeout(5000) | 946 | this.timeout(5000) |
947 | 947 | ||
948 | const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5) | 948 | const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5) |
949 | const threadId = res.body.data.find(c => c.text === 'my super second comment').id | 949 | const threadId = res.body.data.find(c => c.text === 'my super second comment').id |
950 | await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId) | 950 | await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId) |
951 | 951 | ||
952 | await waitJobs(servers) | 952 | await waitJobs(servers) |
953 | }) | 953 | }) |
@@ -1021,7 +1021,7 @@ describe('Test multiple servers', function () { | |||
1021 | const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') | 1021 | const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm') |
1022 | 1022 | ||
1023 | await req.attach('videofile', filePath) | 1023 | await req.attach('videofile', filePath) |
1024 | .expect(200) | 1024 | .expect(200) |
1025 | 1025 | ||
1026 | await waitJobs(servers) | 1026 | await waitJobs(servers) |
1027 | 1027 | ||
@@ -1046,7 +1046,7 @@ describe('Test multiple servers', function () { | |||
1046 | duration: 5, | 1046 | duration: 5, |
1047 | commentsEnabled: true, | 1047 | commentsEnabled: true, |
1048 | downloadEnabled: true, | 1048 | downloadEnabled: true, |
1049 | tags: [ ], | 1049 | tags: [], |
1050 | privacy: VideoPrivacy.PUBLIC, | 1050 | privacy: VideoPrivacy.PUBLIC, |
1051 | channel: { | 1051 | channel: { |
1052 | displayName: 'Main root channel', | 1052 | displayName: 'Main root channel', |
diff --git a/server/tests/api/videos/services.ts b/server/tests/api/videos/services.ts index 17172331f..5505a845a 100644 --- a/server/tests/api/videos/services.ts +++ b/server/tests/api/videos/services.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -31,8 +31,8 @@ describe('Test services', function () { | |||
31 | 31 | ||
32 | const res = await getOEmbed(server.url, oembedUrl) | 32 | const res = await getOEmbed(server.url, oembedUrl) |
33 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + | 33 | const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' + |
34 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + | 34 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + |
35 | 'frameborder="0" allowfullscreen></iframe>' | 35 | 'frameborder="0" allowfullscreen></iframe>' |
36 | const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg' | 36 | const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg' |
37 | 37 | ||
38 | expect(res.body.html).to.equal(expectedHtml) | 38 | expect(res.body.html).to.equal(expectedHtml) |
@@ -53,8 +53,8 @@ describe('Test services', function () { | |||
53 | 53 | ||
54 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) | 54 | const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth) |
55 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + | 55 | const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' + |
56 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + | 56 | `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` + |
57 | 'frameborder="0" allowfullscreen></iframe>' | 57 | 'frameborder="0" allowfullscreen></iframe>' |
58 | 58 | ||
59 | expect(res.body.html).to.equal(expectedHtml) | 59 | expect(res.body.html).to.equal(expectedHtml) |
60 | expect(res.body.title).to.equal(server.video.name) | 60 | expect(res.body.title).to.equal(server.video.name) |
diff --git a/server/tests/api/videos/single-server.ts b/server/tests/api/videos/single-server.ts index 362d6b78f..596fff996 100644 --- a/server/tests/api/videos/single-server.ts +++ b/server/tests/api/videos/single-server.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { keyBy } from 'lodash' | 4 | import { keyBy } from 'lodash' |
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts index 0cd6f22c7..cd6df7267 100644 --- a/server/tests/api/videos/video-abuse.ts +++ b/server/tests/api/videos/video-abuse.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -183,9 +183,9 @@ describe('Test video abuses', function () { | |||
183 | const accountToBlock = 'root@localhost:' + servers[1].port | 183 | const accountToBlock = 'root@localhost:' + servers[1].port |
184 | 184 | ||
185 | { | 185 | { |
186 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) | 186 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
187 | 187 | ||
188 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 188 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
189 | expect(res.body.total).to.equal(2) | 189 | expect(res.body.total).to.equal(2) |
190 | 190 | ||
191 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 191 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -193,9 +193,9 @@ describe('Test video abuses', function () { | |||
193 | } | 193 | } |
194 | 194 | ||
195 | { | 195 | { |
196 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock) | 196 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
197 | 197 | ||
198 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 198 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
199 | expect(res.body.total).to.equal(3) | 199 | expect(res.body.total).to.equal(3) |
200 | } | 200 | } |
201 | }) | 201 | }) |
@@ -204,9 +204,9 @@ describe('Test video abuses', function () { | |||
204 | const serverToBlock = servers[1].host | 204 | const serverToBlock = servers[1].host |
205 | 205 | ||
206 | { | 206 | { |
207 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, servers[1].host) | 207 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) |
208 | 208 | ||
209 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 209 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
210 | expect(res.body.total).to.equal(2) | 210 | expect(res.body.total).to.equal(2) |
211 | 211 | ||
212 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 212 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -214,9 +214,9 @@ describe('Test video abuses', function () { | |||
214 | } | 214 | } |
215 | 215 | ||
216 | { | 216 | { |
217 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, serverToBlock) | 217 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) |
218 | 218 | ||
219 | const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken) | 219 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) |
220 | expect(res.body.total).to.equal(3) | 220 | expect(res.body.total).to.equal(3) |
221 | } | 221 | } |
222 | }) | 222 | }) |
diff --git a/server/tests/api/videos/video-blacklist.ts b/server/tests/api/videos/video-blacklist.ts index 854b2f0cb..67bc0114c 100644 --- a/server/tests/api/videos/video-blacklist.ts +++ b/server/tests/api/videos/video-blacklist.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import { orderBy } from 'lodash' | 4 | import { orderBy } from 'lodash' |
@@ -8,7 +8,8 @@ import { | |||
8 | cleanupTests, | 8 | cleanupTests, |
9 | createUser, | 9 | createUser, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | getBlacklistedVideosList, getMyUserInformation, | 11 | getBlacklistedVideosList, |
12 | getMyUserInformation, | ||
12 | getMyVideos, | 13 | getMyVideos, |
13 | getVideosList, | 14 | getVideosList, |
14 | killallServers, | 15 | killallServers, |
@@ -17,7 +18,6 @@ import { | |||
17 | searchVideo, | 18 | searchVideo, |
18 | ServerInfo, | 19 | ServerInfo, |
19 | setAccessTokensToServers, | 20 | setAccessTokensToServers, |
20 | setDefaultVideoChannel, | ||
21 | updateVideo, | 21 | updateVideo, |
22 | updateVideoBlacklist, | 22 | updateVideoBlacklist, |
23 | uploadVideo, | 23 | uploadVideo, |
@@ -27,7 +27,7 @@ import { doubleFollow } from '../../../../shared/extra-utils/server/follows' | |||
27 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 27 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
28 | import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos' | 28 | import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos' |
29 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' | 29 | import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model' |
30 | import { User, UserRole, UserUpdateMe } from '../../../../shared/models/users' | 30 | import { User, UserRole } from '../../../../shared/models/users' |
31 | import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' | 31 | import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' |
32 | 32 | ||
33 | const expect = chai.expect | 33 | const expect = chai.expect |
@@ -40,7 +40,7 @@ describe('Test video blacklist', function () { | |||
40 | const res = await getVideosList(server.url) | 40 | const res = await getVideosList(server.url) |
41 | 41 | ||
42 | const videos = res.body.data | 42 | const videos = res.body.data |
43 | for (let video of videos) { | 43 | for (const video of videos) { |
44 | await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason') | 44 | await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason') |
45 | } | 45 | } |
46 | } | 46 | } |
@@ -72,7 +72,7 @@ describe('Test video blacklist', function () { | |||
72 | 72 | ||
73 | it('Should not have the video blacklisted in videos list/search on server 1', async function () { | 73 | it('Should not have the video blacklisted in videos list/search on server 1', async function () { |
74 | { | 74 | { |
75 | const res = await getVideosList(servers[ 0 ].url) | 75 | const res = await getVideosList(servers[0].url) |
76 | 76 | ||
77 | expect(res.body.total).to.equal(0) | 77 | expect(res.body.total).to.equal(0) |
78 | expect(res.body.data).to.be.an('array') | 78 | expect(res.body.data).to.be.an('array') |
@@ -80,7 +80,7 @@ describe('Test video blacklist', function () { | |||
80 | } | 80 | } |
81 | 81 | ||
82 | { | 82 | { |
83 | const res = await searchVideo(servers[ 0 ].url, 'name') | 83 | const res = await searchVideo(servers[0].url, 'name') |
84 | 84 | ||
85 | expect(res.body.total).to.equal(0) | 85 | expect(res.body.total).to.equal(0) |
86 | expect(res.body.data).to.be.an('array') | 86 | expect(res.body.data).to.be.an('array') |
@@ -90,7 +90,7 @@ describe('Test video blacklist', function () { | |||
90 | 90 | ||
91 | it('Should have the blacklisted video in videos list/search on server 2', async function () { | 91 | it('Should have the blacklisted video in videos list/search on server 2', async function () { |
92 | { | 92 | { |
93 | const res = await getVideosList(servers[ 1 ].url) | 93 | const res = await getVideosList(servers[1].url) |
94 | 94 | ||
95 | expect(res.body.total).to.equal(2) | 95 | expect(res.body.total).to.equal(2) |
96 | expect(res.body.data).to.be.an('array') | 96 | expect(res.body.data).to.be.an('array') |
@@ -98,7 +98,7 @@ describe('Test video blacklist', function () { | |||
98 | } | 98 | } |
99 | 99 | ||
100 | { | 100 | { |
101 | const res = await searchVideo(servers[ 1 ].url, 'video') | 101 | const res = await searchVideo(servers[1].url, 'video') |
102 | 102 | ||
103 | expect(res.body.total).to.equal(2) | 103 | expect(res.body.total).to.equal(2) |
104 | expect(res.body.data).to.be.an('array') | 104 | expect(res.body.data).to.be.an('array') |
@@ -125,8 +125,8 @@ describe('Test video blacklist', function () { | |||
125 | 125 | ||
126 | it('Should display all the blacklisted videos when applying manual type filter', async function () { | 126 | it('Should display all the blacklisted videos when applying manual type filter', async function () { |
127 | const res = await getBlacklistedVideosList({ | 127 | const res = await getBlacklistedVideosList({ |
128 | url: servers[ 0 ].url, | 128 | url: servers[0].url, |
129 | token: servers[ 0 ].accessToken, | 129 | token: servers[0].accessToken, |
130 | type: VideoBlacklistType.MANUAL | 130 | type: VideoBlacklistType.MANUAL |
131 | }) | 131 | }) |
132 | 132 | ||
@@ -139,8 +139,8 @@ describe('Test video blacklist', function () { | |||
139 | 139 | ||
140 | it('Should display nothing when applying automatic type filter', async function () { | 140 | it('Should display nothing when applying automatic type filter', async function () { |
141 | const res = await getBlacklistedVideosList({ | 141 | const res = await getBlacklistedVideosList({ |
142 | url: servers[ 0 ].url, | 142 | url: servers[0].url, |
143 | token: servers[ 0 ].accessToken, | 143 | token: servers[0].accessToken, |
144 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 144 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
145 | }) | 145 | }) |
146 | 146 | ||
@@ -152,7 +152,7 @@ describe('Test video blacklist', function () { | |||
152 | }) | 152 | }) |
153 | 153 | ||
154 | it('Should get the correct sort when sorting by descending id', async function () { | 154 | it('Should get the correct sort when sorting by descending id', async function () { |
155 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-id' }) | 155 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-id' }) |
156 | expect(res.body.total).to.equal(2) | 156 | expect(res.body.total).to.equal(2) |
157 | 157 | ||
158 | const blacklistedVideos = res.body.data | 158 | const blacklistedVideos = res.body.data |
@@ -165,7 +165,7 @@ describe('Test video blacklist', function () { | |||
165 | }) | 165 | }) |
166 | 166 | ||
167 | it('Should get the correct sort when sorting by descending video name', async function () { | 167 | it('Should get the correct sort when sorting by descending video name', async function () { |
168 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 168 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
169 | expect(res.body.total).to.equal(2) | 169 | expect(res.body.total).to.equal(2) |
170 | 170 | ||
171 | const blacklistedVideos = res.body.data | 171 | const blacklistedVideos = res.body.data |
@@ -178,7 +178,7 @@ describe('Test video blacklist', function () { | |||
178 | }) | 178 | }) |
179 | 179 | ||
180 | it('Should get the correct sort when sorting by ascending creation date', async function () { | 180 | it('Should get the correct sort when sorting by ascending creation date', async function () { |
181 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) | 181 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' }) |
182 | expect(res.body.total).to.equal(2) | 182 | expect(res.body.total).to.equal(2) |
183 | 183 | ||
184 | const blacklistedVideos = res.body.data | 184 | const blacklistedVideos = res.body.data |
@@ -195,7 +195,7 @@ describe('Test video blacklist', function () { | |||
195 | it('Should change the reason', async function () { | 195 | it('Should change the reason', async function () { |
196 | await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated') | 196 | await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated') |
197 | 197 | ||
198 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 198 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
199 | const video = res.body.data.find(b => b.video.id === videoId) | 199 | const video = res.body.data.find(b => b.video.id === videoId) |
200 | 200 | ||
201 | expect(video.reason).to.equal('my super reason updated') | 201 | expect(video.reason).to.equal('my super reason updated') |
@@ -231,7 +231,7 @@ describe('Test video blacklist', function () { | |||
231 | 231 | ||
232 | it('Should remove a video from the blacklist on server 1', async function () { | 232 | it('Should remove a video from the blacklist on server 1', async function () { |
233 | // Get one video in the blacklist | 233 | // Get one video in the blacklist |
234 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 234 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
235 | videoToRemove = res.body.data[0] | 235 | videoToRemove = res.body.data[0] |
236 | blacklist = res.body.data.slice(1) | 236 | blacklist = res.body.data.slice(1) |
237 | 237 | ||
@@ -252,7 +252,7 @@ describe('Test video blacklist', function () { | |||
252 | }) | 252 | }) |
253 | 253 | ||
254 | it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { | 254 | it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () { |
255 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' }) | 255 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' }) |
256 | expect(res.body.total).to.equal(1) | 256 | expect(res.body.total).to.equal(1) |
257 | 257 | ||
258 | const videos = res.body.data | 258 | const videos = res.body.data |
@@ -274,7 +274,7 @@ describe('Test video blacklist', function () { | |||
274 | video3UUID = res.body.video.uuid | 274 | video3UUID = res.body.video.uuid |
275 | } | 275 | } |
276 | { | 276 | { |
277 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'Video 4' }) | 277 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'Video 4' }) |
278 | video4UUID = res.body.video.uuid | 278 | video4UUID = res.body.video.uuid |
279 | } | 279 | } |
280 | 280 | ||
@@ -284,17 +284,17 @@ describe('Test video blacklist', function () { | |||
284 | it('Should blacklist video 3 and keep it federated', async function () { | 284 | it('Should blacklist video 3 and keep it federated', async function () { |
285 | this.timeout(10000) | 285 | this.timeout(10000) |
286 | 286 | ||
287 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video3UUID, 'super reason', false) | 287 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video3UUID, 'super reason', false) |
288 | 288 | ||
289 | await waitJobs(servers) | 289 | await waitJobs(servers) |
290 | 290 | ||
291 | { | 291 | { |
292 | const res = await getVideosList(servers[ 0 ].url) | 292 | const res = await getVideosList(servers[0].url) |
293 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined | 293 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined |
294 | } | 294 | } |
295 | 295 | ||
296 | { | 296 | { |
297 | const res = await getVideosList(servers[ 1 ].url) | 297 | const res = await getVideosList(servers[1].url) |
298 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined | 298 | expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined |
299 | } | 299 | } |
300 | }) | 300 | }) |
@@ -302,7 +302,7 @@ describe('Test video blacklist', function () { | |||
302 | it('Should unfederate the video', async function () { | 302 | it('Should unfederate the video', async function () { |
303 | this.timeout(10000) | 303 | this.timeout(10000) |
304 | 304 | ||
305 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, 'super reason', true) | 305 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video4UUID, 'super reason', true) |
306 | 306 | ||
307 | await waitJobs(servers) | 307 | await waitJobs(servers) |
308 | 308 | ||
@@ -315,7 +315,7 @@ describe('Test video blacklist', function () { | |||
315 | it('Should have the video unfederated even after an Update AP message', async function () { | 315 | it('Should have the video unfederated even after an Update AP message', async function () { |
316 | this.timeout(10000) | 316 | this.timeout(10000) |
317 | 317 | ||
318 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, { description: 'super description' }) | 318 | await updateVideo(servers[0].url, servers[0].accessToken, video4UUID, { description: 'super description' }) |
319 | 319 | ||
320 | await waitJobs(servers) | 320 | await waitJobs(servers) |
321 | 321 | ||
@@ -326,7 +326,7 @@ describe('Test video blacklist', function () { | |||
326 | }) | 326 | }) |
327 | 327 | ||
328 | it('Should have the correct video blacklist unfederate attribute', async function () { | 328 | it('Should have the correct video blacklist unfederate attribute', async function () { |
329 | const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' }) | 329 | const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' }) |
330 | 330 | ||
331 | const blacklistedVideos: VideoBlacklist[] = res.body.data | 331 | const blacklistedVideos: VideoBlacklist[] = res.body.data |
332 | const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) | 332 | const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID) |
@@ -339,7 +339,7 @@ describe('Test video blacklist', function () { | |||
339 | it('Should remove the video from blacklist and refederate the video', async function () { | 339 | it('Should remove the video from blacklist and refederate the video', async function () { |
340 | this.timeout(10000) | 340 | this.timeout(10000) |
341 | 341 | ||
342 | await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID) | 342 | await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video4UUID) |
343 | 343 | ||
344 | await waitJobs(servers) | 344 | await waitJobs(servers) |
345 | 345 | ||
@@ -362,9 +362,9 @@ describe('Test video blacklist', function () { | |||
362 | killallServers([ servers[0] ]) | 362 | killallServers([ servers[0] ]) |
363 | 363 | ||
364 | const config = { | 364 | const config = { |
365 | 'auto_blacklist': { | 365 | auto_blacklist: { |
366 | videos: { | 366 | videos: { |
367 | 'of_users': { | 367 | of_users: { |
368 | enabled: true | 368 | enabled: true |
369 | } | 369 | } |
370 | } | 370 | } |
@@ -375,8 +375,8 @@ describe('Test video blacklist', function () { | |||
375 | { | 375 | { |
376 | const user = { username: 'user_without_flag', password: 'password' } | 376 | const user = { username: 'user_without_flag', password: 'password' } |
377 | await createUser({ | 377 | await createUser({ |
378 | url: servers[ 0 ].url, | 378 | url: servers[0].url, |
379 | accessToken: servers[ 0 ].accessToken, | 379 | accessToken: servers[0].accessToken, |
380 | username: user.username, | 380 | username: user.username, |
381 | adminFlags: UserAdminFlag.NONE, | 381 | adminFlags: UserAdminFlag.NONE, |
382 | password: user.password, | 382 | password: user.password, |
@@ -393,8 +393,8 @@ describe('Test video blacklist', function () { | |||
393 | { | 393 | { |
394 | const user = { username: 'user_with_flag', password: 'password' } | 394 | const user = { username: 'user_with_flag', password: 'password' } |
395 | await createUser({ | 395 | await createUser({ |
396 | url: servers[ 0 ].url, | 396 | url: servers[0].url, |
397 | accessToken: servers[ 0 ].accessToken, | 397 | accessToken: servers[0].accessToken, |
398 | username: user.username, | 398 | username: user.username, |
399 | adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST, | 399 | adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST, |
400 | password: user.password, | 400 | password: user.password, |
@@ -411,8 +411,8 @@ describe('Test video blacklist', function () { | |||
411 | await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' }) | 411 | await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' }) |
412 | 412 | ||
413 | const res = await getBlacklistedVideosList({ | 413 | const res = await getBlacklistedVideosList({ |
414 | url: servers[ 0 ].url, | 414 | url: servers[0].url, |
415 | token: servers[ 0 ].accessToken, | 415 | token: servers[0].accessToken, |
416 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 416 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
417 | }) | 417 | }) |
418 | 418 | ||
@@ -428,11 +428,11 @@ describe('Test video blacklist', function () { | |||
428 | name: 'URL import', | 428 | name: 'URL import', |
429 | channelId: channelOfUserWithoutFlag | 429 | channelId: channelOfUserWithoutFlag |
430 | } | 430 | } |
431 | await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) | 431 | await importVideo(servers[0].url, userWithoutFlag, attributes) |
432 | 432 | ||
433 | const res = await getBlacklistedVideosList({ | 433 | const res = await getBlacklistedVideosList({ |
434 | url: servers[ 0 ].url, | 434 | url: servers[0].url, |
435 | token: servers[ 0 ].accessToken, | 435 | token: servers[0].accessToken, |
436 | sort: 'createdAt', | 436 | sort: 'createdAt', |
437 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 437 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
438 | }) | 438 | }) |
@@ -447,11 +447,11 @@ describe('Test video blacklist', function () { | |||
447 | name: 'Torrent import', | 447 | name: 'Torrent import', |
448 | channelId: channelOfUserWithoutFlag | 448 | channelId: channelOfUserWithoutFlag |
449 | } | 449 | } |
450 | await importVideo(servers[ 0 ].url, userWithoutFlag, attributes) | 450 | await importVideo(servers[0].url, userWithoutFlag, attributes) |
451 | 451 | ||
452 | const res = await getBlacklistedVideosList({ | 452 | const res = await getBlacklistedVideosList({ |
453 | url: servers[ 0 ].url, | 453 | url: servers[0].url, |
454 | token: servers[ 0 ].accessToken, | 454 | token: servers[0].accessToken, |
455 | sort: 'createdAt', | 455 | sort: 'createdAt', |
456 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 456 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
457 | }) | 457 | }) |
@@ -464,8 +464,8 @@ describe('Test video blacklist', function () { | |||
464 | await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' }) | 464 | await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' }) |
465 | 465 | ||
466 | const res = await getBlacklistedVideosList({ | 466 | const res = await getBlacklistedVideosList({ |
467 | url: servers[ 0 ].url, | 467 | url: servers[0].url, |
468 | token: servers[ 0 ].accessToken, | 468 | token: servers[0].accessToken, |
469 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED | 469 | type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED |
470 | }) | 470 | }) |
471 | 471 | ||
diff --git a/server/tests/api/videos/video-captions.ts b/server/tests/api/videos/video-captions.ts index 5e13f5949..b4ecb39f4 100644 --- a/server/tests/api/videos/video-captions.ts +++ b/server/tests/api/videos/video-captions.ts | |||
@@ -1,16 +1,17 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | checkVideoFilesWereRemoved, cleanupTests, | 6 | checkVideoFilesWereRemoved, |
7 | cleanupTests, | ||
7 | doubleFollow, | 8 | doubleFollow, |
8 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
9 | removeVideo, | 10 | removeVideo, |
10 | uploadVideo, | 11 | uploadVideo, |
11 | wait | 12 | wait |
12 | } from '../../../../shared/extra-utils' | 13 | } from '../../../../shared/extra-utils' |
13 | import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' | 14 | import { ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index' |
14 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 15 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
15 | import { | 16 | import { |
16 | createVideoCaption, | 17 | createVideoCaption, |
@@ -36,7 +37,7 @@ describe('Test video captions', function () { | |||
36 | 37 | ||
37 | await waitJobs(servers) | 38 | await waitJobs(servers) |
38 | 39 | ||
39 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name' }) | 40 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'my video name' }) |
40 | videoUUID = res.body.video.uuid | 41 | videoUUID = res.body.video.uuid |
41 | 42 | ||
42 | await waitJobs(servers) | 43 | await waitJobs(servers) |
diff --git a/server/tests/api/videos/video-change-ownership.ts b/server/tests/api/videos/video-change-ownership.ts index 64ee2355a..dee6575b9 100644 --- a/server/tests/api/videos/video-change-ownership.ts +++ b/server/tests/api/videos/video-change-ownership.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -38,7 +38,7 @@ describe('Test video change ownership - nominal', function () { | |||
38 | } | 38 | } |
39 | let firstUserAccessToken = '' | 39 | let firstUserAccessToken = '' |
40 | let secondUserAccessToken = '' | 40 | let secondUserAccessToken = '' |
41 | let lastRequestChangeOwnershipId = undefined | 41 | let lastRequestChangeOwnershipId = '' |
42 | 42 | ||
43 | before(async function () { | 43 | before(async function () { |
44 | this.timeout(50000) | 44 | this.timeout(50000) |
@@ -48,15 +48,15 @@ describe('Test video change ownership - nominal', function () { | |||
48 | 48 | ||
49 | const videoQuota = 42000000 | 49 | const videoQuota = 42000000 |
50 | await createUser({ | 50 | await createUser({ |
51 | url: servers[ 0 ].url, | 51 | url: servers[0].url, |
52 | accessToken: servers[ 0 ].accessToken, | 52 | accessToken: servers[0].accessToken, |
53 | username: firstUser.username, | 53 | username: firstUser.username, |
54 | password: firstUser.password, | 54 | password: firstUser.password, |
55 | videoQuota: videoQuota | 55 | videoQuota: videoQuota |
56 | }) | 56 | }) |
57 | await createUser({ | 57 | await createUser({ |
58 | url: servers[ 0 ].url, | 58 | url: servers[0].url, |
59 | accessToken: servers[ 0 ].accessToken, | 59 | accessToken: servers[0].accessToken, |
60 | username: secondUser.username, | 60 | username: secondUser.username, |
61 | password: secondUser.password, | 61 | password: secondUser.password, |
62 | videoQuota: videoQuota | 62 | videoQuota: videoQuota |
@@ -209,7 +209,7 @@ describe('Test video change ownership - nominal', function () { | |||
209 | }) | 209 | }) |
210 | 210 | ||
211 | describe('Test video change ownership - quota too small', function () { | 211 | describe('Test video change ownership - quota too small', function () { |
212 | let server: ServerInfo = undefined | 212 | let server: ServerInfo |
213 | const firstUser = { | 213 | const firstUser = { |
214 | username: 'first', | 214 | username: 'first', |
215 | password: 'My great password' | 215 | password: 'My great password' |
@@ -220,14 +220,14 @@ describe('Test video change ownership - quota too small', function () { | |||
220 | } | 220 | } |
221 | let firstUserAccessToken = '' | 221 | let firstUserAccessToken = '' |
222 | let secondUserAccessToken = '' | 222 | let secondUserAccessToken = '' |
223 | let lastRequestChangeOwnershipId = undefined | 223 | let lastRequestChangeOwnershipId = '' |
224 | 224 | ||
225 | before(async function () { | 225 | before(async function () { |
226 | this.timeout(50000) | 226 | this.timeout(50000) |
227 | 227 | ||
228 | // Run one server | 228 | // Run one server |
229 | server = await flushAndRunServer(1) | 229 | server = await flushAndRunServer(1) |
230 | await setAccessTokensToServers([server]) | 230 | await setAccessTokensToServers([ server ]) |
231 | 231 | ||
232 | const videoQuota = 42000000 | 232 | const videoQuota = 42000000 |
233 | const limitedVideoQuota = 10 | 233 | const limitedVideoQuota = 10 |
diff --git a/server/tests/api/videos/video-channels.ts b/server/tests/api/videos/video-channels.ts index 4f600cae8..f3a23bf17 100644 --- a/server/tests/api/videos/video-channels.ts +++ b/server/tests/api/videos/video-channels.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -7,7 +7,8 @@ import { | |||
7 | cleanupTests, | 7 | cleanupTests, |
8 | createUser, | 8 | createUser, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, getVideo, | 10 | flushAndRunMultipleServers, |
11 | getVideo, | ||
11 | getVideoChannelVideos, | 12 | getVideoChannelVideos, |
12 | testImage, | 13 | testImage, |
13 | updateVideo, | 14 | updateVideo, |
@@ -73,14 +74,14 @@ describe('Test video channels', function () { | |||
73 | description: 'super video channel description', | 74 | description: 'super video channel description', |
74 | support: 'super video channel support text' | 75 | support: 'super video channel support text' |
75 | } | 76 | } |
76 | const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 77 | const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
77 | secondVideoChannelId = res.body.videoChannel.id | 78 | secondVideoChannelId = res.body.videoChannel.id |
78 | } | 79 | } |
79 | 80 | ||
80 | // The channel is 1 is propagated to servers 2 | 81 | // The channel is 1 is propagated to servers 2 |
81 | { | 82 | { |
82 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } | 83 | const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' } |
83 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg) | 84 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributesArg) |
84 | videoUUID = res.body.video.uuid | 85 | videoUUID = res.body.video.uuid |
85 | } | 86 | } |
86 | 87 | ||
@@ -106,7 +107,7 @@ describe('Test video channels', function () { | |||
106 | 107 | ||
107 | it('Should have two video channels when getting account channels on server 1', async function () { | 108 | it('Should have two video channels when getting account channels on server 1', async function () { |
108 | const res = await getAccountVideoChannelsList({ | 109 | const res = await getAccountVideoChannelsList({ |
109 | url: servers[ 0 ].url, | 110 | url: servers[0].url, |
110 | accountName: userInfo.account.name + '@' + userInfo.account.host | 111 | accountName: userInfo.account.name + '@' + userInfo.account.host |
111 | }) | 112 | }) |
112 | 113 | ||
@@ -127,7 +128,7 @@ describe('Test video channels', function () { | |||
127 | it('Should paginate and sort account channels', async function () { | 128 | it('Should paginate and sort account channels', async function () { |
128 | { | 129 | { |
129 | const res = await getAccountVideoChannelsList({ | 130 | const res = await getAccountVideoChannelsList({ |
130 | url: servers[ 0 ].url, | 131 | url: servers[0].url, |
131 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 132 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
132 | start: 0, | 133 | start: 0, |
133 | count: 1, | 134 | count: 1, |
@@ -137,13 +138,13 @@ describe('Test video channels', function () { | |||
137 | expect(res.body.total).to.equal(2) | 138 | expect(res.body.total).to.equal(2) |
138 | expect(res.body.data).to.have.lengthOf(1) | 139 | expect(res.body.data).to.have.lengthOf(1) |
139 | 140 | ||
140 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 141 | const videoChannel: VideoChannel = res.body.data[0] |
141 | expect(videoChannel.name).to.equal('root_channel') | 142 | expect(videoChannel.name).to.equal('root_channel') |
142 | } | 143 | } |
143 | 144 | ||
144 | { | 145 | { |
145 | const res = await getAccountVideoChannelsList({ | 146 | const res = await getAccountVideoChannelsList({ |
146 | url: servers[ 0 ].url, | 147 | url: servers[0].url, |
147 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 148 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
148 | start: 0, | 149 | start: 0, |
149 | count: 1, | 150 | count: 1, |
@@ -153,13 +154,13 @@ describe('Test video channels', function () { | |||
153 | expect(res.body.total).to.equal(2) | 154 | expect(res.body.total).to.equal(2) |
154 | expect(res.body.data).to.have.lengthOf(1) | 155 | expect(res.body.data).to.have.lengthOf(1) |
155 | 156 | ||
156 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 157 | const videoChannel: VideoChannel = res.body.data[0] |
157 | expect(videoChannel.name).to.equal('second_video_channel') | 158 | expect(videoChannel.name).to.equal('second_video_channel') |
158 | } | 159 | } |
159 | 160 | ||
160 | { | 161 | { |
161 | const res = await getAccountVideoChannelsList({ | 162 | const res = await getAccountVideoChannelsList({ |
162 | url: servers[ 0 ].url, | 163 | url: servers[0].url, |
163 | accountName: userInfo.account.name + '@' + userInfo.account.host, | 164 | accountName: userInfo.account.name + '@' + userInfo.account.host, |
164 | start: 1, | 165 | start: 1, |
165 | count: 1, | 166 | count: 1, |
@@ -169,14 +170,14 @@ describe('Test video channels', function () { | |||
169 | expect(res.body.total).to.equal(2) | 170 | expect(res.body.total).to.equal(2) |
170 | expect(res.body.data).to.have.lengthOf(1) | 171 | expect(res.body.data).to.have.lengthOf(1) |
171 | 172 | ||
172 | const videoChannel: VideoChannel = res.body.data[ 0 ] | 173 | const videoChannel: VideoChannel = res.body.data[0] |
173 | expect(videoChannel.name).to.equal('root_channel') | 174 | expect(videoChannel.name).to.equal('root_channel') |
174 | } | 175 | } |
175 | }) | 176 | }) |
176 | 177 | ||
177 | it('Should have one video channel when getting account channels on server 2', async function () { | 178 | it('Should have one video channel when getting account channels on server 2', async function () { |
178 | const res = await getAccountVideoChannelsList({ | 179 | const res = await getAccountVideoChannelsList({ |
179 | url: servers[ 1 ].url, | 180 | url: servers[1].url, |
180 | accountName: userInfo.account.name + '@' + userInfo.account.host | 181 | accountName: userInfo.account.name + '@' + userInfo.account.host |
181 | }) | 182 | }) |
182 | 183 | ||
@@ -349,15 +350,15 @@ describe('Test video channels', function () { | |||
349 | it('Should create the main channel with an uuid if there is a conflict', async function () { | 350 | it('Should create the main channel with an uuid if there is a conflict', async function () { |
350 | { | 351 | { |
351 | const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } | 352 | const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' } |
352 | await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel) | 353 | await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel) |
353 | } | 354 | } |
354 | 355 | ||
355 | { | 356 | { |
356 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'toto', password: 'password' }) | 357 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'toto', password: 'password' }) |
357 | const accessToken = await userLogin(servers[ 0 ], { username: 'toto', password: 'password' }) | 358 | const accessToken = await userLogin(servers[0], { username: 'toto', password: 'password' }) |
358 | 359 | ||
359 | const res = await getMyUserInformation(servers[ 0 ].url, accessToken) | 360 | const res = await getMyUserInformation(servers[0].url, accessToken) |
360 | const videoChannel = res.body.videoChannels[ 0 ] | 361 | const videoChannel = res.body.videoChannels[0] |
361 | expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/) | 362 | expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/) |
362 | } | 363 | } |
363 | }) | 364 | }) |
diff --git a/server/tests/api/videos/video-comments.ts b/server/tests/api/videos/video-comments.ts index 06e4ff9c8..afb58e95a 100644 --- a/server/tests/api/videos/video-comments.ts +++ b/server/tests/api/videos/video-comments.ts | |||
@@ -1,17 +1,17 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' | 5 | import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' |
6 | import { cleanupTests, testImage } from '../../../../shared/extra-utils' | 6 | import { cleanupTests, testImage } from '../../../../shared/extra-utils' |
7 | import { | 7 | import { |
8 | createUser, | ||
8 | dateIsValid, | 9 | dateIsValid, |
9 | flushAndRunServer, | 10 | flushAndRunServer, |
11 | getAccessToken, | ||
10 | ServerInfo, | 12 | ServerInfo, |
11 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
12 | updateMyAvatar, | 14 | updateMyAvatar, |
13 | getAccessToken, | ||
14 | createUser, | ||
15 | uploadVideo | 15 | uploadVideo |
16 | } from '../../../../shared/extra-utils/index' | 16 | } from '../../../../shared/extra-utils/index' |
17 | import { | 17 | import { |
diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts index db4d278bf..b8e98e45f 100644 --- a/server/tests/api/videos/video-description.ts +++ b/server/tests/api/videos/video-description.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,7 +8,6 @@ import { | |||
8 | getVideo, | 8 | getVideo, |
9 | getVideoDescription, | 9 | getVideoDescription, |
10 | getVideosList, | 10 | getVideosList, |
11 | killallServers, | ||
12 | ServerInfo, | 11 | ServerInfo, |
13 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
14 | updateVideo, | 13 | updateVideo, |
@@ -23,7 +22,7 @@ describe('Test video description', function () { | |||
23 | let servers: ServerInfo[] = [] | 22 | let servers: ServerInfo[] = [] |
24 | let videoUUID = '' | 23 | let videoUUID = '' |
25 | let videoId: number | 24 | let videoId: number |
26 | let longDescription = 'my super description for server 1'.repeat(50) | 25 | const longDescription = 'my super description for server 1'.repeat(50) |
27 | 26 | ||
28 | before(async function () { | 27 | before(async function () { |
29 | this.timeout(40000) | 28 | this.timeout(40000) |
@@ -61,7 +60,7 @@ describe('Test video description', function () { | |||
61 | 60 | ||
62 | // 30 characters * 6 -> 240 characters | 61 | // 30 characters * 6 -> 240 characters |
63 | const truncatedDescription = 'my super description for server 1'.repeat(7) + | 62 | const truncatedDescription = 'my super description for server 1'.repeat(7) + |
64 | 'my super descrip...' | 63 | 'my super descrip...' |
65 | 64 | ||
66 | expect(video.description).to.equal(truncatedDescription) | 65 | expect(video.description).to.equal(truncatedDescription) |
67 | } | 66 | } |
diff --git a/server/tests/api/videos/video-hls.ts b/server/tests/api/videos/video-hls.ts index bde3b5656..6555bc8b6 100644 --- a/server/tests/api/videos/video-hls.ts +++ b/server/tests/api/videos/video-hls.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -10,13 +10,16 @@ import { | |||
10 | doubleFollow, | 10 | doubleFollow, |
11 | flushAndRunMultipleServers, | 11 | flushAndRunMultipleServers, |
12 | getPlaylist, | 12 | getPlaylist, |
13 | getVideo, makeGetRequest, makeRawRequest, | 13 | getVideo, |
14 | makeRawRequest, | ||
14 | removeVideo, | 15 | removeVideo, |
15 | ServerInfo, | 16 | ServerInfo, |
16 | setAccessTokensToServers, updateCustomSubConfig, | 17 | setAccessTokensToServers, |
18 | updateCustomSubConfig, | ||
17 | updateVideo, | 19 | updateVideo, |
18 | uploadVideo, | 20 | uploadVideo, |
19 | waitJobs, webtorrentAdd | 21 | waitJobs, |
22 | webtorrentAdd | ||
20 | } from '../../../../shared/extra-utils' | 23 | } from '../../../../shared/extra-utils' |
21 | import { VideoDetails } from '../../../../shared/models/videos' | 24 | import { VideoDetails } from '../../../../shared/models/videos' |
22 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' | 25 | import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type' |
@@ -48,7 +51,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn | |||
48 | 51 | ||
49 | expect(file.magnetUri).to.have.lengthOf.above(2) | 52 | expect(file.magnetUri).to.have.lengthOf.above(2) |
50 | expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) | 53 | expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`) |
51 | expect(file.fileUrl).to.equal(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`) | 54 | expect(file.fileUrl).to.equal( |
55 | `${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4` | ||
56 | ) | ||
52 | expect(file.resolution.label).to.equal(resolution + 'p') | 57 | expect(file.resolution.label).to.equal(resolution + 'p') |
53 | 58 | ||
54 | await makeRawRequest(file.torrentUrl, 200) | 59 | await makeRawRequest(file.torrentUrl, 200) |
@@ -66,7 +71,9 @@ async function checkHlsPlaylist (servers: ServerInfo[], videoUUID: string, hlsOn | |||
66 | const masterPlaylist = res.text | 71 | const masterPlaylist = res.text |
67 | 72 | ||
68 | for (const resolution of resolutions) { | 73 | for (const resolution of resolutions) { |
69 | const reg = new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"') | 74 | const reg = new RegExp( |
75 | '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"' | ||
76 | ) | ||
70 | 77 | ||
71 | expect(masterPlaylist).to.match(reg) | 78 | expect(masterPlaylist).to.match(reg) |
72 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) | 79 | expect(masterPlaylist).to.contain(`${resolution}.m3u8`) |
@@ -102,7 +109,7 @@ describe('Test HLS videos', function () { | |||
102 | it('Should upload a video and transcode it to HLS', async function () { | 109 | it('Should upload a video and transcode it to HLS', async function () { |
103 | this.timeout(120000) | 110 | this.timeout(120000) |
104 | 111 | ||
105 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) | 112 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1', fixture: 'video_short.webm' }) |
106 | videoUUID = res.body.video.uuid | 113 | videoUUID = res.body.video.uuid |
107 | 114 | ||
108 | await waitJobs(servers) | 115 | await waitJobs(servers) |
@@ -113,7 +120,7 @@ describe('Test HLS videos', function () { | |||
113 | it('Should upload an audio file and transcode it to HLS', async function () { | 120 | it('Should upload an audio file and transcode it to HLS', async function () { |
114 | this.timeout(120000) | 121 | this.timeout(120000) |
115 | 122 | ||
116 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) | 123 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video audio', fixture: 'sample.ogg' }) |
117 | videoAudioUUID = res.body.video.uuid | 124 | videoAudioUUID = res.body.video.uuid |
118 | 125 | ||
119 | await waitJobs(servers) | 126 | await waitJobs(servers) |
@@ -124,7 +131,7 @@ describe('Test HLS videos', function () { | |||
124 | it('Should update the video', async function () { | 131 | it('Should update the video', async function () { |
125 | this.timeout(10000) | 132 | this.timeout(10000) |
126 | 133 | ||
127 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, { name: 'video 1 updated' }) | 134 | await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' }) |
128 | 135 | ||
129 | await waitJobs(servers) | 136 | await waitJobs(servers) |
130 | 137 | ||
@@ -134,8 +141,8 @@ describe('Test HLS videos', function () { | |||
134 | it('Should delete videos', async function () { | 141 | it('Should delete videos', async function () { |
135 | this.timeout(10000) | 142 | this.timeout(10000) |
136 | 143 | ||
137 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID) | 144 | await removeVideo(servers[0].url, servers[0].accessToken, videoUUID) |
138 | await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAudioUUID) | 145 | await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID) |
139 | 146 | ||
140 | await waitJobs(servers) | 147 | await waitJobs(servers) |
141 | 148 | ||
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts index 1233ed6eb..a67e528c6 100644 --- a/server/tests/api/videos/video-imports.ts +++ b/server/tests/api/videos/video-imports.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -12,12 +12,11 @@ import { | |||
12 | getVideo, | 12 | getVideo, |
13 | getVideosList, | 13 | getVideosList, |
14 | immutableAssign, | 14 | immutableAssign, |
15 | killallServers, | ||
16 | ServerInfo, | 15 | ServerInfo, |
17 | setAccessTokensToServers | 16 | setAccessTokensToServers |
18 | } from '../../../../shared/extra-utils' | 17 | } from '../../../../shared/extra-utils' |
19 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' | 18 | import { waitJobs } from '../../../../shared/extra-utils/server/jobs' |
20 | import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/extra-utils/videos/video-imports' | 19 | import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports' |
21 | 20 | ||
22 | const expect = chai.expect | 21 | const expect = chai.expect |
23 | 22 | ||
@@ -88,12 +87,12 @@ describe('Test video imports', function () { | |||
88 | 87 | ||
89 | { | 88 | { |
90 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) | 89 | const res = await getMyUserInformation(servers[0].url, servers[0].accessToken) |
91 | channelIdServer1 = res.body.videoChannels[ 0 ].id | 90 | channelIdServer1 = res.body.videoChannels[0].id |
92 | } | 91 | } |
93 | 92 | ||
94 | { | 93 | { |
95 | const res = await getMyUserInformation(servers[1].url, servers[1].accessToken) | 94 | const res = await getMyUserInformation(servers[1].url, servers[1].accessToken) |
96 | channelIdServer2 = res.body.videoChannels[ 0 ].id | 95 | channelIdServer2 = res.body.videoChannels[0].id |
97 | } | 96 | } |
98 | 97 | ||
99 | await doubleFollow(servers[0], servers[1]) | 98 | await doubleFollow(servers[0], servers[1]) |
@@ -214,7 +213,7 @@ describe('Test video imports', function () { | |||
214 | 213 | ||
215 | await checkVideoServer2(server.url, res.body.data[0].uuid) | 214 | await checkVideoServer2(server.url, res.body.data[0].uuid) |
216 | 215 | ||
217 | const [ ,videoHttp, videoMagnet, videoTorrent ] = res.body.data | 216 | const [ , videoHttp, videoMagnet, videoTorrent ] = res.body.data |
218 | await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) | 217 | await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid) |
219 | } | 218 | } |
220 | }) | 219 | }) |
diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts index ad6a4b43f..7eba8d7d9 100644 --- a/server/tests/api/videos/video-nsfw.ts +++ b/server/tests/api/videos/video-nsfw.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -89,8 +89,8 @@ describe('Test video NSFW policy', function () { | |||
89 | 89 | ||
90 | const videos = res.body.data | 90 | const videos = res.body.data |
91 | expect(videos).to.have.lengthOf(2) | 91 | expect(videos).to.have.lengthOf(2) |
92 | expect(videos[ 0 ].name).to.equal('normal') | 92 | expect(videos[0].name).to.equal('normal') |
93 | expect(videos[ 1 ].name).to.equal('nsfw') | 93 | expect(videos[1].name).to.equal('nsfw') |
94 | } | 94 | } |
95 | }) | 95 | }) |
96 | 96 | ||
@@ -107,7 +107,7 @@ describe('Test video NSFW policy', function () { | |||
107 | 107 | ||
108 | const videos = res.body.data | 108 | const videos = res.body.data |
109 | expect(videos).to.have.lengthOf(1) | 109 | expect(videos).to.have.lengthOf(1) |
110 | expect(videos[ 0 ].name).to.equal('normal') | 110 | expect(videos[0].name).to.equal('normal') |
111 | } | 111 | } |
112 | }) | 112 | }) |
113 | 113 | ||
@@ -124,8 +124,8 @@ describe('Test video NSFW policy', function () { | |||
124 | 124 | ||
125 | const videos = res.body.data | 125 | const videos = res.body.data |
126 | expect(videos).to.have.lengthOf(2) | 126 | expect(videos).to.have.lengthOf(2) |
127 | expect(videos[ 0 ].name).to.equal('normal') | 127 | expect(videos[0].name).to.equal('normal') |
128 | expect(videos[ 1 ].name).to.equal('nsfw') | 128 | expect(videos[1].name).to.equal('nsfw') |
129 | } | 129 | } |
130 | }) | 130 | }) |
131 | }) | 131 | }) |
@@ -154,8 +154,8 @@ describe('Test video NSFW policy', function () { | |||
154 | 154 | ||
155 | const videos = res.body.data | 155 | const videos = res.body.data |
156 | expect(videos).to.have.lengthOf(2) | 156 | expect(videos).to.have.lengthOf(2) |
157 | expect(videos[ 0 ].name).to.equal('normal') | 157 | expect(videos[0].name).to.equal('normal') |
158 | expect(videos[ 1 ].name).to.equal('nsfw') | 158 | expect(videos[1].name).to.equal('nsfw') |
159 | } | 159 | } |
160 | }) | 160 | }) |
161 | 161 | ||
@@ -171,8 +171,8 @@ describe('Test video NSFW policy', function () { | |||
171 | 171 | ||
172 | const videos = res.body.data | 172 | const videos = res.body.data |
173 | expect(videos).to.have.lengthOf(2) | 173 | expect(videos).to.have.lengthOf(2) |
174 | expect(videos[ 0 ].name).to.equal('normal') | 174 | expect(videos[0].name).to.equal('normal') |
175 | expect(videos[ 1 ].name).to.equal('nsfw') | 175 | expect(videos[1].name).to.equal('nsfw') |
176 | } | 176 | } |
177 | }) | 177 | }) |
178 | 178 | ||
@@ -188,7 +188,7 @@ describe('Test video NSFW policy', function () { | |||
188 | 188 | ||
189 | const videos = res.body.data | 189 | const videos = res.body.data |
190 | expect(videos).to.have.lengthOf(1) | 190 | expect(videos).to.have.lengthOf(1) |
191 | expect(videos[ 0 ].name).to.equal('normal') | 191 | expect(videos[0].name).to.equal('normal') |
192 | } | 192 | } |
193 | }) | 193 | }) |
194 | 194 | ||
@@ -198,8 +198,8 @@ describe('Test video NSFW policy', function () { | |||
198 | 198 | ||
199 | const videos = res.body.data | 199 | const videos = res.body.data |
200 | expect(videos).to.have.lengthOf(2) | 200 | expect(videos).to.have.lengthOf(2) |
201 | expect(videos[ 0 ].name).to.equal('normal') | 201 | expect(videos[0].name).to.equal('normal') |
202 | expect(videos[ 1 ].name).to.equal('nsfw') | 202 | expect(videos[1].name).to.equal('nsfw') |
203 | }) | 203 | }) |
204 | 204 | ||
205 | it('Should display NSFW videos when the nsfw param === true', async function () { | 205 | it('Should display NSFW videos when the nsfw param === true', async function () { |
@@ -208,7 +208,7 @@ describe('Test video NSFW policy', function () { | |||
208 | 208 | ||
209 | const videos = res.body.data | 209 | const videos = res.body.data |
210 | expect(videos).to.have.lengthOf(1) | 210 | expect(videos).to.have.lengthOf(1) |
211 | expect(videos[ 0 ].name).to.equal('nsfw') | 211 | expect(videos[0].name).to.equal('nsfw') |
212 | } | 212 | } |
213 | }) | 213 | }) |
214 | 214 | ||
@@ -218,7 +218,7 @@ describe('Test video NSFW policy', function () { | |||
218 | 218 | ||
219 | const videos = res.body.data | 219 | const videos = res.body.data |
220 | expect(videos).to.have.lengthOf(1) | 220 | expect(videos).to.have.lengthOf(1) |
221 | expect(videos[ 0 ].name).to.equal('normal') | 221 | expect(videos[0].name).to.equal('normal') |
222 | } | 222 | } |
223 | }) | 223 | }) |
224 | 224 | ||
@@ -228,8 +228,8 @@ describe('Test video NSFW policy', function () { | |||
228 | 228 | ||
229 | const videos = res.body.data | 229 | const videos = res.body.data |
230 | expect(videos).to.have.lengthOf(2) | 230 | expect(videos).to.have.lengthOf(2) |
231 | expect(videos[ 0 ].name).to.equal('normal') | 231 | expect(videos[0].name).to.equal('normal') |
232 | expect(videos[ 1 ].name).to.equal('nsfw') | 232 | expect(videos[1].name).to.equal('nsfw') |
233 | } | 233 | } |
234 | }) | 234 | }) |
235 | }) | 235 | }) |
diff --git a/server/tests/api/videos/video-playlist-thumbnails.ts b/server/tests/api/videos/video-playlist-thumbnails.ts index 73ab02c17..a93a0b7de 100644 --- a/server/tests/api/videos/video-playlist-thumbnails.ts +++ b/server/tests/api/videos/video-playlist-thumbnails.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -8,14 +8,15 @@ import { | |||
8 | createVideoPlaylist, | 8 | createVideoPlaylist, |
9 | doubleFollow, | 9 | doubleFollow, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | getVideoPlaylistsList, removeVideoFromPlaylist, | 11 | getVideoPlaylistsList, |
12 | removeVideoFromPlaylist, | ||
13 | reorderVideosPlaylist, | ||
12 | ServerInfo, | 14 | ServerInfo, |
13 | setAccessTokensToServers, | 15 | setAccessTokensToServers, |
14 | setDefaultVideoChannel, | 16 | setDefaultVideoChannel, |
15 | testImage, | 17 | testImage, |
16 | uploadVideoAndGetId, | 18 | uploadVideoAndGetId, |
17 | waitJobs, | 19 | waitJobs |
18 | reorderVideosPlaylist | ||
19 | } from '../../../../shared/extra-utils' | 20 | } from '../../../../shared/extra-utils' |
20 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' | 21 | import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' |
21 | 22 | ||
@@ -69,19 +70,19 @@ describe('Playlist thumbnail', function () { | |||
69 | this.timeout(30000) | 70 | this.timeout(30000) |
70 | 71 | ||
71 | const res = await createVideoPlaylist({ | 72 | const res = await createVideoPlaylist({ |
72 | url: servers[ 1 ].url, | 73 | url: servers[1].url, |
73 | token: servers[ 1 ].accessToken, | 74 | token: servers[1].accessToken, |
74 | playlistAttrs: { | 75 | playlistAttrs: { |
75 | displayName: 'playlist without thumbnail', | 76 | displayName: 'playlist without thumbnail', |
76 | privacy: VideoPlaylistPrivacy.PUBLIC, | 77 | privacy: VideoPlaylistPrivacy.PUBLIC, |
77 | videoChannelId: servers[ 1 ].videoChannel.id | 78 | videoChannelId: servers[1].videoChannel.id |
78 | } | 79 | } |
79 | }) | 80 | }) |
80 | playlistWithoutThumbnail = res.body.videoPlaylist.id | 81 | playlistWithoutThumbnail = res.body.videoPlaylist.id |
81 | 82 | ||
82 | const res2 = await addVideoInPlaylist({ | 83 | const res2 = await addVideoInPlaylist({ |
83 | url: servers[ 1 ].url, | 84 | url: servers[1].url, |
84 | token: servers[ 1 ].accessToken, | 85 | token: servers[1].accessToken, |
85 | playlistId: playlistWithoutThumbnail, | 86 | playlistId: playlistWithoutThumbnail, |
86 | elementAttrs: { videoId: video1 } | 87 | elementAttrs: { videoId: video1 } |
87 | }) | 88 | }) |
@@ -99,20 +100,20 @@ describe('Playlist thumbnail', function () { | |||
99 | this.timeout(30000) | 100 | this.timeout(30000) |
100 | 101 | ||
101 | const res = await createVideoPlaylist({ | 102 | const res = await createVideoPlaylist({ |
102 | url: servers[ 1 ].url, | 103 | url: servers[1].url, |
103 | token: servers[ 1 ].accessToken, | 104 | token: servers[1].accessToken, |
104 | playlistAttrs: { | 105 | playlistAttrs: { |
105 | displayName: 'playlist with thumbnail', | 106 | displayName: 'playlist with thumbnail', |
106 | privacy: VideoPlaylistPrivacy.PUBLIC, | 107 | privacy: VideoPlaylistPrivacy.PUBLIC, |
107 | videoChannelId: servers[ 1 ].videoChannel.id, | 108 | videoChannelId: servers[1].videoChannel.id, |
108 | thumbnailfile: 'thumbnail.jpg' | 109 | thumbnailfile: 'thumbnail.jpg' |
109 | } | 110 | } |
110 | }) | 111 | }) |
111 | playlistWithThumbnail = res.body.videoPlaylist.id | 112 | playlistWithThumbnail = res.body.videoPlaylist.id |
112 | 113 | ||
113 | const res2 = await addVideoInPlaylist({ | 114 | const res2 = await addVideoInPlaylist({ |
114 | url: servers[ 1 ].url, | 115 | url: servers[1].url, |
115 | token: servers[ 1 ].accessToken, | 116 | token: servers[1].accessToken, |
116 | playlistId: playlistWithThumbnail, | 117 | playlistId: playlistWithThumbnail, |
117 | elementAttrs: { videoId: video1 } | 118 | elementAttrs: { videoId: video1 } |
118 | }) | 119 | }) |
@@ -130,8 +131,8 @@ describe('Playlist thumbnail', function () { | |||
130 | this.timeout(30000) | 131 | this.timeout(30000) |
131 | 132 | ||
132 | const res = await addVideoInPlaylist({ | 133 | const res = await addVideoInPlaylist({ |
133 | url: servers[ 1 ].url, | 134 | url: servers[1].url, |
134 | token: servers[ 1 ].accessToken, | 135 | token: servers[1].accessToken, |
135 | playlistId: playlistWithoutThumbnail, | 136 | playlistId: playlistWithoutThumbnail, |
136 | elementAttrs: { videoId: video2 } | 137 | elementAttrs: { videoId: video2 } |
137 | }) | 138 | }) |
@@ -159,8 +160,8 @@ describe('Playlist thumbnail', function () { | |||
159 | this.timeout(30000) | 160 | this.timeout(30000) |
160 | 161 | ||
161 | const res = await addVideoInPlaylist({ | 162 | const res = await addVideoInPlaylist({ |
162 | url: servers[ 1 ].url, | 163 | url: servers[1].url, |
163 | token: servers[ 1 ].accessToken, | 164 | token: servers[1].accessToken, |
164 | playlistId: playlistWithThumbnail, | 165 | playlistId: playlistWithThumbnail, |
165 | elementAttrs: { videoId: video2 } | 166 | elementAttrs: { videoId: video2 } |
166 | }) | 167 | }) |
@@ -188,8 +189,8 @@ describe('Playlist thumbnail', function () { | |||
188 | this.timeout(30000) | 189 | this.timeout(30000) |
189 | 190 | ||
190 | await removeVideoFromPlaylist({ | 191 | await removeVideoFromPlaylist({ |
191 | url: servers[ 1 ].url, | 192 | url: servers[1].url, |
192 | token: servers[ 1 ].accessToken, | 193 | token: servers[1].accessToken, |
193 | playlistId: playlistWithoutThumbnail, | 194 | playlistId: playlistWithoutThumbnail, |
194 | playlistElementId: withoutThumbnailE1 | 195 | playlistElementId: withoutThumbnailE1 |
195 | }) | 196 | }) |
@@ -206,8 +207,8 @@ describe('Playlist thumbnail', function () { | |||
206 | this.timeout(30000) | 207 | this.timeout(30000) |
207 | 208 | ||
208 | await removeVideoFromPlaylist({ | 209 | await removeVideoFromPlaylist({ |
209 | url: servers[ 1 ].url, | 210 | url: servers[1].url, |
210 | token: servers[ 1 ].accessToken, | 211 | token: servers[1].accessToken, |
211 | playlistId: playlistWithThumbnail, | 212 | playlistId: playlistWithThumbnail, |
212 | playlistElementId: withThumbnailE1 | 213 | playlistElementId: withThumbnailE1 |
213 | }) | 214 | }) |
@@ -224,8 +225,8 @@ describe('Playlist thumbnail', function () { | |||
224 | this.timeout(30000) | 225 | this.timeout(30000) |
225 | 226 | ||
226 | await removeVideoFromPlaylist({ | 227 | await removeVideoFromPlaylist({ |
227 | url: servers[ 1 ].url, | 228 | url: servers[1].url, |
228 | token: servers[ 1 ].accessToken, | 229 | token: servers[1].accessToken, |
229 | playlistId: playlistWithoutThumbnail, | 230 | playlistId: playlistWithoutThumbnail, |
230 | playlistElementId: withoutThumbnailE2 | 231 | playlistElementId: withoutThumbnailE2 |
231 | }) | 232 | }) |
@@ -242,8 +243,8 @@ describe('Playlist thumbnail', function () { | |||
242 | this.timeout(30000) | 243 | this.timeout(30000) |
243 | 244 | ||
244 | await removeVideoFromPlaylist({ | 245 | await removeVideoFromPlaylist({ |
245 | url: servers[ 1 ].url, | 246 | url: servers[1].url, |
246 | token: servers[ 1 ].accessToken, | 247 | token: servers[1].accessToken, |
247 | playlistId: playlistWithThumbnail, | 248 | playlistId: playlistWithThumbnail, |
248 | playlistElementId: withThumbnailE2 | 249 | playlistElementId: withThumbnailE2 |
249 | }) | 250 | }) |
diff --git a/server/tests/api/videos/video-playlists.ts b/server/tests/api/videos/video-playlists.ts index 9fd48ac7c..2bb97d7a8 100644 --- a/server/tests/api/videos/video-playlists.ts +++ b/server/tests/api/videos/video-playlists.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -141,12 +141,12 @@ describe('Test video playlists', function () { | |||
141 | servers[2].videos = await Promise.all(serverPromises[2]) | 141 | servers[2].videos = await Promise.all(serverPromises[2]) |
142 | } | 142 | } |
143 | 143 | ||
144 | nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'NSFW video', nsfw: true })).id | 144 | nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id |
145 | 145 | ||
146 | { | 146 | { |
147 | await createUser({ | 147 | await createUser({ |
148 | url: servers[ 0 ].url, | 148 | url: servers[0].url, |
149 | accessToken: servers[ 0 ].accessToken, | 149 | accessToken: servers[0].accessToken, |
150 | username: 'user1', | 150 | username: 'user1', |
151 | password: 'password' | 151 | password: 'password' |
152 | }) | 152 | }) |
@@ -158,17 +158,17 @@ describe('Test video playlists', function () { | |||
158 | 158 | ||
159 | describe('Get default playlists', function () { | 159 | describe('Get default playlists', function () { |
160 | it('Should list video playlist privacies', async function () { | 160 | it('Should list video playlist privacies', async function () { |
161 | const res = await getVideoPlaylistPrivacies(servers[ 0 ].url) | 161 | const res = await getVideoPlaylistPrivacies(servers[0].url) |
162 | 162 | ||
163 | const privacies = res.body | 163 | const privacies = res.body |
164 | expect(Object.keys(privacies)).to.have.length.at.least(3) | 164 | expect(Object.keys(privacies)).to.have.length.at.least(3) |
165 | 165 | ||
166 | expect(privacies[ 3 ]).to.equal('Private') | 166 | expect(privacies[3]).to.equal('Private') |
167 | }) | 167 | }) |
168 | 168 | ||
169 | it('Should list watch later playlist', async function () { | 169 | it('Should list watch later playlist', async function () { |
170 | const url = servers[ 0 ].url | 170 | const url = servers[0].url |
171 | const accessToken = servers[ 0 ].accessToken | 171 | const accessToken = servers[0].accessToken |
172 | 172 | ||
173 | { | 173 | { |
174 | const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER) | 174 | const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER) |
@@ -176,7 +176,7 @@ describe('Test video playlists', function () { | |||
176 | expect(res.body.total).to.equal(1) | 176 | expect(res.body.total).to.equal(1) |
177 | expect(res.body.data).to.have.lengthOf(1) | 177 | expect(res.body.data).to.have.lengthOf(1) |
178 | 178 | ||
179 | const playlist: VideoPlaylist = res.body.data[ 0 ] | 179 | const playlist: VideoPlaylist = res.body.data[0] |
180 | expect(playlist.displayName).to.equal('Watch later') | 180 | expect(playlist.displayName).to.equal('Watch later') |
181 | expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) | 181 | expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER) |
182 | expect(playlist.type.label).to.equal('Watch later') | 182 | expect(playlist.type.label).to.equal('Watch later') |
@@ -197,15 +197,15 @@ describe('Test video playlists', function () { | |||
197 | }) | 197 | }) |
198 | 198 | ||
199 | it('Should get private playlist for a classic user', async function () { | 199 | it('Should get private playlist for a classic user', async function () { |
200 | const token = await generateUserAccessToken(servers[ 0 ], 'toto') | 200 | const token = await generateUserAccessToken(servers[0], 'toto') |
201 | 201 | ||
202 | const res = await getAccountPlaylistsListWithToken(servers[ 0 ].url, token, 'toto', 0, 5) | 202 | const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5) |
203 | 203 | ||
204 | expect(res.body.total).to.equal(1) | 204 | expect(res.body.total).to.equal(1) |
205 | expect(res.body.data).to.have.lengthOf(1) | 205 | expect(res.body.data).to.have.lengthOf(1) |
206 | 206 | ||
207 | const playlistId = res.body.data[ 0 ].id | 207 | const playlistId = res.body.data[0].id |
208 | await getPlaylistVideos(servers[ 0 ].url, token, playlistId, 0, 5) | 208 | await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5) |
209 | }) | 209 | }) |
210 | }) | 210 | }) |
211 | 211 | ||
@@ -215,14 +215,14 @@ describe('Test video playlists', function () { | |||
215 | this.timeout(30000) | 215 | this.timeout(30000) |
216 | 216 | ||
217 | await createVideoPlaylist({ | 217 | await createVideoPlaylist({ |
218 | url: servers[ 0 ].url, | 218 | url: servers[0].url, |
219 | token: servers[ 0 ].accessToken, | 219 | token: servers[0].accessToken, |
220 | playlistAttrs: { | 220 | playlistAttrs: { |
221 | displayName: 'my super playlist', | 221 | displayName: 'my super playlist', |
222 | privacy: VideoPlaylistPrivacy.PUBLIC, | 222 | privacy: VideoPlaylistPrivacy.PUBLIC, |
223 | description: 'my super description', | 223 | description: 'my super description', |
224 | thumbnailfile: 'thumbnail.jpg', | 224 | thumbnailfile: 'thumbnail.jpg', |
225 | videoChannelId: servers[ 0 ].videoChannel.id | 225 | videoChannelId: servers[0].videoChannel.id |
226 | } | 226 | } |
227 | }) | 227 | }) |
228 | 228 | ||
@@ -233,7 +233,7 @@ describe('Test video playlists', function () { | |||
233 | expect(res.body.total).to.equal(1) | 233 | expect(res.body.total).to.equal(1) |
234 | expect(res.body.data).to.have.lengthOf(1) | 234 | expect(res.body.data).to.have.lengthOf(1) |
235 | 235 | ||
236 | const playlistFromList = res.body.data[ 0 ] as VideoPlaylist | 236 | const playlistFromList = res.body.data[0] as VideoPlaylist |
237 | 237 | ||
238 | const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid) | 238 | const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid) |
239 | const playlistFromGet = res2.body | 239 | const playlistFromGet = res2.body |
@@ -266,12 +266,12 @@ describe('Test video playlists', function () { | |||
266 | 266 | ||
267 | { | 267 | { |
268 | const res = await createVideoPlaylist({ | 268 | const res = await createVideoPlaylist({ |
269 | url: servers[ 1 ].url, | 269 | url: servers[1].url, |
270 | token: servers[ 1 ].accessToken, | 270 | token: servers[1].accessToken, |
271 | playlistAttrs: { | 271 | playlistAttrs: { |
272 | displayName: 'playlist 2', | 272 | displayName: 'playlist 2', |
273 | privacy: VideoPlaylistPrivacy.PUBLIC, | 273 | privacy: VideoPlaylistPrivacy.PUBLIC, |
274 | videoChannelId: servers[ 1 ].videoChannel.id | 274 | videoChannelId: servers[1].videoChannel.id |
275 | } | 275 | } |
276 | }) | 276 | }) |
277 | playlistServer2Id1 = res.body.videoPlaylist.id | 277 | playlistServer2Id1 = res.body.videoPlaylist.id |
@@ -279,13 +279,13 @@ describe('Test video playlists', function () { | |||
279 | 279 | ||
280 | { | 280 | { |
281 | const res = await createVideoPlaylist({ | 281 | const res = await createVideoPlaylist({ |
282 | url: servers[ 1 ].url, | 282 | url: servers[1].url, |
283 | token: servers[ 1 ].accessToken, | 283 | token: servers[1].accessToken, |
284 | playlistAttrs: { | 284 | playlistAttrs: { |
285 | displayName: 'playlist 3', | 285 | displayName: 'playlist 3', |
286 | privacy: VideoPlaylistPrivacy.PUBLIC, | 286 | privacy: VideoPlaylistPrivacy.PUBLIC, |
287 | thumbnailfile: 'thumbnail.jpg', | 287 | thumbnailfile: 'thumbnail.jpg', |
288 | videoChannelId: servers[ 1 ].videoChannel.id | 288 | videoChannelId: servers[1].videoChannel.id |
289 | } | 289 | } |
290 | }) | 290 | }) |
291 | 291 | ||
@@ -293,24 +293,24 @@ describe('Test video playlists', function () { | |||
293 | playlistServer2UUID2 = res.body.videoPlaylist.uuid | 293 | playlistServer2UUID2 = res.body.videoPlaylist.uuid |
294 | } | 294 | } |
295 | 295 | ||
296 | for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) { | 296 | for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) { |
297 | await addVideoInPlaylist({ | 297 | await addVideoInPlaylist({ |
298 | url: servers[ 1 ].url, | 298 | url: servers[1].url, |
299 | token: servers[ 1 ].accessToken, | 299 | token: servers[1].accessToken, |
300 | playlistId: id, | 300 | playlistId: id, |
301 | elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 } | 301 | elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 } |
302 | }) | 302 | }) |
303 | await addVideoInPlaylist({ | 303 | await addVideoInPlaylist({ |
304 | url: servers[ 1 ].url, | 304 | url: servers[1].url, |
305 | token: servers[ 1 ].accessToken, | 305 | token: servers[1].accessToken, |
306 | playlistId: id, | 306 | playlistId: id, |
307 | elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id } | 307 | elementAttrs: { videoId: servers[1].videos[1].id } |
308 | }) | 308 | }) |
309 | } | 309 | } |
310 | 310 | ||
311 | await waitJobs(servers) | 311 | await waitJobs(servers) |
312 | 312 | ||
313 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 313 | for (const server of [ servers[0], servers[1] ]) { |
314 | const res = await getVideoPlaylistsList(server.url, 0, 5) | 314 | const res = await getVideoPlaylistsList(server.url, 0, 5) |
315 | 315 | ||
316 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') | 316 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') |
@@ -322,7 +322,7 @@ describe('Test video playlists', function () { | |||
322 | await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) | 322 | await testImage(server.url, 'thumbnail', playlist3.thumbnailPath) |
323 | } | 323 | } |
324 | 324 | ||
325 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 325 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
326 | expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined | 326 | expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined |
327 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined | 327 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined |
328 | }) | 328 | }) |
@@ -331,13 +331,13 @@ describe('Test video playlists', function () { | |||
331 | this.timeout(30000) | 331 | this.timeout(30000) |
332 | 332 | ||
333 | // Server 2 and server 3 follow each other | 333 | // Server 2 and server 3 follow each other |
334 | await doubleFollow(servers[ 1 ], servers[ 2 ]) | 334 | await doubleFollow(servers[1], servers[2]) |
335 | 335 | ||
336 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 336 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
337 | 337 | ||
338 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') | 338 | const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2') |
339 | expect(playlist2).to.not.be.undefined | 339 | expect(playlist2).to.not.be.undefined |
340 | await testImage(servers[ 2 ].url, 'thumbnail-playlist', playlist2.thumbnailPath) | 340 | await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath) |
341 | 341 | ||
342 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined | 342 | expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined |
343 | }) | 343 | }) |
@@ -349,25 +349,25 @@ describe('Test video playlists', function () { | |||
349 | this.timeout(30000) | 349 | this.timeout(30000) |
350 | 350 | ||
351 | { | 351 | { |
352 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt') | 352 | const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt') |
353 | 353 | ||
354 | expect(res.body.total).to.equal(3) | 354 | expect(res.body.total).to.equal(3) |
355 | 355 | ||
356 | const data: VideoPlaylist[] = res.body.data | 356 | const data: VideoPlaylist[] = res.body.data |
357 | expect(data).to.have.lengthOf(2) | 357 | expect(data).to.have.lengthOf(2) |
358 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 358 | expect(data[0].displayName).to.equal('playlist 2') |
359 | expect(data[ 1 ].displayName).to.equal('playlist 3') | 359 | expect(data[1].displayName).to.equal('playlist 3') |
360 | } | 360 | } |
361 | 361 | ||
362 | { | 362 | { |
363 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt') | 363 | const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt') |
364 | 364 | ||
365 | expect(res.body.total).to.equal(3) | 365 | expect(res.body.total).to.equal(3) |
366 | 366 | ||
367 | const data: VideoPlaylist[] = res.body.data | 367 | const data: VideoPlaylist[] = res.body.data |
368 | expect(data).to.have.lengthOf(2) | 368 | expect(data).to.have.lengthOf(2) |
369 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 369 | expect(data[0].displayName).to.equal('playlist 2') |
370 | expect(data[ 1 ].displayName).to.equal('my super playlist') | 370 | expect(data[1].displayName).to.equal('my super playlist') |
371 | } | 371 | } |
372 | }) | 372 | }) |
373 | 373 | ||
@@ -375,13 +375,13 @@ describe('Test video playlists', function () { | |||
375 | this.timeout(30000) | 375 | this.timeout(30000) |
376 | 376 | ||
377 | { | 377 | { |
378 | const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt') | 378 | const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt') |
379 | 379 | ||
380 | expect(res.body.total).to.equal(1) | 380 | expect(res.body.total).to.equal(1) |
381 | 381 | ||
382 | const data: VideoPlaylist[] = res.body.data | 382 | const data: VideoPlaylist[] = res.body.data |
383 | expect(data).to.have.lengthOf(1) | 383 | expect(data).to.have.lengthOf(1) |
384 | expect(data[ 0 ].displayName).to.equal('my super playlist') | 384 | expect(data[0].displayName).to.equal('my super playlist') |
385 | } | 385 | } |
386 | }) | 386 | }) |
387 | 387 | ||
@@ -389,37 +389,37 @@ describe('Test video playlists', function () { | |||
389 | this.timeout(30000) | 389 | this.timeout(30000) |
390 | 390 | ||
391 | { | 391 | { |
392 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt') | 392 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt') |
393 | 393 | ||
394 | expect(res.body.total).to.equal(2) | 394 | expect(res.body.total).to.equal(2) |
395 | 395 | ||
396 | const data: VideoPlaylist[] = res.body.data | 396 | const data: VideoPlaylist[] = res.body.data |
397 | expect(data).to.have.lengthOf(1) | 397 | expect(data).to.have.lengthOf(1) |
398 | expect(data[ 0 ].displayName).to.equal('playlist 2') | 398 | expect(data[0].displayName).to.equal('playlist 2') |
399 | } | 399 | } |
400 | 400 | ||
401 | { | 401 | { |
402 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt') | 402 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt') |
403 | 403 | ||
404 | expect(res.body.total).to.equal(2) | 404 | expect(res.body.total).to.equal(2) |
405 | 405 | ||
406 | const data: VideoPlaylist[] = res.body.data | 406 | const data: VideoPlaylist[] = res.body.data |
407 | expect(data).to.have.lengthOf(1) | 407 | expect(data).to.have.lengthOf(1) |
408 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 408 | expect(data[0].displayName).to.equal('playlist 3') |
409 | } | 409 | } |
410 | 410 | ||
411 | { | 411 | { |
412 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '3') | 412 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3') |
413 | 413 | ||
414 | expect(res.body.total).to.equal(1) | 414 | expect(res.body.total).to.equal(1) |
415 | 415 | ||
416 | const data: VideoPlaylist[] = res.body.data | 416 | const data: VideoPlaylist[] = res.body.data |
417 | expect(data).to.have.lengthOf(1) | 417 | expect(data).to.have.lengthOf(1) |
418 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 418 | expect(data[0].displayName).to.equal('playlist 3') |
419 | } | 419 | } |
420 | 420 | ||
421 | { | 421 | { |
422 | const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '4') | 422 | const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4') |
423 | 423 | ||
424 | expect(res.body.total).to.equal(0) | 424 | expect(res.body.total).to.equal(0) |
425 | 425 | ||
@@ -432,8 +432,8 @@ describe('Test video playlists', function () { | |||
432 | this.timeout(30000) | 432 | this.timeout(30000) |
433 | 433 | ||
434 | await createVideoPlaylist({ | 434 | await createVideoPlaylist({ |
435 | url: servers[ 1 ].url, | 435 | url: servers[1].url, |
436 | token: servers[ 1 ].accessToken, | 436 | token: servers[1].accessToken, |
437 | playlistAttrs: { | 437 | playlistAttrs: { |
438 | displayName: 'playlist unlisted', | 438 | displayName: 'playlist unlisted', |
439 | privacy: VideoPlaylistPrivacy.UNLISTED | 439 | privacy: VideoPlaylistPrivacy.UNLISTED |
@@ -441,8 +441,8 @@ describe('Test video playlists', function () { | |||
441 | }) | 441 | }) |
442 | 442 | ||
443 | await createVideoPlaylist({ | 443 | await createVideoPlaylist({ |
444 | url: servers[ 1 ].url, | 444 | url: servers[1].url, |
445 | token: servers[ 1 ].accessToken, | 445 | token: servers[1].accessToken, |
446 | playlistAttrs: { | 446 | playlistAttrs: { |
447 | displayName: 'playlist private', | 447 | displayName: 'playlist private', |
448 | privacy: VideoPlaylistPrivacy.PRIVATE | 448 | privacy: VideoPlaylistPrivacy.PRIVATE |
@@ -453,18 +453,18 @@ describe('Test video playlists', function () { | |||
453 | 453 | ||
454 | for (const server of servers) { | 454 | for (const server of servers) { |
455 | const results = [ | 455 | const results = [ |
456 | await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'), | 456 | await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'), |
457 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') | 457 | await getVideoPlaylistsList(server.url, 0, 2, '-createdAt') |
458 | ] | 458 | ] |
459 | 459 | ||
460 | expect(results[ 0 ].body.total).to.equal(2) | 460 | expect(results[0].body.total).to.equal(2) |
461 | expect(results[ 1 ].body.total).to.equal(3) | 461 | expect(results[1].body.total).to.equal(3) |
462 | 462 | ||
463 | for (const res of results) { | 463 | for (const res of results) { |
464 | const data: VideoPlaylist[] = res.body.data | 464 | const data: VideoPlaylist[] = res.body.data |
465 | expect(data).to.have.lengthOf(2) | 465 | expect(data).to.have.lengthOf(2) |
466 | expect(data[ 0 ].displayName).to.equal('playlist 3') | 466 | expect(data[0].displayName).to.equal('playlist 3') |
467 | expect(data[ 1 ].displayName).to.equal('playlist 2') | 467 | expect(data[1].displayName).to.equal('playlist 2') |
468 | } | 468 | } |
469 | } | 469 | } |
470 | }) | 470 | }) |
@@ -519,32 +519,32 @@ describe('Test video playlists', function () { | |||
519 | this.timeout(30000) | 519 | this.timeout(30000) |
520 | 520 | ||
521 | const addVideo = (elementAttrs: any) => { | 521 | const addVideo = (elementAttrs: any) => { |
522 | return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs }) | 522 | return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs }) |
523 | } | 523 | } |
524 | 524 | ||
525 | const res = await createVideoPlaylist({ | 525 | const res = await createVideoPlaylist({ |
526 | url: servers[ 0 ].url, | 526 | url: servers[0].url, |
527 | token: servers[ 0 ].accessToken, | 527 | token: servers[0].accessToken, |
528 | playlistAttrs: { | 528 | playlistAttrs: { |
529 | displayName: 'playlist 4', | 529 | displayName: 'playlist 4', |
530 | privacy: VideoPlaylistPrivacy.PUBLIC, | 530 | privacy: VideoPlaylistPrivacy.PUBLIC, |
531 | videoChannelId: servers[ 0 ].videoChannel.id | 531 | videoChannelId: servers[0].videoChannel.id |
532 | } | 532 | } |
533 | }) | 533 | }) |
534 | 534 | ||
535 | playlistServer1Id = res.body.videoPlaylist.id | 535 | playlistServer1Id = res.body.videoPlaylist.id |
536 | playlistServer1UUID = res.body.videoPlaylist.uuid | 536 | playlistServer1UUID = res.body.videoPlaylist.uuid |
537 | 537 | ||
538 | await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 }) | 538 | await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 }) |
539 | await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 }) | 539 | await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 }) |
540 | await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid }) | 540 | await addVideo({ videoId: servers[2].videos[2].uuid }) |
541 | { | 541 | { |
542 | const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 }) | 542 | const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 }) |
543 | playlistElementServer1Video4 = res.body.videoPlaylistElement.id | 543 | playlistElementServer1Video4 = res.body.videoPlaylistElement.id |
544 | } | 544 | } |
545 | 545 | ||
546 | { | 546 | { |
547 | const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 }) | 547 | const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 }) |
548 | playlistElementServer1Video5 = res.body.videoPlaylistElement.id | 548 | playlistElementServer1Video5 = res.body.videoPlaylistElement.id |
549 | } | 549 | } |
550 | 550 | ||
@@ -567,35 +567,35 @@ describe('Test video playlists', function () { | |||
567 | const videoElements: VideoPlaylistElement[] = res.body.data | 567 | const videoElements: VideoPlaylistElement[] = res.body.data |
568 | expect(videoElements).to.have.lengthOf(6) | 568 | expect(videoElements).to.have.lengthOf(6) |
569 | 569 | ||
570 | expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1') | 570 | expect(videoElements[0].video.name).to.equal('video 0 server 1') |
571 | expect(videoElements[ 0 ].position).to.equal(1) | 571 | expect(videoElements[0].position).to.equal(1) |
572 | expect(videoElements[ 0 ].startTimestamp).to.equal(15) | 572 | expect(videoElements[0].startTimestamp).to.equal(15) |
573 | expect(videoElements[ 0 ].stopTimestamp).to.equal(28) | 573 | expect(videoElements[0].stopTimestamp).to.equal(28) |
574 | 574 | ||
575 | expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3') | 575 | expect(videoElements[1].video.name).to.equal('video 1 server 3') |
576 | expect(videoElements[ 1 ].position).to.equal(2) | 576 | expect(videoElements[1].position).to.equal(2) |
577 | expect(videoElements[ 1 ].startTimestamp).to.equal(35) | 577 | expect(videoElements[1].startTimestamp).to.equal(35) |
578 | expect(videoElements[ 1 ].stopTimestamp).to.be.null | 578 | expect(videoElements[1].stopTimestamp).to.be.null |
579 | 579 | ||
580 | expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3') | 580 | expect(videoElements[2].video.name).to.equal('video 2 server 3') |
581 | expect(videoElements[ 2 ].position).to.equal(3) | 581 | expect(videoElements[2].position).to.equal(3) |
582 | expect(videoElements[ 2 ].startTimestamp).to.be.null | 582 | expect(videoElements[2].startTimestamp).to.be.null |
583 | expect(videoElements[ 2 ].stopTimestamp).to.be.null | 583 | expect(videoElements[2].stopTimestamp).to.be.null |
584 | 584 | ||
585 | expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1') | 585 | expect(videoElements[3].video.name).to.equal('video 3 server 1') |
586 | expect(videoElements[ 3 ].position).to.equal(4) | 586 | expect(videoElements[3].position).to.equal(4) |
587 | expect(videoElements[ 3 ].startTimestamp).to.be.null | 587 | expect(videoElements[3].startTimestamp).to.be.null |
588 | expect(videoElements[ 3 ].stopTimestamp).to.equal(35) | 588 | expect(videoElements[3].stopTimestamp).to.equal(35) |
589 | 589 | ||
590 | expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1') | 590 | expect(videoElements[4].video.name).to.equal('video 4 server 1') |
591 | expect(videoElements[ 4 ].position).to.equal(5) | 591 | expect(videoElements[4].position).to.equal(5) |
592 | expect(videoElements[ 4 ].startTimestamp).to.equal(45) | 592 | expect(videoElements[4].startTimestamp).to.equal(45) |
593 | expect(videoElements[ 4 ].stopTimestamp).to.equal(60) | 593 | expect(videoElements[4].stopTimestamp).to.equal(60) |
594 | 594 | ||
595 | expect(videoElements[ 5 ].video.name).to.equal('NSFW video') | 595 | expect(videoElements[5].video.name).to.equal('NSFW video') |
596 | expect(videoElements[ 5 ].position).to.equal(6) | 596 | expect(videoElements[5].position).to.equal(6) |
597 | expect(videoElements[ 5 ].startTimestamp).to.equal(5) | 597 | expect(videoElements[5].startTimestamp).to.equal(5) |
598 | expect(videoElements[ 5 ].stopTimestamp).to.be.null | 598 | expect(videoElements[5].stopTimestamp).to.be.null |
599 | 599 | ||
600 | const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) | 600 | const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2) |
601 | expect(res3.body.data).to.have.lengthOf(2) | 601 | expect(res3.body.data).to.have.lengthOf(2) |
@@ -616,18 +616,18 @@ describe('Test video playlists', function () { | |||
616 | before(async function () { | 616 | before(async function () { |
617 | this.timeout(30000) | 617 | this.timeout(30000) |
618 | 618 | ||
619 | groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ] | 619 | groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ] |
620 | groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ] | 620 | groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ] |
621 | group1 = [ servers[ 0 ] ] | 621 | group1 = [ servers[0] ] |
622 | group2 = [ servers[ 1 ], servers[ 2 ] ] | 622 | group2 = [ servers[1], servers[2] ] |
623 | 623 | ||
624 | const res = await createVideoPlaylist({ | 624 | const res = await createVideoPlaylist({ |
625 | url: servers[ 0 ].url, | 625 | url: servers[0].url, |
626 | token: userAccessTokenServer1, | 626 | token: userAccessTokenServer1, |
627 | playlistAttrs: { | 627 | playlistAttrs: { |
628 | displayName: 'playlist 56', | 628 | displayName: 'playlist 56', |
629 | privacy: VideoPlaylistPrivacy.PUBLIC, | 629 | privacy: VideoPlaylistPrivacy.PUBLIC, |
630 | videoChannelId: servers[ 0 ].videoChannel.id | 630 | videoChannelId: servers[0].videoChannel.id |
631 | } | 631 | } |
632 | }) | 632 | }) |
633 | 633 | ||
@@ -635,7 +635,7 @@ describe('Test video playlists', function () { | |||
635 | playlistServer1UUID2 = res.body.videoPlaylist.uuid | 635 | playlistServer1UUID2 = res.body.videoPlaylist.uuid |
636 | 636 | ||
637 | const addVideo = (elementAttrs: any) => { | 637 | const addVideo = (elementAttrs: any) => { |
638 | return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs }) | 638 | return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs }) |
639 | } | 639 | } |
640 | 640 | ||
641 | video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid | 641 | video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid |
@@ -656,7 +656,7 @@ describe('Test video playlists', function () { | |||
656 | const position = 1 | 656 | const position = 1 |
657 | 657 | ||
658 | { | 658 | { |
659 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE }) | 659 | await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE }) |
660 | await waitJobs(servers) | 660 | await waitJobs(servers) |
661 | 661 | ||
662 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 662 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -666,7 +666,7 @@ describe('Test video playlists', function () { | |||
666 | } | 666 | } |
667 | 667 | ||
668 | { | 668 | { |
669 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC }) | 669 | await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC }) |
670 | await waitJobs(servers) | 670 | await waitJobs(servers) |
671 | 671 | ||
672 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 672 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -684,7 +684,7 @@ describe('Test video playlists', function () { | |||
684 | const position = 1 | 684 | const position = 1 |
685 | 685 | ||
686 | { | 686 | { |
687 | await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true) | 687 | await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true) |
688 | await waitJobs(servers) | 688 | await waitJobs(servers) |
689 | 689 | ||
690 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 690 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -694,7 +694,7 @@ describe('Test video playlists', function () { | |||
694 | } | 694 | } |
695 | 695 | ||
696 | { | 696 | { |
697 | await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1) | 697 | await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1) |
698 | await waitJobs(servers) | 698 | await waitJobs(servers) |
699 | 699 | ||
700 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 700 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -712,52 +712,52 @@ describe('Test video playlists', function () { | |||
712 | const position = 2 | 712 | const position = 2 |
713 | 713 | ||
714 | { | 714 | { |
715 | await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) | 715 | await addAccountToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) |
716 | await waitJobs(servers) | 716 | await waitJobs(servers) |
717 | 717 | ||
718 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 718 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
719 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 719 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
720 | 720 | ||
721 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) | 721 | await removeAccountFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port) |
722 | await waitJobs(servers) | 722 | await waitJobs(servers) |
723 | 723 | ||
724 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 724 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
725 | } | 725 | } |
726 | 726 | ||
727 | { | 727 | { |
728 | await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) | 728 | await addServerToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port) |
729 | await waitJobs(servers) | 729 | await waitJobs(servers) |
730 | 730 | ||
731 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 731 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
732 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 732 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
733 | 733 | ||
734 | await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port) | 734 | await removeServerFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port) |
735 | await waitJobs(servers) | 735 | await waitJobs(servers) |
736 | 736 | ||
737 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 737 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
738 | } | 738 | } |
739 | 739 | ||
740 | { | 740 | { |
741 | await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) | 741 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port) |
742 | await waitJobs(servers) | 742 | await waitJobs(servers) |
743 | 743 | ||
744 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 744 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
745 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 745 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
746 | 746 | ||
747 | await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port) | 747 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port) |
748 | await waitJobs(servers) | 748 | await waitJobs(servers) |
749 | 749 | ||
750 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 750 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
751 | } | 751 | } |
752 | 752 | ||
753 | { | 753 | { |
754 | await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 754 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
755 | await waitJobs(servers) | 755 | await waitJobs(servers) |
756 | 756 | ||
757 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) | 757 | await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3) |
758 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 758 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
759 | 759 | ||
760 | await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port) | 760 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port) |
761 | await waitJobs(servers) | 761 | await waitJobs(servers) |
762 | 762 | ||
763 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) | 763 | await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3) |
@@ -785,8 +785,8 @@ describe('Test video playlists', function () { | |||
785 | 785 | ||
786 | { | 786 | { |
787 | await reorderVideosPlaylist({ | 787 | await reorderVideosPlaylist({ |
788 | url: servers[ 0 ].url, | 788 | url: servers[0].url, |
789 | token: servers[ 0 ].accessToken, | 789 | token: servers[0].accessToken, |
790 | playlistId: playlistServer1Id, | 790 | playlistId: playlistServer1Id, |
791 | elementAttrs: { | 791 | elementAttrs: { |
792 | startPosition: 2, | 792 | startPosition: 2, |
@@ -813,8 +813,8 @@ describe('Test video playlists', function () { | |||
813 | 813 | ||
814 | { | 814 | { |
815 | await reorderVideosPlaylist({ | 815 | await reorderVideosPlaylist({ |
816 | url: servers[ 0 ].url, | 816 | url: servers[0].url, |
817 | token: servers[ 0 ].accessToken, | 817 | token: servers[0].accessToken, |
818 | playlistId: playlistServer1Id, | 818 | playlistId: playlistServer1Id, |
819 | elementAttrs: { | 819 | elementAttrs: { |
820 | startPosition: 1, | 820 | startPosition: 1, |
@@ -842,8 +842,8 @@ describe('Test video playlists', function () { | |||
842 | 842 | ||
843 | { | 843 | { |
844 | await reorderVideosPlaylist({ | 844 | await reorderVideosPlaylist({ |
845 | url: servers[ 0 ].url, | 845 | url: servers[0].url, |
846 | token: servers[ 0 ].accessToken, | 846 | token: servers[0].accessToken, |
847 | playlistId: playlistServer1Id, | 847 | playlistId: playlistServer1Id, |
848 | elementAttrs: { | 848 | elementAttrs: { |
849 | startPosition: 6, | 849 | startPosition: 6, |
@@ -868,7 +868,7 @@ describe('Test video playlists', function () { | |||
868 | ]) | 868 | ]) |
869 | 869 | ||
870 | for (let i = 1; i <= elements.length; i++) { | 870 | for (let i = 1; i <= elements.length; i++) { |
871 | expect(elements[ i - 1 ].position).to.equal(i) | 871 | expect(elements[i - 1].position).to.equal(i) |
872 | } | 872 | } |
873 | } | 873 | } |
874 | } | 874 | } |
@@ -878,8 +878,8 @@ describe('Test video playlists', function () { | |||
878 | this.timeout(30000) | 878 | this.timeout(30000) |
879 | 879 | ||
880 | await updateVideoPlaylistElement({ | 880 | await updateVideoPlaylistElement({ |
881 | url: servers[ 0 ].url, | 881 | url: servers[0].url, |
882 | token: servers[ 0 ].accessToken, | 882 | token: servers[0].accessToken, |
883 | playlistId: playlistServer1Id, | 883 | playlistId: playlistServer1Id, |
884 | playlistElementId: playlistElementServer1Video4, | 884 | playlistElementId: playlistElementServer1Video4, |
885 | elementAttrs: { | 885 | elementAttrs: { |
@@ -888,8 +888,8 @@ describe('Test video playlists', function () { | |||
888 | }) | 888 | }) |
889 | 889 | ||
890 | await updateVideoPlaylistElement({ | 890 | await updateVideoPlaylistElement({ |
891 | url: servers[ 0 ].url, | 891 | url: servers[0].url, |
892 | token: servers[ 0 ].accessToken, | 892 | token: servers[0].accessToken, |
893 | playlistId: playlistServer1Id, | 893 | playlistId: playlistServer1Id, |
894 | playlistElementId: playlistElementServer1Video5, | 894 | playlistElementId: playlistElementServer1Video5, |
895 | elementAttrs: { | 895 | elementAttrs: { |
@@ -903,62 +903,62 @@ describe('Test video playlists', function () { | |||
903 | const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) | 903 | const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10) |
904 | const elements: VideoPlaylistElement[] = res.body.data | 904 | const elements: VideoPlaylistElement[] = res.body.data |
905 | 905 | ||
906 | expect(elements[ 0 ].video.name).to.equal('video 3 server 1') | 906 | expect(elements[0].video.name).to.equal('video 3 server 1') |
907 | expect(elements[ 0 ].position).to.equal(1) | 907 | expect(elements[0].position).to.equal(1) |
908 | expect(elements[ 0 ].startTimestamp).to.equal(1) | 908 | expect(elements[0].startTimestamp).to.equal(1) |
909 | expect(elements[ 0 ].stopTimestamp).to.equal(35) | 909 | expect(elements[0].stopTimestamp).to.equal(35) |
910 | 910 | ||
911 | expect(elements[ 5 ].video.name).to.equal('video 4 server 1') | 911 | expect(elements[5].video.name).to.equal('video 4 server 1') |
912 | expect(elements[ 5 ].position).to.equal(6) | 912 | expect(elements[5].position).to.equal(6) |
913 | expect(elements[ 5 ].startTimestamp).to.equal(45) | 913 | expect(elements[5].startTimestamp).to.equal(45) |
914 | expect(elements[ 5 ].stopTimestamp).to.be.null | 914 | expect(elements[5].stopTimestamp).to.be.null |
915 | } | 915 | } |
916 | }) | 916 | }) |
917 | 917 | ||
918 | it('Should check videos existence in my playlist', async function () { | 918 | it('Should check videos existence in my playlist', async function () { |
919 | const videoIds = [ | 919 | const videoIds = [ |
920 | servers[ 0 ].videos[ 0 ].id, | 920 | servers[0].videos[0].id, |
921 | 42000, | 921 | 42000, |
922 | servers[ 0 ].videos[ 3 ].id, | 922 | servers[0].videos[3].id, |
923 | 43000, | 923 | 43000, |
924 | servers[ 0 ].videos[ 4 ].id | 924 | servers[0].videos[4].id |
925 | ] | 925 | ] |
926 | const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds) | 926 | const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds) |
927 | const obj = res.body as VideoExistInPlaylist | 927 | const obj = res.body as VideoExistInPlaylist |
928 | 928 | ||
929 | { | 929 | { |
930 | const elem = obj[ servers[ 0 ].videos[ 0 ].id ] | 930 | const elem = obj[servers[0].videos[0].id] |
931 | expect(elem).to.have.lengthOf(1) | 931 | expect(elem).to.have.lengthOf(1) |
932 | expect(elem[ 0 ].playlistElementId).to.exist | 932 | expect(elem[0].playlistElementId).to.exist |
933 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 933 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
934 | expect(elem[ 0 ].startTimestamp).to.equal(15) | 934 | expect(elem[0].startTimestamp).to.equal(15) |
935 | expect(elem[ 0 ].stopTimestamp).to.equal(28) | 935 | expect(elem[0].stopTimestamp).to.equal(28) |
936 | } | 936 | } |
937 | 937 | ||
938 | { | 938 | { |
939 | const elem = obj[ servers[ 0 ].videos[ 3 ].id ] | 939 | const elem = obj[servers[0].videos[3].id] |
940 | expect(elem).to.have.lengthOf(1) | 940 | expect(elem).to.have.lengthOf(1) |
941 | expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4) | 941 | expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4) |
942 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 942 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
943 | expect(elem[ 0 ].startTimestamp).to.equal(1) | 943 | expect(elem[0].startTimestamp).to.equal(1) |
944 | expect(elem[ 0 ].stopTimestamp).to.equal(35) | 944 | expect(elem[0].stopTimestamp).to.equal(35) |
945 | } | 945 | } |
946 | 946 | ||
947 | { | 947 | { |
948 | const elem = obj[ servers[ 0 ].videos[ 4 ].id ] | 948 | const elem = obj[servers[0].videos[4].id] |
949 | expect(elem).to.have.lengthOf(1) | 949 | expect(elem).to.have.lengthOf(1) |
950 | expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id) | 950 | expect(elem[0].playlistId).to.equal(playlistServer1Id) |
951 | expect(elem[ 0 ].startTimestamp).to.equal(45) | 951 | expect(elem[0].startTimestamp).to.equal(45) |
952 | expect(elem[ 0 ].stopTimestamp).to.equal(null) | 952 | expect(elem[0].stopTimestamp).to.equal(null) |
953 | } | 953 | } |
954 | 954 | ||
955 | expect(obj[ 42000 ]).to.have.lengthOf(0) | 955 | expect(obj[42000]).to.have.lengthOf(0) |
956 | expect(obj[ 43000 ]).to.have.lengthOf(0) | 956 | expect(obj[43000]).to.have.lengthOf(0) |
957 | }) | 957 | }) |
958 | 958 | ||
959 | it('Should automatically update updatedAt field of playlists', async function () { | 959 | it('Should automatically update updatedAt field of playlists', async function () { |
960 | const server = servers[ 1 ] | 960 | const server = servers[1] |
961 | const videoId = servers[ 1 ].videos[ 5 ].id | 961 | const videoId = servers[1].videos[5].id |
962 | 962 | ||
963 | async function getPlaylistNames () { | 963 | async function getPlaylistNames () { |
964 | const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt') | 964 | const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt') |
@@ -974,8 +974,8 @@ describe('Test video playlists', function () { | |||
974 | const element2 = res2.body.videoPlaylistElement.id | 974 | const element2 = res2.body.videoPlaylistElement.id |
975 | 975 | ||
976 | const names1 = await getPlaylistNames() | 976 | const names1 = await getPlaylistNames() |
977 | expect(names1[ 0 ]).to.equal('playlist 3 updated') | 977 | expect(names1[0]).to.equal('playlist 3 updated') |
978 | expect(names1[ 1 ]).to.equal('playlist 2') | 978 | expect(names1[1]).to.equal('playlist 2') |
979 | 979 | ||
980 | await removeVideoFromPlaylist({ | 980 | await removeVideoFromPlaylist({ |
981 | url: server.url, | 981 | url: server.url, |
@@ -985,8 +985,8 @@ describe('Test video playlists', function () { | |||
985 | }) | 985 | }) |
986 | 986 | ||
987 | const names2 = await getPlaylistNames() | 987 | const names2 = await getPlaylistNames() |
988 | expect(names2[ 0 ]).to.equal('playlist 2') | 988 | expect(names2[0]).to.equal('playlist 2') |
989 | expect(names2[ 1 ]).to.equal('playlist 3 updated') | 989 | expect(names2[1]).to.equal('playlist 3 updated') |
990 | 990 | ||
991 | await removeVideoFromPlaylist({ | 991 | await removeVideoFromPlaylist({ |
992 | url: server.url, | 992 | url: server.url, |
@@ -996,23 +996,23 @@ describe('Test video playlists', function () { | |||
996 | }) | 996 | }) |
997 | 997 | ||
998 | const names3 = await getPlaylistNames() | 998 | const names3 = await getPlaylistNames() |
999 | expect(names3[ 0 ]).to.equal('playlist 3 updated') | 999 | expect(names3[0]).to.equal('playlist 3 updated') |
1000 | expect(names3[ 1 ]).to.equal('playlist 2') | 1000 | expect(names3[1]).to.equal('playlist 2') |
1001 | }) | 1001 | }) |
1002 | 1002 | ||
1003 | it('Should delete some elements', async function () { | 1003 | it('Should delete some elements', async function () { |
1004 | this.timeout(30000) | 1004 | this.timeout(30000) |
1005 | 1005 | ||
1006 | await removeVideoFromPlaylist({ | 1006 | await removeVideoFromPlaylist({ |
1007 | url: servers[ 0 ].url, | 1007 | url: servers[0].url, |
1008 | token: servers[ 0 ].accessToken, | 1008 | token: servers[0].accessToken, |
1009 | playlistId: playlistServer1Id, | 1009 | playlistId: playlistServer1Id, |
1010 | playlistElementId: playlistElementServer1Video4 | 1010 | playlistElementId: playlistElementServer1Video4 |
1011 | }) | 1011 | }) |
1012 | 1012 | ||
1013 | await removeVideoFromPlaylist({ | 1013 | await removeVideoFromPlaylist({ |
1014 | url: servers[ 0 ].url, | 1014 | url: servers[0].url, |
1015 | token: servers[ 0 ].accessToken, | 1015 | token: servers[0].accessToken, |
1016 | playlistId: playlistServer1Id, | 1016 | playlistId: playlistServer1Id, |
1017 | playlistElementId: playlistElementNSFW | 1017 | playlistElementId: playlistElementNSFW |
1018 | }) | 1018 | }) |
@@ -1027,17 +1027,17 @@ describe('Test video playlists', function () { | |||
1027 | const elements: VideoPlaylistElement[] = res.body.data | 1027 | const elements: VideoPlaylistElement[] = res.body.data |
1028 | expect(elements).to.have.lengthOf(4) | 1028 | expect(elements).to.have.lengthOf(4) |
1029 | 1029 | ||
1030 | expect(elements[ 0 ].video.name).to.equal('video 0 server 1') | 1030 | expect(elements[0].video.name).to.equal('video 0 server 1') |
1031 | expect(elements[ 0 ].position).to.equal(1) | 1031 | expect(elements[0].position).to.equal(1) |
1032 | 1032 | ||
1033 | expect(elements[ 1 ].video.name).to.equal('video 2 server 3') | 1033 | expect(elements[1].video.name).to.equal('video 2 server 3') |
1034 | expect(elements[ 1 ].position).to.equal(2) | 1034 | expect(elements[1].position).to.equal(2) |
1035 | 1035 | ||
1036 | expect(elements[ 2 ].video.name).to.equal('video 1 server 3') | 1036 | expect(elements[2].video.name).to.equal('video 1 server 3') |
1037 | expect(elements[ 2 ].position).to.equal(3) | 1037 | expect(elements[2].position).to.equal(3) |
1038 | 1038 | ||
1039 | expect(elements[ 3 ].video.name).to.equal('video 4 server 1') | 1039 | expect(elements[3].video.name).to.equal('video 4 server 1') |
1040 | expect(elements[ 3 ].position).to.equal(4) | 1040 | expect(elements[3].position).to.equal(4) |
1041 | } | 1041 | } |
1042 | }) | 1042 | }) |
1043 | 1043 | ||
@@ -1045,12 +1045,12 @@ describe('Test video playlists', function () { | |||
1045 | this.timeout(30000) | 1045 | this.timeout(30000) |
1046 | 1046 | ||
1047 | const res = await createVideoPlaylist({ | 1047 | const res = await createVideoPlaylist({ |
1048 | url: servers[ 0 ].url, | 1048 | url: servers[0].url, |
1049 | token: servers[ 0 ].accessToken, | 1049 | token: servers[0].accessToken, |
1050 | playlistAttrs: { | 1050 | playlistAttrs: { |
1051 | displayName: 'my super public playlist', | 1051 | displayName: 'my super public playlist', |
1052 | privacy: VideoPlaylistPrivacy.PUBLIC, | 1052 | privacy: VideoPlaylistPrivacy.PUBLIC, |
1053 | videoChannelId: servers[ 0 ].videoChannel.id | 1053 | videoChannelId: servers[0].videoChannel.id |
1054 | } | 1054 | } |
1055 | }) | 1055 | }) |
1056 | const videoPlaylistIds = res.body.videoPlaylist | 1056 | const videoPlaylistIds = res.body.videoPlaylist |
@@ -1062,16 +1062,16 @@ describe('Test video playlists', function () { | |||
1062 | } | 1062 | } |
1063 | 1063 | ||
1064 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } | 1064 | const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE } |
1065 | await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) | 1065 | await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs }) |
1066 | 1066 | ||
1067 | await waitJobs(servers) | 1067 | await waitJobs(servers) |
1068 | 1068 | ||
1069 | for (const server of [ servers[ 1 ], servers[ 2 ] ]) { | 1069 | for (const server of [ servers[1], servers[2] ]) { |
1070 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) | 1070 | await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404) |
1071 | } | 1071 | } |
1072 | await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401) | 1072 | await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401) |
1073 | 1073 | ||
1074 | await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200) | 1074 | await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200) |
1075 | }) | 1075 | }) |
1076 | }) | 1076 | }) |
1077 | 1077 | ||
@@ -1080,7 +1080,7 @@ describe('Test video playlists', function () { | |||
1080 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { | 1080 | it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () { |
1081 | this.timeout(30000) | 1081 | this.timeout(30000) |
1082 | 1082 | ||
1083 | await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id) | 1083 | await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id) |
1084 | 1084 | ||
1085 | await waitJobs(servers) | 1085 | await waitJobs(servers) |
1086 | 1086 | ||
@@ -1103,15 +1103,15 @@ describe('Test video playlists', function () { | |||
1103 | const finder = data => data.find(p => p.displayName === 'my super playlist') | 1103 | const finder = data => data.find(p => p.displayName === 'my super playlist') |
1104 | 1104 | ||
1105 | { | 1105 | { |
1106 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 1106 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
1107 | expect(res.body.total).to.equal(3) | 1107 | expect(res.body.total).to.equal(3) |
1108 | expect(finder(res.body.data)).to.not.be.undefined | 1108 | expect(finder(res.body.data)).to.not.be.undefined |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ]) | 1111 | await unfollow(servers[2].url, servers[2].accessToken, servers[0]) |
1112 | 1112 | ||
1113 | { | 1113 | { |
1114 | const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5) | 1114 | const res = await getVideoPlaylistsList(servers[2].url, 0, 5) |
1115 | expect(res.body.total).to.equal(1) | 1115 | expect(res.body.total).to.equal(1) |
1116 | 1116 | ||
1117 | expect(finder(res.body.data)).to.be.undefined | 1117 | expect(finder(res.body.data)).to.be.undefined |
@@ -1121,12 +1121,12 @@ describe('Test video playlists', function () { | |||
1121 | it('Should delete a channel and put the associated playlist in private mode', async function () { | 1121 | it('Should delete a channel and put the associated playlist in private mode', async function () { |
1122 | this.timeout(30000) | 1122 | this.timeout(30000) |
1123 | 1123 | ||
1124 | const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' }) | 1124 | const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' }) |
1125 | const videoChannelId = res.body.videoChannel.id | 1125 | const videoChannelId = res.body.videoChannel.id |
1126 | 1126 | ||
1127 | const res2 = await createVideoPlaylist({ | 1127 | const res2 = await createVideoPlaylist({ |
1128 | url: servers[ 0 ].url, | 1128 | url: servers[0].url, |
1129 | token: servers[ 0 ].accessToken, | 1129 | token: servers[0].accessToken, |
1130 | playlistAttrs: { | 1130 | playlistAttrs: { |
1131 | displayName: 'channel playlist', | 1131 | displayName: 'channel playlist', |
1132 | privacy: VideoPlaylistPrivacy.PUBLIC, | 1132 | privacy: VideoPlaylistPrivacy.PUBLIC, |
@@ -1137,15 +1137,15 @@ describe('Test video playlists', function () { | |||
1137 | 1137 | ||
1138 | await waitJobs(servers) | 1138 | await waitJobs(servers) |
1139 | 1139 | ||
1140 | await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel') | 1140 | await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel') |
1141 | 1141 | ||
1142 | await waitJobs(servers) | 1142 | await waitJobs(servers) |
1143 | 1143 | ||
1144 | const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID) | 1144 | const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID) |
1145 | expect(res3.body.displayName).to.equal('channel playlist') | 1145 | expect(res3.body.displayName).to.equal('channel playlist') |
1146 | expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) | 1146 | expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE) |
1147 | 1147 | ||
1148 | await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404) | 1148 | await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404) |
1149 | }) | 1149 | }) |
1150 | 1150 | ||
1151 | it('Should delete an account and delete its playlists', async function () { | 1151 | it('Should delete an account and delete its playlists', async function () { |
@@ -1153,20 +1153,20 @@ describe('Test video playlists', function () { | |||
1153 | 1153 | ||
1154 | const user = { username: 'user_1', password: 'password' } | 1154 | const user = { username: 'user_1', password: 'password' } |
1155 | const res = await createUser({ | 1155 | const res = await createUser({ |
1156 | url: servers[ 0 ].url, | 1156 | url: servers[0].url, |
1157 | accessToken: servers[ 0 ].accessToken, | 1157 | accessToken: servers[0].accessToken, |
1158 | username: user.username, | 1158 | username: user.username, |
1159 | password: user.password | 1159 | password: user.password |
1160 | }) | 1160 | }) |
1161 | 1161 | ||
1162 | const userId = res.body.user.id | 1162 | const userId = res.body.user.id |
1163 | const userAccessToken = await userLogin(servers[ 0 ], user) | 1163 | const userAccessToken = await userLogin(servers[0], user) |
1164 | 1164 | ||
1165 | const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken) | 1165 | const resChannel = await getMyUserInformation(servers[0].url, userAccessToken) |
1166 | const userChannel = (resChannel.body as User).videoChannels[ 0 ] | 1166 | const userChannel = (resChannel.body as User).videoChannels[0] |
1167 | 1167 | ||
1168 | await createVideoPlaylist({ | 1168 | await createVideoPlaylist({ |
1169 | url: servers[ 0 ].url, | 1169 | url: servers[0].url, |
1170 | token: userAccessToken, | 1170 | token: userAccessToken, |
1171 | playlistAttrs: { | 1171 | playlistAttrs: { |
1172 | displayName: 'playlist to be deleted', | 1172 | displayName: 'playlist to be deleted', |
@@ -1180,17 +1180,17 @@ describe('Test video playlists', function () { | |||
1180 | const finder = data => data.find(p => p.displayName === 'playlist to be deleted') | 1180 | const finder = data => data.find(p => p.displayName === 'playlist to be deleted') |
1181 | 1181 | ||
1182 | { | 1182 | { |
1183 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 1183 | for (const server of [ servers[0], servers[1] ]) { |
1184 | const res = await getVideoPlaylistsList(server.url, 0, 15) | 1184 | const res = await getVideoPlaylistsList(server.url, 0, 15) |
1185 | expect(finder(res.body.data)).to.not.be.undefined | 1185 | expect(finder(res.body.data)).to.not.be.undefined |
1186 | } | 1186 | } |
1187 | } | 1187 | } |
1188 | 1188 | ||
1189 | await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken) | 1189 | await removeUser(servers[0].url, userId, servers[0].accessToken) |
1190 | await waitJobs(servers) | 1190 | await waitJobs(servers) |
1191 | 1191 | ||
1192 | { | 1192 | { |
1193 | for (const server of [ servers[ 0 ], servers[ 1 ] ]) { | 1193 | for (const server of [ servers[0], servers[1] ]) { |
1194 | const res = await getVideoPlaylistsList(server.url, 0, 15) | 1194 | const res = await getVideoPlaylistsList(server.url, 0, 15) |
1195 | expect(finder(res.body.data)).to.be.undefined | 1195 | expect(finder(res.body.data)).to.be.undefined |
1196 | } | 1196 | } |
diff --git a/server/tests/api/videos/video-privacy.ts b/server/tests/api/videos/video-privacy.ts index e630ca84a..4bbbb90f3 100644 --- a/server/tests/api/videos/video-privacy.ts +++ b/server/tests/api/videos/video-privacy.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -6,7 +6,8 @@ import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enu | |||
6 | import { | 6 | import { |
7 | cleanupTests, | 7 | cleanupTests, |
8 | flushAndRunMultipleServers, | 8 | flushAndRunMultipleServers, |
9 | getVideosList, getVideosListWithToken, | 9 | getVideosList, |
10 | getVideosListWithToken, | ||
10 | ServerInfo, | 11 | ServerInfo, |
11 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
12 | uploadVideo | 13 | uploadVideo |
@@ -110,7 +111,7 @@ describe('Test video privacy', function () { | |||
110 | username: 'hello', | 111 | username: 'hello', |
111 | password: 'super password' | 112 | password: 'super password' |
112 | } | 113 | } |
113 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password }) | 114 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password }) |
114 | 115 | ||
115 | anotherUserToken = await userLogin(servers[0], user) | 116 | anotherUserToken = await userLogin(servers[0], user) |
116 | await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) | 117 | await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403) |
@@ -174,7 +175,7 @@ describe('Test video privacy', function () { | |||
174 | privacy: VideoPrivacy.PUBLIC | 175 | privacy: VideoPrivacy.PUBLIC |
175 | } | 176 | } |
176 | 177 | ||
177 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, privateVideoId, attribute) | 178 | await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute) |
178 | } | 179 | } |
179 | 180 | ||
180 | { | 181 | { |
@@ -182,7 +183,7 @@ describe('Test video privacy', function () { | |||
182 | name: 'internal video becomes public', | 183 | name: 'internal video becomes public', |
183 | privacy: VideoPrivacy.PUBLIC | 184 | privacy: VideoPrivacy.PUBLIC |
184 | } | 185 | } |
185 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, internalVideoId, attribute) | 186 | await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute) |
186 | } | 187 | } |
187 | 188 | ||
188 | await waitJobs(servers) | 189 | await waitJobs(servers) |
diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts index 65a8eafb8..204f43611 100644 --- a/server/tests/api/videos/video-schedule-update.ts +++ b/server/tests/api/videos/video-schedule-update.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -10,7 +10,6 @@ import { | |||
10 | getMyVideos, | 10 | getMyVideos, |
11 | getVideosList, | 11 | getVideosList, |
12 | getVideoWithToken, | 12 | getVideoWithToken, |
13 | killallServers, | ||
14 | ServerInfo, | 13 | ServerInfo, |
15 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
16 | updateVideo, | 15 | updateVideo, |
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts index 4be74901a..3e73ccbfa 100644 --- a/server/tests/api/videos/video-transcoder.ts +++ b/server/tests/api/videos/video-transcoder.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -11,6 +11,7 @@ import { | |||
11 | doubleFollow, | 11 | doubleFollow, |
12 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
13 | generateHighBitrateVideo, | 13 | generateHighBitrateVideo, |
14 | generateVideoWithFramerate, | ||
14 | getMyVideos, | 15 | getMyVideos, |
15 | getVideo, | 16 | getVideo, |
16 | getVideosList, | 17 | getVideosList, |
@@ -55,19 +56,19 @@ describe('Test video transcoding', function () { | |||
55 | 56 | ||
56 | for (const server of servers) { | 57 | for (const server of servers) { |
57 | const res = await getVideosList(server.url) | 58 | const res = await getVideosList(server.url) |
58 | const video = res.body.data[ 0 ] | 59 | const video = res.body.data[0] |
59 | 60 | ||
60 | const res2 = await getVideo(server.url, video.id) | 61 | const res2 = await getVideo(server.url, video.id) |
61 | const videoDetails = res2.body | 62 | const videoDetails = res2.body |
62 | expect(videoDetails.files).to.have.lengthOf(1) | 63 | expect(videoDetails.files).to.have.lengthOf(1) |
63 | 64 | ||
64 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 65 | const magnetUri = videoDetails.files[0].magnetUri |
65 | expect(magnetUri).to.match(/\.webm/) | 66 | expect(magnetUri).to.match(/\.webm/) |
66 | 67 | ||
67 | const torrent = await webtorrentAdd(magnetUri, true) | 68 | const torrent = await webtorrentAdd(magnetUri, true) |
68 | expect(torrent.files).to.be.an('array') | 69 | expect(torrent.files).to.be.an('array') |
69 | expect(torrent.files.length).to.equal(1) | 70 | expect(torrent.files.length).to.equal(1) |
70 | expect(torrent.files[ 0 ].path).match(/\.webm$/) | 71 | expect(torrent.files[0].path).match(/\.webm$/) |
71 | } | 72 | } |
72 | }) | 73 | }) |
73 | 74 | ||
@@ -92,13 +93,13 @@ describe('Test video transcoding', function () { | |||
92 | 93 | ||
93 | expect(videoDetails.files).to.have.lengthOf(4) | 94 | expect(videoDetails.files).to.have.lengthOf(4) |
94 | 95 | ||
95 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 96 | const magnetUri = videoDetails.files[0].magnetUri |
96 | expect(magnetUri).to.match(/\.mp4/) | 97 | expect(magnetUri).to.match(/\.mp4/) |
97 | 98 | ||
98 | const torrent = await webtorrentAdd(magnetUri, true) | 99 | const torrent = await webtorrentAdd(magnetUri, true) |
99 | expect(torrent.files).to.be.an('array') | 100 | expect(torrent.files).to.be.an('array') |
100 | expect(torrent.files.length).to.equal(1) | 101 | expect(torrent.files.length).to.equal(1) |
101 | expect(torrent.files[ 0 ].path).match(/\.mp4$/) | 102 | expect(torrent.files[0].path).match(/\.mp4$/) |
102 | } | 103 | } |
103 | }) | 104 | }) |
104 | 105 | ||
@@ -126,8 +127,8 @@ describe('Test video transcoding', function () { | |||
126 | const probe = await audio.get(path) | 127 | const probe = await audio.get(path) |
127 | 128 | ||
128 | if (probe.audioStream) { | 129 | if (probe.audioStream) { |
129 | expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac') | 130 | expect(probe.audioStream['codec_name']).to.be.equal('aac') |
130 | expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) | 131 | expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000) |
131 | } else { | 132 | } else { |
132 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) | 133 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) |
133 | } | 134 | } |
@@ -211,10 +212,10 @@ describe('Test video transcoding', function () { | |||
211 | const videoDetails: VideoDetails = res2.body | 212 | const videoDetails: VideoDetails = res2.body |
212 | 213 | ||
213 | expect(videoDetails.files).to.have.lengthOf(4) | 214 | expect(videoDetails.files).to.have.lengthOf(4) |
214 | expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62) | 215 | expect(videoDetails.files[0].fps).to.be.above(58).and.below(62) |
215 | expect(videoDetails.files[ 1 ].fps).to.be.below(31) | 216 | expect(videoDetails.files[1].fps).to.be.below(31) |
216 | expect(videoDetails.files[ 2 ].fps).to.be.below(31) | 217 | expect(videoDetails.files[2].fps).to.be.below(31) |
217 | expect(videoDetails.files[ 3 ].fps).to.be.below(31) | 218 | expect(videoDetails.files[3].fps).to.be.below(31) |
218 | 219 | ||
219 | for (const resolution of [ '240', '360', '480' ]) { | 220 | for (const resolution of [ '240', '360', '480' ]) { |
220 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') | 221 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
@@ -240,11 +241,11 @@ describe('Test video transcoding', function () { | |||
240 | fixture: 'video_short1.webm', | 241 | fixture: 'video_short1.webm', |
241 | waitTranscoding: true | 242 | waitTranscoding: true |
242 | } | 243 | } |
243 | const resVideo = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) | 244 | const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) |
244 | const videoId = resVideo.body.video.uuid | 245 | const videoId = resVideo.body.video.uuid |
245 | 246 | ||
246 | // Should be in transcode state | 247 | // Should be in transcode state |
247 | const { body } = await getVideo(servers[ 1 ].url, videoId) | 248 | const { body } = await getVideo(servers[1].url, videoId) |
248 | expect(body.name).to.equal('waiting video') | 249 | expect(body.name).to.equal('waiting video') |
249 | expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) | 250 | expect(body.state.id).to.equal(VideoState.TO_TRANSCODE) |
250 | expect(body.state.label).to.equal('To transcode') | 251 | expect(body.state.label).to.equal('To transcode') |
@@ -310,7 +311,7 @@ describe('Test video transcoding', function () { | |||
310 | 311 | ||
311 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 312 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
312 | 313 | ||
313 | for (const resolution of ['240', '360', '480', '720', '1080']) { | 314 | for (const resolution of [ '240', '360', '480', '720', '1080' ]) { |
314 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') | 315 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4') |
315 | const bitrate = await getVideoFileBitrate(path) | 316 | const bitrate = await getVideoFileBitrate(path) |
316 | const fps = await getVideoFileFPS(path) | 317 | const fps = await getVideoFileFPS(path) |
@@ -340,7 +341,7 @@ describe('Test video transcoding', function () { | |||
340 | fixture | 341 | fixture |
341 | } | 342 | } |
342 | 343 | ||
343 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes) | 344 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) |
344 | 345 | ||
345 | await waitJobs(servers) | 346 | await waitJobs(servers) |
346 | 347 | ||
@@ -353,7 +354,7 @@ describe('Test video transcoding', function () { | |||
353 | 354 | ||
354 | expect(videoDetails.files).to.have.lengthOf(4) | 355 | expect(videoDetails.files).to.have.lengthOf(4) |
355 | 356 | ||
356 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 357 | const magnetUri = videoDetails.files[0].magnetUri |
357 | expect(magnetUri).to.contain('.mp4') | 358 | expect(magnetUri).to.contain('.mp4') |
358 | } | 359 | } |
359 | } | 360 | } |
@@ -370,7 +371,7 @@ describe('Test video transcoding', function () { | |||
370 | this.timeout(60000) | 371 | this.timeout(60000) |
371 | 372 | ||
372 | const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } | 373 | const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' } |
373 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | 374 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) |
374 | 375 | ||
375 | await waitJobs(servers) | 376 | await waitJobs(servers) |
376 | 377 | ||
@@ -386,7 +387,7 @@ describe('Test video transcoding', function () { | |||
386 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | 387 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) |
387 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | 388 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) |
388 | 389 | ||
389 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 390 | const magnetUri = videoDetails.files[0].magnetUri |
390 | expect(magnetUri).to.contain('.mp4') | 391 | expect(magnetUri).to.contain('.mp4') |
391 | } | 392 | } |
392 | }) | 393 | }) |
@@ -395,7 +396,7 @@ describe('Test video transcoding', function () { | |||
395 | this.timeout(60000) | 396 | this.timeout(60000) |
396 | 397 | ||
397 | const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } | 398 | const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' } |
398 | await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg) | 399 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg) |
399 | 400 | ||
400 | await waitJobs(servers) | 401 | await waitJobs(servers) |
401 | 402 | ||
@@ -411,11 +412,52 @@ describe('Test video transcoding', function () { | |||
411 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) | 412 | await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 }) |
412 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) | 413 | await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 }) |
413 | 414 | ||
414 | const magnetUri = videoDetails.files[ 0 ].magnetUri | 415 | const magnetUri = videoDetails.files[0].magnetUri |
415 | expect(magnetUri).to.contain('.mp4') | 416 | expect(magnetUri).to.contain('.mp4') |
416 | } | 417 | } |
417 | }) | 418 | }) |
418 | 419 | ||
420 | it('Should downscale to the closest divisor standard framerate', async function () { | ||
421 | this.timeout(160000) | ||
422 | |||
423 | let tempFixturePath: string | ||
424 | |||
425 | { | ||
426 | tempFixturePath = await generateVideoWithFramerate(59) | ||
427 | |||
428 | const fps = await getVideoFileFPS(tempFixturePath) | ||
429 | expect(fps).to.be.equal(59) | ||
430 | } | ||
431 | |||
432 | const videoAttributes = { | ||
433 | name: '59fps video', | ||
434 | description: '59fps video', | ||
435 | fixture: tempFixturePath | ||
436 | } | ||
437 | |||
438 | await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes) | ||
439 | |||
440 | await waitJobs(servers) | ||
441 | |||
442 | for (const server of servers) { | ||
443 | const res = await getVideosList(server.url) | ||
444 | |||
445 | const video = res.body.data.find(v => v.name === videoAttributes.name) | ||
446 | |||
447 | { | ||
448 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4') | ||
449 | const fps = await getVideoFileFPS(path) | ||
450 | expect(fps).to.be.equal(25) | ||
451 | } | ||
452 | |||
453 | { | ||
454 | const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4') | ||
455 | const fps = await getVideoFileFPS(path) | ||
456 | expect(fps).to.be.equal(59) | ||
457 | } | ||
458 | } | ||
459 | }) | ||
460 | |||
419 | after(async function () { | 461 | after(async function () { |
420 | await cleanupTests(servers) | 462 | await cleanupTests(servers) |
421 | }) | 463 | }) |
diff --git a/server/tests/api/videos/videos-filter.ts b/server/tests/api/videos/videos-filter.ts index e1e65260f..95e12e43c 100644 --- a/server/tests/api/videos/videos-filter.ts +++ b/server/tests/api/videos/videos-filter.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -7,8 +7,6 @@ import { | |||
7 | createUser, | 7 | createUser, |
8 | doubleFollow, | 8 | doubleFollow, |
9 | flushAndRunMultipleServers, | 9 | flushAndRunMultipleServers, |
10 | flushTests, | ||
11 | killallServers, | ||
12 | makeGetRequest, | 10 | makeGetRequest, |
13 | ServerInfo, | 11 | ServerInfo, |
14 | setAccessTokensToServers, | 12 | setAccessTokensToServers, |
@@ -98,7 +96,7 @@ describe('Test videos filter validator', function () { | |||
98 | const namesResults = await getVideosNames(server, server.accessToken, 'local') | 96 | const namesResults = await getVideosNames(server, server.accessToken, 'local') |
99 | for (const names of namesResults) { | 97 | for (const names of namesResults) { |
100 | expect(names).to.have.lengthOf(1) | 98 | expect(names).to.have.lengthOf(1) |
101 | expect(names[ 0 ]).to.equal('public ' + server.serverNumber) | 99 | expect(names[0]).to.equal('public ' + server.serverNumber) |
102 | } | 100 | } |
103 | } | 101 | } |
104 | }) | 102 | }) |
@@ -111,9 +109,9 @@ describe('Test videos filter validator', function () { | |||
111 | for (const names of namesResults) { | 109 | for (const names of namesResults) { |
112 | expect(names).to.have.lengthOf(3) | 110 | expect(names).to.have.lengthOf(3) |
113 | 111 | ||
114 | expect(names[ 0 ]).to.equal('public ' + server.serverNumber) | 112 | expect(names[0]).to.equal('public ' + server.serverNumber) |
115 | expect(names[ 1 ]).to.equal('unlisted ' + server.serverNumber) | 113 | expect(names[1]).to.equal('unlisted ' + server.serverNumber) |
116 | expect(names[ 2 ]).to.equal('private ' + server.serverNumber) | 114 | expect(names[2]).to.equal('private ' + server.serverNumber) |
117 | } | 115 | } |
118 | } | 116 | } |
119 | } | 117 | } |
diff --git a/server/tests/api/videos/videos-history.ts b/server/tests/api/videos/videos-history.ts index c7e55c1ab..6f90e9a57 100644 --- a/server/tests/api/videos/videos-history.ts +++ b/server/tests/api/videos/videos-history.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/videos/videos-overview.ts b/server/tests/api/videos/videos-overview.ts index 975a5c87a..ca08ab5b1 100644 --- a/server/tests/api/videos/videos-overview.ts +++ b/server/tests/api/videos/videos-overview.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/api/videos/videos-views-cleaner.ts b/server/tests/api/videos/videos-views-cleaner.ts index fbddd40f4..d063d7973 100644 --- a/server/tests/api/videos/videos-views-cleaner.ts +++ b/server/tests/api/videos/videos-views-cleaner.ts | |||
@@ -1,20 +1,22 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { |
6 | cleanupTests, | ||
7 | closeAllSequelize, | ||
8 | countVideoViewsOf, | ||
9 | doubleFollow, | ||
6 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
7 | flushTests, | ||
8 | killallServers, | 11 | killallServers, |
9 | reRunServer, | 12 | reRunServer, |
10 | flushAndRunServer, | ||
11 | ServerInfo, | 13 | ServerInfo, |
12 | setAccessTokensToServers, | 14 | setAccessTokensToServers, |
13 | uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize | 15 | uploadVideoAndGetId, |
16 | viewVideo, | ||
17 | wait, | ||
18 | waitJobs | ||
14 | } from '../../../../shared/extra-utils' | 19 | } from '../../../../shared/extra-utils' |
15 | import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews' | ||
16 | import { VideosOverview } from '../../../../shared/models/overviews' | ||
17 | import { listMyVideosHistory } from '../../../../shared/extra-utils/videos/video-history' | ||
18 | 20 | ||
19 | const expect = chai.expect | 21 | const expect = chai.expect |
20 | 22 | ||
diff --git a/server/tests/cli/create-import-video-file-job.ts b/server/tests/cli/create-import-video-file-job.ts index aca3216bb..dac049fe4 100644 --- a/server/tests/cli/create-import-video-file-job.ts +++ b/server/tests/cli/create-import-video-file-job.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -71,7 +71,7 @@ describe('Test create import video jobs', function () { | |||
71 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body | 71 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body |
72 | 72 | ||
73 | expect(videoDetail.files).to.have.lengthOf(2) | 73 | expect(videoDetail.files).to.have.lengthOf(2) |
74 | const [originalVideo, transcodedVideo] = videoDetail.files | 74 | const [ originalVideo, transcodedVideo ] = videoDetail.files |
75 | assertVideoProperties(originalVideo, 720, 'webm', 218910) | 75 | assertVideoProperties(originalVideo, 720, 'webm', 218910) |
76 | assertVideoProperties(transcodedVideo, 480, 'webm', 69217) | 76 | assertVideoProperties(transcodedVideo, 480, 'webm', 69217) |
77 | 77 | ||
@@ -95,7 +95,7 @@ describe('Test create import video jobs', function () { | |||
95 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body | 95 | const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body |
96 | 96 | ||
97 | expect(videoDetail.files).to.have.lengthOf(4) | 97 | expect(videoDetail.files).to.have.lengthOf(4) |
98 | const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files | 98 | const [ originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240 ] = videoDetail.files |
99 | assertVideoProperties(originalVideo, 720, 'ogv', 140849) | 99 | assertVideoProperties(originalVideo, 720, 'ogv', 140849) |
100 | assertVideoProperties(transcodedVideo420, 480, 'mp4') | 100 | assertVideoProperties(transcodedVideo420, 480, 'mp4') |
101 | assertVideoProperties(transcodedVideo320, 360, 'mp4') | 101 | assertVideoProperties(transcodedVideo320, 360, 'mp4') |
diff --git a/server/tests/cli/create-transcoding-job.ts b/server/tests/cli/create-transcoding-job.ts index 7897ff1b3..997a9a1fd 100644 --- a/server/tests/cli/create-transcoding-job.ts +++ b/server/tests/cli/create-transcoding-job.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -8,14 +8,13 @@ import { | |||
8 | doubleFollow, | 8 | doubleFollow, |
9 | execCLI, | 9 | execCLI, |
10 | flushAndRunMultipleServers, | 10 | flushAndRunMultipleServers, |
11 | flushTests, | ||
12 | getEnvCli, | 11 | getEnvCli, |
13 | getVideo, | 12 | getVideo, |
14 | getVideosList, | 13 | getVideosList, |
15 | killallServers, | ||
16 | ServerInfo, | 14 | ServerInfo, |
17 | setAccessTokensToServers, updateCustomSubConfig, | 15 | setAccessTokensToServers, |
18 | uploadVideo, wait | 16 | updateCustomSubConfig, |
17 | uploadVideo | ||
19 | } from '../../../shared/extra-utils' | 18 | } from '../../../shared/extra-utils' |
20 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' | 19 | import { waitJobs } from '../../../shared/extra-utils/server/jobs' |
21 | 20 | ||
@@ -23,7 +22,7 @@ const expect = chai.expect | |||
23 | 22 | ||
24 | describe('Test create transcoding jobs', function () { | 23 | describe('Test create transcoding jobs', function () { |
25 | let servers: ServerInfo[] = [] | 24 | let servers: ServerInfo[] = [] |
26 | let videosUUID: string[] = [] | 25 | const videosUUID: string[] = [] |
27 | 26 | ||
28 | const config = { | 27 | const config = { |
29 | transcoding: { | 28 | transcoding: { |
@@ -54,7 +53,7 @@ describe('Test create transcoding jobs', function () { | |||
54 | await doubleFollow(servers[0], servers[1]) | 53 | await doubleFollow(servers[0], servers[1]) |
55 | 54 | ||
56 | for (let i = 1; i <= 5; i++) { | 55 | for (let i = 1; i <= 5; i++) { |
57 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' + i }) | 56 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' + i }) |
58 | videosUUID.push(res.body.video.uuid) | 57 | videosUUID.push(res.body.video.uuid) |
59 | } | 58 | } |
60 | 59 | ||
@@ -90,7 +89,7 @@ describe('Test create transcoding jobs', function () { | |||
90 | const res = await getVideosList(server.url) | 89 | const res = await getVideosList(server.url) |
91 | const videos = res.body.data | 90 | const videos = res.body.data |
92 | 91 | ||
93 | let infoHashes: { [ id: number ]: string } | 92 | let infoHashes: { [id: number]: string } |
94 | 93 | ||
95 | for (const video of videos) { | 94 | for (const video of videos) { |
96 | const res2 = await getVideo(server.url, video.uuid) | 95 | const res2 = await getVideo(server.url, video.uuid) |
diff --git a/server/tests/cli/optimize-old-videos.ts b/server/tests/cli/optimize-old-videos.ts index de5d672f5..e2e13598f 100644 --- a/server/tests/cli/optimize-old-videos.ts +++ b/server/tests/cli/optimize-old-videos.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -28,7 +28,9 @@ const expect = chai.expect | |||
28 | 28 | ||
29 | describe('Test optimize old videos', function () { | 29 | describe('Test optimize old videos', function () { |
30 | let servers: ServerInfo[] = [] | 30 | let servers: ServerInfo[] = [] |
31 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
31 | let video1UUID: string | 32 | let video1UUID: string |
33 | // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
32 | let video2UUID: string | 34 | let video2UUID: string |
33 | 35 | ||
34 | before(async function () { | 36 | before(async function () { |
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index b8c0b1f79..27fbde02d 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { expect } from 'chai' | 4 | import { expect } from 'chai' |
@@ -7,14 +7,17 @@ import { | |||
7 | buildAbsoluteFixturePath, | 7 | buildAbsoluteFixturePath, |
8 | cleanupTests, | 8 | cleanupTests, |
9 | createUser, | 9 | createUser, |
10 | doubleFollow, | ||
10 | execCLI, | 11 | execCLI, |
11 | flushAndRunServer, | 12 | flushAndRunServer, |
12 | getEnvCli, | 13 | getEnvCli, |
14 | getLocalIdByUUID, | ||
13 | getVideo, | 15 | getVideo, |
14 | getVideosList, | 16 | getVideosList, |
15 | getVideosListWithToken, removeVideo, | 17 | removeVideo, |
16 | ServerInfo, | 18 | ServerInfo, |
17 | setAccessTokensToServers, | 19 | setAccessTokensToServers, |
20 | uploadVideoAndGetId, | ||
18 | userLogin, | 21 | userLogin, |
19 | waitJobs | 22 | waitJobs |
20 | } from '../../../shared/extra-utils' | 23 | } from '../../../shared/extra-utils' |
@@ -101,7 +104,7 @@ describe('Test CLI wrapper', function () { | |||
101 | 104 | ||
102 | const videos: Video[] = res.body.data | 105 | const videos: Video[] = res.body.data |
103 | 106 | ||
104 | const video: VideoDetails = (await getVideo(server.url, videos[ 0 ].uuid)).body | 107 | const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body |
105 | 108 | ||
106 | expect(video.name).to.equal('test upload') | 109 | expect(video.name).to.equal('test upload') |
107 | expect(video.support).to.equal('support_text') | 110 | expect(video.support).to.equal('support_text') |
@@ -210,6 +213,81 @@ describe('Test CLI wrapper', function () { | |||
210 | }) | 213 | }) |
211 | }) | 214 | }) |
212 | 215 | ||
216 | describe('Manage video redundancies', function () { | ||
217 | let anotherServer: ServerInfo | ||
218 | let video1Server2: number | ||
219 | let servers: ServerInfo[] | ||
220 | |||
221 | before(async function () { | ||
222 | this.timeout(120000) | ||
223 | |||
224 | anotherServer = await flushAndRunServer(2) | ||
225 | await setAccessTokensToServers([ anotherServer ]) | ||
226 | |||
227 | await doubleFollow(server, anotherServer) | ||
228 | |||
229 | servers = [ server, anotherServer ] | ||
230 | await waitJobs(servers) | ||
231 | |||
232 | const uuid = (await uploadVideoAndGetId({ server: anotherServer, videoName: 'super video' })).uuid | ||
233 | await waitJobs(servers) | ||
234 | |||
235 | video1Server2 = await getLocalIdByUUID(server.url, uuid) | ||
236 | }) | ||
237 | |||
238 | it('Should add a redundancy', async function () { | ||
239 | this.timeout(60000) | ||
240 | |||
241 | const env = getEnvCli(server) | ||
242 | |||
243 | const params = `add --video ${video1Server2}` | ||
244 | |||
245 | await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
246 | |||
247 | await waitJobs(servers) | ||
248 | }) | ||
249 | |||
250 | it('Should list redundancies', async function () { | ||
251 | this.timeout(60000) | ||
252 | |||
253 | { | ||
254 | const env = getEnvCli(server) | ||
255 | |||
256 | const params = 'list-my-redundancies' | ||
257 | const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
258 | |||
259 | expect(stdout).to.contain('super video') | ||
260 | expect(stdout).to.contain(`localhost:${server.port}`) | ||
261 | } | ||
262 | }) | ||
263 | |||
264 | it('Should remove a redundancy', async function () { | ||
265 | this.timeout(60000) | ||
266 | |||
267 | const env = getEnvCli(server) | ||
268 | |||
269 | const params = `remove --video ${video1Server2}` | ||
270 | |||
271 | await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
272 | |||
273 | await waitJobs(servers) | ||
274 | |||
275 | { | ||
276 | const env = getEnvCli(server) | ||
277 | const params = 'list-my-redundancies' | ||
278 | const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`) | ||
279 | |||
280 | expect(stdout).to.not.contain('super video') | ||
281 | } | ||
282 | }) | ||
283 | |||
284 | after(async function () { | ||
285 | this.timeout(10000) | ||
286 | |||
287 | await cleanupTests([ anotherServer ]) | ||
288 | }) | ||
289 | }) | ||
290 | |||
213 | after(async function () { | 291 | after(async function () { |
214 | this.timeout(10000) | 292 | this.timeout(10000) |
215 | 293 | ||
diff --git a/server/tests/cli/plugins.ts b/server/tests/cli/plugins.ts index a5257d671..7f19f14b7 100644 --- a/server/tests/cli/plugins.ts +++ b/server/tests/cli/plugins.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { | 4 | import { |
diff --git a/server/tests/cli/prune-storage.ts b/server/tests/cli/prune-storage.ts index 144e67c44..304c8ca56 100644 --- a/server/tests/cli/prune-storage.ts +++ b/server/tests/cli/prune-storage.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
@@ -11,9 +11,11 @@ import { | |||
11 | execCLI, | 11 | execCLI, |
12 | flushAndRunMultipleServers, | 12 | flushAndRunMultipleServers, |
13 | getAccount, | 13 | getAccount, |
14 | getEnvCli, makeGetRequest, makeRawRequest, | 14 | getEnvCli, |
15 | makeGetRequest, | ||
15 | ServerInfo, | 16 | ServerInfo, |
16 | setAccessTokensToServers, setDefaultVideoChannel, | 17 | setAccessTokensToServers, |
18 | setDefaultVideoChannel, | ||
17 | updateMyAvatar, | 19 | updateMyAvatar, |
18 | uploadVideo, | 20 | uploadVideo, |
19 | wait | 21 | wait |
@@ -22,7 +24,6 @@ import { Account, VideoPlaylistPrivacy } from '../../../shared/models' | |||
22 | import { createFile, readdir } from 'fs-extra' | 24 | import { createFile, readdir } from 'fs-extra' |
23 | import * as uuidv4 from 'uuid/v4' | 25 | import * as uuidv4 from 'uuid/v4' |
24 | import { join } from 'path' | 26 | import { join } from 'path' |
25 | import * as request from 'supertest' | ||
26 | 27 | ||
27 | const expect = chai.expect | 28 | const expect = chai.expect |
28 | 29 | ||
@@ -61,7 +62,7 @@ async function assertCountAreOkay (servers: ServerInfo[]) { | |||
61 | 62 | ||
62 | describe('Test prune storage scripts', function () { | 63 | describe('Test prune storage scripts', function () { |
63 | let servers: ServerInfo[] | 64 | let servers: ServerInfo[] |
64 | const badNames: { [ directory: string ]: string[] } = {} | 65 | const badNames: { [directory: string]: string[] } = {} |
65 | 66 | ||
66 | before(async function () { | 67 | before(async function () { |
67 | this.timeout(120000) | 68 | this.timeout(120000) |
@@ -92,20 +93,20 @@ describe('Test prune storage scripts', function () { | |||
92 | 93 | ||
93 | // Lazy load the remote avatar | 94 | // Lazy load the remote avatar |
94 | { | 95 | { |
95 | const res = await getAccount(servers[ 0 ].url, 'root@localhost:' + servers[ 1 ].port) | 96 | const res = await getAccount(servers[0].url, 'root@localhost:' + servers[1].port) |
96 | const account: Account = res.body | 97 | const account: Account = res.body |
97 | await makeGetRequest({ | 98 | await makeGetRequest({ |
98 | url: servers[ 0 ].url, | 99 | url: servers[0].url, |
99 | path: account.avatar.path, | 100 | path: account.avatar.path, |
100 | statusCodeExpected: 200 | 101 | statusCodeExpected: 200 |
101 | }) | 102 | }) |
102 | } | 103 | } |
103 | 104 | ||
104 | { | 105 | { |
105 | const res = await getAccount(servers[ 1 ].url, 'root@localhost:' + servers[ 0 ].port) | 106 | const res = await getAccount(servers[1].url, 'root@localhost:' + servers[0].port) |
106 | const account: Account = res.body | 107 | const account: Account = res.body |
107 | await makeGetRequest({ | 108 | await makeGetRequest({ |
108 | url: servers[ 1 ].url, | 109 | url: servers[1].url, |
109 | path: account.avatar.path, | 110 | path: account.avatar.path, |
110 | statusCodeExpected: 200 | 111 | statusCodeExpected: 200 |
111 | }) | 112 | }) |
diff --git a/server/tests/cli/update-host.ts b/server/tests/cli/update-host.ts index 55c43b32f..2070f16f5 100644 --- a/server/tests/cli/update-host.ts +++ b/server/tests/cli/update-host.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/client.ts b/server/tests/client.ts index 778dcd08e..d61724e51 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 437470327..4510177cc 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -51,7 +51,7 @@ describe('Test syndication feeds', () => { | |||
51 | 51 | ||
52 | { | 52 | { |
53 | const attr = { username: 'john', password: 'password' } | 53 | const attr = { username: 'john', password: 'password' } |
54 | await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: attr.username, password: attr.password }) | 54 | await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: attr.username, password: attr.password }) |
55 | userAccessToken = await userLogin(servers[0], attr) | 55 | userAccessToken = await userLogin(servers[0], attr) |
56 | 56 | ||
57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) | 57 | const res = await getMyUserInformation(servers[0].url, userAccessToken) |
@@ -61,7 +61,7 @@ describe('Test syndication feeds', () => { | |||
61 | } | 61 | } |
62 | 62 | ||
63 | { | 63 | { |
64 | await uploadVideo(servers[ 0 ].url, userAccessToken, { name: 'user video' }) | 64 | await uploadVideo(servers[0].url, userAccessToken, { name: 'user video' }) |
65 | } | 65 | } |
66 | 66 | ||
67 | { | 67 | { |
@@ -70,11 +70,11 @@ describe('Test syndication feeds', () => { | |||
70 | description: 'my super description for server 1', | 70 | description: 'my super description for server 1', |
71 | fixture: 'video_short.webm' | 71 | fixture: 'video_short.webm' |
72 | } | 72 | } |
73 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes) | 73 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes) |
74 | const videoId = res.body.video.id | 74 | const videoId = res.body.video.id |
75 | 75 | ||
76 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 1') | 76 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 1') |
77 | await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 2') | 77 | await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 2') |
78 | } | 78 | } |
79 | 79 | ||
80 | await waitJobs(servers) | 80 | await waitJobs(servers) |
@@ -84,18 +84,18 @@ describe('Test syndication feeds', () => { | |||
84 | 84 | ||
85 | it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { | 85 | it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () { |
86 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { | 86 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { |
87 | const rss = await getXMLfeed(servers[ 0 ].url, feed) | 87 | const rss = await getXMLfeed(servers[0].url, feed) |
88 | expect(rss.text).xml.to.be.valid() | 88 | expect(rss.text).xml.to.be.valid() |
89 | 89 | ||
90 | const atom = await getXMLfeed(servers[ 0 ].url, feed, 'atom') | 90 | const atom = await getXMLfeed(servers[0].url, feed, 'atom') |
91 | expect(atom.text).xml.to.be.valid() | 91 | expect(atom.text).xml.to.be.valid() |
92 | } | 92 | } |
93 | }) | 93 | }) |
94 | 94 | ||
95 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { | 95 | it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () { |
96 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { | 96 | for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) { |
97 | const json = await getJSONfeed(servers[ 0 ].url, feed) | 97 | const json = await getJSONfeed(servers[0].url, feed) |
98 | expect(JSON.parse(json.text)).to.be.jsonSchema({ 'type': 'object' }) | 98 | expect(JSON.parse(json.text)).to.be.jsonSchema({ type: 'object' }) |
99 | } | 99 | } |
100 | }) | 100 | }) |
101 | }) | 101 | }) |
@@ -118,11 +118,11 @@ describe('Test syndication feeds', () => { | |||
118 | const json = await getJSONfeed(server.url, 'videos') | 118 | const json = await getJSONfeed(server.url, 'videos') |
119 | const jsonObj = JSON.parse(json.text) | 119 | const jsonObj = JSON.parse(json.text) |
120 | expect(jsonObj.items.length).to.be.equal(2) | 120 | expect(jsonObj.items.length).to.be.equal(2) |
121 | expect(jsonObj.items[ 0 ].attachments).to.exist | 121 | expect(jsonObj.items[0].attachments).to.exist |
122 | expect(jsonObj.items[ 0 ].attachments.length).to.be.eq(1) | 122 | expect(jsonObj.items[0].attachments.length).to.be.eq(1) |
123 | expect(jsonObj.items[ 0 ].attachments[ 0 ].mime_type).to.be.eq('application/x-bittorrent') | 123 | expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent') |
124 | expect(jsonObj.items[ 0 ].attachments[ 0 ].size_in_bytes).to.be.eq(218910) | 124 | expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910) |
125 | expect(jsonObj.items[ 0 ].attachments[ 0 ].url).to.contain('720.torrent') | 125 | expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent') |
126 | } | 126 | } |
127 | }) | 127 | }) |
128 | 128 | ||
@@ -131,16 +131,16 @@ describe('Test syndication feeds', () => { | |||
131 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) | 131 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId }) |
132 | const jsonObj = JSON.parse(json.text) | 132 | const jsonObj = JSON.parse(json.text) |
133 | expect(jsonObj.items.length).to.be.equal(1) | 133 | expect(jsonObj.items.length).to.be.equal(1) |
134 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 134 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
135 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | 135 | expect(jsonObj.items[0].author.name).to.equal('root') |
136 | } | 136 | } |
137 | 137 | ||
138 | { | 138 | { |
139 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) | 139 | const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId }) |
140 | const jsonObj = JSON.parse(json.text) | 140 | const jsonObj = JSON.parse(json.text) |
141 | expect(jsonObj.items.length).to.be.equal(1) | 141 | expect(jsonObj.items.length).to.be.equal(1) |
142 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 142 | expect(jsonObj.items[0].title).to.equal('user video') |
143 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | 143 | expect(jsonObj.items[0].author.name).to.equal('john') |
144 | } | 144 | } |
145 | 145 | ||
146 | for (const server of servers) { | 146 | for (const server of servers) { |
@@ -148,14 +148,14 @@ describe('Test syndication feeds', () => { | |||
148 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) | 148 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port }) |
149 | const jsonObj = JSON.parse(json.text) | 149 | const jsonObj = JSON.parse(json.text) |
150 | expect(jsonObj.items.length).to.be.equal(1) | 150 | expect(jsonObj.items.length).to.be.equal(1) |
151 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 151 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
152 | } | 152 | } |
153 | 153 | ||
154 | { | 154 | { |
155 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) | 155 | const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port }) |
156 | const jsonObj = JSON.parse(json.text) | 156 | const jsonObj = JSON.parse(json.text) |
157 | expect(jsonObj.items.length).to.be.equal(1) | 157 | expect(jsonObj.items.length).to.be.equal(1) |
158 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 158 | expect(jsonObj.items[0].title).to.equal('user video') |
159 | } | 159 | } |
160 | } | 160 | } |
161 | }) | 161 | }) |
@@ -165,16 +165,16 @@ describe('Test syndication feeds', () => { | |||
165 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) | 165 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId }) |
166 | const jsonObj = JSON.parse(json.text) | 166 | const jsonObj = JSON.parse(json.text) |
167 | expect(jsonObj.items.length).to.be.equal(1) | 167 | expect(jsonObj.items.length).to.be.equal(1) |
168 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 168 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
169 | expect(jsonObj.items[ 0 ].author.name).to.equal('root') | 169 | expect(jsonObj.items[0].author.name).to.equal('root') |
170 | } | 170 | } |
171 | 171 | ||
172 | { | 172 | { |
173 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) | 173 | const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId }) |
174 | const jsonObj = JSON.parse(json.text) | 174 | const jsonObj = JSON.parse(json.text) |
175 | expect(jsonObj.items.length).to.be.equal(1) | 175 | expect(jsonObj.items.length).to.be.equal(1) |
176 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 176 | expect(jsonObj.items[0].title).to.equal('user video') |
177 | expect(jsonObj.items[ 0 ].author.name).to.equal('john') | 177 | expect(jsonObj.items[0].author.name).to.equal('john') |
178 | } | 178 | } |
179 | 179 | ||
180 | for (const server of servers) { | 180 | for (const server of servers) { |
@@ -182,14 +182,14 @@ describe('Test syndication feeds', () => { | |||
182 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) | 182 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port }) |
183 | const jsonObj = JSON.parse(json.text) | 183 | const jsonObj = JSON.parse(json.text) |
184 | expect(jsonObj.items.length).to.be.equal(1) | 184 | expect(jsonObj.items.length).to.be.equal(1) |
185 | expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1') | 185 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
186 | } | 186 | } |
187 | 187 | ||
188 | { | 188 | { |
189 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) | 189 | const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port }) |
190 | const jsonObj = JSON.parse(json.text) | 190 | const jsonObj = JSON.parse(json.text) |
191 | expect(jsonObj.items.length).to.be.equal(1) | 191 | expect(jsonObj.items.length).to.be.equal(1) |
192 | expect(jsonObj.items[ 0 ].title).to.equal('user video') | 192 | expect(jsonObj.items[0].title).to.equal('user video') |
193 | } | 193 | } |
194 | } | 194 | } |
195 | }) | 195 | }) |
@@ -202,8 +202,8 @@ describe('Test syndication feeds', () => { | |||
202 | 202 | ||
203 | const jsonObj = JSON.parse(json.text) | 203 | const jsonObj = JSON.parse(json.text) |
204 | expect(jsonObj.items.length).to.be.equal(2) | 204 | expect(jsonObj.items.length).to.be.equal(2) |
205 | expect(jsonObj.items[ 0 ].html_content).to.equal('super comment 2') | 205 | expect(jsonObj.items[0].html_content).to.equal('super comment 2') |
206 | expect(jsonObj.items[ 1 ].html_content).to.equal('super comment 1') | 206 | expect(jsonObj.items[1].html_content).to.equal('super comment 1') |
207 | } | 207 | } |
208 | }) | 208 | }) |
209 | }) | 209 | }) |
diff --git a/server/tests/helpers/comment-model.ts b/server/tests/helpers/comment-model.ts index ebfd779e1..4c51b7000 100644 --- a/server/tests/helpers/comment-model.ts +++ b/server/tests/helpers/comment-model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
@@ -20,7 +20,7 @@ describe('Comment model', function () { | |||
20 | 20 | ||
21 | comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + | 21 | comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' + |
22 | 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' | 22 | 'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end' |
23 | const result = comment.extractMentions().sort() | 23 | const result = comment.extractMentions().sort((a, b) => a.localeCompare(b)) |
24 | 24 | ||
25 | expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) | 25 | expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ]) |
26 | }) | 26 | }) |
diff --git a/server/tests/helpers/core-utils.ts b/server/tests/helpers/core-utils.ts index 31fc6dd7c..c028b316d 100644 --- a/server/tests/helpers/core-utils.ts +++ b/server/tests/helpers/core-utils.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
diff --git a/server/tests/helpers/request.ts b/server/tests/helpers/request.ts index a754bc6e2..f8b2d599b 100644 --- a/server/tests/helpers/request.ts +++ b/server/tests/helpers/request.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 4 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
diff --git a/server/tests/misc-endpoints.ts b/server/tests/misc-endpoints.ts index ab2dd3a0f..32b035c9e 100644 --- a/server/tests/misc-endpoints.ts +++ b/server/tests/misc-endpoints.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import 'mocha' | 3 | import 'mocha' |
4 | import * as chai from 'chai' | 4 | import * as chai from 'chai' |
diff --git a/server/tests/plugins/action-hooks.ts b/server/tests/plugins/action-hooks.ts index 510ec3151..ca57a4b51 100644 --- a/server/tests/plugins/action-hooks.ts +++ b/server/tests/plugins/action-hooks.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | 3 | import 'mocha' |
5 | import { | 4 | import { |
6 | cleanupTests, | 5 | cleanupTests, |
@@ -17,18 +16,18 @@ import { | |||
17 | createUser, | 16 | createUser, |
18 | deleteVideoComment, | 17 | deleteVideoComment, |
19 | getPluginTestPath, | 18 | getPluginTestPath, |
20 | installPlugin, login, | 19 | installPlugin, |
21 | registerUser, removeUser, | 20 | registerUser, |
21 | removeUser, | ||
22 | setAccessTokensToServers, | 22 | setAccessTokensToServers, |
23 | unblockUser, updateUser, | 23 | unblockUser, |
24 | updateUser, | ||
24 | updateVideo, | 25 | updateVideo, |
25 | uploadVideo, | 26 | uploadVideo, |
26 | viewVideo, | 27 | userLogin, |
27 | userLogin | 28 | viewVideo |
28 | } from '../../../shared/extra-utils' | 29 | } from '../../../shared/extra-utils' |
29 | 30 | ||
30 | const expect = chai.expect | ||
31 | |||
32 | describe('Test plugin action hooks', function () { | 31 | describe('Test plugin action hooks', function () { |
33 | let servers: ServerInfo[] | 32 | let servers: ServerInfo[] |
34 | let videoUUID: string | 33 | let videoUUID: string |
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 6a5ea4641..6c1fd40ba 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts | |||
@@ -1,34 +1,27 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { | 5 | import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../shared/extra-utils/server/servers' |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | 6 | import { |
13 | addVideoCommentReply, | 7 | addVideoCommentReply, |
14 | addVideoCommentThread, | 8 | addVideoCommentThread, |
15 | deleteVideoComment, | 9 | doubleFollow, |
10 | getConfig, | ||
16 | getPluginTestPath, | 11 | getPluginTestPath, |
17 | getVideosList, | ||
18 | installPlugin, | ||
19 | removeVideo, | ||
20 | setAccessTokensToServers, | ||
21 | updateVideo, | ||
22 | uploadVideo, | ||
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | 12 | getVideo, |
26 | getVideoCommentThreads, | 13 | getVideoCommentThreads, |
14 | getVideosList, | ||
15 | getVideosListPagination, | ||
27 | getVideoThreadComments, | 16 | getVideoThreadComments, |
28 | getVideoWithToken, | 17 | getVideoWithToken, |
18 | installPlugin, | ||
19 | registerUser, | ||
20 | setAccessTokensToServers, | ||
29 | setDefaultVideoChannel, | 21 | setDefaultVideoChannel, |
30 | waitJobs, | 22 | updateVideo, |
31 | doubleFollow, getConfig, registerUser | 23 | uploadVideo, |
24 | waitJobs | ||
32 | } from '../../../shared/extra-utils' | 25 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | 26 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' |
34 | import { VideoDetails } from '../../../shared/models/videos' | 27 | import { VideoDetails } from '../../../shared/models/videos' |
@@ -140,7 +133,7 @@ describe('Test plugin filter hooks', function () { | |||
140 | } | 133 | } |
141 | 134 | ||
142 | it('Should blacklist on upload', async function () { | 135 | it('Should blacklist on upload', async function () { |
143 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video please blacklist me' }) | 136 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video please blacklist me' }) |
144 | await checkIsBlacklisted(res, true) | 137 | await checkIsBlacklisted(res, true) |
145 | }) | 138 | }) |
146 | 139 | ||
@@ -157,18 +150,18 @@ describe('Test plugin filter hooks', function () { | |||
157 | }) | 150 | }) |
158 | 151 | ||
159 | it('Should blacklist on update', async function () { | 152 | it('Should blacklist on update', async function () { |
160 | const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' }) | 153 | const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' }) |
161 | const videoId = res.body.video.uuid | 154 | const videoId = res.body.video.uuid |
162 | await checkIsBlacklisted(res, false) | 155 | await checkIsBlacklisted(res, false) |
163 | 156 | ||
164 | await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, { name: 'please blacklist me' }) | 157 | await updateVideo(servers[0].url, servers[0].accessToken, videoId, { name: 'please blacklist me' }) |
165 | await checkIsBlacklisted(res, true) | 158 | await checkIsBlacklisted(res, true) |
166 | }) | 159 | }) |
167 | 160 | ||
168 | it('Should blacklist on remote upload', async function () { | 161 | it('Should blacklist on remote upload', async function () { |
169 | this.timeout(45000) | 162 | this.timeout(45000) |
170 | 163 | ||
171 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'remote please blacklist me' }) | 164 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' }) |
172 | await waitJobs(servers) | 165 | await waitJobs(servers) |
173 | 166 | ||
174 | await checkIsBlacklisted(res, true) | 167 | await checkIsBlacklisted(res, true) |
@@ -177,7 +170,7 @@ describe('Test plugin filter hooks', function () { | |||
177 | it('Should blacklist on remote update', async function () { | 170 | it('Should blacklist on remote update', async function () { |
178 | this.timeout(45000) | 171 | this.timeout(45000) |
179 | 172 | ||
180 | const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video' }) | 173 | const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' }) |
181 | await waitJobs(servers) | 174 | await waitJobs(servers) |
182 | 175 | ||
183 | const videoId = res.body.video.uuid | 176 | const videoId = res.body.video.uuid |
diff --git a/server/tests/plugins/translations.ts b/server/tests/plugins/translations.ts index 88d91a033..8dc2043b8 100644 --- a/server/tests/plugins/translations.ts +++ b/server/tests/plugins/translations.ts | |||
@@ -1,38 +1,15 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | ||
13 | addVideoCommentReply, | ||
14 | addVideoCommentThread, | ||
15 | deleteVideoComment, | ||
16 | getPluginTestPath, | 7 | getPluginTestPath, |
17 | getVideosList, | 8 | getPluginTranslations, |
18 | installPlugin, | 9 | installPlugin, |
19 | removeVideo, | ||
20 | setAccessTokensToServers, | 10 | setAccessTokensToServers, |
21 | updateVideo, | 11 | uninstallPlugin |
22 | uploadVideo, | ||
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | ||
26 | getVideoCommentThreads, | ||
27 | getVideoThreadComments, | ||
28 | getVideoWithToken, | ||
29 | setDefaultVideoChannel, | ||
30 | waitJobs, | ||
31 | doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin, getPluginTranslations | ||
32 | } from '../../../shared/extra-utils' | 12 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | ||
34 | import { VideoDetails } from '../../../shared/models/videos' | ||
35 | import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports' | ||
36 | 13 | ||
37 | const expect = chai.expect | 14 | const expect = chai.expect |
38 | 15 | ||
@@ -69,7 +46,7 @@ describe('Test plugin translations', function () { | |||
69 | 46 | ||
70 | expect(res.body).to.deep.equal({ | 47 | expect(res.body).to.deep.equal({ |
71 | 'peertube-plugin-test': { | 48 | 'peertube-plugin-test': { |
72 | 'Hi': 'Coucou' | 49 | Hi: 'Coucou' |
73 | }, | 50 | }, |
74 | 'peertube-plugin-test-two': { | 51 | 'peertube-plugin-test-two': { |
75 | 'Hello world': 'Bonjour le monde' | 52 | 'Hello world': 'Bonjour le monde' |
@@ -95,7 +72,7 @@ describe('Test plugin translations', function () { | |||
95 | 72 | ||
96 | expect(res.body).to.deep.equal({ | 73 | expect(res.body).to.deep.equal({ |
97 | 'peertube-plugin-test': { | 74 | 'peertube-plugin-test': { |
98 | 'Hi': 'Coucou' | 75 | Hi: 'Coucou' |
99 | } | 76 | } |
100 | }) | 77 | }) |
101 | } | 78 | } |
diff --git a/server/tests/plugins/video-constants.ts b/server/tests/plugins/video-constants.ts index 6562e2b45..5374b5ecc 100644 --- a/server/tests/plugins/video-constants.ts +++ b/server/tests/plugins/video-constants.ts | |||
@@ -1,38 +1,20 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | 1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ |
2 | 2 | ||
3 | import * as chai from 'chai' | 3 | import * as chai from 'chai' |
4 | import 'mocha' | 4 | import 'mocha' |
5 | import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers' | ||
5 | import { | 6 | import { |
6 | cleanupTests, | ||
7 | flushAndRunMultipleServers, | ||
8 | flushAndRunServer, killallServers, reRunServer, | ||
9 | ServerInfo, | ||
10 | waitUntilLog | ||
11 | } from '../../../shared/extra-utils/server/servers' | ||
12 | import { | ||
13 | addVideoCommentReply, | ||
14 | addVideoCommentThread, | ||
15 | deleteVideoComment, | ||
16 | getPluginTestPath, | 7 | getPluginTestPath, |
17 | getVideosList, | 8 | getVideo, |
9 | getVideoCategories, | ||
10 | getVideoLanguages, | ||
11 | getVideoLicences, | ||
18 | installPlugin, | 12 | installPlugin, |
19 | removeVideo, | ||
20 | setAccessTokensToServers, | 13 | setAccessTokensToServers, |
21 | updateVideo, | 14 | uninstallPlugin, |
22 | uploadVideo, | 15 | uploadVideo |
23 | viewVideo, | ||
24 | getVideosListPagination, | ||
25 | getVideo, | ||
26 | getVideoCommentThreads, | ||
27 | getVideoThreadComments, | ||
28 | getVideoWithToken, | ||
29 | setDefaultVideoChannel, | ||
30 | waitJobs, | ||
31 | doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin | ||
32 | } from '../../../shared/extra-utils' | 16 | } from '../../../shared/extra-utils' |
33 | import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model' | ||
34 | import { VideoDetails } from '../../../shared/models/videos' | 17 | import { VideoDetails } from '../../../shared/models/videos' |
35 | import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports' | ||
36 | 18 | ||
37 | const expect = chai.expect | 19 | const expect = chai.expect |
38 | 20 | ||
@@ -104,33 +86,33 @@ describe('Test plugin altering video constants', function () { | |||
104 | const res = await getVideoLanguages(server.url) | 86 | const res = await getVideoLanguages(server.url) |
105 | const languages = res.body | 87 | const languages = res.body |
106 | 88 | ||
107 | expect(languages[ 'en' ]).to.equal('English') | 89 | expect(languages['en']).to.equal('English') |
108 | expect(languages[ 'fr' ]).to.equal('French') | 90 | expect(languages['fr']).to.equal('French') |
109 | 91 | ||
110 | expect(languages[ 'al_bhed' ]).to.not.exist | 92 | expect(languages['al_bhed']).to.not.exist |
111 | expect(languages[ 'al_bhed2' ]).to.not.exist | 93 | expect(languages['al_bhed2']).to.not.exist |
112 | } | 94 | } |
113 | 95 | ||
114 | { | 96 | { |
115 | const res = await getVideoCategories(server.url) | 97 | const res = await getVideoCategories(server.url) |
116 | const categories = res.body | 98 | const categories = res.body |
117 | 99 | ||
118 | expect(categories[ 1 ]).to.equal('Music') | 100 | expect(categories[1]).to.equal('Music') |
119 | expect(categories[ 2 ]).to.equal('Films') | 101 | expect(categories[2]).to.equal('Films') |
120 | 102 | ||
121 | expect(categories[ 42 ]).to.not.exist | 103 | expect(categories[42]).to.not.exist |
122 | expect(categories[ 43 ]).to.not.exist | 104 | expect(categories[43]).to.not.exist |
123 | } | 105 | } |
124 | 106 | ||
125 | { | 107 | { |
126 | const res = await getVideoLicences(server.url) | 108 | const res = await getVideoLicences(server.url) |
127 | const licences = res.body | 109 | const licences = res.body |
128 | 110 | ||
129 | expect(licences[ 1 ]).to.equal('Attribution') | 111 | expect(licences[1]).to.equal('Attribution') |
130 | expect(licences[ 7 ]).to.equal('Public Domain Dedication') | 112 | expect(licences[7]).to.equal('Public Domain Dedication') |
131 | 113 | ||
132 | expect(licences[ 42 ]).to.not.exist | 114 | expect(licences[42]).to.not.exist |
133 | expect(licences[ 43 ]).to.not.exist | 115 | expect(licences[43]).to.not.exist |
134 | } | 116 | } |
135 | }) | 117 | }) |
136 | 118 | ||
diff --git a/server/tests/real-world/populate-database.ts b/server/tests/real-world/populate-database.ts deleted file mode 100644 index b1c1688e7..000000000 --- a/server/tests/real-world/populate-database.ts +++ /dev/null | |||
@@ -1,122 +0,0 @@ | |||
1 | import { VideoRateType } from '../../../shared' | ||
2 | import { | ||
3 | addVideoChannel, | ||
4 | createUser, | ||
5 | flushTests, | ||
6 | getVideosList, | ||
7 | killallServers, | ||
8 | rateVideo, | ||
9 | flushAndRunServer, | ||
10 | ServerInfo, | ||
11 | setAccessTokensToServers, | ||
12 | uploadVideo | ||
13 | } from '../../../shared/extra-utils' | ||
14 | import * as Bluebird from 'bluebird' | ||
15 | |||
16 | start() | ||
17 | .catch(err => console.error(err)) | ||
18 | |||
19 | // ---------------------------------------------------------------------------- | ||
20 | |||
21 | async function start () { | ||
22 | |||
23 | console.log('Flushed tests.') | ||
24 | |||
25 | const server = await flushAndRunServer(6) | ||
26 | |||
27 | process.on('exit', async () => { | ||
28 | killallServers([ server ]) | ||
29 | return | ||
30 | }) | ||
31 | process.on('SIGINT', goodbye) | ||
32 | process.on('SIGTERM', goodbye) | ||
33 | |||
34 | await setAccessTokensToServers([ server ]) | ||
35 | |||
36 | console.log('Servers ran.') | ||
37 | |||
38 | // Forever | ||
39 | const fakeTab = Array.from(Array(1000000).keys()) | ||
40 | const funs = [ | ||
41 | uploadCustom | ||
42 | // uploadCustom, | ||
43 | // uploadCustom, | ||
44 | // uploadCustom, | ||
45 | // likeCustom, | ||
46 | // createUserCustom, | ||
47 | // createCustomChannel | ||
48 | ] | ||
49 | const promises = [] | ||
50 | |||
51 | for (const fun of funs) { | ||
52 | promises.push( | ||
53 | Bluebird.map(fakeTab, () => { | ||
54 | return fun(server).catch(err => console.error(err)) | ||
55 | }, { concurrency: 3 }) | ||
56 | ) | ||
57 | } | ||
58 | |||
59 | await Promise.all(promises) | ||
60 | } | ||
61 | |||
62 | function getRandomInt (min, max) { | ||
63 | return Math.floor(Math.random() * (max - min)) + min | ||
64 | } | ||
65 | |||
66 | function createCustomChannel (server: ServerInfo) { | ||
67 | const videoChannel = { | ||
68 | name: Date.now().toString(), | ||
69 | displayName: Date.now().toString(), | ||
70 | description: Date.now().toString() | ||
71 | } | ||
72 | |||
73 | return addVideoChannel(server.url, server.accessToken, videoChannel) | ||
74 | } | ||
75 | |||
76 | function createUserCustom (server: ServerInfo) { | ||
77 | const username = Date.now().toString() + getRandomInt(0, 100000) | ||
78 | console.log('Creating user %s.', username) | ||
79 | |||
80 | return createUser({ url: server.url, accessToken: server.accessToken, username: username, password: 'coucou' }) | ||
81 | } | ||
82 | |||
83 | function uploadCustom (server: ServerInfo) { | ||
84 | console.log('Uploading video.') | ||
85 | |||
86 | const videoAttributes = { | ||
87 | name: Date.now() + ' name', | ||
88 | category: 4, | ||
89 | nsfw: false, | ||
90 | licence: 2, | ||
91 | language: 'en', | ||
92 | description: Date.now() + ' description', | ||
93 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | ||
94 | fixture: 'video_short.mp4' | ||
95 | } | ||
96 | |||
97 | return uploadVideo(server.url, server.accessToken, videoAttributes) | ||
98 | } | ||
99 | |||
100 | function likeCustom (server: ServerInfo) { | ||
101 | return rateCustom(server, 'like') | ||
102 | } | ||
103 | |||
104 | function dislikeCustom (server: ServerInfo) { | ||
105 | return rateCustom(server, 'dislike') | ||
106 | } | ||
107 | |||
108 | async function rateCustom (server: ServerInfo, rating: VideoRateType) { | ||
109 | const res = await getVideosList(server.url) | ||
110 | |||
111 | const videos = res.body.data | ||
112 | if (videos.length === 0) return undefined | ||
113 | |||
114 | const videoToRate = videos[getRandomInt(0, videos.length)] | ||
115 | |||
116 | console.log('Rating (%s) video.', rating) | ||
117 | return rateVideo(server.url, server.accessToken, videoToRate.id, rating) | ||
118 | } | ||
119 | |||
120 | function goodbye () { | ||
121 | return process.exit(-1) | ||
122 | } | ||
diff --git a/server/tests/real-world/real-world.ts b/server/tests/real-world/real-world.ts deleted file mode 100644 index cba5ac311..000000000 --- a/server/tests/real-world/real-world.ts +++ /dev/null | |||
@@ -1,375 +0,0 @@ | |||
1 | // /!\ Before imports /!\ | ||
2 | process.env.NODE_ENV = 'test' | ||
3 | |||
4 | import * as program from 'commander' | ||
5 | import { Video, VideoFile, VideoRateType } from '../../../shared' | ||
6 | import { JobState } from '../../../shared/models' | ||
7 | import { | ||
8 | flushAndRunMultipleServers, | ||
9 | flushTests, follow, | ||
10 | getVideo, | ||
11 | getVideosList, getVideosListPagination, | ||
12 | killallServers, | ||
13 | removeVideo, | ||
14 | ServerInfo as DefaultServerInfo, | ||
15 | setAccessTokensToServers, | ||
16 | updateVideo, | ||
17 | uploadVideo, viewVideo, | ||
18 | wait | ||
19 | } from '../../../shared/extra-utils' | ||
20 | import { getJobsListPaginationAndSort } from '../../../shared/extra-utils/server/jobs' | ||
21 | |||
22 | interface ServerInfo extends DefaultServerInfo { | ||
23 | requestsNumber: number | ||
24 | } | ||
25 | |||
26 | program | ||
27 | .option('-c, --create [weight]', 'Weight for creating videos') | ||
28 | .option('-r, --remove [weight]', 'Weight for removing videos') | ||
29 | .option('-u, --update [weight]', 'Weight for updating videos') | ||
30 | .option('-v, --view [weight]', 'Weight for viewing videos') | ||
31 | .option('-l, --like [weight]', 'Weight for liking videos') | ||
32 | .option('-s, --dislike [weight]', 'Weight for disliking videos') | ||
33 | .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3) | ||
34 | .option('-i, --interval-action [interval]', 'Interval in ms for an action') | ||
35 | .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check') | ||
36 | .option('-f, --flush', 'Flush data on exit') | ||
37 | .option('-d, --difference', 'Display difference if integrity is not okay') | ||
38 | .parse(process.argv) | ||
39 | |||
40 | const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5 | ||
41 | const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4 | ||
42 | const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4 | ||
43 | const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4 | ||
44 | const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4 | ||
45 | const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4 | ||
46 | const flushAtExit = program['flush'] || false | ||
47 | const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500 | ||
48 | const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000 | ||
49 | const displayDiffOnFail = program['difference'] || false | ||
50 | |||
51 | const numberOfServers = 6 | ||
52 | |||
53 | console.log( | ||
54 | 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.', | ||
55 | createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight | ||
56 | ) | ||
57 | |||
58 | if (flushAtExit) { | ||
59 | console.log('Program will flush data on exit.') | ||
60 | } else { | ||
61 | console.log('Program will not flush data on exit.') | ||
62 | } | ||
63 | if (displayDiffOnFail) { | ||
64 | console.log('Program will display diff on failure.') | ||
65 | } else { | ||
66 | console.log('Program will not display diff on failure') | ||
67 | } | ||
68 | console.log('Interval in ms for each action: %d.', actionInterval) | ||
69 | console.log('Interval in ms for each integrity check: %d.', integrityInterval) | ||
70 | |||
71 | console.log('Run servers...') | ||
72 | |||
73 | start() | ||
74 | |||
75 | // ---------------------------------------------------------------------------- | ||
76 | |||
77 | async function start () { | ||
78 | const servers = await runServers(numberOfServers) | ||
79 | |||
80 | process.on('exit', async () => { | ||
81 | await exitServers(servers, flushAtExit) | ||
82 | |||
83 | return | ||
84 | }) | ||
85 | process.on('SIGINT', goodbye) | ||
86 | process.on('SIGTERM', goodbye) | ||
87 | |||
88 | console.log('Servers ran') | ||
89 | initializeRequestsPerServer(servers) | ||
90 | |||
91 | let checking = false | ||
92 | |||
93 | setInterval(async () => { | ||
94 | if (checking === true) return | ||
95 | |||
96 | const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight) | ||
97 | |||
98 | const numServer = getRandomNumServer(servers) | ||
99 | servers[numServer].requestsNumber++ | ||
100 | |||
101 | if (rand < createWeight) { | ||
102 | await upload(servers, numServer) | ||
103 | } else if (rand < createWeight + updateWeight) { | ||
104 | await update(servers, numServer) | ||
105 | } else if (rand < createWeight + updateWeight + removeWeight) { | ||
106 | await remove(servers, numServer) | ||
107 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) { | ||
108 | await view(servers, numServer) | ||
109 | } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) { | ||
110 | await like(servers, numServer) | ||
111 | } else { | ||
112 | await dislike(servers, numServer) | ||
113 | } | ||
114 | }, actionInterval) | ||
115 | |||
116 | // The function will check the consistency between servers (should have the same videos with same attributes...) | ||
117 | setInterval(function () { | ||
118 | if (checking === true) return | ||
119 | |||
120 | console.log('Checking integrity...') | ||
121 | checking = true | ||
122 | |||
123 | const waitingInterval = setInterval(async () => { | ||
124 | const pendingRequests = await isTherePendingRequests(servers) | ||
125 | if (pendingRequests === true) { | ||
126 | console.log('A server has pending requests, waiting...') | ||
127 | return | ||
128 | } | ||
129 | |||
130 | // Even if there are no pending request, wait some potential processes | ||
131 | await wait(2000) | ||
132 | await checkIntegrity(servers) | ||
133 | |||
134 | initializeRequestsPerServer(servers) | ||
135 | checking = false | ||
136 | clearInterval(waitingInterval) | ||
137 | }, 10000) | ||
138 | }, integrityInterval) | ||
139 | } | ||
140 | |||
141 | function initializeRequestsPerServer (servers: ServerInfo[]) { | ||
142 | servers.forEach(server => server.requestsNumber = 0) | ||
143 | } | ||
144 | |||
145 | function getRandomInt (min, max) { | ||
146 | return Math.floor(Math.random() * (max - min)) + min | ||
147 | } | ||
148 | |||
149 | function getRandomNumServer (servers) { | ||
150 | return getRandomInt(0, servers.length) | ||
151 | } | ||
152 | |||
153 | async function runServers (numberOfServers: number) { | ||
154 | const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers)) | ||
155 | .map(s => Object.assign({ requestsNumber: 0 }, s)) | ||
156 | |||
157 | // Get the access tokens | ||
158 | await setAccessTokensToServers(servers) | ||
159 | |||
160 | for (let i = 0; i < numberOfServers; i++) { | ||
161 | for (let j = 0; j < numberOfServers; j++) { | ||
162 | if (i === j) continue | ||
163 | |||
164 | await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken) | ||
165 | } | ||
166 | } | ||
167 | |||
168 | return servers | ||
169 | } | ||
170 | |||
171 | async function exitServers (servers: ServerInfo[], flushAtExit: boolean) { | ||
172 | killallServers(servers) | ||
173 | |||
174 | if (flushAtExit) await flushTests() | ||
175 | } | ||
176 | |||
177 | function upload (servers: ServerInfo[], numServer: number) { | ||
178 | console.log('Uploading video to server ' + numServer) | ||
179 | |||
180 | const videoAttributes = { | ||
181 | name: Date.now() + ' name', | ||
182 | category: 4, | ||
183 | nsfw: false, | ||
184 | licence: 2, | ||
185 | language: 'en', | ||
186 | description: Date.now() + ' description', | ||
187 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ], | ||
188 | fixture: 'video_short1.webm' | ||
189 | } | ||
190 | return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes) | ||
191 | } | ||
192 | |||
193 | async function update (servers: ServerInfo[], numServer: number) { | ||
194 | const res = await getVideosList(servers[numServer].url) | ||
195 | |||
196 | const videos = res.body.data.filter(video => video.isLocal === true) | ||
197 | if (videos.length === 0) return undefined | ||
198 | |||
199 | const toUpdate = videos[getRandomInt(0, videos.length)].id | ||
200 | const attributes = { | ||
201 | name: Date.now() + ' name', | ||
202 | description: Date.now() + ' description', | ||
203 | tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ] | ||
204 | } | ||
205 | |||
206 | console.log('Updating video of server ' + numServer) | ||
207 | |||
208 | return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes) | ||
209 | } | ||
210 | |||
211 | async function remove (servers: ServerInfo[], numServer: number) { | ||
212 | const res = await getVideosList(servers[numServer].url) | ||
213 | const videos = res.body.data.filter(video => video.isLocal === true) | ||
214 | if (videos.length === 0) return undefined | ||
215 | |||
216 | const toRemove = videos[getRandomInt(0, videos.length)].id | ||
217 | |||
218 | console.log('Removing video from server ' + numServer) | ||
219 | return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove) | ||
220 | } | ||
221 | |||
222 | async function view (servers: ServerInfo[], numServer: number) { | ||
223 | const res = await getVideosList(servers[numServer].url) | ||
224 | |||
225 | const videos = res.body.data | ||
226 | if (videos.length === 0) return undefined | ||
227 | |||
228 | const toView = videos[getRandomInt(0, videos.length)].id | ||
229 | |||
230 | console.log('Viewing video from server ' + numServer) | ||
231 | return viewVideo(servers[numServer].url, toView) | ||
232 | } | ||
233 | |||
234 | function like (servers: ServerInfo[], numServer: number) { | ||
235 | return rate(servers, numServer, 'like') | ||
236 | } | ||
237 | |||
238 | function dislike (servers: ServerInfo[], numServer: number) { | ||
239 | return rate(servers, numServer, 'dislike') | ||
240 | } | ||
241 | |||
242 | async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) { | ||
243 | const res = await getVideosList(servers[numServer].url) | ||
244 | |||
245 | const videos = res.body.data | ||
246 | if (videos.length === 0) return undefined | ||
247 | |||
248 | const toRate = videos[getRandomInt(0, videos.length)].id | ||
249 | |||
250 | console.log('Rating (%s) video from server %d', rating, numServer) | ||
251 | return getVideo(servers[numServer].url, toRate) | ||
252 | } | ||
253 | |||
254 | async function checkIntegrity (servers: ServerInfo[]) { | ||
255 | const videos: Video[][] = [] | ||
256 | const tasks: Promise<any>[] = [] | ||
257 | |||
258 | // Fetch all videos and remove some fields that can differ between servers | ||
259 | for (const server of servers) { | ||
260 | const p = getVideosListPagination(server.url, 0, 1000000, '-createdAt') | ||
261 | .then(res => videos.push(res.body.data)) | ||
262 | tasks.push(p) | ||
263 | } | ||
264 | |||
265 | await Promise.all(tasks) | ||
266 | |||
267 | let i = 0 | ||
268 | for (const video of videos) { | ||
269 | const differences = areDifferences(video, videos[0]) | ||
270 | if (differences !== undefined) { | ||
271 | console.error('Integrity not ok with server %d!', i + 1) | ||
272 | |||
273 | if (displayDiffOnFail) { | ||
274 | console.log(differences) | ||
275 | } | ||
276 | |||
277 | process.exit(-1) | ||
278 | } | ||
279 | |||
280 | i++ | ||
281 | } | ||
282 | |||
283 | console.log('Integrity ok.') | ||
284 | } | ||
285 | |||
286 | function areDifferences (videos1: Video[], videos2: Video[]) { | ||
287 | // Remove some keys we don't want to compare | ||
288 | videos1.concat(videos2).forEach(video => { | ||
289 | delete video.id | ||
290 | delete video.isLocal | ||
291 | delete video.thumbnailPath | ||
292 | delete video.updatedAt | ||
293 | delete video.views | ||
294 | }) | ||
295 | |||
296 | if (videos1.length !== videos2.length) { | ||
297 | return `Videos length are different (${videos1.length}/${videos2.length}).` | ||
298 | } | ||
299 | |||
300 | for (const video1 of videos1) { | ||
301 | const video2 = videos2.find(video => video.uuid === video1.uuid) | ||
302 | |||
303 | if (!video2) return 'Video ' + video1.uuid + ' is missing.' | ||
304 | |||
305 | for (const videoKey of Object.keys(video1)) { | ||
306 | const attribute1 = video1[videoKey] | ||
307 | const attribute2 = video2[videoKey] | ||
308 | |||
309 | if (videoKey === 'tags') { | ||
310 | if (attribute1.length !== attribute2.length) { | ||
311 | return 'Tags are different.' | ||
312 | } | ||
313 | |||
314 | attribute1.forEach(tag1 => { | ||
315 | if (attribute2.indexOf(tag1) === -1) { | ||
316 | return 'Tag ' + tag1 + ' is missing.' | ||
317 | } | ||
318 | }) | ||
319 | } else if (videoKey === 'files') { | ||
320 | if (attribute1.length !== attribute2.length) { | ||
321 | return 'Video files are different.' | ||
322 | } | ||
323 | |||
324 | attribute1.forEach((videoFile1: VideoFile) => { | ||
325 | const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri) | ||
326 | if (!videoFile2) { | ||
327 | return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.` | ||
328 | } | ||
329 | |||
330 | if (videoFile1.size !== videoFile2.size || videoFile1.resolution.label !== videoFile2.resolution.label) { | ||
331 | return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.` | ||
332 | } | ||
333 | }) | ||
334 | } else { | ||
335 | if (attribute1 !== attribute2) { | ||
336 | return `Video ${video1.uuid} has different value for attribute ${videoKey}.` | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | |||
342 | return undefined | ||
343 | } | ||
344 | |||
345 | function goodbye () { | ||
346 | return process.exit(-1) | ||
347 | } | ||
348 | |||
349 | async function isTherePendingRequests (servers: ServerInfo[]) { | ||
350 | const states: JobState[] = [ 'waiting', 'active', 'delayed' ] | ||
351 | const tasks: Promise<any>[] = [] | ||
352 | let pendingRequests = false | ||
353 | |||
354 | // Check if each server has pending request | ||
355 | for (const server of servers) { | ||
356 | for (const state of states) { | ||
357 | const p = getJobsListPaginationAndSort({ | ||
358 | url: server.url, | ||
359 | accessToken: server.accessToken, | ||
360 | state: state, | ||
361 | start: 0, | ||
362 | count: 10, | ||
363 | sort: '-createdAt' | ||
364 | }) | ||
365 | .then(res => { | ||
366 | if (res.body.total > 0) pendingRequests = true | ||
367 | }) | ||
368 | tasks.push(p) | ||
369 | } | ||
370 | } | ||
371 | |||
372 | await Promise.all(tasks) | ||
373 | |||
374 | return pendingRequests | ||
375 | } | ||
diff --git a/server/tools/cli.ts b/server/tools/cli.ts index 58e2445ac..d1a631b69 100644 --- a/server/tools/cli.ts +++ b/server/tools/cli.ts | |||
@@ -6,6 +6,9 @@ import { getVideoChannel } from '../../shared/extra-utils/videos/video-channels' | |||
6 | import { Command } from 'commander' | 6 | import { Command } from 'commander' |
7 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' | 7 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' |
8 | import { createLogger, format, transports } from 'winston' | 8 | import { createLogger, format, transports } from 'winston' |
9 | import { getMyUserInformation } from '@shared/extra-utils/users/users' | ||
10 | import { User, UserRole } from '@shared/models' | ||
11 | import { getAccessToken } from '@shared/extra-utils/users/login' | ||
9 | 12 | ||
10 | let configName = 'PeerTube/CLI' | 13 | let configName = 'PeerTube/CLI' |
11 | if (isTestInstance()) configName += `-${getAppNumber()}` | 14 | if (isTestInstance()) configName += `-${getAppNumber()}` |
@@ -14,8 +17,21 @@ const config = require('application-config')(configName) | |||
14 | 17 | ||
15 | const version = require('../../../package.json').version | 18 | const version = require('../../../package.json').version |
16 | 19 | ||
20 | async function getAdminTokenOrDie (url: string, username: string, password: string) { | ||
21 | const accessToken = await getAccessToken(url, username, password) | ||
22 | const resMe = await getMyUserInformation(url, accessToken) | ||
23 | const me: User = resMe.body | ||
24 | |||
25 | if (me.role !== UserRole.ADMINISTRATOR) { | ||
26 | console.error('You must be an administrator.') | ||
27 | process.exit(-1) | ||
28 | } | ||
29 | |||
30 | return accessToken | ||
31 | } | ||
32 | |||
17 | interface Settings { | 33 | interface Settings { |
18 | remotes: any[], | 34 | remotes: any[] |
19 | default: number | 35 | default: number |
20 | } | 36 | } |
21 | 37 | ||
@@ -74,9 +90,9 @@ function getRemoteObjectOrDie ( | |||
74 | if (!program['url'] || !program['username'] || !program['password']) { | 90 | if (!program['url'] || !program['username'] || !program['password']) { |
75 | // No remote and we don't have program parameters: quit | 91 | // No remote and we don't have program parameters: quit |
76 | if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { | 92 | if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) { |
77 | if (!program[ 'url' ]) console.error('--url field is required.') | 93 | if (!program['url']) console.error('--url field is required.') |
78 | if (!program[ 'username' ]) console.error('--username field is required.') | 94 | if (!program['username']) console.error('--username field is required.') |
79 | if (!program[ 'password' ]) console.error('--password field is required.') | 95 | if (!program['password']) console.error('--password field is required.') |
80 | 96 | ||
81 | return process.exit(-1) | 97 | return process.exit(-1) |
82 | } | 98 | } |
@@ -96,9 +112,9 @@ function getRemoteObjectOrDie ( | |||
96 | } | 112 | } |
97 | 113 | ||
98 | return { | 114 | return { |
99 | url: program[ 'url' ], | 115 | url: program['url'], |
100 | username: program[ 'username' ], | 116 | username: program['username'], |
101 | password: program[ 'password' ] | 117 | password: program['password'] |
102 | } | 118 | } |
103 | } | 119 | } |
104 | 120 | ||
@@ -134,8 +150,8 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
134 | const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} | 150 | const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {} |
135 | 151 | ||
136 | for (const key of Object.keys(defaultBooleanAttributes)) { | 152 | for (const key of Object.keys(defaultBooleanAttributes)) { |
137 | if (command[ key ] !== undefined) { | 153 | if (command[key] !== undefined) { |
138 | booleanAttributes[key] = command[ key ] | 154 | booleanAttributes[key] = command[key] |
139 | } else if (defaultAttributes[key] !== undefined) { | 155 | } else if (defaultAttributes[key] !== undefined) { |
140 | booleanAttributes[key] = defaultAttributes[key] | 156 | booleanAttributes[key] = defaultAttributes[key] |
141 | } else { | 157 | } else { |
@@ -144,19 +160,19 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
144 | } | 160 | } |
145 | 161 | ||
146 | const videoAttributes = { | 162 | const videoAttributes = { |
147 | name: command[ 'videoName' ] || defaultAttributes.name, | 163 | name: command['videoName'] || defaultAttributes.name, |
148 | category: command[ 'category' ] || defaultAttributes.category || undefined, | 164 | category: command['category'] || defaultAttributes.category || undefined, |
149 | licence: command[ 'licence' ] || defaultAttributes.licence || undefined, | 165 | licence: command['licence'] || defaultAttributes.licence || undefined, |
150 | language: command[ 'language' ] || defaultAttributes.language || undefined, | 166 | language: command['language'] || defaultAttributes.language || undefined, |
151 | privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, | 167 | privacy: command['privacy'] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, |
152 | support: command[ 'support' ] || defaultAttributes.support || undefined, | 168 | support: command['support'] || defaultAttributes.support || undefined, |
153 | description: command[ 'videoDescription' ] || defaultAttributes.description || undefined, | 169 | description: command['videoDescription'] || defaultAttributes.description || undefined, |
154 | tags: command[ 'tags' ] || defaultAttributes.tags || undefined | 170 | tags: command['tags'] || defaultAttributes.tags || undefined |
155 | } | 171 | } |
156 | 172 | ||
157 | Object.assign(videoAttributes, booleanAttributes) | 173 | Object.assign(videoAttributes, booleanAttributes) |
158 | 174 | ||
159 | if (command[ 'channelName' ]) { | 175 | if (command['channelName']) { |
160 | const res = await getVideoChannel(url, command['channelName']) | 176 | const res = await getVideoChannel(url, command['channelName']) |
161 | const videoChannel: VideoChannel = res.body | 177 | const videoChannel: VideoChannel = res.body |
162 | 178 | ||
@@ -172,9 +188,9 @@ async function buildVideoAttributesFromCommander (url: string, command: Command, | |||
172 | 188 | ||
173 | function getServerCredentials (program: any) { | 189 | function getServerCredentials (program: any) { |
174 | return Promise.all([ getSettings(), getNetrc() ]) | 190 | return Promise.all([ getSettings(), getNetrc() ]) |
175 | .then(([ settings, netrc ]) => { | 191 | .then(([ settings, netrc ]) => { |
176 | return getRemoteObjectOrDie(program, settings, netrc) | 192 | return getRemoteObjectOrDie(program, settings, netrc) |
177 | }) | 193 | }) |
178 | } | 194 | } |
179 | 195 | ||
180 | function getLogger (logLevel = 'info') { | 196 | function getLogger (logLevel = 'info') { |
@@ -222,5 +238,7 @@ export { | |||
222 | getServerCredentials, | 238 | getServerCredentials, |
223 | 239 | ||
224 | buildCommonVideoOptions, | 240 | buildCommonVideoOptions, |
225 | buildVideoAttributesFromCommander | 241 | buildVideoAttributesFromCommander, |
242 | |||
243 | getAdminTokenOrDie | ||
226 | } | 244 | } |
diff --git a/server/tools/package.json b/server/tools/package.json index 40959d76e..06ad31cab 100644 --- a/server/tools/package.json +++ b/server/tools/package.json | |||
@@ -4,11 +4,12 @@ | |||
4 | "private": true, | 4 | "private": true, |
5 | "dependencies": { | 5 | "dependencies": { |
6 | "application-config": "^1.0.1", | 6 | "application-config": "^1.0.1", |
7 | "cli-table": "^0.3.1", | 7 | "cli-table3": "^0.5.1", |
8 | "netrc-parser": "^3.1.6", | 8 | "netrc-parser": "^3.1.6", |
9 | "webtorrent-hybrid": "^4.0.1" | 9 | "webtorrent-hybrid": "^4.0.1" |
10 | }, | 10 | }, |
11 | "summon": { | 11 | "summon": { |
12 | "silent": true | 12 | "silent": true |
13 | } | 13 | }, |
14 | "devDependencies": {} | ||
14 | } | 15 | } |
diff --git a/server/tools/peertube-auth.ts b/server/tools/peertube-auth.ts index 6597a5c36..6b486e575 100644 --- a/server/tools/peertube-auth.ts +++ b/server/tools/peertube-auth.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 3 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | 4 | registerTSPaths() |
3 | 5 | ||
@@ -5,9 +7,8 @@ import * as program from 'commander' | |||
5 | import * as prompt from 'prompt' | 7 | import * as prompt from 'prompt' |
6 | import { getNetrc, getSettings, writeSettings } from './cli' | 8 | import { getNetrc, getSettings, writeSettings } from './cli' |
7 | import { isUserUsernameValid } from '../helpers/custom-validators/users' | 9 | import { isUserUsernameValid } from '../helpers/custom-validators/users' |
8 | import { getAccessToken, login } from '../../shared/extra-utils' | 10 | import { getAccessToken } from '../../shared/extra-utils' |
9 | 11 | import * as CliTable3 from 'cli-table3' | |
10 | const Table = require('cli-table') | ||
11 | 12 | ||
12 | async function delInstance (url: string) { | 13 | async function delInstance (url: string) { |
13 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 14 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
@@ -108,10 +109,10 @@ program | |||
108 | .action(async () => { | 109 | .action(async () => { |
109 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) | 110 | const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ]) |
110 | 111 | ||
111 | const table = new Table({ | 112 | const table = new CliTable3({ |
112 | head: ['instance', 'login'], | 113 | head: [ 'instance', 'login' ], |
113 | colWidths: [30, 30] | 114 | colWidths: [ 30, 30 ] |
114 | }) | 115 | }) as any |
115 | 116 | ||
116 | settings.remotes.forEach(element => { | 117 | settings.remotes.forEach(element => { |
117 | if (!netrc.machines[element]) return | 118 | if (!netrc.machines[element]) return |
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts index eaa792763..3fb9979df 100644 --- a/server/tools/peertube-import-videos.ts +++ b/server/tools/peertube-import-videos.ts | |||
@@ -1,10 +1,6 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 1 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | |||
3 | registerTSPaths() | 2 | registerTSPaths() |
4 | 3 | ||
5 | // FIXME: https://github.com/nodejs/node/pull/16853 | ||
6 | require('tls').DEFAULT_ECDH_CURVE = 'auto' | ||
7 | |||
8 | import * as program from 'commander' | 4 | import * as program from 'commander' |
9 | import { join } from 'path' | 5 | import { join } from 'path' |
10 | import { doRequestAndSaveToFile } from '../helpers/requests' | 6 | import { doRequestAndSaveToFile } from '../helpers/requests' |
@@ -16,7 +12,7 @@ import { accessSync, constants } from 'fs' | |||
16 | import { remove } from 'fs-extra' | 12 | import { remove } from 'fs-extra' |
17 | import { sha256 } from '../helpers/core-utils' | 13 | import { sha256 } from '../helpers/core-utils' |
18 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' | 14 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' |
19 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials, getLogger } from './cli' | 15 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getLogger, getServerCredentials } from './cli' |
20 | 16 | ||
21 | type UserInfo = { | 17 | type UserInfo = { |
22 | username: string | 18 | username: string |
@@ -42,32 +38,32 @@ command | |||
42 | .option('--first <first>', 'Process first n elements of returned playlist') | 38 | .option('--first <first>', 'Process first n elements of returned playlist') |
43 | .option('--last <last>', 'Process last n elements of returned playlist') | 39 | .option('--last <last>', 'Process last n elements of returned playlist') |
44 | .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname) | 40 | .option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname) |
41 | .usage("[global options] [ -- youtube-dl options]") | ||
45 | .parse(process.argv) | 42 | .parse(process.argv) |
46 | 43 | ||
47 | let log = getLogger(program[ 'verbose' ]) | 44 | const log = getLogger(program['verbose']) |
48 | 45 | ||
49 | getServerCredentials(command) | 46 | getServerCredentials(command) |
50 | .then(({ url, username, password }) => { | 47 | .then(({ url, username, password }) => { |
51 | if (!program[ 'targetUrl' ]) { | 48 | if (!program['targetUrl']) { |
52 | exitError('--target-url field is required.') | 49 | exitError('--target-url field is required.') |
53 | } | 50 | } |
54 | 51 | ||
55 | try { | 52 | try { |
56 | accessSync(program[ 'tmpdir' ], constants.R_OK | constants.W_OK) | 53 | accessSync(program['tmpdir'], constants.R_OK | constants.W_OK) |
57 | } catch (e) { | 54 | } catch (e) { |
58 | exitError('--tmpdir %s: directory does not exist or is not accessible', program[ 'tmpdir' ]) | 55 | exitError('--tmpdir %s: directory does not exist or is not accessible', program['tmpdir']) |
59 | } | 56 | } |
60 | 57 | ||
61 | url = normalizeTargetUrl(url) | 58 | url = normalizeTargetUrl(url) |
62 | program[ 'targetUrl' ] = normalizeTargetUrl(program[ 'targetUrl' ]) | 59 | program['targetUrl'] = normalizeTargetUrl(program['targetUrl']) |
63 | 60 | ||
64 | const user = { username, password } | 61 | const user = { username, password } |
65 | 62 | ||
66 | run(url, user) | 63 | run(url, user) |
67 | .catch(err => { | 64 | .catch(err => exitError(err)) |
68 | exitError(err) | ||
69 | }) | ||
70 | }) | 65 | }) |
66 | .catch(err => console.error(err)) | ||
71 | 67 | ||
72 | async function run (url: string, user: UserInfo) { | 68 | async function run (url: string, user: UserInfo) { |
73 | if (!user.password) { | 69 | if (!user.password) { |
@@ -76,20 +72,21 @@ async function run (url: string, user: UserInfo) { | |||
76 | 72 | ||
77 | const youtubeDL = await safeGetYoutubeDL() | 73 | const youtubeDL = await safeGetYoutubeDL() |
78 | 74 | ||
79 | const options = [ '-j', '--flat-playlist', '--playlist-reverse' ] | 75 | const options = [ '-j', '--flat-playlist', '--playlist-reverse', ...command.args ] |
80 | youtubeDL.getInfo(program[ 'targetUrl' ], options, processOptions, async (err, info) => { | 76 | |
77 | youtubeDL.getInfo(program['targetUrl'], options, processOptions, async (err, info) => { | ||
81 | if (err) { | 78 | if (err) { |
82 | exitError(err.message) | 79 | exitError(err.stderr + ' ' + err.message) |
83 | } | 80 | } |
84 | 81 | ||
85 | let infoArray: any[] | 82 | let infoArray: any[] |
86 | 83 | ||
87 | // Normalize utf8 fields | 84 | // Normalize utf8 fields |
88 | infoArray = [].concat(info) | 85 | infoArray = [].concat(info) |
89 | if (program[ 'first' ]) { | 86 | if (program['first']) { |
90 | infoArray = infoArray.slice(0, program[ 'first' ]) | 87 | infoArray = infoArray.slice(0, program['first']) |
91 | } else if (program[ 'last' ]) { | 88 | } else if (program['last']) { |
92 | infoArray = infoArray.slice(-program[ 'last' ]) | 89 | infoArray = infoArray.slice(-program['last']) |
93 | } | 90 | } |
94 | infoArray = infoArray.map(i => normalizeObject(i)) | 91 | infoArray = infoArray.map(i => normalizeObject(i)) |
95 | 92 | ||
@@ -97,22 +94,22 @@ async function run (url: string, user: UserInfo) { | |||
97 | 94 | ||
98 | for (const info of infoArray) { | 95 | for (const info of infoArray) { |
99 | await processVideo({ | 96 | await processVideo({ |
100 | cwd: program[ 'tmpdir' ], | 97 | cwd: program['tmpdir'], |
101 | url, | 98 | url, |
102 | user, | 99 | user, |
103 | youtubeInfo: info | 100 | youtubeInfo: info |
104 | }) | 101 | }) |
105 | } | 102 | } |
106 | 103 | ||
107 | log.info('Video/s for user %s imported: %s', user.username, program[ 'targetUrl' ]) | 104 | log.info('Video/s for user %s imported: %s', user.username, program['targetUrl']) |
108 | process.exit(0) | 105 | process.exit(0) |
109 | }) | 106 | }) |
110 | } | 107 | } |
111 | 108 | ||
112 | function processVideo (parameters: { | 109 | function processVideo (parameters: { |
113 | cwd: string, | 110 | cwd: string |
114 | url: string, | 111 | url: string |
115 | user: { username: string, password: string }, | 112 | user: { username: string, password: string } |
116 | youtubeInfo: any | 113 | youtubeInfo: any |
117 | }) { | 114 | }) { |
118 | const { youtubeInfo, cwd, url, user } = parameters | 115 | const { youtubeInfo, cwd, url, user } = parameters |
@@ -123,17 +120,17 @@ function processVideo (parameters: { | |||
123 | const videoInfo = await fetchObject(youtubeInfo) | 120 | const videoInfo = await fetchObject(youtubeInfo) |
124 | log.debug('Fetched object.', videoInfo) | 121 | log.debug('Fetched object.', videoInfo) |
125 | 122 | ||
126 | if (program[ 'since' ]) { | 123 | if (program['since']) { |
127 | if (buildOriginallyPublishedAt(videoInfo).getTime() < program[ 'since' ].getTime()) { | 124 | if (buildOriginallyPublishedAt(videoInfo).getTime() < program['since'].getTime()) { |
128 | log.info('Video "%s" has been published before "%s", don\'t upload it.\n', | 125 | log.info('Video "%s" has been published before "%s", don\'t upload it.\n', |
129 | videoInfo.title, formatDate(program[ 'since' ])) | 126 | videoInfo.title, formatDate(program['since'])) |
130 | return res() | 127 | return res() |
131 | } | 128 | } |
132 | } | 129 | } |
133 | if (program[ 'until' ]) { | 130 | if (program['until']) { |
134 | if (buildOriginallyPublishedAt(videoInfo).getTime() > program[ 'until' ].getTime()) { | 131 | if (buildOriginallyPublishedAt(videoInfo).getTime() > program['until'].getTime()) { |
135 | log.info('Video "%s" has been published after "%s", don\'t upload it.\n', | 132 | log.info('Video "%s" has been published after "%s", don\'t upload it.\n', |
136 | videoInfo.title, formatDate(program[ 'until' ])) | 133 | videoInfo.title, formatDate(program['until'])) |
137 | return res() | 134 | return res() |
138 | } | 135 | } |
139 | } | 136 | } |
@@ -151,7 +148,7 @@ function processVideo (parameters: { | |||
151 | 148 | ||
152 | log.info('Downloading video "%s"...', videoInfo.title) | 149 | log.info('Downloading video "%s"...', videoInfo.title) |
153 | 150 | ||
154 | const options = [ '-f', 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best', '-o', path ] | 151 | const options = [ '-f', 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best', ...command.args, '-o', path ] |
155 | try { | 152 | try { |
156 | const youtubeDL = await safeGetYoutubeDL() | 153 | const youtubeDL = await safeGetYoutubeDL() |
157 | youtubeDL.exec(videoInfo.url, options, processOptions, async (err, output) => { | 154 | youtubeDL.exec(videoInfo.url, options, processOptions, async (err, output) => { |
@@ -178,11 +175,11 @@ function processVideo (parameters: { | |||
178 | } | 175 | } |
179 | 176 | ||
180 | async function uploadVideoOnPeerTube (parameters: { | 177 | async function uploadVideoOnPeerTube (parameters: { |
181 | videoInfo: any, | 178 | videoInfo: any |
182 | videoPath: string, | 179 | videoPath: string |
183 | cwd: string, | 180 | cwd: string |
184 | url: string, | 181 | url: string |
185 | user: { username: string; password: string } | 182 | user: { username: string, password: string } |
186 | }) { | 183 | }) { |
187 | const { videoInfo, videoPath, cwd, url, user } = parameters | 184 | const { videoInfo, videoPath, cwd, url, user } = parameters |
188 | 185 | ||
@@ -210,9 +207,9 @@ async function uploadVideoOnPeerTube (parameters: { | |||
210 | 207 | ||
211 | const defaultAttributes = { | 208 | const defaultAttributes = { |
212 | name: truncate(videoInfo.title, { | 209 | name: truncate(videoInfo.title, { |
213 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, | 210 | length: CONSTRAINTS_FIELDS.VIDEOS.NAME.max, |
214 | 'separator': /,? +/, | 211 | separator: /,? +/, |
215 | 'omission': ' […]' | 212 | omission: ' […]' |
216 | }), | 213 | }), |
217 | category, | 214 | category, |
218 | licence, | 215 | licence, |
@@ -259,7 +256,7 @@ async function uploadVideoOnPeerTube (parameters: { | |||
259 | async function getCategory (categories: string[], url: string) { | 256 | async function getCategory (categories: string[], url: string) { |
260 | if (!categories) return undefined | 257 | if (!categories) return undefined |
261 | 258 | ||
262 | const categoryString = categories[ 0 ] | 259 | const categoryString = categories[0] |
263 | 260 | ||
264 | if (categoryString === 'News & Politics') return 11 | 261 | if (categoryString === 'News & Politics') return 11 |
265 | 262 | ||
@@ -267,7 +264,7 @@ async function getCategory (categories: string[], url: string) { | |||
267 | const categoriesServer = res.body | 264 | const categoriesServer = res.body |
268 | 265 | ||
269 | for (const key of Object.keys(categoriesServer)) { | 266 | for (const key of Object.keys(categoriesServer)) { |
270 | const categoryServer = categoriesServer[ key ] | 267 | const categoryServer = categoriesServer[key] |
271 | if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10) | 268 | if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10) |
272 | } | 269 | } |
273 | 270 | ||
@@ -289,12 +286,12 @@ function normalizeObject (obj: any) { | |||
289 | // Deprecated key | 286 | // Deprecated key |
290 | if (key === 'resolution') continue | 287 | if (key === 'resolution') continue |
291 | 288 | ||
292 | const value = obj[ key ] | 289 | const value = obj[key] |
293 | 290 | ||
294 | if (typeof value === 'string') { | 291 | if (typeof value === 'string') { |
295 | newObj[ key ] = value.normalize() | 292 | newObj[key] = value.normalize() |
296 | } else { | 293 | } else { |
297 | newObj[ key ] = value | 294 | newObj[key] = value |
298 | } | 295 | } |
299 | } | 296 | } |
300 | 297 | ||
@@ -306,7 +303,7 @@ function fetchObject (info: any) { | |||
306 | 303 | ||
307 | return new Promise<any>(async (res, rej) => { | 304 | return new Promise<any>(async (res, rej) => { |
308 | const youtubeDL = await safeGetYoutubeDL() | 305 | const youtubeDL = await safeGetYoutubeDL() |
309 | youtubeDL.getInfo(url, undefined, processOptions, async (err, videoInfo) => { | 306 | youtubeDL.getInfo(url, undefined, processOptions, (err, videoInfo) => { |
310 | if (err) return rej(err) | 307 | if (err) return rej(err) |
311 | 308 | ||
312 | const videoInfoWithUrl = Object.assign(videoInfo, { url }) | 309 | const videoInfoWithUrl = Object.assign(videoInfo, { url }) |
@@ -317,10 +314,10 @@ function fetchObject (info: any) { | |||
317 | 314 | ||
318 | function buildUrl (info: any) { | 315 | function buildUrl (info: any) { |
319 | const webpageUrl = info.webpage_url as string | 316 | const webpageUrl = info.webpage_url as string |
320 | if (webpageUrl && webpageUrl.match(/^https?:\/\//)) return webpageUrl | 317 | if (webpageUrl?.match(/^https?:\/\//)) return webpageUrl |
321 | 318 | ||
322 | const url = info.url as string | 319 | const url = info.url as string |
323 | if (url && url.match(/^https?:\/\//)) return url | 320 | if (url?.match(/^https?:\/\//)) return url |
324 | 321 | ||
325 | // It seems youtube-dl does not return the video url | 322 | // It seems youtube-dl does not return the video url |
326 | return 'https://www.youtube.com/watch?v=' + info.id | 323 | return 'https://www.youtube.com/watch?v=' + info.id |
@@ -388,7 +385,7 @@ function parseDate (dateAsStr: string): Date { | |||
388 | } | 385 | } |
389 | 386 | ||
390 | function formatDate (date: Date): string { | 387 | function formatDate (date: Date): string { |
391 | return date.toISOString().split('T')[ 0 ] | 388 | return date.toISOString().split('T')[0] |
392 | } | 389 | } |
393 | 390 | ||
394 | function exitError (message: string, ...meta: any[]) { | 391 | function exitError (message: string, ...meta: any[]) { |
diff --git a/server/tools/peertube-plugins.ts b/server/tools/peertube-plugins.ts index e40606107..05b75fab2 100644 --- a/server/tools/peertube-plugins.ts +++ b/server/tools/peertube-plugins.ts | |||
@@ -1,17 +1,15 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 3 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | 4 | registerTSPaths() |
3 | 5 | ||
4 | import * as program from 'commander' | 6 | import * as program from 'commander' |
5 | import { PluginType } from '../../shared/models/plugins/plugin.type' | 7 | import { PluginType } from '../../shared/models/plugins/plugin.type' |
6 | import { getAccessToken } from '../../shared/extra-utils/users/login' | ||
7 | import { getMyUserInformation } from '../../shared/extra-utils/users/users' | ||
8 | import { installPlugin, listPlugins, uninstallPlugin, updatePlugin } from '../../shared/extra-utils/server/plugins' | 8 | import { installPlugin, listPlugins, uninstallPlugin, updatePlugin } from '../../shared/extra-utils/server/plugins' |
9 | import { getServerCredentials } from './cli' | 9 | import { getAdminTokenOrDie, getServerCredentials } from './cli' |
10 | import { User, UserRole } from '../../shared/models/users' | ||
11 | import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model' | 10 | import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model' |
12 | import { isAbsolute } from 'path' | 11 | import { isAbsolute } from 'path' |
13 | 12 | import * as CliTable3 from 'cli-table3' | |
14 | const Table = require('cli-table') | ||
15 | 13 | ||
16 | program | 14 | program |
17 | .name('plugins') | 15 | .name('plugins') |
@@ -82,10 +80,10 @@ async function pluginsListCLI () { | |||
82 | }) | 80 | }) |
83 | const plugins: PeerTubePlugin[] = res.body.data | 81 | const plugins: PeerTubePlugin[] = res.body.data |
84 | 82 | ||
85 | const table = new Table({ | 83 | const table = new CliTable3({ |
86 | head: ['name', 'version', 'homepage'], | 84 | head: [ 'name', 'version', 'homepage' ], |
87 | colWidths: [ 50, 10, 50 ] | 85 | colWidths: [ 50, 10, 50 ] |
88 | }) | 86 | }) as any |
89 | 87 | ||
90 | for (const plugin of plugins) { | 88 | for (const plugin of plugins) { |
91 | const npmName = plugin.type === PluginType.PLUGIN | 89 | const npmName = plugin.type === PluginType.PLUGIN |
@@ -128,7 +126,6 @@ async function installPluginCLI (options: any) { | |||
128 | } catch (err) { | 126 | } catch (err) { |
129 | console.error('Cannot install plugin.', err) | 127 | console.error('Cannot install plugin.', err) |
130 | process.exit(-1) | 128 | process.exit(-1) |
131 | return | ||
132 | } | 129 | } |
133 | 130 | ||
134 | console.log('Plugin installed.') | 131 | console.log('Plugin installed.') |
@@ -160,7 +157,6 @@ async function updatePluginCLI (options: any) { | |||
160 | } catch (err) { | 157 | } catch (err) { |
161 | console.error('Cannot update plugin.', err) | 158 | console.error('Cannot update plugin.', err) |
162 | process.exit(-1) | 159 | process.exit(-1) |
163 | return | ||
164 | } | 160 | } |
165 | 161 | ||
166 | console.log('Plugin updated.') | 162 | console.log('Plugin updated.') |
@@ -181,27 +177,13 @@ async function uninstallPluginCLI (options: any) { | |||
181 | await uninstallPlugin({ | 177 | await uninstallPlugin({ |
182 | url, | 178 | url, |
183 | accessToken, | 179 | accessToken, |
184 | npmName: options[ 'npmName' ] | 180 | npmName: options['npmName'] |
185 | }) | 181 | }) |
186 | } catch (err) { | 182 | } catch (err) { |
187 | console.error('Cannot uninstall plugin.', err) | 183 | console.error('Cannot uninstall plugin.', err) |
188 | process.exit(-1) | 184 | process.exit(-1) |
189 | return | ||
190 | } | 185 | } |
191 | 186 | ||
192 | console.log('Plugin uninstalled.') | 187 | console.log('Plugin uninstalled.') |
193 | process.exit(0) | 188 | process.exit(0) |
194 | } | 189 | } |
195 | |||
196 | async function getAdminTokenOrDie (url: string, username: string, password: string) { | ||
197 | const accessToken = await getAccessToken(url, username, password) | ||
198 | const resMe = await getMyUserInformation(url, accessToken) | ||
199 | const me: User = resMe.body | ||
200 | |||
201 | if (me.role !== UserRole.ADMINISTRATOR) { | ||
202 | console.error('Cannot list plugins if you are not administrator.') | ||
203 | process.exit(-1) | ||
204 | } | ||
205 | |||
206 | return accessToken | ||
207 | } | ||
diff --git a/server/tools/peertube-redundancy.ts b/server/tools/peertube-redundancy.ts new file mode 100644 index 000000000..1ab58a438 --- /dev/null +++ b/server/tools/peertube-redundancy.ts | |||
@@ -0,0 +1,197 @@ | |||
1 | // eslint-disable @typescript-eslint/no-unnecessary-type-assertion | ||
2 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | ||
4 | registerTSPaths() | ||
5 | |||
6 | import * as program from 'commander' | ||
7 | import { getAdminTokenOrDie, getServerCredentials } from './cli' | ||
8 | import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models' | ||
9 | import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy' | ||
10 | import validator from 'validator' | ||
11 | import * as CliTable3 from 'cli-table3' | ||
12 | import { URL } from 'url' | ||
13 | import { uniq } from 'lodash' | ||
14 | |||
15 | import bytes = require('bytes') | ||
16 | |||
17 | program | ||
18 | .name('plugins') | ||
19 | .usage('[command] [options]') | ||
20 | |||
21 | program | ||
22 | .command('list-remote-redundancies') | ||
23 | .description('List remote redundancies on your videos') | ||
24 | .option('-u, --url <url>', 'Server url') | ||
25 | .option('-U, --username <username>', 'Username') | ||
26 | .option('-p, --password <token>', 'Password') | ||
27 | .action(() => listRedundanciesCLI('my-videos')) | ||
28 | |||
29 | program | ||
30 | .command('list-my-redundancies') | ||
31 | .description('List your redundancies of remote videos') | ||
32 | .option('-u, --url <url>', 'Server url') | ||
33 | .option('-U, --username <username>', 'Username') | ||
34 | .option('-p, --password <token>', 'Password') | ||
35 | .action(() => listRedundanciesCLI('remote-videos')) | ||
36 | |||
37 | program | ||
38 | .command('add') | ||
39 | .description('Duplicate a video in your redundancy system') | ||
40 | .option('-u, --url <url>', 'Server url') | ||
41 | .option('-U, --username <username>', 'Username') | ||
42 | .option('-p, --password <token>', 'Password') | ||
43 | .option('-v, --video <videoId>', 'Video id to duplicate') | ||
44 | .action((options) => addRedundancyCLI(options)) | ||
45 | |||
46 | program | ||
47 | .command('remove') | ||
48 | .description('Remove a video from your redundancies') | ||
49 | .option('-u, --url <url>', 'Server url') | ||
50 | .option('-U, --username <username>', 'Username') | ||
51 | .option('-p, --password <token>', 'Password') | ||
52 | .option('-v, --video <videoId>', 'Video id to remove from redundancies') | ||
53 | .action((options) => removeRedundancyCLI(options)) | ||
54 | |||
55 | if (!process.argv.slice(2).length) { | ||
56 | program.outputHelp() | ||
57 | } | ||
58 | |||
59 | program.parse(process.argv) | ||
60 | |||
61 | // ---------------------------------------------------------------------------- | ||
62 | |||
63 | async function listRedundanciesCLI (target: VideoRedundanciesTarget) { | ||
64 | const { url, username, password } = await getServerCredentials(program) | ||
65 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
66 | |||
67 | const redundancies = await listVideoRedundanciesData(url, accessToken, target) | ||
68 | |||
69 | const table = new CliTable3({ | ||
70 | head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ] | ||
71 | }) as any | ||
72 | |||
73 | for (const redundancy of redundancies) { | ||
74 | const webtorrentFiles = redundancy.redundancies.files | ||
75 | const streamingPlaylists = redundancy.redundancies.streamingPlaylists | ||
76 | |||
77 | let totalSize = '' | ||
78 | if (target === 'remote-videos') { | ||
79 | const tmp = webtorrentFiles.concat(streamingPlaylists) | ||
80 | .reduce((a, b) => a + b.size, 0) | ||
81 | |||
82 | totalSize = bytes(tmp) | ||
83 | } | ||
84 | |||
85 | const instances = uniq( | ||
86 | webtorrentFiles.concat(streamingPlaylists) | ||
87 | .map(r => r.fileUrl) | ||
88 | .map(u => new URL(u).host) | ||
89 | ) | ||
90 | |||
91 | table.push([ | ||
92 | redundancy.id.toString(), | ||
93 | redundancy.name, | ||
94 | redundancy.url, | ||
95 | webtorrentFiles.length, | ||
96 | streamingPlaylists.length, | ||
97 | instances.join('\n'), | ||
98 | totalSize | ||
99 | ]) | ||
100 | } | ||
101 | |||
102 | console.log(table.toString()) | ||
103 | process.exit(0) | ||
104 | } | ||
105 | |||
106 | async function addRedundancyCLI (options: { videoId: number }) { | ||
107 | const { url, username, password } = await getServerCredentials(program) | ||
108 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
109 | |||
110 | if (!options['video'] || validator.isInt('' + options['video']) === false) { | ||
111 | console.error('You need to specify the video id to duplicate and it should be a number.\n') | ||
112 | program.outputHelp() | ||
113 | process.exit(-1) | ||
114 | } | ||
115 | |||
116 | try { | ||
117 | await addVideoRedundancy({ | ||
118 | url, | ||
119 | accessToken, | ||
120 | videoId: options['video'] | ||
121 | }) | ||
122 | |||
123 | console.log('Video will be duplicated by your instance!') | ||
124 | |||
125 | process.exit(0) | ||
126 | } catch (err) { | ||
127 | if (err.message.includes(409)) { | ||
128 | console.error('This video is already duplicated by your instance.') | ||
129 | } else if (err.message.includes(404)) { | ||
130 | console.error('This video id does not exist.') | ||
131 | } else { | ||
132 | console.error(err) | ||
133 | } | ||
134 | |||
135 | process.exit(-1) | ||
136 | } | ||
137 | } | ||
138 | |||
139 | async function removeRedundancyCLI (options: { videoId: number }) { | ||
140 | const { url, username, password } = await getServerCredentials(program) | ||
141 | const accessToken = await getAdminTokenOrDie(url, username, password) | ||
142 | |||
143 | if (!options['video'] || validator.isInt('' + options['video']) === false) { | ||
144 | console.error('You need to specify the video id to remove from your redundancies.\n') | ||
145 | program.outputHelp() | ||
146 | process.exit(-1) | ||
147 | } | ||
148 | |||
149 | const videoId = parseInt(options['video'] + '', 10) | ||
150 | |||
151 | let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos') | ||
152 | let videoRedundancy = redundancies.find(r => videoId === r.id) | ||
153 | |||
154 | if (!videoRedundancy) { | ||
155 | redundancies = await listVideoRedundanciesData(url, accessToken, 'remote-videos') | ||
156 | videoRedundancy = redundancies.find(r => videoId === r.id) | ||
157 | } | ||
158 | |||
159 | if (!videoRedundancy) { | ||
160 | console.error('Video redundancy not found.') | ||
161 | process.exit(-1) | ||
162 | } | ||
163 | |||
164 | try { | ||
165 | const ids = videoRedundancy.redundancies.files | ||
166 | .concat(videoRedundancy.redundancies.streamingPlaylists) | ||
167 | .map(r => r.id) | ||
168 | |||
169 | for (const id of ids) { | ||
170 | await removeVideoRedundancy({ | ||
171 | url, | ||
172 | accessToken, | ||
173 | redundancyId: id | ||
174 | }) | ||
175 | } | ||
176 | |||
177 | console.log('Video redundancy removed!') | ||
178 | |||
179 | process.exit(0) | ||
180 | } catch (err) { | ||
181 | console.error(err) | ||
182 | process.exit(-1) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | async function listVideoRedundanciesData (url: string, accessToken: string, target: VideoRedundanciesTarget) { | ||
187 | const res = await listVideoRedundancies({ | ||
188 | url, | ||
189 | accessToken, | ||
190 | start: 0, | ||
191 | count: 100, | ||
192 | sort: 'name', | ||
193 | target | ||
194 | }) | ||
195 | |||
196 | return res.body.data as VideoRedundancy[] | ||
197 | } | ||
diff --git a/server/tools/peertube-repl.ts b/server/tools/peertube-repl.ts index ab6e215d9..7c936ae0d 100644 --- a/server/tools/peertube-repl.ts +++ b/server/tools/peertube-repl.ts | |||
@@ -1,6 +1,4 @@ | |||
1 | import { registerTSPaths } from '../helpers/register-ts-paths' | 1 | import { registerTSPaths } from '../helpers/register-ts-paths' |
2 | registerTSPaths() | ||
3 | |||
4 | import * as repl from 'repl' | 2 | import * as repl from 'repl' |
5 | import * as path from 'path' | 3 | import * as path from 'path' |
6 | import * as _ from 'lodash' | 4 | import * as _ from 'lodash' |
@@ -23,6 +21,8 @@ import * as signupUtils from '../helpers/signup' | |||
23 | import * as utils from '../helpers/utils' | 21 | import * as utils from '../helpers/utils' |
24 | import * as YoutubeDLUtils from '../helpers/youtube-dl' | 22 | import * as YoutubeDLUtils from '../helpers/youtube-dl' |
25 | 23 | ||
24 | registerTSPaths() | ||
25 | |||
26 | const start = async () => { | 26 | const start = async () => { |
27 | await initDatabaseModels(true) | 27 | await initDatabaseModels(true) |
28 | 28 | ||
@@ -31,22 +31,39 @@ const start = async () => { | |||
31 | const initContext = (replServer) => { | 31 | const initContext = (replServer) => { |
32 | return (context) => { | 32 | return (context) => { |
33 | const properties = { | 33 | const properties = { |
34 | context, repl: replServer, env: process.env, | 34 | context, |
35 | lodash: _, path, | 35 | repl: replServer, |
36 | uuidv1, uuidv3, uuidv4, uuidv5, | 36 | env: process.env, |
37 | cli, logger, constants, | 37 | lodash: _, |
38 | Sequelize, sequelizeTypescript, modelsUtils, | 38 | path, |
39 | models: sequelizeTypescript.models, transaction: sequelizeTypescript.transaction, | 39 | uuidv1, |
40 | query: sequelizeTypescript.query, queryInterface: sequelizeTypescript.getQueryInterface(), | 40 | uuidv3, |
41 | uuidv4, | ||
42 | uuidv5, | ||
43 | cli, | ||
44 | logger, | ||
45 | constants, | ||
46 | Sequelize, | ||
47 | sequelizeTypescript, | ||
48 | modelsUtils, | ||
49 | models: sequelizeTypescript.models, | ||
50 | transaction: sequelizeTypescript.transaction, | ||
51 | query: sequelizeTypescript.query, | ||
52 | queryInterface: sequelizeTypescript.getQueryInterface(), | ||
41 | YoutubeDL, | 53 | YoutubeDL, |
42 | coreUtils, ffmpegUtils, peertubeCryptoUtils, signupUtils, utils, YoutubeDLUtils | 54 | coreUtils, |
55 | ffmpegUtils, | ||
56 | peertubeCryptoUtils, | ||
57 | signupUtils, | ||
58 | utils, | ||
59 | YoutubeDLUtils | ||
43 | } | 60 | } |
44 | 61 | ||
45 | for (let prop in properties) { | 62 | for (const prop in properties) { |
46 | Object.defineProperty(context, prop, { | 63 | Object.defineProperty(context, prop, { |
47 | configurable: false, | 64 | configurable: false, |
48 | enumerable: true, | 65 | enumerable: true, |
49 | value: properties[ prop ] | 66 | value: properties[prop] |
50 | }) | 67 | }) |
51 | } | 68 | } |
52 | } | 69 | } |
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts index f604c9bee..8de952e7b 100644 --- a/server/tools/peertube-upload.ts +++ b/server/tools/peertube-upload.ts | |||
@@ -24,14 +24,14 @@ command | |||
24 | 24 | ||
25 | getServerCredentials(command) | 25 | getServerCredentials(command) |
26 | .then(({ url, username, password }) => { | 26 | .then(({ url, username, password }) => { |
27 | if (!program[ 'videoName' ] || !program[ 'file' ]) { | 27 | if (!program['videoName'] || !program['file']) { |
28 | if (!program[ 'videoName' ]) console.error('--video-name is required.') | 28 | if (!program['videoName']) console.error('--video-name is required.') |
29 | if (!program[ 'file' ]) console.error('--file is required.') | 29 | if (!program['file']) console.error('--file is required.') |
30 | 30 | ||
31 | process.exit(-1) | 31 | process.exit(-1) |
32 | } | 32 | } |
33 | 33 | ||
34 | if (isAbsolute(program[ 'file' ]) === false) { | 34 | if (isAbsolute(program['file']) === false) { |
35 | console.error('File path should be absolute.') | 35 | console.error('File path should be absolute.') |
36 | process.exit(-1) | 36 | process.exit(-1) |
37 | } | 37 | } |
@@ -41,25 +41,26 @@ getServerCredentials(command) | |||
41 | process.exit(-1) | 41 | process.exit(-1) |
42 | }) | 42 | }) |
43 | }) | 43 | }) |
44 | .catch(err => console.error(err)) | ||
44 | 45 | ||
45 | async function run (url: string, username: string, password: string) { | 46 | async function run (url: string, username: string, password: string) { |
46 | const accessToken = await getAccessToken(url, username, password) | 47 | const accessToken = await getAccessToken(url, username, password) |
47 | 48 | ||
48 | await access(program[ 'file' ], constants.F_OK) | 49 | await access(program['file'], constants.F_OK) |
49 | 50 | ||
50 | console.log('Uploading %s video...', program[ 'videoName' ]) | 51 | console.log('Uploading %s video...', program['videoName']) |
51 | 52 | ||
52 | const videoAttributes = await buildVideoAttributesFromCommander(url, program) | 53 | const videoAttributes = await buildVideoAttributesFromCommander(url, program) |
53 | 54 | ||
54 | Object.assign(videoAttributes, { | 55 | Object.assign(videoAttributes, { |
55 | fixture: program[ 'file' ], | 56 | fixture: program['file'], |
56 | thumbnailfile: program[ 'thumbnail' ], | 57 | thumbnailfile: program['thumbnail'], |
57 | previewfile: program[ 'preview' ] | 58 | previewfile: program['preview'] |
58 | }) | 59 | }) |
59 | 60 | ||
60 | try { | 61 | try { |
61 | await uploadVideo(url, accessToken, videoAttributes) | 62 | await uploadVideo(url, accessToken, videoAttributes) |
62 | console.log(`Video ${program[ 'videoName' ]} uploaded.`) | 63 | console.log(`Video ${program['videoName']} uploaded.`) |
63 | process.exit(0) | 64 | process.exit(0) |
64 | } catch (err) { | 65 | } catch (err) { |
65 | console.error(require('util').inspect(err)) | 66 | console.error(require('util').inspect(err)) |
diff --git a/server/tools/peertube-watch.ts b/server/tools/peertube-watch.ts index 9ac1d05f9..5f7d1bb07 100644 --- a/server/tools/peertube-watch.ts +++ b/server/tools/peertube-watch.ts | |||
@@ -29,16 +29,10 @@ program | |||
29 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') | 29 | console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10') |
30 | console.log() | 30 | console.log() |
31 | }) | 31 | }) |
32 | .action((url, cmd) => { | 32 | .action((url, cmd) => run(url, cmd)) |
33 | run(url, cmd) | ||
34 | .catch(err => { | ||
35 | console.error(err) | ||
36 | process.exit(-1) | ||
37 | }) | ||
38 | }) | ||
39 | .parse(process.argv) | 33 | .parse(process.argv) |
40 | 34 | ||
41 | async function run (url: string, program: any) { | 35 | function run (url: string, program: any) { |
42 | if (!url) { | 36 | if (!url) { |
43 | console.error('<url> positional argument is required.') | 37 | console.error('<url> positional argument is required.') |
44 | process.exit(-1) | 38 | process.exit(-1) |
diff --git a/server/tools/peertube.ts b/server/tools/peertube.ts index fc85c4210..88dd5f7f6 100644 --- a/server/tools/peertube.ts +++ b/server/tools/peertube.ts | |||
@@ -1,13 +1,12 @@ | |||
1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
2 | 2 | ||
3 | /* eslint-disable no-useless-escape */ | ||
4 | |||
3 | import { registerTSPaths } from '../helpers/register-ts-paths' | 5 | import { registerTSPaths } from '../helpers/register-ts-paths' |
4 | registerTSPaths() | 6 | registerTSPaths() |
5 | 7 | ||
6 | import * as program from 'commander' | 8 | import * as program from 'commander' |
7 | import { | 9 | import { getSettings, version } from './cli' |
8 | version, | ||
9 | getSettings | ||
10 | } from './cli' | ||
11 | 10 | ||
12 | program | 11 | program |
13 | .version(version, '-v, --version') | 12 | .version(version, '-v, --version') |
@@ -22,17 +21,19 @@ program | |||
22 | .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') | 21 | .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') |
23 | .command('repl', 'initiate a REPL to access internals') | 22 | .command('repl', 'initiate a REPL to access internals') |
24 | .command('plugins [action]', 'manage instance plugins/themes').alias('p') | 23 | .command('plugins [action]', 'manage instance plugins/themes').alias('p') |
24 | .command('redundancy [action]', 'manage instance redundancies').alias('r') | ||
25 | 25 | ||
26 | /* Not Yet Implemented */ | 26 | /* Not Yet Implemented */ |
27 | program | 27 | program |
28 | .command('diagnostic [action]', | 28 | .command( |
29 | 'like couple therapy, but for your instance', | 29 | 'diagnostic [action]', |
30 | { noHelp: true } as program.CommandOptions | 30 | 'like couple therapy, but for your instance', |
31 | ).alias('d') | 31 | { noHelp: true } as program.CommandOptions |
32 | ).alias('d') | ||
32 | .command('admin', | 33 | .command('admin', |
33 | 'manage an instance where you have elevated rights', | 34 | 'manage an instance where you have elevated rights', |
34 | { noHelp: true } as program.CommandOptions | 35 | { noHelp: true } as program.CommandOptions |
35 | ).alias('a') | 36 | ).alias('a') |
36 | 37 | ||
37 | // help on no command | 38 | // help on no command |
38 | if (!process.argv.slice(2).length) { | 39 | if (!process.argv.slice(2).length) { |
@@ -81,3 +82,4 @@ getSettings() | |||
81 | }) | 82 | }) |
82 | .parse(process.argv) | 83 | .parse(process.argv) |
83 | }) | 84 | }) |
85 | .catch(err => console.error(err)) | ||
diff --git a/server/tools/yarn.lock b/server/tools/yarn.lock index 28756cbc2..ccd716a51 100644 --- a/server/tools/yarn.lock +++ b/server/tools/yarn.lock | |||
@@ -347,12 +347,15 @@ chunk-store-stream@^4.0.0: | |||
347 | block-stream2 "^2.0.0" | 347 | block-stream2 "^2.0.0" |
348 | readable-stream "^3.4.0" | 348 | readable-stream "^3.4.0" |
349 | 349 | ||
350 | cli-table@^0.3.1: | 350 | cli-table3@^0.5.1: |
351 | version "0.3.1" | 351 | version "0.5.1" |
352 | resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" | 352 | resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" |
353 | integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= | 353 | integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== |
354 | dependencies: | 354 | dependencies: |
355 | colors "1.0.3" | 355 | object-assign "^4.1.0" |
356 | string-width "^2.1.1" | ||
357 | optionalDependencies: | ||
358 | colors "^1.1.2" | ||
356 | 359 | ||
357 | clivas@^0.2.0: | 360 | clivas@^0.2.0: |
358 | version "0.2.0" | 361 | version "0.2.0" |
@@ -364,10 +367,10 @@ code-point-at@^1.0.0: | |||
364 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" | 367 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" |
365 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= | 368 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= |
366 | 369 | ||
367 | colors@1.0.3: | 370 | colors@^1.1.2: |
368 | version "1.0.3" | 371 | version "1.4.0" |
369 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" | 372 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" |
370 | integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= | 373 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== |
371 | 374 | ||
372 | common-tags@^1.8.0: | 375 | common-tags@^1.8.0: |
373 | version "1.8.0" | 376 | version "1.8.0" |
@@ -1609,7 +1612,7 @@ string-width@^1.0.1: | |||
1609 | is-fullwidth-code-point "^1.0.0" | 1612 | is-fullwidth-code-point "^1.0.0" |
1610 | strip-ansi "^3.0.0" | 1613 | strip-ansi "^3.0.0" |
1611 | 1614 | ||
1612 | "string-width@^1.0.2 || 2": | 1615 | "string-width@^1.0.2 || 2", string-width@^2.1.1: |
1613 | version "2.1.1" | 1616 | version "2.1.1" |
1614 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" | 1617 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" |
1615 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== | 1618 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== |
diff --git a/server/typings/express.ts b/server/typings/express.ts index 3cc7c7632..f4188bf3d 100644 --- a/server/typings/express.ts +++ b/server/typings/express.ts | |||
@@ -21,7 +21,7 @@ import { | |||
21 | } from './models' | 21 | } from './models' |
22 | import { MVideoPlaylistFull, MVideoPlaylistFullSummary } from './models/video/video-playlist' | 22 | import { MVideoPlaylistFull, MVideoPlaylistFullSummary } from './models/video/video-playlist' |
23 | import { MVideoImportDefault } from '@server/typings/models/video/video-import' | 23 | import { MVideoImportDefault } from '@server/typings/models/video/video-import' |
24 | import { MAccountBlocklist, MStreamingPlaylist, MVideoFile } from '@server/typings/models' | 24 | import { MAccountBlocklist, MActorUrl, MStreamingPlaylist, MVideoFile, MVideoImmutable } from '@server/typings/models' |
25 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/typings/models/video/video-playlist-element' | 25 | import { MVideoPlaylistElement, MVideoPlaylistElementVideoUrlPlaylistPrivacy } from '@server/typings/models/video/video-playlist-element' |
26 | import { MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate' | 26 | import { MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate' |
27 | import { MVideoChangeOwnershipFull } from './models/video/video-change-ownership' | 27 | import { MVideoChangeOwnershipFull } from './models/video/video-change-ownership' |
@@ -35,6 +35,7 @@ declare module 'express' { | |||
35 | 35 | ||
36 | locals: { | 36 | locals: { |
37 | videoAll?: MVideoFullLight | 37 | videoAll?: MVideoFullLight |
38 | onlyImmutableVideo?: MVideoImmutable | ||
38 | onlyVideo?: MVideoThumbnail | 39 | onlyVideo?: MVideoThumbnail |
39 | onlyVideoWithRights?: MVideoWithRights | 40 | onlyVideoWithRights?: MVideoWithRights |
40 | videoId?: MVideoIdThumbnail | 41 | videoId?: MVideoIdThumbnail |
@@ -74,6 +75,7 @@ declare module 'express' { | |||
74 | 75 | ||
75 | account?: MAccountDefault | 76 | account?: MAccountDefault |
76 | 77 | ||
78 | actorUrl?: MActorUrl | ||
77 | actorFull?: MActorFull | 79 | actorFull?: MActorFull |
78 | 80 | ||
79 | user?: MUserDefault | 81 | user?: MUserDefault |
diff --git a/server/typings/models/account/account-blocklist.ts b/server/typings/models/account/account-blocklist.ts index c9cb55332..0d8bf11bd 100644 --- a/server/typings/models/account/account-blocklist.ts +++ b/server/typings/models/account/account-blocklist.ts | |||
@@ -12,7 +12,8 @@ export type MAccountBlocklist = Omit<AccountBlocklistModel, 'ByAccount' | 'Block | |||
12 | 12 | ||
13 | export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'> | 13 | export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'> |
14 | 14 | ||
15 | export type MAccountBlocklistAccounts = MAccountBlocklist & | 15 | export type MAccountBlocklistAccounts = |
16 | MAccountBlocklist & | ||
16 | Use<'ByAccount', MAccountDefault> & | 17 | Use<'ByAccount', MAccountDefault> & |
17 | Use<'BlockedAccount', MAccountDefault> | 18 | Use<'BlockedAccount', MAccountDefault> |
18 | 19 | ||
@@ -20,6 +21,7 @@ export type MAccountBlocklistAccounts = MAccountBlocklist & | |||
20 | 21 | ||
21 | // Format for API or AP object | 22 | // Format for API or AP object |
22 | 23 | ||
23 | export type MAccountBlocklistFormattable = Pick<MAccountBlocklist, 'createdAt'> & | 24 | export type MAccountBlocklistFormattable = |
25 | Pick<MAccountBlocklist, 'createdAt'> & | ||
24 | Use<'ByAccount', MAccountFormattable> & | 26 | Use<'ByAccount', MAccountFormattable> & |
25 | Use<'BlockedAccount', MAccountFormattable> | 27 | Use<'BlockedAccount', MAccountFormattable> |
diff --git a/server/typings/models/account/account.ts b/server/typings/models/account/account.ts index adb1f3689..7b826ee04 100644 --- a/server/typings/models/account/account.ts +++ b/server/typings/models/account/account.ts | |||
@@ -21,7 +21,8 @@ type Use<K extends keyof AccountModel, M> = PickWith<AccountModel, K, M> | |||
21 | 21 | ||
22 | // ############################################################################ | 22 | // ############################################################################ |
23 | 23 | ||
24 | export type MAccount = Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' | | 24 | export type MAccount = |
25 | Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' | | ||
25 | 'VideoComments' | 'BlockedAccounts'> | 26 | 'VideoComments' | 'BlockedAccounts'> |
26 | 27 | ||
27 | // ############################################################################ | 28 | // ############################################################################ |
@@ -34,62 +35,75 @@ export type MAccountUserId = Pick<MAccount, 'userId'> | |||
34 | export type MAccountUrl = Use<'Actor', MActorUrl> | 35 | export type MAccountUrl = Use<'Actor', MActorUrl> |
35 | export type MAccountAudience = Use<'Actor', MActorAudience> | 36 | export type MAccountAudience = Use<'Actor', MActorAudience> |
36 | 37 | ||
37 | export type MAccountIdActor = MAccountId & | 38 | export type MAccountIdActor = |
39 | MAccountId & | ||
38 | Use<'Actor', MActor> | 40 | Use<'Actor', MActor> |
39 | 41 | ||
40 | export type MAccountIdActorId = MAccountId & | 42 | export type MAccountIdActorId = |
43 | MAccountId & | ||
41 | Use<'Actor', MActorId> | 44 | Use<'Actor', MActorId> |
42 | 45 | ||
43 | // ############################################################################ | 46 | // ############################################################################ |
44 | 47 | ||
45 | // Default scope | 48 | // Default scope |
46 | export type MAccountDefault = MAccount & | 49 | export type MAccountDefault = |
50 | MAccount & | ||
47 | Use<'Actor', MActorDefault> | 51 | Use<'Actor', MActorDefault> |
48 | 52 | ||
49 | // Default with default association scopes | 53 | // Default with default association scopes |
50 | export type MAccountDefaultChannelDefault = MAccount & | 54 | export type MAccountDefaultChannelDefault = |
55 | MAccount & | ||
51 | Use<'Actor', MActorDefault> & | 56 | Use<'Actor', MActorDefault> & |
52 | Use<'VideoChannels', MChannelDefault[]> | 57 | Use<'VideoChannels', MChannelDefault[]> |
53 | 58 | ||
54 | // We don't need some actors attributes | 59 | // We don't need some actors attributes |
55 | export type MAccountLight = MAccount & | 60 | export type MAccountLight = |
61 | MAccount & | ||
56 | Use<'Actor', MActorDefaultLight> | 62 | Use<'Actor', MActorDefaultLight> |
57 | 63 | ||
58 | // ############################################################################ | 64 | // ############################################################################ |
59 | 65 | ||
60 | // Full actor | 66 | // Full actor |
61 | export type MAccountActor = MAccount & | 67 | export type MAccountActor = |
68 | MAccount & | ||
62 | Use<'Actor', MActor> | 69 | Use<'Actor', MActor> |
63 | 70 | ||
64 | // Full actor with server | 71 | // Full actor with server |
65 | export type MAccountServer = MAccount & | 72 | export type MAccountServer = |
73 | MAccount & | ||
66 | Use<'Actor', MActorServer> | 74 | Use<'Actor', MActorServer> |
67 | 75 | ||
68 | // ############################################################################ | 76 | // ############################################################################ |
69 | 77 | ||
70 | // For API | 78 | // For API |
71 | 79 | ||
72 | export type MAccountSummary = FunctionProperties<MAccount> & | 80 | export type MAccountSummary = |
81 | FunctionProperties<MAccount> & | ||
73 | Pick<MAccount, 'id' | 'name'> & | 82 | Pick<MAccount, 'id' | 'name'> & |
74 | Use<'Actor', MActorSummary> | 83 | Use<'Actor', MActorSummary> |
75 | 84 | ||
76 | export type MAccountSummaryBlocks = MAccountSummary & | 85 | export type MAccountSummaryBlocks = |
86 | MAccountSummary & | ||
77 | Use<'BlockedAccounts', MAccountBlocklistId[]> | 87 | Use<'BlockedAccounts', MAccountBlocklistId[]> |
78 | 88 | ||
79 | export type MAccountAPI = MAccount & | 89 | export type MAccountAPI = |
90 | MAccount & | ||
80 | Use<'Actor', MActorAPI> | 91 | Use<'Actor', MActorAPI> |
81 | 92 | ||
82 | // ############################################################################ | 93 | // ############################################################################ |
83 | 94 | ||
84 | // Format for API or AP object | 95 | // Format for API or AP object |
85 | 96 | ||
86 | export type MAccountSummaryFormattable = FunctionProperties<MAccount> & | 97 | export type MAccountSummaryFormattable = |
98 | FunctionProperties<MAccount> & | ||
87 | Pick<MAccount, 'id' | 'name'> & | 99 | Pick<MAccount, 'id' | 'name'> & |
88 | Use<'Actor', MActorSummaryFormattable> | 100 | Use<'Actor', MActorSummaryFormattable> |
89 | 101 | ||
90 | export type MAccountFormattable = FunctionProperties<MAccount> & | 102 | export type MAccountFormattable = |
103 | FunctionProperties<MAccount> & | ||
91 | Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> & | 104 | Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> & |
92 | Use<'Actor', MActorFormattable> | 105 | Use<'Actor', MActorFormattable> |
93 | 106 | ||
94 | export type MAccountAP = Pick<MAccount, 'name' | 'description'> & | 107 | export type MAccountAP = |
108 | Pick<MAccount, 'name' | 'description'> & | ||
95 | Use<'Actor', MActorAP> | 109 | Use<'Actor', MActorAP> |
diff --git a/server/typings/models/account/actor-follow.ts b/server/typings/models/account/actor-follow.ts index f44157eba..5d0c03c8d 100644 --- a/server/typings/models/account/actor-follow.ts +++ b/server/typings/models/account/actor-follow.ts | |||
@@ -20,22 +20,26 @@ export type MActorFollow = Omit<ActorFollowModel, 'ActorFollower' | 'ActorFollow | |||
20 | 20 | ||
21 | // ############################################################################ | 21 | // ############################################################################ |
22 | 22 | ||
23 | export type MActorFollowFollowingHost = MActorFollow & | 23 | export type MActorFollowFollowingHost = |
24 | MActorFollow & | ||
24 | Use<'ActorFollowing', MActorUsername & MActorHost> | 25 | Use<'ActorFollowing', MActorUsername & MActorHost> |
25 | 26 | ||
26 | // ############################################################################ | 27 | // ############################################################################ |
27 | 28 | ||
28 | // With actors or actors default | 29 | // With actors or actors default |
29 | 30 | ||
30 | export type MActorFollowActors = MActorFollow & | 31 | export type MActorFollowActors = |
32 | MActorFollow & | ||
31 | Use<'ActorFollower', MActor> & | 33 | Use<'ActorFollower', MActor> & |
32 | Use<'ActorFollowing', MActor> | 34 | Use<'ActorFollowing', MActor> |
33 | 35 | ||
34 | export type MActorFollowActorsDefault = MActorFollow & | 36 | export type MActorFollowActorsDefault = |
37 | MActorFollow & | ||
35 | Use<'ActorFollower', MActorDefault> & | 38 | Use<'ActorFollower', MActorDefault> & |
36 | Use<'ActorFollowing', MActorDefault> | 39 | Use<'ActorFollowing', MActorDefault> |
37 | 40 | ||
38 | export type MActorFollowFull = MActorFollow & | 41 | export type MActorFollowFull = |
42 | MActorFollow & | ||
39 | Use<'ActorFollower', MActorDefaultAccountChannel> & | 43 | Use<'ActorFollower', MActorDefaultAccountChannel> & |
40 | Use<'ActorFollowing', MActorDefaultAccountChannel> | 44 | Use<'ActorFollowing', MActorDefaultAccountChannel> |
41 | 45 | ||
@@ -43,20 +47,24 @@ export type MActorFollowFull = MActorFollow & | |||
43 | 47 | ||
44 | // For subscriptions | 48 | // For subscriptions |
45 | 49 | ||
46 | type SubscriptionFollowing = MActorDefault & | 50 | type SubscriptionFollowing = |
51 | MActorDefault & | ||
47 | PickWith<ActorModel, 'VideoChannel', MChannelDefault> | 52 | PickWith<ActorModel, 'VideoChannel', MChannelDefault> |
48 | 53 | ||
49 | export type MActorFollowActorsDefaultSubscription = MActorFollow & | 54 | export type MActorFollowActorsDefaultSubscription = |
55 | MActorFollow & | ||
50 | Use<'ActorFollower', MActorDefault> & | 56 | Use<'ActorFollower', MActorDefault> & |
51 | Use<'ActorFollowing', SubscriptionFollowing> | 57 | Use<'ActorFollowing', SubscriptionFollowing> |
52 | 58 | ||
53 | export type MActorFollowSubscriptions = MActorFollow & | 59 | export type MActorFollowSubscriptions = |
60 | MActorFollow & | ||
54 | Use<'ActorFollowing', MActorChannelAccountActor> | 61 | Use<'ActorFollowing', MActorChannelAccountActor> |
55 | 62 | ||
56 | // ############################################################################ | 63 | // ############################################################################ |
57 | 64 | ||
58 | // Format for API or AP object | 65 | // Format for API or AP object |
59 | 66 | ||
60 | export type MActorFollowFormattable = Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> & | 67 | export type MActorFollowFormattable = |
68 | Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> & | ||
61 | Use<'ActorFollower', MActorFormattable> & | 69 | Use<'ActorFollower', MActorFormattable> & |
62 | Use<'ActorFollowing', MActorFormattable> | 70 | Use<'ActorFollowing', MActorFormattable> |
diff --git a/server/typings/models/account/actor.ts b/server/typings/models/account/actor.ts index ee4ece755..1160e84cb 100644 --- a/server/typings/models/account/actor.ts +++ b/server/typings/models/account/actor.ts | |||
@@ -31,18 +31,23 @@ export type MActorLight = Omit<MActor, 'privateKey' | 'privateKey'> | |||
31 | export type MActorHost = Use<'Server', MServerHost> | 31 | export type MActorHost = Use<'Server', MServerHost> |
32 | export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed> | 32 | export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed> |
33 | 33 | ||
34 | export type MActorDefaultLight = MActorLight & | 34 | export type MActorDefaultLight = |
35 | MActorLight & | ||
35 | Use<'Server', MServerHost> & | 36 | Use<'Server', MServerHost> & |
36 | Use<'Avatar', MAvatar> | 37 | Use<'Avatar', MAvatar> |
37 | 38 | ||
38 | export type MActorAccountId = MActor & | 39 | export type MActorAccountId = |
40 | MActor & | ||
39 | Use<'Account', MAccountId> | 41 | Use<'Account', MAccountId> |
40 | export type MActorAccountIdActor = MActor & | 42 | export type MActorAccountIdActor = |
43 | MActor & | ||
41 | Use<'Account', MAccountIdActor> | 44 | Use<'Account', MAccountIdActor> |
42 | 45 | ||
43 | export type MActorChannelId = MActor & | 46 | export type MActorChannelId = |
47 | MActor & | ||
44 | Use<'VideoChannel', MChannelId> | 48 | Use<'VideoChannel', MChannelId> |
45 | export type MActorChannelIdActor = MActor & | 49 | export type MActorChannelIdActor = |
50 | MActor & | ||
46 | Use<'VideoChannel', MChannelIdActor> | 51 | Use<'VideoChannel', MChannelIdActor> |
47 | 52 | ||
48 | export type MActorAccountChannelId = MActorAccountId & MActorChannelId | 53 | export type MActorAccountChannelId = MActorAccountId & MActorChannelId |
@@ -52,38 +57,45 @@ export type MActorAccountChannelIdActor = MActorAccountIdActor & MActorChannelId | |||
52 | 57 | ||
53 | // Include raw account/channel/server | 58 | // Include raw account/channel/server |
54 | 59 | ||
55 | export type MActorAccount = MActor & | 60 | export type MActorAccount = |
61 | MActor & | ||
56 | Use<'Account', MAccount> | 62 | Use<'Account', MAccount> |
57 | 63 | ||
58 | export type MActorChannel = MActor & | 64 | export type MActorChannel = |
65 | MActor & | ||
59 | Use<'VideoChannel', MChannel> | 66 | Use<'VideoChannel', MChannel> |
60 | 67 | ||
61 | export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel | 68 | export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel |
62 | 69 | ||
63 | export type MActorServer = MActor & | 70 | export type MActorServer = |
71 | MActor & | ||
64 | Use<'Server', MServer> | 72 | Use<'Server', MServer> |
65 | 73 | ||
66 | // ############################################################################ | 74 | // ############################################################################ |
67 | 75 | ||
68 | // Complex actor associations | 76 | // Complex actor associations |
69 | 77 | ||
70 | export type MActorDefault = MActor & | 78 | export type MActorDefault = |
79 | MActor & | ||
71 | Use<'Server', MServer> & | 80 | Use<'Server', MServer> & |
72 | Use<'Avatar', MAvatar> | 81 | Use<'Avatar', MAvatar> |
73 | 82 | ||
74 | // Actor with channel that is associated to an account and its actor | 83 | // Actor with channel that is associated to an account and its actor |
75 | // Actor -> VideoChannel -> Account -> Actor | 84 | // Actor -> VideoChannel -> Account -> Actor |
76 | export type MActorChannelAccountActor = MActor & | 85 | export type MActorChannelAccountActor = |
86 | MActor & | ||
77 | Use<'VideoChannel', MChannelAccountActor> | 87 | Use<'VideoChannel', MChannelAccountActor> |
78 | 88 | ||
79 | export type MActorFull = MActor & | 89 | export type MActorFull = |
90 | MActor & | ||
80 | Use<'Server', MServer> & | 91 | Use<'Server', MServer> & |
81 | Use<'Avatar', MAvatar> & | 92 | Use<'Avatar', MAvatar> & |
82 | Use<'Account', MAccount> & | 93 | Use<'Account', MAccount> & |
83 | Use<'VideoChannel', MChannelAccountActor> | 94 | Use<'VideoChannel', MChannelAccountActor> |
84 | 95 | ||
85 | // Same than ActorFull, but the account and the channel have their actor | 96 | // Same than ActorFull, but the account and the channel have their actor |
86 | export type MActorFullActor = MActor & | 97 | export type MActorFullActor = |
98 | MActor & | ||
87 | Use<'Server', MServer> & | 99 | Use<'Server', MServer> & |
88 | Use<'Avatar', MAvatar> & | 100 | Use<'Avatar', MAvatar> & |
89 | Use<'Account', MAccountDefault> & | 101 | Use<'Account', MAccountDefault> & |
@@ -93,29 +105,35 @@ export type MActorFullActor = MActor & | |||
93 | 105 | ||
94 | // API | 106 | // API |
95 | 107 | ||
96 | export type MActorSummary = FunctionProperties<MActor> & | 108 | export type MActorSummary = |
109 | FunctionProperties<MActor> & | ||
97 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & | 110 | Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> & |
98 | Use<'Server', MServerHost> & | 111 | Use<'Server', MServerHost> & |
99 | Use<'Avatar', MAvatar> | 112 | Use<'Avatar', MAvatar> |
100 | 113 | ||
101 | export type MActorSummaryBlocks = MActorSummary & | 114 | export type MActorSummaryBlocks = |
115 | MActorSummary & | ||
102 | Use<'Server', MServerHostBlocks> | 116 | Use<'Server', MServerHostBlocks> |
103 | 117 | ||
104 | export type MActorAPI = Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' | | 118 | export type MActorAPI = |
119 | Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' | | ||
105 | 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'> | 120 | 'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'> |
106 | 121 | ||
107 | // ############################################################################ | 122 | // ############################################################################ |
108 | 123 | ||
109 | // Format for API or AP object | 124 | // Format for API or AP object |
110 | 125 | ||
111 | export type MActorSummaryFormattable = FunctionProperties<MActor> & | 126 | export type MActorSummaryFormattable = |
127 | FunctionProperties<MActor> & | ||
112 | Pick<MActor, 'url' | 'preferredUsername'> & | 128 | Pick<MActor, 'url' | 'preferredUsername'> & |
113 | Use<'Server', MServerHost> & | 129 | Use<'Server', MServerHost> & |
114 | Use<'Avatar', MAvatarFormattable> | 130 | Use<'Avatar', MAvatarFormattable> |
115 | 131 | ||
116 | export type MActorFormattable = MActorSummaryFormattable & | 132 | export type MActorFormattable = |
133 | MActorSummaryFormattable & | ||
117 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> & | 134 | Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> & |
118 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> | 135 | Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>> |
119 | 136 | ||
120 | export type MActorAP = MActor & | 137 | export type MActorAP = |
138 | MActor & | ||
121 | Use<'Avatar', MAvatar> | 139 | Use<'Avatar', MAvatar> |
diff --git a/server/typings/models/account/avatar.ts b/server/typings/models/account/avatar.ts index 8af6cc787..21b47180f 100644 --- a/server/typings/models/account/avatar.ts +++ b/server/typings/models/account/avatar.ts | |||
@@ -7,5 +7,6 @@ export type MAvatar = AvatarModel | |||
7 | 7 | ||
8 | // Format for API or AP object | 8 | // Format for API or AP object |
9 | 9 | ||
10 | export type MAvatarFormattable = FunctionProperties<MAvatar> & | 10 | export type MAvatarFormattable = |
11 | FunctionProperties<MAvatar> & | ||
11 | Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> | 12 | Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'> |
diff --git a/server/typings/models/oauth/oauth-token.ts b/server/typings/models/oauth/oauth-token.ts index 8ef042d4e..b24a95fd8 100644 --- a/server/typings/models/oauth/oauth-token.ts +++ b/server/typings/models/oauth/oauth-token.ts | |||
@@ -8,6 +8,7 @@ type Use<K extends keyof OAuthTokenModel, M> = PickWith<OAuthTokenModel, K, M> | |||
8 | 8 | ||
9 | export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'> | 9 | export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'> |
10 | 10 | ||
11 | export type MOAuthTokenUser = MOAuthToken & | 11 | export type MOAuthTokenUser = |
12 | MOAuthToken & | ||
12 | Use<'User', MUserAccountUrl> & | 13 | Use<'User', MUserAccountUrl> & |
13 | { user?: MUserAccountUrl } | 14 | { user?: MUserAccountUrl } |
diff --git a/server/typings/models/server/plugin.ts b/server/typings/models/server/plugin.ts index 94674c318..83eb83794 100644 --- a/server/typings/models/server/plugin.ts +++ b/server/typings/models/server/plugin.ts | |||
@@ -6,5 +6,6 @@ export type MPlugin = PluginModel | |||
6 | 6 | ||
7 | // Format for API or AP object | 7 | // Format for API or AP object |
8 | 8 | ||
9 | export type MPluginFormattable = Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled' | 9 | export type MPluginFormattable = |
10 | Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled' | ||
10 | | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'> | 11 | | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'> |
diff --git a/server/typings/models/server/server-blocklist.ts b/server/typings/models/server/server-blocklist.ts index c3e6230f2..ff6f49176 100644 --- a/server/typings/models/server/server-blocklist.ts +++ b/server/typings/models/server/server-blocklist.ts | |||
@@ -11,7 +11,8 @@ export type MServerBlocklist = Omit<ServerBlocklistModel, 'ByAccount' | 'Blocked | |||
11 | 11 | ||
12 | // ############################################################################ | 12 | // ############################################################################ |
13 | 13 | ||
14 | export type MServerBlocklistAccountServer = MServerBlocklist & | 14 | export type MServerBlocklistAccountServer = |
15 | MServerBlocklist & | ||
15 | Use<'ByAccount', MAccountDefault> & | 16 | Use<'ByAccount', MAccountDefault> & |
16 | Use<'BlockedServer', MServer> | 17 | Use<'BlockedServer', MServer> |
17 | 18 | ||
@@ -19,6 +20,7 @@ export type MServerBlocklistAccountServer = MServerBlocklist & | |||
19 | 20 | ||
20 | // Format for API or AP object | 21 | // Format for API or AP object |
21 | 22 | ||
22 | export type MServerBlocklistFormattable = Pick<MServerBlocklist, 'createdAt'> & | 23 | export type MServerBlocklistFormattable = |
24 | Pick<MServerBlocklist, 'createdAt'> & | ||
23 | Use<'ByAccount', MAccountFormattable> & | 25 | Use<'ByAccount', MAccountFormattable> & |
24 | Use<'BlockedServer', MServerFormattable> | 26 | Use<'BlockedServer', MServerFormattable> |
diff --git a/server/typings/models/server/server.ts b/server/typings/models/server/server.ts index 190cc0c28..b35e55aeb 100644 --- a/server/typings/models/server/server.ts +++ b/server/typings/models/server/server.ts | |||
@@ -13,12 +13,14 @@ export type MServer = Omit<ServerModel, 'Actors' | 'BlockedByAccounts'> | |||
13 | export type MServerHost = Pick<MServer, 'host'> | 13 | export type MServerHost = Pick<MServer, 'host'> |
14 | export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'> | 14 | export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'> |
15 | 15 | ||
16 | export type MServerHostBlocks = MServerHost & | 16 | export type MServerHostBlocks = |
17 | MServerHost & | ||
17 | Use<'BlockedByAccounts', MAccountBlocklistId[]> | 18 | Use<'BlockedByAccounts', MAccountBlocklistId[]> |
18 | 19 | ||
19 | // ############################################################################ | 20 | // ############################################################################ |
20 | 21 | ||
21 | // Format for API or AP object | 22 | // Format for API or AP object |
22 | 23 | ||
23 | export type MServerFormattable = FunctionProperties<MServer> & | 24 | export type MServerFormattable = |
25 | FunctionProperties<MServer> & | ||
24 | Pick<MServer, 'host'> | 26 | Pick<MServer, 'host'> |
diff --git a/server/typings/models/user/user-notification.ts b/server/typings/models/user/user-notification.ts index 1cdc691b0..2080360e1 100644 --- a/server/typings/models/user/user-notification.ts +++ b/server/typings/models/user/user-notification.ts | |||
@@ -16,59 +16,73 @@ type Use<K extends keyof UserNotificationModel, M> = PickWith<UserNotificationMo | |||
16 | 16 | ||
17 | // ############################################################################ | 17 | // ############################################################################ |
18 | 18 | ||
19 | export namespace UserNotificationIncludes { | 19 | export module UserNotificationIncludes { |
20 | |||
20 | export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'> | 21 | export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'> |
21 | export type VideoIncludeChannel = VideoInclude & | 22 | export type VideoIncludeChannel = |
23 | VideoInclude & | ||
22 | PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor> | 24 | PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor> |
23 | 25 | ||
24 | export type ActorInclude = Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 26 | export type ActorInclude = |
27 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | ||
25 | PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & | 28 | PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> & |
26 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> | 29 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> |
27 | 30 | ||
28 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> | 31 | export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'> |
29 | export type VideoChannelIncludeActor = VideoChannelInclude & | 32 | export type VideoChannelIncludeActor = |
33 | VideoChannelInclude & | ||
30 | PickWith<VideoChannelModel, 'Actor', ActorInclude> | 34 | PickWith<VideoChannelModel, 'Actor', ActorInclude> |
31 | 35 | ||
32 | export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'> | 36 | export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'> |
33 | export type AccountIncludeActor = AccountInclude & | 37 | export type AccountIncludeActor = |
38 | AccountInclude & | ||
34 | PickWith<AccountModel, 'Actor', ActorInclude> | 39 | PickWith<AccountModel, 'Actor', ActorInclude> |
35 | 40 | ||
36 | export type VideoCommentInclude = Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & | 41 | export type VideoCommentInclude = |
42 | Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> & | ||
37 | PickWith<VideoCommentModel, 'Account', AccountIncludeActor> & | 43 | PickWith<VideoCommentModel, 'Account', AccountIncludeActor> & |
38 | PickWith<VideoCommentModel, 'Video', VideoInclude> | 44 | PickWith<VideoCommentModel, 'Video', VideoInclude> |
39 | 45 | ||
40 | export type VideoAbuseInclude = Pick<VideoAbuseModel, 'id'> & | 46 | export type VideoAbuseInclude = |
47 | Pick<VideoAbuseModel, 'id'> & | ||
41 | PickWith<VideoAbuseModel, 'Video', VideoInclude> | 48 | PickWith<VideoAbuseModel, 'Video', VideoInclude> |
42 | 49 | ||
43 | export type VideoBlacklistInclude = Pick<VideoBlacklistModel, 'id'> & | 50 | export type VideoBlacklistInclude = |
51 | Pick<VideoBlacklistModel, 'id'> & | ||
44 | PickWith<VideoAbuseModel, 'Video', VideoInclude> | 52 | PickWith<VideoAbuseModel, 'Video', VideoInclude> |
45 | 53 | ||
46 | export type VideoImportInclude = Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> & | 54 | export type VideoImportInclude = |
55 | Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> & | ||
47 | PickWith<VideoImportModel, 'Video', VideoInclude> | 56 | PickWith<VideoImportModel, 'Video', VideoInclude> |
48 | 57 | ||
49 | export type ActorFollower = Pick<ActorModel, 'preferredUsername' | 'getHost'> & | 58 | export type ActorFollower = |
59 | Pick<ActorModel, 'preferredUsername' | 'getHost'> & | ||
50 | PickWith<ActorModel, 'Account', AccountInclude> & | 60 | PickWith<ActorModel, 'Account', AccountInclude> & |
51 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & | 61 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> & |
52 | PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> | 62 | PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> |
53 | 63 | ||
54 | export type ActorFollowing = Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & | 64 | export type ActorFollowing = |
65 | Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> & | ||
55 | PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> & | 66 | PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> & |
56 | PickWith<ActorModel, 'Account', AccountInclude> & | 67 | PickWith<ActorModel, 'Account', AccountInclude> & |
57 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> | 68 | PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> |
58 | 69 | ||
59 | export type ActorFollowInclude = Pick<ActorFollowModel, 'id' | 'state'> & | 70 | export type ActorFollowInclude = |
71 | Pick<ActorFollowModel, 'id' | 'state'> & | ||
60 | PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> & | 72 | PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> & |
61 | PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing> | 73 | PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing> |
62 | } | 74 | } |
63 | 75 | ||
64 | // ############################################################################ | 76 | // ############################################################################ |
65 | 77 | ||
66 | export type MUserNotification = Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' | | 78 | export type MUserNotification = |
79 | Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' | | ||
67 | 'VideoImport' | 'Account' | 'ActorFollow'> | 80 | 'VideoImport' | 'Account' | 'ActorFollow'> |
68 | 81 | ||
69 | // ############################################################################ | 82 | // ############################################################################ |
70 | 83 | ||
71 | export type UserNotificationModelForApi = MUserNotification & | 84 | export type UserNotificationModelForApi = |
85 | MUserNotification & | ||
72 | Use<'Video', UserNotificationIncludes.VideoIncludeChannel> & | 86 | Use<'Video', UserNotificationIncludes.VideoIncludeChannel> & |
73 | Use<'Comment', UserNotificationIncludes.VideoCommentInclude> & | 87 | Use<'Comment', UserNotificationIncludes.VideoCommentInclude> & |
74 | Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> & | 88 | Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> & |
diff --git a/server/typings/models/user/user.ts b/server/typings/models/user/user.ts index 6ac19c20b..31cf075ef 100644 --- a/server/typings/models/user/user.ts +++ b/server/typings/models/user/user.ts | |||
@@ -29,36 +29,44 @@ export type MUserId = Pick<UserModel, 'id'> | |||
29 | 29 | ||
30 | // With account | 30 | // With account |
31 | 31 | ||
32 | export type MUserAccountId = MUser & | 32 | export type MUserAccountId = |
33 | MUser & | ||
33 | Use<'Account', MAccountId> | 34 | Use<'Account', MAccountId> |
34 | 35 | ||
35 | export type MUserAccountUrl = MUser & | 36 | export type MUserAccountUrl = |
37 | MUser & | ||
36 | Use<'Account', MAccountUrl & MAccountIdActorId> | 38 | Use<'Account', MAccountUrl & MAccountIdActorId> |
37 | 39 | ||
38 | export type MUserAccount = MUser & | 40 | export type MUserAccount = |
41 | MUser & | ||
39 | Use<'Account', MAccount> | 42 | Use<'Account', MAccount> |
40 | 43 | ||
41 | export type MUserAccountDefault = MUser & | 44 | export type MUserAccountDefault = |
45 | MUser & | ||
42 | Use<'Account', MAccountDefault> | 46 | Use<'Account', MAccountDefault> |
43 | 47 | ||
44 | // With channel | 48 | // With channel |
45 | 49 | ||
46 | export type MUserNotifSettingChannelDefault = MUser & | 50 | export type MUserNotifSettingChannelDefault = |
51 | MUser & | ||
47 | Use<'NotificationSetting', MNotificationSetting> & | 52 | Use<'NotificationSetting', MNotificationSetting> & |
48 | Use<'Account', MAccountDefaultChannelDefault> | 53 | Use<'Account', MAccountDefaultChannelDefault> |
49 | 54 | ||
50 | // With notification settings | 55 | // With notification settings |
51 | 56 | ||
52 | export type MUserWithNotificationSetting = MUser & | 57 | export type MUserWithNotificationSetting = |
58 | MUser & | ||
53 | Use<'NotificationSetting', MNotificationSetting> | 59 | Use<'NotificationSetting', MNotificationSetting> |
54 | 60 | ||
55 | export type MUserNotifSettingAccount = MUser & | 61 | export type MUserNotifSettingAccount = |
62 | MUser & | ||
56 | Use<'NotificationSetting', MNotificationSetting> & | 63 | Use<'NotificationSetting', MNotificationSetting> & |
57 | Use<'Account', MAccount> | 64 | Use<'Account', MAccount> |
58 | 65 | ||
59 | // Default scope | 66 | // Default scope |
60 | 67 | ||
61 | export type MUserDefault = MUser & | 68 | export type MUserDefault = |
69 | MUser & | ||
62 | Use<'NotificationSetting', MNotificationSetting> & | 70 | Use<'NotificationSetting', MNotificationSetting> & |
63 | Use<'Account', MAccountDefault> | 71 | Use<'Account', MAccountDefault> |
64 | 72 | ||
@@ -67,12 +75,15 @@ export type MUserDefault = MUser & | |||
67 | // Format for API or AP object | 75 | // Format for API or AP object |
68 | 76 | ||
69 | type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]> | 77 | type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]> |
70 | type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels & | 78 | type MAccountWithChannelsAndSpecialPlaylists = |
79 | MAccountWithChannels & | ||
71 | PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]> | 80 | PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]> |
72 | 81 | ||
73 | export type MUserFormattable = MUserQuotaUsed & | 82 | export type MUserFormattable = |
83 | MUserQuotaUsed & | ||
74 | Use<'Account', MAccountWithChannels> & | 84 | Use<'Account', MAccountWithChannels> & |
75 | PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable> | 85 | PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable> |
76 | 86 | ||
77 | export type MMyUserFormattable = MUserFormattable & | 87 | export type MMyUserFormattable = |
88 | MUserFormattable & | ||
78 | Use<'Account', MAccountWithChannelsAndSpecialPlaylists> | 89 | Use<'Account', MAccountWithChannelsAndSpecialPlaylists> |
diff --git a/server/typings/models/video/schedule-video-update.ts b/server/typings/models/video/schedule-video-update.ts index e6f478cdf..95a53d139 100644 --- a/server/typings/models/video/schedule-video-update.ts +++ b/server/typings/models/video/schedule-video-update.ts | |||
@@ -10,7 +10,8 @@ export type MScheduleVideoUpdate = Omit<ScheduleVideoUpdateModel, 'Video'> | |||
10 | 10 | ||
11 | // ############################################################################ | 11 | // ############################################################################ |
12 | 12 | ||
13 | export type MScheduleVideoUpdateVideoAll = MScheduleVideoUpdate & | 13 | export type MScheduleVideoUpdateVideoAll = |
14 | MScheduleVideoUpdate & | ||
14 | Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight> | 15 | Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight> |
15 | 16 | ||
16 | // Format for API or AP object | 17 | // Format for API or AP object |
diff --git a/server/typings/models/video/video-abuse.ts b/server/typings/models/video/video-abuse.ts index e38c3f586..955ec4780 100644 --- a/server/typings/models/video/video-abuse.ts +++ b/server/typings/models/video/video-abuse.ts | |||
@@ -13,11 +13,13 @@ export type MVideoAbuse = Omit<VideoAbuseModel, 'Account' | 'Video' | 'toActivit | |||
13 | 13 | ||
14 | export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'> | 14 | export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'> |
15 | 15 | ||
16 | export type MVideoAbuseVideo = MVideoAbuse & | 16 | export type MVideoAbuseVideo = |
17 | MVideoAbuse & | ||
17 | Pick<VideoAbuseModel, 'toActivityPubObject'> & | 18 | Pick<VideoAbuseModel, 'toActivityPubObject'> & |
18 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
19 | 20 | ||
20 | export type MVideoAbuseAccountVideo = MVideoAbuse & | 21 | export type MVideoAbuseAccountVideo = |
22 | MVideoAbuse & | ||
21 | Pick<VideoAbuseModel, 'toActivityPubObject'> & | 23 | Pick<VideoAbuseModel, 'toActivityPubObject'> & |
22 | Use<'Video', MVideo> & | 24 | Use<'Video', MVideo> & |
23 | Use<'Account', MAccountDefault> | 25 | Use<'Account', MAccountDefault> |
@@ -26,6 +28,7 @@ export type MVideoAbuseAccountVideo = MVideoAbuse & | |||
26 | 28 | ||
27 | // Format for API or AP object | 29 | // Format for API or AP object |
28 | 30 | ||
29 | export type MVideoAbuseFormattable = MVideoAbuse & | 31 | export type MVideoAbuseFormattable = |
32 | MVideoAbuse & | ||
30 | Use<'Account', MAccountFormattable> & | 33 | Use<'Account', MAccountFormattable> & |
31 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> | 34 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>> |
diff --git a/server/typings/models/video/video-blacklist.ts b/server/typings/models/video/video-blacklist.ts index 7122a9dc0..ddb4db832 100644 --- a/server/typings/models/video/video-blacklist.ts +++ b/server/typings/models/video/video-blacklist.ts | |||
@@ -13,15 +13,18 @@ export type MVideoBlacklistUnfederated = Pick<MVideoBlacklist, 'unfederated'> | |||
13 | 13 | ||
14 | // ############################################################################ | 14 | // ############################################################################ |
15 | 15 | ||
16 | export type MVideoBlacklistLightVideo = MVideoBlacklistLight & | 16 | export type MVideoBlacklistLightVideo = |
17 | MVideoBlacklistLight & | ||
17 | Use<'Video', MVideo> | 18 | Use<'Video', MVideo> |
18 | 19 | ||
19 | export type MVideoBlacklistVideo = MVideoBlacklist & | 20 | export type MVideoBlacklistVideo = |
21 | MVideoBlacklist & | ||
20 | Use<'Video', MVideo> | 22 | Use<'Video', MVideo> |
21 | 23 | ||
22 | // ############################################################################ | 24 | // ############################################################################ |
23 | 25 | ||
24 | // Format for API or AP object | 26 | // Format for API or AP object |
25 | 27 | ||
26 | export type MVideoBlacklistFormattable = MVideoBlacklist & | 28 | export type MVideoBlacklistFormattable = |
29 | MVideoBlacklist & | ||
27 | Use<'Video', MVideoFormattable> | 30 | Use<'Video', MVideoFormattable> |
diff --git a/server/typings/models/video/video-caption.ts b/server/typings/models/video/video-caption.ts index ffa56f544..e7aff6956 100644 --- a/server/typings/models/video/video-caption.ts +++ b/server/typings/models/video/video-caption.ts | |||
@@ -11,14 +11,17 @@ export type MVideoCaption = Omit<VideoCaptionModel, 'Video'> | |||
11 | // ############################################################################ | 11 | // ############################################################################ |
12 | 12 | ||
13 | export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'> | 13 | export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'> |
14 | export type MVideoCaptionLanguageUrl = Pick<MVideoCaption, 'language' | 'fileUrl' | 'getFileUrl'> | ||
14 | 15 | ||
15 | export type MVideoCaptionVideo = MVideoCaption & | 16 | export type MVideoCaptionVideo = |
17 | MVideoCaption & | ||
16 | Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>> | 18 | Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>> |
17 | 19 | ||
18 | // ############################################################################ | 20 | // ############################################################################ |
19 | 21 | ||
20 | // Format for API or AP object | 22 | // Format for API or AP object |
21 | 23 | ||
22 | export type MVideoCaptionFormattable = FunctionProperties<MVideoCaption> & | 24 | export type MVideoCaptionFormattable = |
25 | FunctionProperties<MVideoCaption> & | ||
23 | Pick<MVideoCaption, 'language'> & | 26 | Pick<MVideoCaption, 'language'> & |
24 | Use<'Video', MVideoUUID> | 27 | Use<'Video', MVideoUUID> |
diff --git a/server/typings/models/video/video-change-ownership.ts b/server/typings/models/video/video-change-ownership.ts index e5b5bbc1d..971dc3db5 100644 --- a/server/typings/models/video/video-change-ownership.ts +++ b/server/typings/models/video/video-change-ownership.ts | |||
@@ -9,7 +9,8 @@ type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwn | |||
9 | 9 | ||
10 | export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'> | 10 | export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'> |
11 | 11 | ||
12 | export type MVideoChangeOwnershipFull = MVideoChangeOwnership & | 12 | export type MVideoChangeOwnershipFull = |
13 | MVideoChangeOwnership & | ||
13 | Use<'Initiator', MAccountDefault> & | 14 | Use<'Initiator', MAccountDefault> & |
14 | Use<'NextOwner', MAccountDefault> & | 15 | Use<'NextOwner', MAccountDefault> & |
15 | Use<'Video', MVideoWithAllFiles> | 16 | Use<'Video', MVideoWithAllFiles> |
@@ -18,7 +19,8 @@ export type MVideoChangeOwnershipFull = MVideoChangeOwnership & | |||
18 | 19 | ||
19 | // Format for API or AP object | 20 | // Format for API or AP object |
20 | 21 | ||
21 | export type MVideoChangeOwnershipFormattable = Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> & | 22 | export type MVideoChangeOwnershipFormattable = |
23 | Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> & | ||
22 | Use<'Initiator', MAccountFormattable> & | 24 | Use<'Initiator', MAccountFormattable> & |
23 | Use<'NextOwner', MAccountFormattable> & | 25 | Use<'NextOwner', MAccountFormattable> & |
24 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>> | 26 | Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>> |
diff --git a/server/typings/models/video/video-channels.ts b/server/typings/models/video/video-channels.ts index 292d0ac95..50f7c2d8a 100644 --- a/server/typings/models/video/video-channels.ts +++ b/server/typings/models/video/video-channels.ts | |||
@@ -35,32 +35,39 @@ export type MChannelId = Pick<MChannel, 'id'> | |||
35 | 35 | ||
36 | // ############################################################################ | 36 | // ############################################################################ |
37 | 37 | ||
38 | export type MChannelIdActor = MChannelId & | 38 | export type MChannelIdActor = |
39 | MChannelId & | ||
39 | Use<'Actor', MActorAccountChannelId> | 40 | Use<'Actor', MActorAccountChannelId> |
40 | 41 | ||
41 | export type MChannelUserId = Pick<MChannel, 'accountId'> & | 42 | export type MChannelUserId = |
43 | Pick<MChannel, 'accountId'> & | ||
42 | Use<'Account', MAccountUserId> | 44 | Use<'Account', MAccountUserId> |
43 | 45 | ||
44 | export type MChannelActor = MChannel & | 46 | export type MChannelActor = |
47 | MChannel & | ||
45 | Use<'Actor', MActor> | 48 | Use<'Actor', MActor> |
46 | 49 | ||
47 | export type MChannelUrl = Use<'Actor', MActorUrl> | 50 | export type MChannelUrl = Use<'Actor', MActorUrl> |
48 | 51 | ||
49 | // Default scope | 52 | // Default scope |
50 | export type MChannelDefault = MChannel & | 53 | export type MChannelDefault = |
54 | MChannel & | ||
51 | Use<'Actor', MActorDefault> | 55 | Use<'Actor', MActorDefault> |
52 | 56 | ||
53 | // ############################################################################ | 57 | // ############################################################################ |
54 | 58 | ||
55 | // Not all association attributes | 59 | // Not all association attributes |
56 | 60 | ||
57 | export type MChannelLight = MChannel & | 61 | export type MChannelLight = |
62 | MChannel & | ||
58 | Use<'Actor', MActorDefaultLight> | 63 | Use<'Actor', MActorDefaultLight> |
59 | 64 | ||
60 | export type MChannelActorLight = MChannel & | 65 | export type MChannelActorLight = |
66 | MChannel & | ||
61 | Use<'Actor', MActorLight> | 67 | Use<'Actor', MActorLight> |
62 | 68 | ||
63 | export type MChannelAccountLight = MChannel & | 69 | export type MChannelAccountLight = |
70 | MChannel & | ||
64 | Use<'Actor', MActorDefaultLight> & | 71 | Use<'Actor', MActorDefaultLight> & |
65 | Use<'Account', MAccountLight> | 72 | Use<'Account', MAccountLight> |
66 | 73 | ||
@@ -68,24 +75,29 @@ export type MChannelAccountLight = MChannel & | |||
68 | 75 | ||
69 | // Account associations | 76 | // Account associations |
70 | 77 | ||
71 | export type MChannelAccountActor = MChannel & | 78 | export type MChannelAccountActor = |
79 | MChannel & | ||
72 | Use<'Account', MAccountActor> | 80 | Use<'Account', MAccountActor> |
73 | 81 | ||
74 | export type MChannelAccountDefault = MChannel & | 82 | export type MChannelAccountDefault = |
83 | MChannel & | ||
75 | Use<'Actor', MActorDefault> & | 84 | Use<'Actor', MActorDefault> & |
76 | Use<'Account', MAccountDefault> | 85 | Use<'Account', MAccountDefault> |
77 | 86 | ||
78 | export type MChannelActorAccountActor = MChannel & | 87 | export type MChannelActorAccountActor = |
88 | MChannel & | ||
79 | Use<'Account', MAccountActor> & | 89 | Use<'Account', MAccountActor> & |
80 | Use<'Actor', MActor> | 90 | Use<'Actor', MActor> |
81 | 91 | ||
82 | // ############################################################################ | 92 | // ############################################################################ |
83 | 93 | ||
84 | // Videos associations | 94 | // Videos associations |
85 | export type MChannelVideos = MChannel & | 95 | export type MChannelVideos = |
96 | MChannel & | ||
86 | Use<'Videos', MVideo[]> | 97 | Use<'Videos', MVideo[]> |
87 | 98 | ||
88 | export type MChannelActorAccountDefaultVideos = MChannel & | 99 | export type MChannelActorAccountDefaultVideos = |
100 | MChannel & | ||
89 | Use<'Actor', MActorDefault> & | 101 | Use<'Actor', MActorDefault> & |
90 | Use<'Account', MAccountDefault> & | 102 | Use<'Account', MAccountDefault> & |
91 | Use<'Videos', MVideo[]> | 103 | Use<'Videos', MVideo[]> |
@@ -94,14 +106,17 @@ export type MChannelActorAccountDefaultVideos = MChannel & | |||
94 | 106 | ||
95 | // For API | 107 | // For API |
96 | 108 | ||
97 | export type MChannelSummary = FunctionProperties<MChannel> & | 109 | export type MChannelSummary = |
110 | FunctionProperties<MChannel> & | ||
98 | Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> & | 111 | Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> & |
99 | Use<'Actor', MActorSummary> | 112 | Use<'Actor', MActorSummary> |
100 | 113 | ||
101 | export type MChannelSummaryAccount = MChannelSummary & | 114 | export type MChannelSummaryAccount = |
115 | MChannelSummary & | ||
102 | Use<'Account', MAccountSummaryBlocks> | 116 | Use<'Account', MAccountSummaryBlocks> |
103 | 117 | ||
104 | export type MChannelAPI = MChannel & | 118 | export type MChannelAPI = |
119 | MChannel & | ||
105 | Use<'Actor', MActorAPI> & | 120 | Use<'Actor', MActorAPI> & |
106 | Use<'Account', MAccountAPI> | 121 | Use<'Account', MAccountAPI> |
107 | 122 | ||
@@ -109,18 +124,22 @@ export type MChannelAPI = MChannel & | |||
109 | 124 | ||
110 | // Format for API or AP object | 125 | // Format for API or AP object |
111 | 126 | ||
112 | export type MChannelSummaryFormattable = FunctionProperties<MChannel> & | 127 | export type MChannelSummaryFormattable = |
128 | FunctionProperties<MChannel> & | ||
113 | Pick<MChannel, 'id' | 'name'> & | 129 | Pick<MChannel, 'id' | 'name'> & |
114 | Use<'Actor', MActorSummaryFormattable> | 130 | Use<'Actor', MActorSummaryFormattable> |
115 | 131 | ||
116 | export type MChannelAccountSummaryFormattable = MChannelSummaryFormattable & | 132 | export type MChannelAccountSummaryFormattable = |
133 | MChannelSummaryFormattable & | ||
117 | Use<'Account', MAccountSummaryFormattable> | 134 | Use<'Account', MAccountSummaryFormattable> |
118 | 135 | ||
119 | export type MChannelFormattable = FunctionProperties<MChannel> & | 136 | export type MChannelFormattable = |
137 | FunctionProperties<MChannel> & | ||
120 | Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> & | 138 | Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> & |
121 | Use<'Actor', MActorFormattable> & | 139 | Use<'Actor', MActorFormattable> & |
122 | PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable> | 140 | PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable> |
123 | 141 | ||
124 | export type MChannelAP = Pick<MChannel, 'name' | 'description' | 'support'> & | 142 | export type MChannelAP = |
143 | Pick<MChannel, 'name' | 'description' | 'support'> & | ||
125 | Use<'Actor', MActorAP> & | 144 | Use<'Actor', MActorAP> & |
126 | Use<'Account', MAccountUrl> | 145 | Use<'Account', MAccountUrl> |
diff --git a/server/typings/models/video/video-comment.ts b/server/typings/models/video/video-comment.ts index d693f9186..d6e0b66f5 100644 --- a/server/typings/models/video/video-comment.ts +++ b/server/typings/models/video/video-comment.ts | |||
@@ -14,30 +14,37 @@ export type MCommentUrl = Pick<MComment, 'url'> | |||
14 | 14 | ||
15 | // ############################################################################ | 15 | // ############################################################################ |
16 | 16 | ||
17 | export type MCommentOwner = MComment & | 17 | export type MCommentOwner = |
18 | MComment & | ||
18 | Use<'Account', MAccountDefault> | 19 | Use<'Account', MAccountDefault> |
19 | 20 | ||
20 | export type MCommentVideo = MComment & | 21 | export type MCommentVideo = |
22 | MComment & | ||
21 | Use<'Video', MVideoAccountLight> | 23 | Use<'Video', MVideoAccountLight> |
22 | 24 | ||
23 | export type MCommentReply = MComment & | 25 | export type MCommentReply = |
26 | MComment & | ||
24 | Use<'InReplyToVideoComment', MComment> | 27 | Use<'InReplyToVideoComment', MComment> |
25 | 28 | ||
26 | export type MCommentOwnerVideo = MComment & | 29 | export type MCommentOwnerVideo = |
30 | MComment & | ||
27 | Use<'Account', MAccountDefault> & | 31 | Use<'Account', MAccountDefault> & |
28 | Use<'Video', MVideoAccountLight> | 32 | Use<'Video', MVideoAccountLight> |
29 | 33 | ||
30 | export type MCommentOwnerVideoReply = MComment & | 34 | export type MCommentOwnerVideoReply = |
35 | MComment & | ||
31 | Use<'Account', MAccountDefault> & | 36 | Use<'Account', MAccountDefault> & |
32 | Use<'Video', MVideoAccountLight> & | 37 | Use<'Video', MVideoAccountLight> & |
33 | Use<'InReplyToVideoComment', MComment> | 38 | Use<'InReplyToVideoComment', MComment> |
34 | 39 | ||
35 | export type MCommentOwnerReplyVideoLight = MComment & | 40 | export type MCommentOwnerReplyVideoLight = |
41 | MComment & | ||
36 | Use<'Account', MAccountDefault> & | 42 | Use<'Account', MAccountDefault> & |
37 | Use<'InReplyToVideoComment', MComment> & | 43 | Use<'InReplyToVideoComment', MComment> & |
38 | Use<'Video', MVideoIdUrl> | 44 | Use<'Video', MVideoIdUrl> |
39 | 45 | ||
40 | export type MCommentOwnerVideoFeed = MCommentOwner & | 46 | export type MCommentOwnerVideoFeed = |
47 | MCommentOwner & | ||
41 | Use<'Video', MVideoFeed> | 48 | Use<'Video', MVideoFeed> |
42 | 49 | ||
43 | // ############################################################################ | 50 | // ############################################################################ |
@@ -48,10 +55,12 @@ export type MCommentAPI = MComment & { totalReplies: number } | |||
48 | 55 | ||
49 | // Format for API or AP object | 56 | // Format for API or AP object |
50 | 57 | ||
51 | export type MCommentFormattable = MCommentTotalReplies & | 58 | export type MCommentFormattable = |
59 | MCommentTotalReplies & | ||
52 | Use<'Account', MAccountFormattable> | 60 | Use<'Account', MAccountFormattable> |
53 | 61 | ||
54 | export type MCommentAP = MComment & | 62 | export type MCommentAP = |
63 | MComment & | ||
55 | Use<'Account', MAccountUrl> & | 64 | Use<'Account', MAccountUrl> & |
56 | PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> & | 65 | PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> & |
57 | PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl> | 66 | PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl> |
diff --git a/server/typings/models/video/video-file.ts b/server/typings/models/video/video-file.ts index 352fe3d32..3fcaca78f 100644 --- a/server/typings/models/video/video-file.ts +++ b/server/typings/models/video/video-file.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { VideoFileModel } from '../../../models/video/video-file' | 1 | import { VideoFileModel } from '../../../models/video/video-file' |
2 | import { PickWith, PickWithOpt } from '../../utils' | 2 | import { PickWith, PickWithOpt } from '../../utils' |
3 | import { MVideo, MVideoUUID } from './video' | 3 | import { MVideo, MVideoUUID } from './video' |
4 | import { MVideoRedundancyFileUrl } from './video-redundancy' | 4 | import { MVideoRedundancy, MVideoRedundancyFileUrl } from './video-redundancy' |
5 | import { MStreamingPlaylistVideo, MStreamingPlaylist } from './video-streaming-playlist' | 5 | import { MStreamingPlaylistVideo, MStreamingPlaylist } 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> |
@@ -10,19 +10,28 @@ type Use<K extends keyof VideoFileModel, M> = PickWith<VideoFileModel, K, M> | |||
10 | 10 | ||
11 | export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'> | 11 | export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'> |
12 | 12 | ||
13 | export type MVideoFileVideo = MVideoFile & | 13 | export type MVideoFileVideo = |
14 | MVideoFile & | ||
14 | Use<'Video', MVideo> | 15 | Use<'Video', MVideo> |
15 | 16 | ||
16 | export type MVideoFileStreamingPlaylist = MVideoFile & | 17 | export type MVideoFileStreamingPlaylist = |
18 | MVideoFile & | ||
17 | Use<'VideoStreamingPlaylist', MStreamingPlaylist> | 19 | Use<'VideoStreamingPlaylist', MStreamingPlaylist> |
18 | 20 | ||
19 | export type MVideoFileStreamingPlaylistVideo = MVideoFile & | 21 | export type MVideoFileStreamingPlaylistVideo = |
22 | MVideoFile & | ||
20 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 23 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
21 | 24 | ||
22 | export type MVideoFileVideoUUID = MVideoFile & | 25 | export type MVideoFileVideoUUID = |
26 | MVideoFile & | ||
23 | Use<'Video', MVideoUUID> | 27 | Use<'Video', MVideoUUID> |
24 | 28 | ||
25 | export type MVideoFileRedundanciesOpt = MVideoFile & | 29 | export type MVideoFileRedundanciesAll = |
30 | MVideoFile & | ||
31 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancy[]> | ||
32 | |||
33 | export type MVideoFileRedundanciesOpt = | ||
34 | MVideoFile & | ||
26 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> | 35 | PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> |
27 | 36 | ||
28 | export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist { | 37 | export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist { |
diff --git a/server/typings/models/video/video-import.ts b/server/typings/models/video/video-import.ts index e119f17f9..4e5c2e4f0 100644 --- a/server/typings/models/video/video-import.ts +++ b/server/typings/models/video/video-import.ts | |||
@@ -9,18 +9,21 @@ type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M> | |||
9 | 9 | ||
10 | export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'> | 10 | export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'> |
11 | 11 | ||
12 | export type MVideoImportVideo = MVideoImport & | 12 | export type MVideoImportVideo = |
13 | MVideoImport & | ||
13 | Use<'Video', MVideo> | 14 | Use<'Video', MVideo> |
14 | 15 | ||
15 | // ############################################################################ | 16 | // ############################################################################ |
16 | 17 | ||
17 | type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail | 18 | type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail |
18 | 19 | ||
19 | export type MVideoImportDefault = MVideoImport & | 20 | export type MVideoImportDefault = |
21 | MVideoImport & | ||
20 | Use<'User', MUser> & | 22 | Use<'User', MUser> & |
21 | Use<'Video', VideoAssociation> | 23 | Use<'Video', VideoAssociation> |
22 | 24 | ||
23 | export type MVideoImportDefaultFiles = MVideoImport & | 25 | export type MVideoImportDefaultFiles = |
26 | MVideoImport & | ||
24 | Use<'User', MUser> & | 27 | Use<'User', MUser> & |
25 | Use<'Video', VideoAssociation & MVideoWithFile> | 28 | Use<'Video', VideoAssociation & MVideoWithFile> |
26 | 29 | ||
@@ -28,5 +31,6 @@ export type MVideoImportDefaultFiles = MVideoImport & | |||
28 | 31 | ||
29 | // Format for API or AP object | 32 | // Format for API or AP object |
30 | 33 | ||
31 | export type MVideoImportFormattable = MVideoImport & | 34 | export type MVideoImportFormattable = |
35 | MVideoImport & | ||
32 | PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag> | 36 | PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag> |
diff --git a/server/typings/models/video/video-playlist-element.ts b/server/typings/models/video/video-playlist-element.ts index 1aeff78d8..f33c76594 100644 --- a/server/typings/models/video/video-playlist-element.ts +++ b/server/typings/models/video/video-playlist-element.ts | |||
@@ -17,10 +17,12 @@ export type MVideoPlaylistElementLight = Pick<MVideoPlaylistElement, 'id' | 'vid | |||
17 | 17 | ||
18 | // ############################################################################ | 18 | // ############################################################################ |
19 | 19 | ||
20 | export type MVideoPlaylistVideoThumbnail = MVideoPlaylistElement & | 20 | export type MVideoPlaylistVideoThumbnail = |
21 | MVideoPlaylistElement & | ||
21 | Use<'Video', MVideoThumbnail> | 22 | Use<'Video', MVideoThumbnail> |
22 | 23 | ||
23 | export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement & | 24 | export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = |
25 | MVideoPlaylistElement & | ||
24 | Use<'Video', MVideoUrl> & | 26 | Use<'Video', MVideoUrl> & |
25 | Use<'VideoPlaylist', MVideoPlaylistPrivacy> | 27 | Use<'VideoPlaylist', MVideoPlaylistPrivacy> |
26 | 28 | ||
@@ -28,8 +30,10 @@ export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement | |||
28 | 30 | ||
29 | // Format for API or AP object | 31 | // Format for API or AP object |
30 | 32 | ||
31 | export type MVideoPlaylistElementFormattable = MVideoPlaylistElement & | 33 | export type MVideoPlaylistElementFormattable = |
34 | MVideoPlaylistElement & | ||
32 | Use<'Video', MVideoFormattable> | 35 | Use<'Video', MVideoFormattable> |
33 | 36 | ||
34 | export type MVideoPlaylistElementAP = MVideoPlaylistElement & | 37 | export type MVideoPlaylistElementAP = |
38 | MVideoPlaylistElement & | ||
35 | Use<'Video', MVideoUrl> | 39 | Use<'Video', MVideoUrl> |
diff --git a/server/typings/models/video/video-playlist.ts b/server/typings/models/video/video-playlist.ts index a40c7aca9..49c27f4a7 100644 --- a/server/typings/models/video/video-playlist.ts +++ b/server/typings/models/video/video-playlist.ts | |||
@@ -22,30 +22,36 @@ export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: numbe | |||
22 | 22 | ||
23 | // With elements | 23 | // With elements |
24 | 24 | ||
25 | export type MVideoPlaylistWithElements = MVideoPlaylist & | 25 | export type MVideoPlaylistWithElements = |
26 | MVideoPlaylist & | ||
26 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> | 27 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> |
27 | 28 | ||
28 | export type MVideoPlaylistIdWithElements = MVideoPlaylistId & | 29 | export type MVideoPlaylistIdWithElements = |
30 | MVideoPlaylistId & | ||
29 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> | 31 | Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]> |
30 | 32 | ||
31 | // ############################################################################ | 33 | // ############################################################################ |
32 | 34 | ||
33 | // With account | 35 | // With account |
34 | 36 | ||
35 | export type MVideoPlaylistOwner = MVideoPlaylist & | 37 | export type MVideoPlaylistOwner = |
38 | MVideoPlaylist & | ||
36 | Use<'OwnerAccount', MAccount> | 39 | Use<'OwnerAccount', MAccount> |
37 | 40 | ||
38 | export type MVideoPlaylistOwnerDefault = MVideoPlaylist & | 41 | export type MVideoPlaylistOwnerDefault = |
42 | MVideoPlaylist & | ||
39 | Use<'OwnerAccount', MAccountDefault> | 43 | Use<'OwnerAccount', MAccountDefault> |
40 | 44 | ||
41 | // ############################################################################ | 45 | // ############################################################################ |
42 | 46 | ||
43 | // With thumbnail | 47 | // With thumbnail |
44 | 48 | ||
45 | export type MVideoPlaylistThumbnail = MVideoPlaylist & | 49 | export type MVideoPlaylistThumbnail = |
50 | MVideoPlaylist & | ||
46 | Use<'Thumbnail', MThumbnail> | 51 | Use<'Thumbnail', MThumbnail> |
47 | 52 | ||
48 | export type MVideoPlaylistAccountThumbnail = MVideoPlaylist & | 53 | export type MVideoPlaylistAccountThumbnail = |
54 | MVideoPlaylist & | ||
49 | Use<'OwnerAccount', MAccountDefault> & | 55 | Use<'OwnerAccount', MAccountDefault> & |
50 | Use<'Thumbnail', MThumbnail> | 56 | Use<'Thumbnail', MThumbnail> |
51 | 57 | ||
@@ -53,7 +59,8 @@ export type MVideoPlaylistAccountThumbnail = MVideoPlaylist & | |||
53 | 59 | ||
54 | // With channel | 60 | // With channel |
55 | 61 | ||
56 | export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist & | 62 | export type MVideoPlaylistAccountChannelDefault = |
63 | MVideoPlaylist & | ||
57 | Use<'OwnerAccount', MAccountDefault> & | 64 | Use<'OwnerAccount', MAccountDefault> & |
58 | Use<'VideoChannel', MChannelDefault> | 65 | Use<'VideoChannel', MChannelDefault> |
59 | 66 | ||
@@ -61,7 +68,8 @@ export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist & | |||
61 | 68 | ||
62 | // With all associations | 69 | // With all associations |
63 | 70 | ||
64 | export type MVideoPlaylistFull = MVideoPlaylist & | 71 | export type MVideoPlaylistFull = |
72 | MVideoPlaylist & | ||
65 | Use<'OwnerAccount', MAccountDefault> & | 73 | Use<'OwnerAccount', MAccountDefault> & |
66 | Use<'VideoChannel', MChannelDefault> & | 74 | Use<'VideoChannel', MChannelDefault> & |
67 | Use<'Thumbnail', MThumbnail> | 75 | Use<'Thumbnail', MThumbnail> |
@@ -70,11 +78,13 @@ export type MVideoPlaylistFull = MVideoPlaylist & | |||
70 | 78 | ||
71 | // For API | 79 | // For API |
72 | 80 | ||
73 | export type MVideoPlaylistAccountChannelSummary = MVideoPlaylist & | 81 | export type MVideoPlaylistAccountChannelSummary = |
82 | MVideoPlaylist & | ||
74 | Use<'OwnerAccount', MAccountSummary> & | 83 | Use<'OwnerAccount', MAccountSummary> & |
75 | Use<'VideoChannel', MChannelSummary> | 84 | Use<'VideoChannel', MChannelSummary> |
76 | 85 | ||
77 | export type MVideoPlaylistFullSummary = MVideoPlaylist & | 86 | export type MVideoPlaylistFullSummary = |
87 | MVideoPlaylist & | ||
78 | Use<'Thumbnail', MThumbnail> & | 88 | Use<'Thumbnail', MThumbnail> & |
79 | Use<'OwnerAccount', MAccountSummary> & | 89 | Use<'OwnerAccount', MAccountSummary> & |
80 | Use<'VideoChannel', MChannelSummary> | 90 | Use<'VideoChannel', MChannelSummary> |
@@ -83,10 +93,12 @@ export type MVideoPlaylistFullSummary = MVideoPlaylist & | |||
83 | 93 | ||
84 | // Format for API or AP object | 94 | // Format for API or AP object |
85 | 95 | ||
86 | export type MVideoPlaylistFormattable = MVideoPlaylistVideosLength & | 96 | export type MVideoPlaylistFormattable = |
97 | MVideoPlaylistVideosLength & | ||
87 | Use<'OwnerAccount', MAccountSummaryFormattable> & | 98 | Use<'OwnerAccount', MAccountSummaryFormattable> & |
88 | Use<'VideoChannel', MChannelSummaryFormattable> | 99 | Use<'VideoChannel', MChannelSummaryFormattable> |
89 | 100 | ||
90 | export type MVideoPlaylistAP = MVideoPlaylist & | 101 | export type MVideoPlaylistAP = |
102 | MVideoPlaylist & | ||
91 | Use<'Thumbnail', MThumbnail> & | 103 | Use<'Thumbnail', MThumbnail> & |
92 | Use<'VideoChannel', MChannelUrl> | 104 | Use<'VideoChannel', MChannelUrl> |
diff --git a/server/typings/models/video/video-rate.ts b/server/typings/models/video/video-rate.ts index f6bb527fc..64ce4965b 100644 --- a/server/typings/models/video/video-rate.ts +++ b/server/typings/models/video/video-rate.ts | |||
@@ -9,10 +9,12 @@ type Use<K extends keyof AccountVideoRateModel, M> = PickWith<AccountVideoRateMo | |||
9 | 9 | ||
10 | export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'> | 10 | export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'> |
11 | 11 | ||
12 | export type MAccountVideoRateAccountUrl = MAccountVideoRate & | 12 | export type MAccountVideoRateAccountUrl = |
13 | MAccountVideoRate & | ||
13 | Use<'Account', MAccountUrl> | 14 | Use<'Account', MAccountUrl> |
14 | 15 | ||
15 | export type MAccountVideoRateAccountVideo = MAccountVideoRate & | 16 | export type MAccountVideoRateAccountVideo = |
17 | MAccountVideoRate & | ||
16 | Use<'Account', MAccountAudience> & | 18 | Use<'Account', MAccountAudience> & |
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
18 | 20 | ||
@@ -20,5 +22,6 @@ export type MAccountVideoRateAccountVideo = MAccountVideoRate & | |||
20 | 22 | ||
21 | // Format for API or AP object | 23 | // Format for API or AP object |
22 | 24 | ||
23 | export type MAccountVideoRateFormattable = Pick<MAccountVideoRate, 'type'> & | 25 | export type MAccountVideoRateFormattable = |
26 | Pick<MAccountVideoRate, 'type'> & | ||
24 | Use<'Video', MVideoFormattable> | 27 | Use<'Video', MVideoFormattable> |
diff --git a/server/typings/models/video/video-redundancy.ts b/server/typings/models/video/video-redundancy.ts index 25bdac057..5107aa7f4 100644 --- a/server/typings/models/video/video-redundancy.ts +++ b/server/typings/models/video/video-redundancy.ts | |||
@@ -16,16 +16,20 @@ export type MVideoRedundancyFileUrl = Pick<MVideoRedundancy, 'fileUrl'> | |||
16 | 16 | ||
17 | // ############################################################################ | 17 | // ############################################################################ |
18 | 18 | ||
19 | export type MVideoRedundancyFile = MVideoRedundancy & | 19 | export type MVideoRedundancyFile = |
20 | MVideoRedundancy & | ||
20 | Use<'VideoFile', MVideoFile> | 21 | Use<'VideoFile', MVideoFile> |
21 | 22 | ||
22 | export type MVideoRedundancyFileVideo = MVideoRedundancy & | 23 | export type MVideoRedundancyFileVideo = |
24 | MVideoRedundancy & | ||
23 | Use<'VideoFile', MVideoFileVideo> | 25 | Use<'VideoFile', MVideoFileVideo> |
24 | 26 | ||
25 | export type MVideoRedundancyStreamingPlaylistVideo = MVideoRedundancy & | 27 | export type MVideoRedundancyStreamingPlaylistVideo = |
28 | MVideoRedundancy & | ||
26 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 29 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
27 | 30 | ||
28 | export type MVideoRedundancyVideo = MVideoRedundancy & | 31 | export type MVideoRedundancyVideo = |
32 | MVideoRedundancy & | ||
29 | Use<'VideoFile', MVideoFileVideo> & | 33 | Use<'VideoFile', MVideoFileVideo> & |
30 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> | 34 | Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo> |
31 | 35 | ||
@@ -33,6 +37,7 @@ export type MVideoRedundancyVideo = MVideoRedundancy & | |||
33 | 37 | ||
34 | // Format for API or AP object | 38 | // Format for API or AP object |
35 | 39 | ||
36 | export type MVideoRedundancyAP = MVideoRedundancy & | 40 | export type MVideoRedundancyAP = |
41 | MVideoRedundancy & | ||
37 | PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> & | 42 | PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> & |
38 | PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>> | 43 | PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>> |
diff --git a/server/typings/models/video/video-share.ts b/server/typings/models/video/video-share.ts index a7a90beeb..50ca75d26 100644 --- a/server/typings/models/video/video-share.ts +++ b/server/typings/models/video/video-share.ts | |||
@@ -9,9 +9,11 @@ type Use<K extends keyof VideoShareModel, M> = PickWith<VideoShareModel, K, M> | |||
9 | 9 | ||
10 | export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'> | 10 | export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'> |
11 | 11 | ||
12 | export type MVideoShareActor = MVideoShare & | 12 | export type MVideoShareActor = |
13 | MVideoShare & | ||
13 | Use<'Actor', MActorDefault> | 14 | Use<'Actor', MActorDefault> |
14 | 15 | ||
15 | export type MVideoShareFull = MVideoShare & | 16 | export type MVideoShareFull = |
17 | MVideoShare & | ||
16 | Use<'Actor', MActorDefault> & | 18 | Use<'Actor', MActorDefault> & |
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
diff --git a/server/typings/models/video/video-streaming-playlist.ts b/server/typings/models/video/video-streaming-playlist.ts index 436c0c072..3f54aa560 100644 --- a/server/typings/models/video/video-streaming-playlist.ts +++ b/server/typings/models/video/video-streaming-playlist.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' | 1 | import { VideoStreamingPlaylistModel } from '../../../models/video/video-streaming-playlist' |
2 | import { PickWith, PickWithOpt } from '../../utils' | 2 | import { PickWith, PickWithOpt } from '../../utils' |
3 | import { MVideoRedundancyFileUrl } from './video-redundancy' | 3 | import { MVideoRedundancyFileUrl, MVideoRedundancy } from './video-redundancy' |
4 | import { MVideo } from './video' | 4 | import { MVideo } from './video' |
5 | import { MVideoFile } from './video-file' | 5 | import { MVideoFile } from './video-file' |
6 | 6 | ||
@@ -10,21 +10,31 @@ type Use<K extends keyof VideoStreamingPlaylistModel, M> = PickWith<VideoStreami | |||
10 | 10 | ||
11 | export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'> | 11 | export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'> |
12 | 12 | ||
13 | export type MStreamingPlaylistFiles = MStreamingPlaylist & | 13 | export type MStreamingPlaylistFiles = |
14 | MStreamingPlaylist & | ||
14 | Use<'VideoFiles', MVideoFile[]> | 15 | Use<'VideoFiles', MVideoFile[]> |
15 | 16 | ||
16 | export type MStreamingPlaylistVideo = MStreamingPlaylist & | 17 | export type MStreamingPlaylistVideo = |
18 | MStreamingPlaylist & | ||
17 | Use<'Video', MVideo> | 19 | Use<'Video', MVideo> |
18 | 20 | ||
19 | export type MStreamingPlaylistFilesVideo = MStreamingPlaylist & | 21 | export type MStreamingPlaylistFilesVideo = |
22 | MStreamingPlaylist & | ||
20 | Use<'VideoFiles', MVideoFile[]> & | 23 | Use<'VideoFiles', MVideoFile[]> & |
21 | Use<'Video', MVideo> | 24 | Use<'Video', MVideo> |
22 | 25 | ||
23 | export type MStreamingPlaylistRedundancies = MStreamingPlaylist & | 26 | export type MStreamingPlaylistRedundanciesAll = |
27 | MStreamingPlaylist & | ||
28 | Use<'VideoFiles', MVideoFile[]> & | ||
29 | Use<'RedundancyVideos', MVideoRedundancy[]> | ||
30 | |||
31 | export type MStreamingPlaylistRedundancies = | ||
32 | MStreamingPlaylist & | ||
24 | Use<'VideoFiles', MVideoFile[]> & | 33 | Use<'VideoFiles', MVideoFile[]> & |
25 | Use<'RedundancyVideos', MVideoRedundancyFileUrl[]> | 34 | Use<'RedundancyVideos', MVideoRedundancyFileUrl[]> |
26 | 35 | ||
27 | export type MStreamingPlaylistRedundanciesOpt = MStreamingPlaylist & | 36 | export type MStreamingPlaylistRedundanciesOpt = |
37 | MStreamingPlaylist & | ||
28 | Use<'VideoFiles', MVideoFile[]> & | 38 | Use<'VideoFiles', MVideoFile[]> & |
29 | PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> | 39 | PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]> |
30 | 40 | ||
diff --git a/server/typings/models/video/video.ts b/server/typings/models/video/video.ts index 7f69a91de..022a9566d 100644 --- a/server/typings/models/video/video.ts +++ b/server/typings/models/video/video.ts | |||
@@ -9,9 +9,14 @@ import { | |||
9 | MChannelUserId | 9 | MChannelUserId |
10 | } from './video-channels' | 10 | } from './video-channels' |
11 | import { MTag } from './tag' | 11 | import { MTag } from './tag' |
12 | import { MVideoCaptionLanguage } from './video-caption' | 12 | import { MVideoCaptionLanguage, MVideoCaptionLanguageUrl } from './video-caption' |
13 | import { MStreamingPlaylistFiles, MStreamingPlaylistRedundancies, MStreamingPlaylistRedundanciesOpt } from './video-streaming-playlist' | 13 | import { |
14 | import { MVideoFile, MVideoFileRedundanciesOpt } from './video-file' | 14 | MStreamingPlaylistFiles, |
15 | MStreamingPlaylistRedundancies, | ||
16 | MStreamingPlaylistRedundanciesAll, | ||
17 | MStreamingPlaylistRedundanciesOpt | ||
18 | } from './video-streaming-playlist' | ||
19 | import { MVideoFile, MVideoFileRedundanciesAll, MVideoFileRedundanciesOpt } from './video-file' | ||
15 | import { MThumbnail } from './thumbnail' | 20 | import { MThumbnail } from './thumbnail' |
16 | import { MVideoBlacklist, MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist' | 21 | import { MVideoBlacklist, MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist' |
17 | import { MScheduleVideoUpdate } from './schedule-video-update' | 22 | import { MScheduleVideoUpdate } from './schedule-video-update' |
@@ -21,7 +26,8 @@ type Use<K extends keyof VideoModel, M> = PickWith<VideoModel, K, M> | |||
21 | 26 | ||
22 | // ############################################################################ | 27 | // ############################################################################ |
23 | 28 | ||
24 | export type MVideo = Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' | | 29 | export type MVideo = |
30 | Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' | | ||
25 | 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' | | 31 | 'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' | |
26 | 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'> | 32 | 'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'> |
27 | 33 | ||
@@ -31,6 +37,7 @@ export type MVideoId = Pick<MVideo, 'id'> | |||
31 | export type MVideoUrl = Pick<MVideo, 'url'> | 37 | export type MVideoUrl = Pick<MVideo, 'url'> |
32 | export type MVideoUUID = Pick<MVideo, 'uuid'> | 38 | export type MVideoUUID = Pick<MVideo, 'uuid'> |
33 | 39 | ||
40 | export type MVideoImmutable = Pick<MVideo, 'id' | 'url' | 'uuid' | 'remote' | 'isOwned'> | ||
34 | export type MVideoIdUrl = MVideoId & MVideoUrl | 41 | export type MVideoIdUrl = MVideoId & MVideoUrl |
35 | export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'> | 42 | export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'> |
36 | 43 | ||
@@ -39,50 +46,63 @@ export type MVideoFeed = Pick<MVideo, 'name' | 'uuid'> | |||
39 | // Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists | 46 | // Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists |
40 | 47 | ||
41 | // "With" to not confuse with the VideoFile model | 48 | // "With" to not confuse with the VideoFile model |
42 | export type MVideoWithFile = MVideo & | 49 | export type MVideoWithFile = |
50 | MVideo & | ||
43 | Use<'VideoFiles', MVideoFile[]> & | 51 | Use<'VideoFiles', MVideoFile[]> & |
44 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 52 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
45 | 53 | ||
46 | export type MVideoThumbnail = MVideo & | 54 | export type MVideoThumbnail = |
55 | MVideo & | ||
47 | Use<'Thumbnails', MThumbnail[]> | 56 | Use<'Thumbnails', MThumbnail[]> |
48 | 57 | ||
49 | export type MVideoIdThumbnail = MVideoId & | 58 | export type MVideoIdThumbnail = |
59 | MVideoId & | ||
50 | Use<'Thumbnails', MThumbnail[]> | 60 | Use<'Thumbnails', MThumbnail[]> |
51 | 61 | ||
52 | export type MVideoWithFileThumbnail = MVideo & | 62 | export type MVideoWithFileThumbnail = |
63 | MVideo & | ||
53 | Use<'VideoFiles', MVideoFile[]> & | 64 | Use<'VideoFiles', MVideoFile[]> & |
54 | Use<'Thumbnails', MThumbnail[]> | 65 | Use<'Thumbnails', MThumbnail[]> |
55 | 66 | ||
56 | export type MVideoThumbnailBlacklist = MVideo & | 67 | export type MVideoThumbnailBlacklist = |
68 | MVideo & | ||
57 | Use<'Thumbnails', MThumbnail[]> & | 69 | Use<'Thumbnails', MThumbnail[]> & |
58 | Use<'VideoBlacklist', MVideoBlacklistLight> | 70 | Use<'VideoBlacklist', MVideoBlacklistLight> |
59 | 71 | ||
60 | export type MVideoTag = MVideo & | 72 | export type MVideoTag = |
73 | MVideo & | ||
61 | Use<'Tags', MTag[]> | 74 | Use<'Tags', MTag[]> |
62 | 75 | ||
63 | export type MVideoWithSchedule = MVideo & | 76 | export type MVideoWithSchedule = |
77 | MVideo & | ||
64 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate> | 78 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate> |
65 | 79 | ||
66 | export type MVideoWithCaptions = MVideo & | 80 | export type MVideoWithCaptions = |
81 | MVideo & | ||
67 | Use<'VideoCaptions', MVideoCaptionLanguage[]> | 82 | Use<'VideoCaptions', MVideoCaptionLanguage[]> |
68 | 83 | ||
69 | export type MVideoWithStreamingPlaylist = MVideo & | 84 | export type MVideoWithStreamingPlaylist = |
85 | MVideo & | ||
70 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 86 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
71 | 87 | ||
72 | // ############################################################################ | 88 | // ############################################################################ |
73 | 89 | ||
74 | // Associations with not all their attributes | 90 | // Associations with not all their attributes |
75 | 91 | ||
76 | export type MVideoUserHistory = MVideo & | 92 | export type MVideoUserHistory = |
93 | MVideo & | ||
77 | Use<'UserVideoHistories', MUserVideoHistoryTime[]> | 94 | Use<'UserVideoHistories', MUserVideoHistoryTime[]> |
78 | 95 | ||
79 | export type MVideoWithBlacklistLight = MVideo & | 96 | export type MVideoWithBlacklistLight = |
97 | MVideo & | ||
80 | Use<'VideoBlacklist', MVideoBlacklistLight> | 98 | Use<'VideoBlacklist', MVideoBlacklistLight> |
81 | 99 | ||
82 | export type MVideoAccountLight = MVideo & | 100 | export type MVideoAccountLight = |
101 | MVideo & | ||
83 | Use<'VideoChannel', MChannelAccountLight> | 102 | Use<'VideoChannel', MChannelAccountLight> |
84 | 103 | ||
85 | export type MVideoWithRights = MVideo & | 104 | export type MVideoWithRights = |
105 | MVideo & | ||
86 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 106 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
87 | Use<'Thumbnails', MThumbnail[]> & | 107 | Use<'Thumbnails', MThumbnail[]> & |
88 | Use<'VideoChannel', MChannelUserId> | 108 | Use<'VideoChannel', MChannelUserId> |
@@ -91,12 +111,14 @@ export type MVideoWithRights = MVideo & | |||
91 | 111 | ||
92 | // All files with some additional associations | 112 | // All files with some additional associations |
93 | 113 | ||
94 | export type MVideoWithAllFiles = MVideo & | 114 | export type MVideoWithAllFiles = |
115 | MVideo & | ||
95 | Use<'VideoFiles', MVideoFile[]> & | 116 | Use<'VideoFiles', MVideoFile[]> & |
96 | Use<'Thumbnails', MThumbnail[]> & | 117 | Use<'Thumbnails', MThumbnail[]> & |
97 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> | 118 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> |
98 | 119 | ||
99 | export type MVideoAccountLightBlacklistAllFiles = MVideo & | 120 | export type MVideoAccountLightBlacklistAllFiles = |
121 | MVideo & | ||
100 | Use<'VideoFiles', MVideoFile[]> & | 122 | Use<'VideoFiles', MVideoFile[]> & |
101 | Use<'Thumbnails', MThumbnail[]> & | 123 | Use<'Thumbnails', MThumbnail[]> & |
102 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & | 124 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & |
@@ -107,17 +129,21 @@ export type MVideoAccountLightBlacklistAllFiles = MVideo & | |||
107 | 129 | ||
108 | // With account | 130 | // With account |
109 | 131 | ||
110 | export type MVideoAccountDefault = MVideo & | 132 | export type MVideoAccountDefault = |
133 | MVideo & | ||
111 | Use<'VideoChannel', MChannelAccountDefault> | 134 | Use<'VideoChannel', MChannelAccountDefault> |
112 | 135 | ||
113 | export type MVideoThumbnailAccountDefault = MVideo & | 136 | export type MVideoThumbnailAccountDefault = |
137 | MVideo & | ||
114 | Use<'Thumbnails', MThumbnail[]> & | 138 | Use<'Thumbnails', MThumbnail[]> & |
115 | Use<'VideoChannel', MChannelAccountDefault> | 139 | Use<'VideoChannel', MChannelAccountDefault> |
116 | 140 | ||
117 | export type MVideoWithChannelActor = MVideo & | 141 | export type MVideoWithChannelActor = |
142 | MVideo & | ||
118 | Use<'VideoChannel', MChannelActor> | 143 | Use<'VideoChannel', MChannelActor> |
119 | 144 | ||
120 | export type MVideoFullLight = MVideo & | 145 | export type MVideoFullLight = |
146 | MVideo & | ||
121 | Use<'Thumbnails', MThumbnail[]> & | 147 | Use<'Thumbnails', MThumbnail[]> & |
122 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 148 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
123 | Use<'Tags', MTag[]> & | 149 | Use<'Tags', MTag[]> & |
@@ -131,18 +157,20 @@ export type MVideoFullLight = MVideo & | |||
131 | 157 | ||
132 | // API | 158 | // API |
133 | 159 | ||
134 | export type MVideoAP = MVideo & | 160 | export type MVideoAP = |
161 | MVideo & | ||
135 | Use<'Tags', MTag[]> & | 162 | Use<'Tags', MTag[]> & |
136 | Use<'VideoChannel', MChannelAccountLight> & | 163 | Use<'VideoChannel', MChannelAccountLight> & |
137 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & | 164 | Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> & |
138 | Use<'VideoCaptions', MVideoCaptionLanguage[]> & | 165 | Use<'VideoCaptions', MVideoCaptionLanguageUrl[]> & |
139 | Use<'VideoBlacklist', MVideoBlacklistUnfederated> & | 166 | Use<'VideoBlacklist', MVideoBlacklistUnfederated> & |
140 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> & | 167 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> & |
141 | Use<'Thumbnails', MThumbnail[]> | 168 | Use<'Thumbnails', MThumbnail[]> |
142 | 169 | ||
143 | export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'> | 170 | export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'> |
144 | 171 | ||
145 | export type MVideoDetails = MVideo & | 172 | export type MVideoDetails = |
173 | MVideo & | ||
146 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 174 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
147 | Use<'Tags', MTag[]> & | 175 | Use<'Tags', MTag[]> & |
148 | Use<'VideoChannel', MChannelAccountLight> & | 176 | Use<'VideoChannel', MChannelAccountLight> & |
@@ -152,23 +180,31 @@ export type MVideoDetails = MVideo & | |||
152 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> & | 180 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> & |
153 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> | 181 | Use<'VideoFiles', MVideoFileRedundanciesOpt[]> |
154 | 182 | ||
155 | export type MVideoForUser = MVideo & | 183 | export type MVideoForUser = |
184 | MVideo & | ||
156 | Use<'VideoChannel', MChannelAccountDefault> & | 185 | Use<'VideoChannel', MChannelAccountDefault> & |
157 | Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> & | 186 | Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> & |
158 | Use<'VideoBlacklist', MVideoBlacklistLight> & | 187 | Use<'VideoBlacklist', MVideoBlacklistLight> & |
159 | Use<'Thumbnails', MThumbnail[]> | 188 | Use<'Thumbnails', MThumbnail[]> |
160 | 189 | ||
190 | export type MVideoForRedundancyAPI = | ||
191 | MVideo & | ||
192 | Use<'VideoFiles', MVideoFileRedundanciesAll[]> & | ||
193 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesAll[]> | ||
194 | |||
161 | // ############################################################################ | 195 | // ############################################################################ |
162 | 196 | ||
163 | // Format for API or AP object | 197 | // Format for API or AP object |
164 | 198 | ||
165 | export type MVideoFormattable = MVideo & | 199 | export type MVideoFormattable = |
200 | MVideo & | ||
166 | PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> & | 201 | PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> & |
167 | Use<'VideoChannel', MChannelAccountSummaryFormattable> & | 202 | Use<'VideoChannel', MChannelAccountSummaryFormattable> & |
168 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> & | 203 | PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> & |
169 | PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> | 204 | PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> |
170 | 205 | ||
171 | export type MVideoFormattableDetails = MVideoFormattable & | 206 | export type MVideoFormattableDetails = |
207 | MVideoFormattable & | ||
172 | Use<'VideoChannel', MChannelFormattable> & | 208 | Use<'VideoChannel', MChannelFormattable> & |
173 | Use<'Tags', MTag[]> & | 209 | Use<'Tags', MTag[]> & |
174 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> & | 210 | Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> & |
diff --git a/server/typings/utils.ts b/server/typings/utils.ts index 24d43b258..55500d8c4 100644 --- a/server/typings/utils.ts +++ b/server/typings/utils.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | /* eslint-disable @typescript-eslint/array-type */ | ||
2 | |||
1 | export type FunctionPropertyNames<T> = { | 3 | export type FunctionPropertyNames<T> = { |
2 | [K in keyof T]: T[K] extends Function ? K : never | 4 | [K in keyof T]: T[K] extends Function ? K : never |
3 | }[keyof T] | 5 | }[keyof T] |