diff options
34 files changed, 111 insertions, 1367 deletions
diff --git a/server/controllers/activitypub/videos.ts b/server/controllers/activitypub/videos.ts index 9a1868ff7..a9b31bf75 100644 --- a/server/controllers/activitypub/videos.ts +++ b/server/controllers/activitypub/videos.ts | |||
@@ -32,8 +32,8 @@ | |||
32 | // RemoteVideoChannelCreateData, | 32 | // RemoteVideoChannelCreateData, |
33 | // RemoteVideoChannelUpdateData, | 33 | // RemoteVideoChannelUpdateData, |
34 | // RemoteVideoChannelRemoveData, | 34 | // RemoteVideoChannelRemoveData, |
35 | // RemoteVideoAuthorRemoveData, | 35 | // RemoteVideoAccountRemoveData, |
36 | // RemoteVideoAuthorCreateData | 36 | // RemoteVideoAccountCreateData |
37 | // } from '../../../../shared' | 37 | // } from '../../../../shared' |
38 | // import { VideoInstance } from '../../../models/video/video-interface' | 38 | // import { VideoInstance } from '../../../models/video/video-interface' |
39 | // | 39 | // |
@@ -49,8 +49,8 @@ | |||
49 | // functionsHash[ENDPOINT_ACTIONS.UPDATE_CHANNEL] = updateRemoteVideoChannelRetryWrapper | 49 | // functionsHash[ENDPOINT_ACTIONS.UPDATE_CHANNEL] = updateRemoteVideoChannelRetryWrapper |
50 | // functionsHash[ENDPOINT_ACTIONS.REMOVE_CHANNEL] = removeRemoteVideoChannelRetryWrapper | 50 | // functionsHash[ENDPOINT_ACTIONS.REMOVE_CHANNEL] = removeRemoteVideoChannelRetryWrapper |
51 | // functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideoRetryWrapper | 51 | // functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideoRetryWrapper |
52 | // functionsHash[ENDPOINT_ACTIONS.ADD_AUTHOR] = addRemoteVideoAuthorRetryWrapper | 52 | // functionsHash[ENDPOINT_ACTIONS.ADD_ACCOUNT] = addRemoteVideoAccountRetryWrapper |
53 | // functionsHash[ENDPOINT_ACTIONS.REMOVE_AUTHOR] = removeRemoteVideoAuthorRetryWrapper | 53 | // functionsHash[ENDPOINT_ACTIONS.REMOVE_ACCOUNT] = removeRemoteVideoAccountRetryWrapper |
54 | // | 54 | // |
55 | // const remoteVideosRouter = express.Router() | 55 | // const remoteVideosRouter = express.Router() |
56 | // | 56 | // |
@@ -245,24 +245,24 @@ | |||
245 | // logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid) | 245 | // logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid) |
246 | // } | 246 | // } |
247 | // | 247 | // |
248 | // async function removeRemoteVideoAuthorRetryWrapper (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) { | 248 | // async function removeRemoteVideoAccountRetryWrapper (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) { |
249 | // const options = { | 249 | // const options = { |
250 | // arguments: [ authorAttributesToRemove, fromPod ], | 250 | // arguments: [ accountAttributesToRemove, fromPod ], |
251 | // errorMessage: 'Cannot remove the remote video author with many retries.' | 251 | // errorMessage: 'Cannot remove the remote video account with many retries.' |
252 | // } | 252 | // } |
253 | // | 253 | // |
254 | // await retryTransactionWrapper(removeRemoteVideoAuthor, options) | 254 | // await retryTransactionWrapper(removeRemoteVideoAccount, options) |
255 | // } | 255 | // } |
256 | // | 256 | // |
257 | // async function removeRemoteVideoAuthor (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) { | 257 | // async function removeRemoteVideoAccount (accountAttributesToRemove: RemoteVideoAccountRemoveData, fromPod: PodInstance) { |
258 | // logger.debug('Removing remote video author "%s".', authorAttributesToRemove.uuid) | 258 | // logger.debug('Removing remote video account "%s".', accountAttributesToRemove.uuid) |
259 | // | 259 | // |
260 | // await db.sequelize.transaction(async t => { | 260 | // await db.sequelize.transaction(async t => { |
261 | // const videoAuthor = await db.Author.loadAuthorByPodAndUUID(authorAttributesToRemove.uuid, fromPod.id, t) | 261 | // const videoAccount = await db.Account.loadAccountByPodAndUUID(accountAttributesToRemove.uuid, fromPod.id, t) |
262 | // await videoAuthor.destroy({ transaction: t }) | 262 | // await videoAccount.destroy({ transaction: t }) |
263 | // }) | 263 | // }) |
264 | // | 264 | // |
265 | // logger.info('Remote video author with uuid %s removed.', authorAttributesToRemove.uuid) | 265 | // logger.info('Remote video account with uuid %s removed.', accountAttributesToRemove.uuid) |
266 | // } | 266 | // } |
267 | // | 267 | // |
268 | // async function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) { | 268 | // async function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) { |
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index bacfc4552..9ec6feb57 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts | |||
@@ -28,7 +28,7 @@ import { | |||
28 | UserRole, | 28 | UserRole, |
29 | UserRight | 29 | UserRight |
30 | } from '../../../shared' | 30 | } from '../../../shared' |
31 | import { createUserAuthorAndChannel } from '../../lib' | 31 | import { createUserAccountAndChannel } from '../../lib' |
32 | import { UserInstance } from '../../models' | 32 | import { UserInstance } from '../../models' |
33 | import { videosSortValidator } from '../../middlewares/validators/sort' | 33 | import { videosSortValidator } from '../../middlewares/validators/sort' |
34 | import { setVideosSort } from '../../middlewares/sort' | 34 | import { setVideosSort } from '../../middlewares/sort' |
@@ -142,9 +142,9 @@ async function createUser (req: express.Request, res: express.Response, next: ex | |||
142 | videoQuota: body.videoQuota | 142 | videoQuota: body.videoQuota |
143 | }) | 143 | }) |
144 | 144 | ||
145 | await createUserAuthorAndChannel(user) | 145 | await createUserAccountAndChannel(user) |
146 | 146 | ||
147 | logger.info('User %s with its channel and author created.', body.username) | 147 | logger.info('User %s with its channel and account created.', body.username) |
148 | } | 148 | } |
149 | 149 | ||
150 | async function registerUser (req: express.Request, res: express.Response, next: express.NextFunction) { | 150 | async function registerUser (req: express.Request, res: express.Response, next: express.NextFunction) { |
@@ -159,7 +159,7 @@ async function registerUser (req: express.Request, res: express.Response, next: | |||
159 | videoQuota: CONFIG.USER.VIDEO_QUOTA | 159 | videoQuota: CONFIG.USER.VIDEO_QUOTA |
160 | }) | 160 | }) |
161 | 161 | ||
162 | await createUserAuthorAndChannel(user) | 162 | await createUserAccountAndChannel(user) |
163 | return res.type('json').status(204).end() | 163 | return res.type('json').status(204).end() |
164 | } | 164 | } |
165 | 165 | ||
diff --git a/server/controllers/api/videos/channel.ts b/server/controllers/api/videos/channel.ts index ab54eedee..4d1f03903 100644 --- a/server/controllers/api/videos/channel.ts +++ b/server/controllers/api/videos/channel.ts | |||
@@ -17,14 +17,14 @@ import { | |||
17 | videoChannelsRemoveValidator, | 17 | videoChannelsRemoveValidator, |
18 | videoChannelGetValidator, | 18 | videoChannelGetValidator, |
19 | videoChannelsUpdateValidator, | 19 | videoChannelsUpdateValidator, |
20 | listVideoAuthorChannelsValidator, | 20 | listVideoAccountChannelsValidator, |
21 | asyncMiddleware | 21 | asyncMiddleware |
22 | } from '../../../middlewares' | 22 | } from '../../../middlewares' |
23 | import { | 23 | import { |
24 | createVideoChannel, | 24 | createVideoChannel, |
25 | updateVideoChannelToFriends | 25 | updateVideoChannelToFriends |
26 | } from '../../../lib' | 26 | } from '../../../lib' |
27 | import { VideoChannelInstance, AuthorInstance } from '../../../models' | 27 | import { VideoChannelInstance, AccountInstance } from '../../../models' |
28 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared' | 28 | import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared' |
29 | 29 | ||
30 | const videoChannelRouter = express.Router() | 30 | const videoChannelRouter = express.Router() |
@@ -37,9 +37,9 @@ videoChannelRouter.get('/channels', | |||
37 | asyncMiddleware(listVideoChannels) | 37 | asyncMiddleware(listVideoChannels) |
38 | ) | 38 | ) |
39 | 39 | ||
40 | videoChannelRouter.get('/authors/:authorId/channels', | 40 | videoChannelRouter.get('/accounts/:accountId/channels', |
41 | listVideoAuthorChannelsValidator, | 41 | listVideoAccountChannelsValidator, |
42 | asyncMiddleware(listVideoAuthorChannels) | 42 | asyncMiddleware(listVideoAccountChannels) |
43 | ) | 43 | ) |
44 | 44 | ||
45 | videoChannelRouter.post('/channels', | 45 | videoChannelRouter.post('/channels', |
@@ -79,8 +79,8 @@ async function listVideoChannels (req: express.Request, res: express.Response, n | |||
79 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 79 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
80 | } | 80 | } |
81 | 81 | ||
82 | async function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) { | 82 | async function listVideoAccountChannels (req: express.Request, res: express.Response, next: express.NextFunction) { |
83 | const resultList = await db.VideoChannel.listByAuthor(res.locals.author.id) | 83 | const resultList = await db.VideoChannel.listByAccount(res.locals.account.id) |
84 | 84 | ||
85 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 85 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
86 | } | 86 | } |
@@ -101,11 +101,11 @@ async function addVideoChannelRetryWrapper (req: express.Request, res: express.R | |||
101 | 101 | ||
102 | async function addVideoChannel (req: express.Request, res: express.Response) { | 102 | async function addVideoChannel (req: express.Request, res: express.Response) { |
103 | const videoChannelInfo: VideoChannelCreate = req.body | 103 | const videoChannelInfo: VideoChannelCreate = req.body |
104 | const author: AuthorInstance = res.locals.oauth.token.User.Author | 104 | const account: AccountInstance = res.locals.oauth.token.User.Account |
105 | let videoChannelCreated: VideoChannelInstance | 105 | let videoChannelCreated: VideoChannelInstance |
106 | 106 | ||
107 | await db.sequelize.transaction(async t => { | 107 | await db.sequelize.transaction(async t => { |
108 | videoChannelCreated = await createVideoChannel(videoChannelInfo, author, t) | 108 | videoChannelCreated = await createVideoChannel(videoChannelInfo, account, t) |
109 | }) | 109 | }) |
110 | 110 | ||
111 | logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid) | 111 | logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid) |
@@ -179,7 +179,7 @@ async function removeVideoChannel (req: express.Request, res: express.Response) | |||
179 | } | 179 | } |
180 | 180 | ||
181 | async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { | 181 | async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { |
182 | const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id) | 182 | const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAccountAndVideos(res.locals.videoChannel.id) |
183 | 183 | ||
184 | return res.json(videoChannelWithVideos.toFormattedJSON()) | 184 | return res.json(videoChannelWithVideos.toFormattedJSON()) |
185 | } | 185 | } |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 964db151d..9ad84609f 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -395,7 +395,7 @@ async function removeVideo (req: express.Request, res: express.Response) { | |||
395 | } | 395 | } |
396 | 396 | ||
397 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 397 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
398 | const resultList = await db.Video.searchAndPopulateAuthorAndPodAndTags( | 398 | const resultList = await db.Video.searchAndPopulateAccountAndPodAndTags( |
399 | req.params.value, | 399 | req.params.value, |
400 | req.query.field, | 400 | req.query.field, |
401 | req.query.start, | 401 | req.query.start, |
diff --git a/server/controllers/client.ts b/server/controllers/client.ts index 67ebfcf1d..40dda7584 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts | |||
@@ -110,9 +110,9 @@ async function generateWatchHtmlPage (req: express.Request, res: express.Respons | |||
110 | 110 | ||
111 | // Let Angular application handle errors | 111 | // Let Angular application handle errors |
112 | if (validator.isUUID(videoId, 4)) { | 112 | if (validator.isUUID(videoId, 4)) { |
113 | videoPromise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(videoId) | 113 | videoPromise = db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(videoId) |
114 | } else if (validator.isInt(videoId)) { | 114 | } else if (validator.isInt(videoId)) { |
115 | videoPromise = db.Video.loadAndPopulateAuthorAndPodAndTags(+videoId) | 115 | videoPromise = db.Video.loadAndPopulateAccountAndPodAndTags(+videoId) |
116 | } else { | 116 | } else { |
117 | return res.sendFile(indexPath) | 117 | return res.sendFile(indexPath) |
118 | } | 118 | } |
diff --git a/server/controllers/services.ts b/server/controllers/services.ts index 99a33a716..0db6e5498 100644 --- a/server/controllers/services.ts +++ b/server/controllers/services.ts | |||
@@ -47,7 +47,7 @@ function generateOEmbed (req: express.Request, res: express.Response, next: expr | |||
47 | width: embedWidth, | 47 | width: embedWidth, |
48 | height: embedHeight, | 48 | height: embedHeight, |
49 | title: video.name, | 49 | title: video.name, |
50 | author_name: video.VideoChannel.Author.name, | 50 | author_name: video.VideoChannel.Account.name, |
51 | provider_name: 'PeerTube', | 51 | provider_name: 'PeerTube', |
52 | provider_url: webserverUrl | 52 | provider_url: webserverUrl |
53 | } | 53 | } |
diff --git a/server/helpers/custom-validators/index.ts b/server/helpers/custom-validators/index.ts index 58a40249b..33922b8fe 100644 --- a/server/helpers/custom-validators/index.ts +++ b/server/helpers/custom-validators/index.ts | |||
@@ -3,5 +3,6 @@ export * from './misc' | |||
3 | export * from './pods' | 3 | export * from './pods' |
4 | export * from './pods' | 4 | export * from './pods' |
5 | export * from './users' | 5 | export * from './users' |
6 | export * from './video-accounts' | ||
6 | export * from './video-channels' | 7 | export * from './video-channels' |
7 | export * from './videos' | 8 | export * from './videos' |
diff --git a/server/helpers/custom-validators/video-accounts.ts b/server/helpers/custom-validators/video-accounts.ts new file mode 100644 index 000000000..3f3e9edd1 --- /dev/null +++ b/server/helpers/custom-validators/video-accounts.ts | |||
@@ -0,0 +1,45 @@ | |||
1 | import * as Promise from 'bluebird' | ||
2 | import * as validator from 'validator' | ||
3 | import * as express from 'express' | ||
4 | import 'express-validator' | ||
5 | |||
6 | import { database as db } from '../../initializers' | ||
7 | import { AccountInstance } from '../../models' | ||
8 | import { logger } from '../logger' | ||
9 | |||
10 | import { isUserUsernameValid } from './users' | ||
11 | |||
12 | function isVideoAccountNameValid (value: string) { | ||
13 | return isUserUsernameValid(value) | ||
14 | } | ||
15 | |||
16 | function checkVideoAccountExists (id: string, res: express.Response, callback: () => void) { | ||
17 | let promise: Promise<AccountInstance> | ||
18 | if (validator.isInt(id)) { | ||
19 | promise = db.Account.load(+id) | ||
20 | } else { // UUID | ||
21 | promise = db.Account.loadByUUID(id) | ||
22 | } | ||
23 | |||
24 | promise.then(account => { | ||
25 | if (!account) { | ||
26 | return res.status(404) | ||
27 | .json({ error: 'Video account not found' }) | ||
28 | .end() | ||
29 | } | ||
30 | |||
31 | res.locals.account = account | ||
32 | callback() | ||
33 | }) | ||
34 | .catch(err => { | ||
35 | logger.error('Error in video account request validator.', err) | ||
36 | return res.sendStatus(500) | ||
37 | }) | ||
38 | } | ||
39 | |||
40 | // --------------------------------------------------------------------------- | ||
41 | |||
42 | export { | ||
43 | checkVideoAccountExists, | ||
44 | isVideoAccountNameValid | ||
45 | } | ||
diff --git a/server/helpers/custom-validators/video-channels.ts b/server/helpers/custom-validators/video-channels.ts index b6be557e6..acc42f4a4 100644 --- a/server/helpers/custom-validators/video-channels.ts +++ b/server/helpers/custom-validators/video-channels.ts | |||
@@ -26,9 +26,9 @@ function isVideoChannelUUIDValid (value: string) { | |||
26 | function checkVideoChannelExists (id: string, res: express.Response, callback: () => void) { | 26 | function checkVideoChannelExists (id: string, res: express.Response, callback: () => void) { |
27 | let promise: Promise<VideoChannelInstance> | 27 | let promise: Promise<VideoChannelInstance> |
28 | if (validator.isInt(id)) { | 28 | if (validator.isInt(id)) { |
29 | promise = db.VideoChannel.loadAndPopulateAuthor(+id) | 29 | promise = db.VideoChannel.loadAndPopulateAccount(+id) |
30 | } else { // UUID | 30 | } else { // UUID |
31 | promise = db.VideoChannel.loadByUUIDAndPopulateAuthor(id) | 31 | promise = db.VideoChannel.loadByUUIDAndPopulateAccount(id) |
32 | } | 32 | } |
33 | 33 | ||
34 | promise.then(videoChannel => { | 34 | promise.then(videoChannel => { |
diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 83407f17b..487b3d646 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts | |||
@@ -166,9 +166,9 @@ function isVideoFileInfoHashValid (value: string) { | |||
166 | function checkVideoExists (id: string, res: express.Response, callback: () => void) { | 166 | function checkVideoExists (id: string, res: express.Response, callback: () => void) { |
167 | let promise: Promise<VideoInstance> | 167 | let promise: Promise<VideoInstance> |
168 | if (validator.isInt(id)) { | 168 | if (validator.isInt(id)) { |
169 | promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id) | 169 | promise = db.Video.loadAndPopulateAccountAndPodAndTags(+id) |
170 | } else { // UUID | 170 | } else { // UUID |
171 | promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id) | 171 | promise = db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(id) |
172 | } | 172 | } |
173 | 173 | ||
174 | promise.then(video => { | 174 | promise.then(video => { |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index e1f877e80..e6fda88c2 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -29,7 +29,7 @@ const PAGINATION_COUNT_DEFAULT = 15 | |||
29 | 29 | ||
30 | // Sortable columns per schema | 30 | // Sortable columns per schema |
31 | const SEARCHABLE_COLUMNS = { | 31 | const SEARCHABLE_COLUMNS = { |
32 | VIDEOS: [ 'name', 'magnetUri', 'host', 'author', 'tags' ] | 32 | VIDEOS: [ 'name', 'magnetUri', 'host', 'account', 'tags' ] |
33 | } | 33 | } |
34 | 34 | ||
35 | // Sortable columns per schema | 35 | // Sortable columns per schema |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 52e766394..aefb6da3a 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -44,10 +44,6 @@ const database: { | |||
44 | OAuthClient?: OAuthClientModel, | 44 | OAuthClient?: OAuthClientModel, |
45 | OAuthToken?: OAuthTokenModel, | 45 | OAuthToken?: OAuthTokenModel, |
46 | Pod?: PodModel, | 46 | Pod?: PodModel, |
47 | RequestToPod?: RequestToPodModel, | ||
48 | RequestVideoEvent?: RequestVideoEventModel, | ||
49 | RequestVideoQadu?: RequestVideoQaduModel, | ||
50 | Request?: RequestModel, | ||
51 | Tag?: TagModel, | 47 | Tag?: TagModel, |
52 | AccountVideoRate?: AccountVideoRateModel, | 48 | AccountVideoRate?: AccountVideoRateModel, |
53 | AccountFollow?: AccountFollowModel, | 49 | AccountFollow?: AccountFollowModel, |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 077472341..c8f6b3bc2 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts | |||
@@ -5,7 +5,7 @@ import { database as db } from './database' | |||
5 | import { CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants' | 5 | import { CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants' |
6 | import { clientsExist, usersExist } from './checker' | 6 | import { clientsExist, usersExist } from './checker' |
7 | import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers' | 7 | import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers' |
8 | import { createUserAuthorAndChannel } from '../lib' | 8 | import { createUserAccountAndChannel } from '../lib' |
9 | import { UserRole } from '../../shared' | 9 | import { UserRole } from '../../shared' |
10 | 10 | ||
11 | async function installApplication () { | 11 | async function installApplication () { |
@@ -117,7 +117,7 @@ async function createOAuthAdminIfNotExist () { | |||
117 | } | 117 | } |
118 | const user = db.User.build(userData) | 118 | const user = db.User.build(userData) |
119 | 119 | ||
120 | await createUserAuthorAndChannel(user, validatePassword) | 120 | await createUserAccountAndChannel(user, validatePassword) |
121 | logger.info('Username: ' + username) | 121 | logger.info('Username: ' + username) |
122 | logger.info('User password: ' + password) | 122 | logger.info('User password: ' + password) |
123 | 123 | ||
diff --git a/server/lib/cache/videos-preview-cache.ts b/server/lib/cache/videos-preview-cache.ts index 0fe4d2f78..791ad1cbf 100644 --- a/server/lib/cache/videos-preview-cache.ts +++ b/server/lib/cache/videos-preview-cache.ts | |||
@@ -43,7 +43,7 @@ class VideosPreviewCache { | |||
43 | } | 43 | } |
44 | 44 | ||
45 | private async loadPreviews (key: string) { | 45 | private async loadPreviews (key: string) { |
46 | const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(key) | 46 | const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(key) |
47 | if (!video) return undefined | 47 | if (!video) return undefined |
48 | 48 | ||
49 | if (video.isOwned()) return join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()) | 49 | if (video.isOwned()) return join(CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName()) |
diff --git a/server/lib/friends.ts b/server/lib/friends.ts deleted file mode 100644 index 5c9baef47..000000000 --- a/server/lib/friends.ts +++ /dev/null | |||
@@ -1,567 +0,0 @@ | |||
1 | import * as request from 'request' | ||
2 | import * as Sequelize from 'sequelize' | ||
3 | import * as Bluebird from 'bluebird' | ||
4 | import { join } from 'path' | ||
5 | |||
6 | import { database as db } from '../initializers/database' | ||
7 | import { | ||
8 | API_VERSION, | ||
9 | CONFIG, | ||
10 | REQUESTS_IN_PARALLEL, | ||
11 | REQUEST_ENDPOINTS, | ||
12 | REQUEST_ENDPOINT_ACTIONS, | ||
13 | REMOTE_SCHEME, | ||
14 | STATIC_PATHS | ||
15 | } from '../initializers' | ||
16 | import { | ||
17 | logger, | ||
18 | getMyPublicCert, | ||
19 | makeSecureRequest, | ||
20 | makeRetryRequest | ||
21 | } from '../helpers' | ||
22 | import { | ||
23 | RequestScheduler, | ||
24 | RequestSchedulerOptions, | ||
25 | |||
26 | RequestVideoQaduScheduler, | ||
27 | RequestVideoQaduSchedulerOptions, | ||
28 | |||
29 | RequestVideoEventScheduler, | ||
30 | RequestVideoEventSchedulerOptions | ||
31 | } from './request' | ||
32 | import { | ||
33 | PodInstance, | ||
34 | VideoInstance | ||
35 | } from '../models' | ||
36 | import { | ||
37 | RequestEndpoint, | ||
38 | RequestVideoEventType, | ||
39 | RequestVideoQaduType, | ||
40 | RemoteVideoCreateData, | ||
41 | RemoteVideoUpdateData, | ||
42 | RemoteVideoRemoveData, | ||
43 | RemoteVideoReportAbuseData, | ||
44 | ResultList, | ||
45 | RemoteVideoRequestType, | ||
46 | Pod as FormattedPod, | ||
47 | RemoteVideoChannelCreateData, | ||
48 | RemoteVideoChannelUpdateData, | ||
49 | RemoteVideoChannelRemoveData, | ||
50 | RemoteVideoAuthorCreateData, | ||
51 | RemoteVideoAuthorRemoveData | ||
52 | } from '../../shared' | ||
53 | |||
54 | type QaduParam = { videoId: number, type: RequestVideoQaduType } | ||
55 | type EventParam = { videoId: number, type: RequestVideoEventType } | ||
56 | |||
57 | const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] | ||
58 | |||
59 | const requestScheduler = new RequestScheduler() | ||
60 | const requestVideoQaduScheduler = new RequestVideoQaduScheduler() | ||
61 | const requestVideoEventScheduler = new RequestVideoEventScheduler() | ||
62 | |||
63 | function activateSchedulers () { | ||
64 | requestScheduler.activate() | ||
65 | requestVideoQaduScheduler.activate() | ||
66 | requestVideoEventScheduler.activate() | ||
67 | } | ||
68 | |||
69 | function addVideoToFriends (videoData: RemoteVideoCreateData, transaction: Sequelize.Transaction) { | ||
70 | const options = { | ||
71 | type: ENDPOINT_ACTIONS.ADD_VIDEO, | ||
72 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
73 | data: videoData, | ||
74 | transaction | ||
75 | } | ||
76 | return createRequest(options) | ||
77 | } | ||
78 | |||
79 | function updateVideoToFriends (videoData: RemoteVideoUpdateData, transaction: Sequelize.Transaction) { | ||
80 | const options = { | ||
81 | type: ENDPOINT_ACTIONS.UPDATE_VIDEO, | ||
82 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
83 | data: videoData, | ||
84 | transaction | ||
85 | } | ||
86 | return createRequest(options) | ||
87 | } | ||
88 | |||
89 | function removeVideoToFriends (videoParams: RemoteVideoRemoveData, transaction?: Sequelize.Transaction) { | ||
90 | const options = { | ||
91 | type: ENDPOINT_ACTIONS.REMOVE_VIDEO, | ||
92 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
93 | data: videoParams, | ||
94 | transaction | ||
95 | } | ||
96 | return createRequest(options) | ||
97 | } | ||
98 | |||
99 | function addVideoAuthorToFriends (authorData: RemoteVideoAuthorCreateData, transaction: Sequelize.Transaction) { | ||
100 | const options = { | ||
101 | type: ENDPOINT_ACTIONS.ADD_AUTHOR, | ||
102 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
103 | data: authorData, | ||
104 | transaction | ||
105 | } | ||
106 | return createRequest(options) | ||
107 | } | ||
108 | |||
109 | function removeVideoAuthorToFriends (authorData: RemoteVideoAuthorRemoveData, transaction?: Sequelize.Transaction) { | ||
110 | const options = { | ||
111 | type: ENDPOINT_ACTIONS.REMOVE_AUTHOR, | ||
112 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
113 | data: authorData, | ||
114 | transaction | ||
115 | } | ||
116 | return createRequest(options) | ||
117 | } | ||
118 | |||
119 | function addVideoChannelToFriends (videoChannelData: RemoteVideoChannelCreateData, transaction: Sequelize.Transaction) { | ||
120 | const options = { | ||
121 | type: ENDPOINT_ACTIONS.ADD_CHANNEL, | ||
122 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
123 | data: videoChannelData, | ||
124 | transaction | ||
125 | } | ||
126 | return createRequest(options) | ||
127 | } | ||
128 | |||
129 | function updateVideoChannelToFriends (videoChannelData: RemoteVideoChannelUpdateData, transaction: Sequelize.Transaction) { | ||
130 | const options = { | ||
131 | type: ENDPOINT_ACTIONS.UPDATE_CHANNEL, | ||
132 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
133 | data: videoChannelData, | ||
134 | transaction | ||
135 | } | ||
136 | return createRequest(options) | ||
137 | } | ||
138 | |||
139 | function removeVideoChannelToFriends (videoChannelParams: RemoteVideoChannelRemoveData, transaction?: Sequelize.Transaction) { | ||
140 | const options = { | ||
141 | type: ENDPOINT_ACTIONS.REMOVE_CHANNEL, | ||
142 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
143 | data: videoChannelParams, | ||
144 | transaction | ||
145 | } | ||
146 | return createRequest(options) | ||
147 | } | ||
148 | |||
149 | function reportAbuseVideoToFriend (reportData: RemoteVideoReportAbuseData, video: VideoInstance, transaction: Sequelize.Transaction) { | ||
150 | const options = { | ||
151 | type: ENDPOINT_ACTIONS.REPORT_ABUSE, | ||
152 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
153 | data: reportData, | ||
154 | toIds: [ video.VideoChannel.Author.podId ], | ||
155 | transaction | ||
156 | } | ||
157 | return createRequest(options) | ||
158 | } | ||
159 | |||
160 | function quickAndDirtyUpdateVideoToFriends (qaduParam: QaduParam, transaction?: Sequelize.Transaction) { | ||
161 | const options = { | ||
162 | videoId: qaduParam.videoId, | ||
163 | type: qaduParam.type, | ||
164 | transaction | ||
165 | } | ||
166 | return createVideoQaduRequest(options) | ||
167 | } | ||
168 | |||
169 | function quickAndDirtyUpdatesVideoToFriends (qadusParams: QaduParam[], transaction: Sequelize.Transaction) { | ||
170 | const tasks = [] | ||
171 | |||
172 | qadusParams.forEach(qaduParams => { | ||
173 | tasks.push(quickAndDirtyUpdateVideoToFriends(qaduParams, transaction)) | ||
174 | }) | ||
175 | |||
176 | return Promise.all(tasks) | ||
177 | } | ||
178 | |||
179 | function addEventToRemoteVideo (eventParam: EventParam, transaction?: Sequelize.Transaction) { | ||
180 | const options = { | ||
181 | videoId: eventParam.videoId, | ||
182 | type: eventParam.type, | ||
183 | transaction | ||
184 | } | ||
185 | return createVideoEventRequest(options) | ||
186 | } | ||
187 | |||
188 | function addEventsToRemoteVideo (eventsParams: EventParam[], transaction: Sequelize.Transaction) { | ||
189 | const tasks = [] | ||
190 | |||
191 | for (const eventParams of eventsParams) { | ||
192 | tasks.push(addEventToRemoteVideo(eventParams, transaction)) | ||
193 | } | ||
194 | |||
195 | return Promise.all(tasks) | ||
196 | } | ||
197 | |||
198 | async function hasFriends () { | ||
199 | const count = await db.Pod.countAll() | ||
200 | |||
201 | return count !== 0 | ||
202 | } | ||
203 | |||
204 | async function makeFriends (hosts: string[]) { | ||
205 | const podsScore = {} | ||
206 | |||
207 | logger.info('Make friends!') | ||
208 | const cert = await getMyPublicCert() | ||
209 | |||
210 | for (const host of hosts) { | ||
211 | await computeForeignPodsList(host, podsScore) | ||
212 | } | ||
213 | |||
214 | logger.debug('Pods scores computed.', { podsScore: podsScore }) | ||
215 | |||
216 | const podsList = computeWinningPods(hosts, podsScore) | ||
217 | logger.debug('Pods that we keep.', { podsToKeep: podsList }) | ||
218 | |||
219 | return makeRequestsToWinningPods(cert, podsList) | ||
220 | } | ||
221 | |||
222 | async function quitFriends () { | ||
223 | // Stop pool requests | ||
224 | requestScheduler.deactivate() | ||
225 | |||
226 | try { | ||
227 | await requestScheduler.flush() | ||
228 | |||
229 | await requestVideoQaduScheduler.flush() | ||
230 | |||
231 | const pods = await db.Pod.list() | ||
232 | const requestParams = { | ||
233 | method: 'POST' as 'POST', | ||
234 | path: '/api/' + API_VERSION + '/remote/pods/remove', | ||
235 | toPod: null | ||
236 | } | ||
237 | |||
238 | // Announce we quit them | ||
239 | // We don't care if the request fails | ||
240 | // The other pod will exclude us automatically after a while | ||
241 | try { | ||
242 | await Bluebird.map(pods, pod => { | ||
243 | requestParams.toPod = pod | ||
244 | |||
245 | return makeSecureRequest(requestParams) | ||
246 | }, { concurrency: REQUESTS_IN_PARALLEL }) | ||
247 | } catch (err) { // Don't stop the process | ||
248 | logger.error('Some errors while quitting friends.', err) | ||
249 | } | ||
250 | |||
251 | const tasks = [] | ||
252 | for (const pod of pods) { | ||
253 | tasks.push(pod.destroy()) | ||
254 | } | ||
255 | await Promise.all(pods) | ||
256 | |||
257 | logger.info('Removed all remote videos.') | ||
258 | |||
259 | requestScheduler.activate() | ||
260 | } catch (err) { | ||
261 | // Don't forget to re activate the scheduler, even if there was an error | ||
262 | requestScheduler.activate() | ||
263 | |||
264 | throw err | ||
265 | } | ||
266 | } | ||
267 | |||
268 | async function sendOwnedDataToPod (podId: number) { | ||
269 | // First send authors | ||
270 | await sendOwnedAuthorsToPod(podId) | ||
271 | await sendOwnedChannelsToPod(podId) | ||
272 | await sendOwnedVideosToPod(podId) | ||
273 | } | ||
274 | |||
275 | async function sendOwnedChannelsToPod (podId: number) { | ||
276 | const videoChannels = await db.VideoChannel.listOwned() | ||
277 | |||
278 | const tasks: Promise<any>[] = [] | ||
279 | for (const videoChannel of videoChannels) { | ||
280 | const remoteVideoChannel = videoChannel.toAddRemoteJSON() | ||
281 | const options = { | ||
282 | type: 'add-channel' as 'add-channel', | ||
283 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
284 | data: remoteVideoChannel, | ||
285 | toIds: [ podId ], | ||
286 | transaction: null | ||
287 | } | ||
288 | |||
289 | const p = createRequest(options) | ||
290 | tasks.push(p) | ||
291 | } | ||
292 | |||
293 | await Promise.all(tasks) | ||
294 | } | ||
295 | |||
296 | async function sendOwnedAuthorsToPod (podId: number) { | ||
297 | const authors = await db.Author.listOwned() | ||
298 | const tasks: Promise<any>[] = [] | ||
299 | |||
300 | for (const author of authors) { | ||
301 | const remoteAuthor = author.toAddRemoteJSON() | ||
302 | const options = { | ||
303 | type: 'add-author' as 'add-author', | ||
304 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
305 | data: remoteAuthor, | ||
306 | toIds: [ podId ], | ||
307 | transaction: null | ||
308 | } | ||
309 | |||
310 | const p = createRequest(options) | ||
311 | tasks.push(p) | ||
312 | } | ||
313 | |||
314 | await Promise.all(tasks) | ||
315 | } | ||
316 | |||
317 | async function sendOwnedVideosToPod (podId: number) { | ||
318 | const videosList = await db.Video.listOwnedAndPopulateAuthorAndTags() | ||
319 | const tasks: Bluebird<any>[] = [] | ||
320 | |||
321 | for (const video of videosList) { | ||
322 | const promise = video.toAddRemoteJSON() | ||
323 | .then(remoteVideo => { | ||
324 | const options = { | ||
325 | type: 'add-video' as 'add-video', | ||
326 | endpoint: REQUEST_ENDPOINTS.VIDEOS, | ||
327 | data: remoteVideo, | ||
328 | toIds: [ podId ], | ||
329 | transaction: null | ||
330 | } | ||
331 | return createRequest(options) | ||
332 | }) | ||
333 | .catch(err => { | ||
334 | logger.error('Cannot convert video to remote.', err) | ||
335 | // Don't break the process | ||
336 | return undefined | ||
337 | }) | ||
338 | |||
339 | tasks.push(promise) | ||
340 | } | ||
341 | |||
342 | await Promise.all(tasks) | ||
343 | } | ||
344 | |||
345 | function fetchRemotePreview (video: VideoInstance) { | ||
346 | const host = video.VideoChannel.Author.Pod.host | ||
347 | const path = join(STATIC_PATHS.PREVIEWS, video.getPreviewName()) | ||
348 | |||
349 | return request.get(REMOTE_SCHEME.HTTP + '://' + host + path) | ||
350 | } | ||
351 | |||
352 | function fetchRemoteDescription (video: VideoInstance) { | ||
353 | const host = video.VideoChannel.Author.Pod.host | ||
354 | const path = video.getDescriptionPath() | ||
355 | |||
356 | const requestOptions = { | ||
357 | url: REMOTE_SCHEME.HTTP + '://' + host + path, | ||
358 | json: true | ||
359 | } | ||
360 | |||
361 | return new Promise<string>((res, rej) => { | ||
362 | request.get(requestOptions, (err, response, body) => { | ||
363 | if (err) return rej(err) | ||
364 | |||
365 | return res(body.description ? body.description : '') | ||
366 | }) | ||
367 | }) | ||
368 | } | ||
369 | |||
370 | async function removeFriend (pod: PodInstance) { | ||
371 | const requestParams = { | ||
372 | method: 'POST' as 'POST', | ||
373 | path: '/api/' + API_VERSION + '/remote/pods/remove', | ||
374 | toPod: pod | ||
375 | } | ||
376 | |||
377 | try { | ||
378 | await makeSecureRequest(requestParams) | ||
379 | } catch (err) { | ||
380 | logger.warn('Cannot notify friends %s we are quitting him.', pod.host, err) | ||
381 | } | ||
382 | |||
383 | try { | ||
384 | await pod.destroy() | ||
385 | |||
386 | logger.info('Removed friend %s.', pod.host) | ||
387 | } catch (err) { | ||
388 | logger.error('Cannot destroy friend %s.', pod.host, err) | ||
389 | } | ||
390 | } | ||
391 | |||
392 | function getRequestScheduler () { | ||
393 | return requestScheduler | ||
394 | } | ||
395 | |||
396 | function getRequestVideoQaduScheduler () { | ||
397 | return requestVideoQaduScheduler | ||
398 | } | ||
399 | |||
400 | function getRequestVideoEventScheduler () { | ||
401 | return requestVideoEventScheduler | ||
402 | } | ||
403 | |||
404 | // --------------------------------------------------------------------------- | ||
405 | |||
406 | export { | ||
407 | activateSchedulers, | ||
408 | addVideoToFriends, | ||
409 | removeVideoAuthorToFriends, | ||
410 | updateVideoToFriends, | ||
411 | addVideoAuthorToFriends, | ||
412 | reportAbuseVideoToFriend, | ||
413 | quickAndDirtyUpdateVideoToFriends, | ||
414 | quickAndDirtyUpdatesVideoToFriends, | ||
415 | addEventToRemoteVideo, | ||
416 | addEventsToRemoteVideo, | ||
417 | hasFriends, | ||
418 | makeFriends, | ||
419 | quitFriends, | ||
420 | removeFriend, | ||
421 | removeVideoToFriends, | ||
422 | sendOwnedDataToPod, | ||
423 | getRequestScheduler, | ||
424 | getRequestVideoQaduScheduler, | ||
425 | getRequestVideoEventScheduler, | ||
426 | fetchRemotePreview, | ||
427 | addVideoChannelToFriends, | ||
428 | fetchRemoteDescription, | ||
429 | updateVideoChannelToFriends, | ||
430 | removeVideoChannelToFriends | ||
431 | } | ||
432 | |||
433 | // --------------------------------------------------------------------------- | ||
434 | |||
435 | async function computeForeignPodsList (host: string, podsScore: { [ host: string ]: number }) { | ||
436 | const result = await getForeignPodsList(host) | ||
437 | const foreignPodsList: { host: string }[] = result.data | ||
438 | |||
439 | // Let's give 1 point to the pod we ask the friends list | ||
440 | foreignPodsList.push({ host }) | ||
441 | |||
442 | for (const foreignPod of foreignPodsList) { | ||
443 | const foreignPodHost = foreignPod.host | ||
444 | |||
445 | if (podsScore[foreignPodHost]) podsScore[foreignPodHost]++ | ||
446 | else podsScore[foreignPodHost] = 1 | ||
447 | } | ||
448 | |||
449 | return undefined | ||
450 | } | ||
451 | |||
452 | function computeWinningPods (hosts: string[], podsScore: { [ host: string ]: number }) { | ||
453 | // Build the list of pods to add | ||
454 | // Only add a pod if it exists in more than a half base pods | ||
455 | const podsList = [] | ||
456 | const baseScore = hosts.length / 2 | ||
457 | |||
458 | for (const podHost of Object.keys(podsScore)) { | ||
459 | // If the pod is not me and with a good score we add it | ||
460 | if (isMe(podHost) === false && podsScore[podHost] > baseScore) { | ||
461 | podsList.push({ host: podHost }) | ||
462 | } | ||
463 | } | ||
464 | |||
465 | return podsList | ||
466 | } | ||
467 | |||
468 | function getForeignPodsList (host: string) { | ||
469 | return new Promise< ResultList<FormattedPod> >((res, rej) => { | ||
470 | const path = '/api/' + API_VERSION + '/remote/pods/list' | ||
471 | |||
472 | request.post(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => { | ||
473 | if (err) return rej(err) | ||
474 | |||
475 | try { | ||
476 | const json: ResultList<FormattedPod> = JSON.parse(body) | ||
477 | return res(json) | ||
478 | } catch (err) { | ||
479 | return rej(err) | ||
480 | } | ||
481 | }) | ||
482 | }) | ||
483 | } | ||
484 | |||
485 | async function makeRequestsToWinningPods (cert: string, podsList: PodInstance[]) { | ||
486 | // Stop pool requests | ||
487 | requestScheduler.deactivate() | ||
488 | // Flush pool requests | ||
489 | requestScheduler.forceSend() | ||
490 | |||
491 | try { | ||
492 | await Bluebird.map(podsList, async pod => { | ||
493 | const params = { | ||
494 | url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/remote/pods/add', | ||
495 | method: 'POST' as 'POST', | ||
496 | json: { | ||
497 | host: CONFIG.WEBSERVER.HOST, | ||
498 | email: CONFIG.ADMIN.EMAIL, | ||
499 | publicKey: cert | ||
500 | } | ||
501 | } | ||
502 | |||
503 | const { response, body } = await makeRetryRequest(params) | ||
504 | const typedBody = body as { cert: string, email: string } | ||
505 | |||
506 | if (response.statusCode === 200) { | ||
507 | const podObj = db.Pod.build({ host: pod.host, publicKey: typedBody.cert, email: typedBody.email }) | ||
508 | |||
509 | let podCreated: PodInstance | ||
510 | try { | ||
511 | podCreated = await podObj.save() | ||
512 | } catch (err) { | ||
513 | logger.error('Cannot add friend %s pod.', pod.host, err) | ||
514 | } | ||
515 | |||
516 | // Add our videos to the request scheduler | ||
517 | sendOwnedDataToPod(podCreated.id) | ||
518 | .catch(err => logger.warn('Cannot send owned data to pod %d.', podCreated.id, err)) | ||
519 | } else { | ||
520 | logger.error('Status not 200 for %s pod.', pod.host) | ||
521 | } | ||
522 | }, { concurrency: REQUESTS_IN_PARALLEL }) | ||
523 | |||
524 | logger.debug('makeRequestsToWinningPods finished.') | ||
525 | |||
526 | requestScheduler.activate() | ||
527 | } catch (err) { | ||
528 | // Final callback, we've ended all the requests | ||
529 | // Now we made new friends, we can re activate the pool of requests | ||
530 | requestScheduler.activate() | ||
531 | } | ||
532 | } | ||
533 | |||
534 | // Wrapper that populate "toIds" argument with all our friends if it is not specified | ||
535 | type CreateRequestOptions = { | ||
536 | type: RemoteVideoRequestType | ||
537 | endpoint: RequestEndpoint | ||
538 | data: Object | ||
539 | toIds?: number[] | ||
540 | transaction: Sequelize.Transaction | ||
541 | } | ||
542 | async function createRequest (options: CreateRequestOptions) { | ||
543 | if (options.toIds !== undefined) { | ||
544 | await requestScheduler.createRequest(options as RequestSchedulerOptions) | ||
545 | return undefined | ||
546 | } | ||
547 | |||
548 | // If the "toIds" pods is not specified, we send the request to all our friends | ||
549 | const podIds = await db.Pod.listAllIds(options.transaction) | ||
550 | |||
551 | const newOptions = Object.assign(options, { toIds: podIds }) | ||
552 | await requestScheduler.createRequest(newOptions) | ||
553 | |||
554 | return undefined | ||
555 | } | ||
556 | |||
557 | function createVideoQaduRequest (options: RequestVideoQaduSchedulerOptions) { | ||
558 | return requestVideoQaduScheduler.createRequest(options) | ||
559 | } | ||
560 | |||
561 | function createVideoEventRequest (options: RequestVideoEventSchedulerOptions) { | ||
562 | return requestVideoEventScheduler.createRequest(options) | ||
563 | } | ||
564 | |||
565 | function isMe (host: string) { | ||
566 | return host === CONFIG.WEBSERVER.HOST | ||
567 | } | ||
diff --git a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts index ccded4721..f019c28bc 100644 --- a/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts +++ b/server/lib/jobs/transcoding-job-scheduler/video-file-optimizer-handler.ts | |||
@@ -7,7 +7,7 @@ import { addVideoToFriends } from '../../friends' | |||
7 | import { JobScheduler } from '../job-scheduler' | 7 | import { JobScheduler } from '../job-scheduler' |
8 | 8 | ||
9 | async function process (data: { videoUUID: string }, jobId: number) { | 9 | async function process (data: { videoUUID: string }, jobId: number) { |
10 | const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(data.videoUUID) | 10 | const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID) |
11 | // No video, maybe deleted? | 11 | // No video, maybe deleted? |
12 | if (!video) { | 12 | if (!video) { |
13 | logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid }) | 13 | logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid }) |
@@ -30,7 +30,7 @@ async function onSuccess (jobId: number, video: VideoInstance) { | |||
30 | logger.info('Job %d is a success.', jobId) | 30 | logger.info('Job %d is a success.', jobId) |
31 | 31 | ||
32 | // Maybe the video changed in database, refresh it | 32 | // Maybe the video changed in database, refresh it |
33 | const videoDatabase = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(video.uuid) | 33 | const videoDatabase = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(video.uuid) |
34 | // Video does not exist anymore | 34 | // Video does not exist anymore |
35 | if (!videoDatabase) return undefined | 35 | if (!videoDatabase) return undefined |
36 | 36 | ||
diff --git a/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts b/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts index 853645510..397b95795 100644 --- a/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts +++ b/server/lib/jobs/transcoding-job-scheduler/video-file-transcoder-handler.ts | |||
@@ -5,7 +5,7 @@ import { VideoInstance } from '../../../models' | |||
5 | import { VideoResolution } from '../../../../shared' | 5 | import { VideoResolution } from '../../../../shared' |
6 | 6 | ||
7 | async function process (data: { videoUUID: string, resolution: VideoResolution }, jobId: number) { | 7 | async function process (data: { videoUUID: string, resolution: VideoResolution }, jobId: number) { |
8 | const video = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(data.videoUUID) | 8 | const video = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(data.videoUUID) |
9 | // No video, maybe deleted? | 9 | // No video, maybe deleted? |
10 | if (!video) { | 10 | if (!video) { |
11 | logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid }) | 11 | logger.info('Do not process job %d, video does not exist.', jobId, { videoUUID: video.uuid }) |
@@ -28,7 +28,7 @@ async function onSuccess (jobId: number, video: VideoInstance) { | |||
28 | logger.info('Job %d is a success.', jobId) | 28 | logger.info('Job %d is a success.', jobId) |
29 | 29 | ||
30 | // Maybe the video changed in database, refresh it | 30 | // Maybe the video changed in database, refresh it |
31 | const videoDatabase = await db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(video.uuid) | 31 | const videoDatabase = await db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(video.uuid) |
32 | // Video does not exist anymore | 32 | // Video does not exist anymore |
33 | if (!videoDatabase) return undefined | 33 | if (!videoDatabase) return undefined |
34 | 34 | ||
diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index a6dd4d061..f81383ce8 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts | |||
@@ -11,7 +11,7 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account | |||
11 | name: videoChannelInfo.name, | 11 | name: videoChannelInfo.name, |
12 | description: videoChannelInfo.description, | 12 | description: videoChannelInfo.description, |
13 | remote: false, | 13 | remote: false, |
14 | authorId: account.id | 14 | accountId: account.id |
15 | } | 15 | } |
16 | 16 | ||
17 | const videoChannel = db.VideoChannel.build(videoChannelData) | 17 | const videoChannel = db.VideoChannel.build(videoChannelData) |
diff --git a/server/middlewares/validators/video-channels.ts b/server/middlewares/validators/video-channels.ts index 7d611728b..53416a857 100644 --- a/server/middlewares/validators/video-channels.ts +++ b/server/middlewares/validators/video-channels.ts | |||
@@ -9,19 +9,19 @@ import { | |||
9 | isVideoChannelDescriptionValid, | 9 | isVideoChannelDescriptionValid, |
10 | isVideoChannelNameValid, | 10 | isVideoChannelNameValid, |
11 | checkVideoChannelExists, | 11 | checkVideoChannelExists, |
12 | checkVideoAuthorExists | 12 | checkVideoAccountExists |
13 | } from '../../helpers' | 13 | } from '../../helpers' |
14 | import { UserInstance } from '../../models' | 14 | import { UserInstance } from '../../models' |
15 | import { UserRight } from '../../../shared' | 15 | import { UserRight } from '../../../shared' |
16 | 16 | ||
17 | const listVideoAuthorChannelsValidator = [ | 17 | const listVideoAccountChannelsValidator = [ |
18 | param('authorId').custom(isIdOrUUIDValid).withMessage('Should have a valid author id'), | 18 | param('accountId').custom(isIdOrUUIDValid).withMessage('Should have a valid account id'), |
19 | 19 | ||
20 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 20 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
21 | logger.debug('Checking listVideoAuthorChannelsValidator parameters', { parameters: req.body }) | 21 | logger.debug('Checking listVideoAccountChannelsValidator parameters', { parameters: req.body }) |
22 | 22 | ||
23 | checkErrors(req, res, () => { | 23 | checkErrors(req, res, () => { |
24 | checkVideoAuthorExists(req.params.authorId, res, next) | 24 | checkVideoAccountExists(req.params.accountId, res, next) |
25 | }) | 25 | }) |
26 | } | 26 | } |
27 | ] | 27 | ] |
@@ -54,7 +54,7 @@ const videoChannelsUpdateValidator = [ | |||
54 | .end() | 54 | .end() |
55 | } | 55 | } |
56 | 56 | ||
57 | if (res.locals.videoChannel.Author.userId !== res.locals.oauth.token.User.id) { | 57 | if (res.locals.videoChannel.Account.userId !== res.locals.oauth.token.User.id) { |
58 | return res.status(403) | 58 | return res.status(403) |
59 | .json({ error: 'Cannot update video channel of another user' }) | 59 | .json({ error: 'Cannot update video channel of another user' }) |
60 | .end() | 60 | .end() |
@@ -98,7 +98,7 @@ const videoChannelGetValidator = [ | |||
98 | // --------------------------------------------------------------------------- | 98 | // --------------------------------------------------------------------------- |
99 | 99 | ||
100 | export { | 100 | export { |
101 | listVideoAuthorChannelsValidator, | 101 | listVideoAccountChannelsValidator, |
102 | videoChannelsAddValidator, | 102 | videoChannelsAddValidator, |
103 | videoChannelsUpdateValidator, | 103 | videoChannelsUpdateValidator, |
104 | videoChannelsRemoveValidator, | 104 | videoChannelsRemoveValidator, |
@@ -119,8 +119,8 @@ function checkUserCanDeleteVideoChannel (res: express.Response, callback: () => | |||
119 | 119 | ||
120 | // Check if the user can delete the video channel | 120 | // Check if the user can delete the video channel |
121 | // The user can delete it if s/he is an admin | 121 | // The user can delete it if s/he is an admin |
122 | // Or if s/he is the video channel's author | 122 | // Or if s/he is the video channel's account |
123 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && res.locals.videoChannel.Author.userId !== user.id) { | 123 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && res.locals.videoChannel.Account.userId !== user.id) { |
124 | return res.status(403) | 124 | return res.status(403) |
125 | .json({ error: 'Cannot remove video channel of another user' }) | 125 | .json({ error: 'Cannot remove video channel of another user' }) |
126 | .end() | 126 | .end() |
@@ -131,7 +131,7 @@ function checkUserCanDeleteVideoChannel (res: express.Response, callback: () => | |||
131 | } | 131 | } |
132 | 132 | ||
133 | function checkVideoChannelIsNotTheLastOne (res: express.Response, callback: () => void) { | 133 | function checkVideoChannelIsNotTheLastOne (res: express.Response, callback: () => void) { |
134 | db.VideoChannel.countByAuthor(res.locals.oauth.token.User.Author.id) | 134 | db.VideoChannel.countByAccount(res.locals.oauth.token.User.Account.id) |
135 | .then(count => { | 135 | .then(count => { |
136 | if (count <= 1) { | 136 | if (count <= 1) { |
137 | return res.status(409) | 137 | return res.status(409) |
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index 15b4629c1..10b426df3 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts | |||
@@ -48,11 +48,11 @@ const videosAddValidator = [ | |||
48 | const videoFile: Express.Multer.File = req.files['videofile'][0] | 48 | const videoFile: Express.Multer.File = req.files['videofile'][0] |
49 | const user = res.locals.oauth.token.User | 49 | const user = res.locals.oauth.token.User |
50 | 50 | ||
51 | return db.VideoChannel.loadByIdAndAuthor(req.body.channelId, user.Author.id) | 51 | return db.VideoChannel.loadByIdAndAccount(req.body.channelId, user.Account.id) |
52 | .then(videoChannel => { | 52 | .then(videoChannel => { |
53 | if (!videoChannel) { | 53 | if (!videoChannel) { |
54 | res.status(400) | 54 | res.status(400) |
55 | .json({ error: 'Unknown video video channel for this author.' }) | 55 | .json({ error: 'Unknown video video channel for this account.' }) |
56 | .end() | 56 | .end() |
57 | 57 | ||
58 | return undefined | 58 | return undefined |
@@ -131,7 +131,7 @@ const videosUpdateValidator = [ | |||
131 | .end() | 131 | .end() |
132 | } | 132 | } |
133 | 133 | ||
134 | if (video.VideoChannel.Author.userId !== res.locals.oauth.token.User.id) { | 134 | if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) { |
135 | return res.status(403) | 135 | return res.status(403) |
136 | .json({ error: 'Cannot update video of another user' }) | 136 | .json({ error: 'Cannot update video of another user' }) |
137 | .end() | 137 | .end() |
@@ -163,7 +163,7 @@ const videosGetValidator = [ | |||
163 | if (video.privacy !== VideoPrivacy.PRIVATE) return next() | 163 | if (video.privacy !== VideoPrivacy.PRIVATE) return next() |
164 | 164 | ||
165 | authenticate(req, res, () => { | 165 | authenticate(req, res, () => { |
166 | if (video.VideoChannel.Author.userId !== res.locals.oauth.token.User.id) { | 166 | if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) { |
167 | return res.status(403) | 167 | return res.status(403) |
168 | .json({ error: 'Cannot get this private video of another user' }) | 168 | .json({ error: 'Cannot get this private video of another user' }) |
169 | .end() | 169 | .end() |
@@ -256,10 +256,10 @@ function checkUserCanDeleteVideo (userId: number, res: express.Response, callbac | |||
256 | 256 | ||
257 | // Check if the user can delete the video | 257 | // Check if the user can delete the video |
258 | // The user can delete it if s/he is an admin | 258 | // The user can delete it if s/he is an admin |
259 | // Or if s/he is the video's author | 259 | // Or if s/he is the video's account |
260 | const author = res.locals.video.VideoChannel.Author | 260 | const account = res.locals.video.VideoChannel.Account |
261 | const user = res.locals.oauth.token.User | 261 | const user = res.locals.oauth.token.User |
262 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && author.userId !== user.id) { | 262 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && account.userId !== user.id) { |
263 | return res.status(403) | 263 | return res.status(403) |
264 | .json({ error: 'Cannot remove video of another user' }) | 264 | .json({ error: 'Cannot remove video of another user' }) |
265 | .end() | 265 | .end() |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 1401762c5..7390baf91 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -164,7 +164,7 @@ toFormattedJSON = function (this: UserInstance) { | |||
164 | roleLabel: USER_ROLE_LABELS[this.role], | 164 | roleLabel: USER_ROLE_LABELS[this.role], |
165 | videoQuota: this.videoQuota, | 165 | videoQuota: this.videoQuota, |
166 | createdAt: this.createdAt, | 166 | createdAt: this.createdAt, |
167 | author: { | 167 | account: { |
168 | id: this.Account.id, | 168 | id: this.Account.id, |
169 | uuid: this.Account.uuid | 169 | uuid: this.Account.uuid |
170 | } | 170 | } |
@@ -295,7 +295,7 @@ function getOriginalVideoFileTotalFromUser (user: UserInstance) { | |||
295 | '(SELECT MAX("VideoFiles"."size") AS "size" FROM "VideoFiles" ' + | 295 | '(SELECT MAX("VideoFiles"."size") AS "size" FROM "VideoFiles" ' + |
296 | 'INNER JOIN "Videos" ON "VideoFiles"."videoId" = "Videos"."id" ' + | 296 | 'INNER JOIN "Videos" ON "VideoFiles"."videoId" = "Videos"."id" ' + |
297 | 'INNER JOIN "VideoChannels" ON "VideoChannels"."id" = "Videos"."channelId" ' + | 297 | 'INNER JOIN "VideoChannels" ON "VideoChannels"."id" = "Videos"."channelId" ' + |
298 | 'INNER JOIN "Accounts" ON "VideoChannels"."authorId" = "Accounts"."id" ' + | 298 | 'INNER JOIN "Accounts" ON "VideoChannels"."accountId" = "Accounts"."id" ' + |
299 | 'INNER JOIN "Users" ON "Accounts"."userId" = "Users"."id" ' + | 299 | 'INNER JOIN "Users" ON "Accounts"."userId" = "Users"."id" ' + |
300 | 'WHERE "Users"."id" = $userId GROUP BY "Videos"."id") t' | 300 | 'WHERE "Users"."id" = $userId GROUP BY "Videos"."id") t' |
301 | 301 | ||
diff --git a/server/models/index.ts b/server/models/index.ts index 29479e067..0aec2d3b1 100644 --- a/server/models/index.ts +++ b/server/models/index.ts | |||
@@ -2,6 +2,5 @@ export * from './application' | |||
2 | export * from './job' | 2 | export * from './job' |
3 | export * from './oauth' | 3 | export * from './oauth' |
4 | export * from './pod' | 4 | export * from './pod' |
5 | export * from './request' | ||
6 | export * from './account' | 5 | export * from './account' |
7 | export * from './video' | 6 | export * from './video' |
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts index dc8bcd872..c7afcc38c 100644 --- a/server/models/oauth/oauth-token.ts +++ b/server/models/oauth/oauth-token.ts | |||
@@ -131,7 +131,7 @@ getByTokenAndPopulateUser = function (bearerToken: string) { | |||
131 | model: OAuthToken['sequelize'].models.User, | 131 | model: OAuthToken['sequelize'].models.User, |
132 | include: [ | 132 | include: [ |
133 | { | 133 | { |
134 | model: OAuthToken['sequelize'].models.Author, | 134 | model: OAuthToken['sequelize'].models.Account, |
135 | required: true | 135 | required: true |
136 | } | 136 | } |
137 | ] | 137 | ] |
@@ -156,7 +156,7 @@ getByRefreshTokenAndPopulateUser = function (refreshToken: string) { | |||
156 | model: OAuthToken['sequelize'].models.User, | 156 | model: OAuthToken['sequelize'].models.User, |
157 | include: [ | 157 | include: [ |
158 | { | 158 | { |
159 | model: OAuthToken['sequelize'].models.Author, | 159 | model: OAuthToken['sequelize'].models.Account, |
160 | required: true | 160 | required: true |
161 | } | 161 | } |
162 | ] | 162 | ] |
diff --git a/server/models/request/abstract-request-interface.ts b/server/models/request/abstract-request-interface.ts deleted file mode 100644 index a384f4d27..000000000 --- a/server/models/request/abstract-request-interface.ts +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | import * as Promise from 'bluebird' | ||
2 | |||
3 | export interface AbstractRequestClass <T> { | ||
4 | countTotalRequests: () => Promise<number> | ||
5 | listWithLimitAndRandom: (limitPods: number, limitRequestsPerPod: number) => Promise<T> | ||
6 | removeWithEmptyTo: () => Promise<number> | ||
7 | removeAll: () => Promise<void> | ||
8 | } | ||
9 | |||
10 | export interface AbstractRequestToPodClass { | ||
11 | removeByRequestIdsAndPod: (ids: number[], podId: number) => Promise<number> | ||
12 | } | ||
diff --git a/server/models/request/index.ts b/server/models/request/index.ts deleted file mode 100644 index 3dd6aedc2..000000000 --- a/server/models/request/index.ts +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | export * from './abstract-request-interface' | ||
2 | export * from './request-interface' | ||
3 | export * from './request-to-pod-interface' | ||
4 | export * from './request-video-event-interface' | ||
5 | export * from './request-video-qadu-interface' | ||
diff --git a/server/models/request/request-interface.ts b/server/models/request/request-interface.ts deleted file mode 100644 index dae35651b..000000000 --- a/server/models/request/request-interface.ts +++ /dev/null | |||
@@ -1,46 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | import { AbstractRequestClass } from './abstract-request-interface' | ||
5 | import { PodInstance, PodAttributes } from '../pod/pod-interface' | ||
6 | import { RequestEndpoint } from '../../../shared/models/request-scheduler.model' | ||
7 | |||
8 | export type RequestsGrouped = { | ||
9 | [ podId: number ]: { | ||
10 | request: RequestInstance, | ||
11 | pod: PodInstance | ||
12 | }[] | ||
13 | } | ||
14 | |||
15 | export namespace RequestMethods { | ||
16 | export type CountTotalRequests = () => Promise<number> | ||
17 | |||
18 | export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsGrouped> | ||
19 | |||
20 | export type RemoveWithEmptyTo = () => Promise<number> | ||
21 | |||
22 | export type RemoveAll = () => Promise<void> | ||
23 | } | ||
24 | |||
25 | export interface RequestClass extends AbstractRequestClass<RequestsGrouped> { | ||
26 | countTotalRequests: RequestMethods.CountTotalRequests | ||
27 | listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom | ||
28 | removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo | ||
29 | removeAll: RequestMethods.RemoveAll | ||
30 | } | ||
31 | |||
32 | export interface RequestAttributes { | ||
33 | request: object | ||
34 | endpoint: RequestEndpoint | ||
35 | } | ||
36 | |||
37 | export interface RequestInstance extends RequestClass, RequestAttributes, Sequelize.Instance<RequestAttributes> { | ||
38 | id: number | ||
39 | createdAt: Date | ||
40 | updatedAt: Date | ||
41 | |||
42 | setPods: Sequelize.HasManySetAssociationsMixin<PodAttributes, number> | ||
43 | Pods: PodInstance[] | ||
44 | } | ||
45 | |||
46 | export interface RequestModel extends RequestClass, Sequelize.Model<RequestInstance, RequestAttributes> {} | ||
diff --git a/server/models/request/request-to-pod-interface.ts b/server/models/request/request-to-pod-interface.ts deleted file mode 100644 index 7ca99f4d4..000000000 --- a/server/models/request/request-to-pod-interface.ts +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | import { AbstractRequestToPodClass } from './abstract-request-interface' | ||
5 | |||
6 | export namespace RequestToPodMethods { | ||
7 | export type RemoveByRequestIdsAndPod = (requestsIds: number[], podId: number) => Promise<number> | ||
8 | } | ||
9 | |||
10 | export interface RequestToPodClass extends AbstractRequestToPodClass { | ||
11 | removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod | ||
12 | } | ||
13 | |||
14 | export interface RequestToPodAttributes { | ||
15 | } | ||
16 | |||
17 | export interface RequestToPodInstance extends RequestToPodClass, RequestToPodAttributes, Sequelize.Instance<RequestToPodAttributes> { | ||
18 | id: number | ||
19 | createdAt: Date | ||
20 | updatedAt: Date | ||
21 | } | ||
22 | |||
23 | export interface RequestToPodModel extends RequestToPodClass, Sequelize.Model<RequestToPodInstance, RequestToPodAttributes> {} | ||
diff --git a/server/models/request/request-to-pod.ts b/server/models/request/request-to-pod.ts deleted file mode 100644 index 4e14e918b..000000000 --- a/server/models/request/request-to-pod.ts +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | import { addMethodsToModel } from '../utils' | ||
4 | import { | ||
5 | RequestToPodInstance, | ||
6 | RequestToPodAttributes, | ||
7 | |||
8 | RequestToPodMethods | ||
9 | } from './request-to-pod-interface' | ||
10 | |||
11 | let RequestToPod: Sequelize.Model<RequestToPodInstance, RequestToPodAttributes> | ||
12 | let removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod | ||
13 | |||
14 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
15 | RequestToPod = sequelize.define<RequestToPodInstance, RequestToPodAttributes>('RequestToPod', {}, { | ||
16 | indexes: [ | ||
17 | { | ||
18 | fields: [ 'requestId' ] | ||
19 | }, | ||
20 | { | ||
21 | fields: [ 'podId' ] | ||
22 | }, | ||
23 | { | ||
24 | fields: [ 'requestId', 'podId' ], | ||
25 | unique: true | ||
26 | } | ||
27 | ] | ||
28 | }) | ||
29 | |||
30 | const classMethods = [ | ||
31 | removeByRequestIdsAndPod | ||
32 | ] | ||
33 | addMethodsToModel(RequestToPod, classMethods) | ||
34 | |||
35 | return RequestToPod | ||
36 | } | ||
37 | |||
38 | // --------------------------------------------------------------------------- | ||
39 | |||
40 | removeByRequestIdsAndPod = function (requestsIds: number[], podId: number) { | ||
41 | const query = { | ||
42 | where: { | ||
43 | requestId: { | ||
44 | [Sequelize.Op.in]: requestsIds | ||
45 | }, | ||
46 | podId: podId | ||
47 | } | ||
48 | } | ||
49 | |||
50 | return RequestToPod.destroy(query) | ||
51 | } | ||
diff --git a/server/models/request/request-video-event-interface.ts b/server/models/request/request-video-event-interface.ts deleted file mode 100644 index 26cabe3ba..000000000 --- a/server/models/request/request-video-event-interface.ts +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface' | ||
5 | import { VideoInstance } from '../video/video-interface' | ||
6 | import { PodInstance } from '../pod/pod-interface' | ||
7 | |||
8 | import { RequestVideoEventType } from '../../../shared/models/request-scheduler.model' | ||
9 | |||
10 | export type RequestsVideoEventGrouped = { | ||
11 | [ podId: number ]: { | ||
12 | id: number | ||
13 | type: RequestVideoEventType | ||
14 | count: number | ||
15 | video: VideoInstance | ||
16 | pod: PodInstance | ||
17 | }[] | ||
18 | } | ||
19 | |||
20 | export namespace RequestVideoEventMethods { | ||
21 | export type CountTotalRequests = () => Promise<number> | ||
22 | |||
23 | export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsVideoEventGrouped> | ||
24 | |||
25 | export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise<number> | ||
26 | |||
27 | export type RemoveAll = () => Promise<void> | ||
28 | } | ||
29 | |||
30 | export interface RequestVideoEventClass extends AbstractRequestClass<RequestsVideoEventGrouped>, AbstractRequestToPodClass { | ||
31 | countTotalRequests: RequestVideoEventMethods.CountTotalRequests | ||
32 | listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom | ||
33 | removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod | ||
34 | removeAll: RequestVideoEventMethods.RemoveAll | ||
35 | } | ||
36 | |||
37 | export interface RequestVideoEventAttributes { | ||
38 | type: RequestVideoEventType | ||
39 | count: number | ||
40 | } | ||
41 | |||
42 | export interface RequestVideoEventInstance | ||
43 | extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance<RequestVideoEventAttributes> { | ||
44 | id: number | ||
45 | |||
46 | Video: VideoInstance | ||
47 | } | ||
48 | |||
49 | export interface RequestVideoEventModel | ||
50 | extends RequestVideoEventClass, Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> {} | ||
diff --git a/server/models/request/request-video-event.ts b/server/models/request/request-video-event.ts deleted file mode 100644 index 8954407e1..000000000 --- a/server/models/request/request-video-event.ts +++ /dev/null | |||
@@ -1,191 +0,0 @@ | |||
1 | /* | ||
2 | Request Video events (likes, dislikes, views...) | ||
3 | */ | ||
4 | |||
5 | import { values } from 'lodash' | ||
6 | import * as Sequelize from 'sequelize' | ||
7 | |||
8 | import { database as db } from '../../initializers/database' | ||
9 | import { REQUEST_VIDEO_EVENT_TYPES } from '../../initializers' | ||
10 | import { isVideoEventCountValid } from '../../helpers' | ||
11 | import { addMethodsToModel } from '../utils' | ||
12 | import { | ||
13 | RequestVideoEventInstance, | ||
14 | RequestVideoEventAttributes, | ||
15 | |||
16 | RequestVideoEventMethods, | ||
17 | RequestsVideoEventGrouped | ||
18 | } from './request-video-event-interface' | ||
19 | |||
20 | let RequestVideoEvent: Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> | ||
21 | let countTotalRequests: RequestVideoEventMethods.CountTotalRequests | ||
22 | let listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom | ||
23 | let removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod | ||
24 | let removeAll: RequestVideoEventMethods.RemoveAll | ||
25 | |||
26 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
27 | RequestVideoEvent = sequelize.define<RequestVideoEventInstance, RequestVideoEventAttributes>('RequestVideoEvent', | ||
28 | { | ||
29 | type: { | ||
30 | type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)), | ||
31 | allowNull: false | ||
32 | }, | ||
33 | count: { | ||
34 | type: DataTypes.INTEGER, | ||
35 | allowNull: false, | ||
36 | validate: { | ||
37 | countValid: function (value) { | ||
38 | const res = isVideoEventCountValid(value) | ||
39 | if (res === false) throw new Error('Video event count is not valid.') | ||
40 | } | ||
41 | } | ||
42 | } | ||
43 | }, | ||
44 | { | ||
45 | updatedAt: false, | ||
46 | indexes: [ | ||
47 | { | ||
48 | fields: [ 'videoId' ] | ||
49 | } | ||
50 | ] | ||
51 | } | ||
52 | ) | ||
53 | |||
54 | const classMethods = [ | ||
55 | associate, | ||
56 | |||
57 | listWithLimitAndRandom, | ||
58 | countTotalRequests, | ||
59 | removeAll, | ||
60 | removeByRequestIdsAndPod | ||
61 | ] | ||
62 | addMethodsToModel(RequestVideoEvent, classMethods) | ||
63 | |||
64 | return RequestVideoEvent | ||
65 | } | ||
66 | |||
67 | // ------------------------------ STATICS ------------------------------ | ||
68 | |||
69 | function associate (models) { | ||
70 | RequestVideoEvent.belongsTo(models.Video, { | ||
71 | foreignKey: { | ||
72 | name: 'videoId', | ||
73 | allowNull: false | ||
74 | }, | ||
75 | onDelete: 'CASCADE' | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | countTotalRequests = function () { | ||
80 | const query = {} | ||
81 | return RequestVideoEvent.count(query) | ||
82 | } | ||
83 | |||
84 | listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) { | ||
85 | const Pod = db.Pod | ||
86 | |||
87 | // We make a join between videos and authors to find the podId of our video event requests | ||
88 | const podJoins = 'INNER JOIN "VideoChannels" ON "VideoChannels"."authorId" = "Authors"."id" ' + | ||
89 | 'INNER JOIN "Videos" ON "Videos"."channelId" = "VideoChannels"."id" ' + | ||
90 | 'INNER JOIN "RequestVideoEvents" ON "RequestVideoEvents"."videoId" = "Videos"."id"' | ||
91 | |||
92 | return Pod.listRandomPodIdsWithRequest(limitPods, 'Authors', podJoins).then(podIds => { | ||
93 | // We don't have friends that have requests | ||
94 | if (podIds.length === 0) return [] | ||
95 | |||
96 | const query = { | ||
97 | order: [ | ||
98 | [ 'id', 'ASC' ] | ||
99 | ], | ||
100 | include: [ | ||
101 | { | ||
102 | model: RequestVideoEvent['sequelize'].models.Video, | ||
103 | include: [ | ||
104 | { | ||
105 | model: RequestVideoEvent['sequelize'].models.VideoChannel, | ||
106 | include: [ | ||
107 | { | ||
108 | model: RequestVideoEvent['sequelize'].models.Author, | ||
109 | include: [ | ||
110 | { | ||
111 | model: RequestVideoEvent['sequelize'].models.Pod, | ||
112 | where: { | ||
113 | id: { | ||
114 | [Sequelize.Op.in]: podIds | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | ] | ||
119 | } | ||
120 | ] | ||
121 | } | ||
122 | ] | ||
123 | } | ||
124 | ] | ||
125 | } | ||
126 | |||
127 | return RequestVideoEvent.findAll(query).then(requests => { | ||
128 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | ||
129 | return requestsGrouped | ||
130 | }) | ||
131 | }) | ||
132 | } | ||
133 | |||
134 | removeByRequestIdsAndPod = function (ids: number[], podId: number) { | ||
135 | const query = { | ||
136 | where: { | ||
137 | id: { | ||
138 | [Sequelize.Op.in]: ids | ||
139 | } | ||
140 | }, | ||
141 | include: [ | ||
142 | { | ||
143 | model: RequestVideoEvent['sequelize'].models.Video, | ||
144 | include: [ | ||
145 | { | ||
146 | model: RequestVideoEvent['sequelize'].models.VideoChannel, | ||
147 | include: [ | ||
148 | { | ||
149 | model: RequestVideoEvent['sequelize'].models.Author, | ||
150 | where: { | ||
151 | podId | ||
152 | } | ||
153 | } | ||
154 | ] | ||
155 | } | ||
156 | ] | ||
157 | } | ||
158 | ] | ||
159 | } | ||
160 | |||
161 | return RequestVideoEvent.destroy(query) | ||
162 | } | ||
163 | |||
164 | removeAll = function () { | ||
165 | // Delete all requests | ||
166 | return RequestVideoEvent.truncate({ cascade: true }) | ||
167 | } | ||
168 | |||
169 | // --------------------------------------------------------------------------- | ||
170 | |||
171 | function groupAndTruncateRequests (events: RequestVideoEventInstance[], limitRequestsPerPod: number) { | ||
172 | const eventsGrouped: RequestsVideoEventGrouped = {} | ||
173 | |||
174 | events.forEach(event => { | ||
175 | const pod = event.Video.VideoChannel.Author.Pod | ||
176 | |||
177 | if (!eventsGrouped[pod.id]) eventsGrouped[pod.id] = [] | ||
178 | |||
179 | if (eventsGrouped[pod.id].length < limitRequestsPerPod) { | ||
180 | eventsGrouped[pod.id].push({ | ||
181 | id: event.id, | ||
182 | type: event.type, | ||
183 | count: event.count, | ||
184 | video: event.Video, | ||
185 | pod | ||
186 | }) | ||
187 | } | ||
188 | }) | ||
189 | |||
190 | return eventsGrouped | ||
191 | } | ||
diff --git a/server/models/request/request-video-qadu-interface.ts b/server/models/request/request-video-qadu-interface.ts deleted file mode 100644 index b7b7b1ecc..000000000 --- a/server/models/request/request-video-qadu-interface.ts +++ /dev/null | |||
@@ -1,48 +0,0 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | import * as Promise from 'bluebird' | ||
3 | |||
4 | import { AbstractRequestClass, AbstractRequestToPodClass } from './abstract-request-interface' | ||
5 | import { VideoInstance } from '../video/video-interface' | ||
6 | import { PodInstance } from '../pod/pod-interface' | ||
7 | |||
8 | import { RequestVideoQaduType } from '../../../shared/models/request-scheduler.model' | ||
9 | |||
10 | export type RequestsVideoQaduGrouped = { | ||
11 | [ podId: number ]: { | ||
12 | request: RequestVideoQaduInstance | ||
13 | video: VideoInstance | ||
14 | pod: PodInstance | ||
15 | } | ||
16 | } | ||
17 | |||
18 | export namespace RequestVideoQaduMethods { | ||
19 | export type CountTotalRequests = () => Promise<number> | ||
20 | |||
21 | export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number) => Promise<RequestsVideoQaduGrouped> | ||
22 | |||
23 | export type RemoveByRequestIdsAndPod = (ids: number[], podId: number) => Promise<number> | ||
24 | |||
25 | export type RemoveAll = () => Promise<void> | ||
26 | } | ||
27 | |||
28 | export interface RequestVideoQaduClass extends AbstractRequestClass<RequestsVideoQaduGrouped>, AbstractRequestToPodClass { | ||
29 | countTotalRequests: RequestVideoQaduMethods.CountTotalRequests | ||
30 | listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom | ||
31 | removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod | ||
32 | removeAll: RequestVideoQaduMethods.RemoveAll | ||
33 | } | ||
34 | |||
35 | export interface RequestVideoQaduAttributes { | ||
36 | type: RequestVideoQaduType | ||
37 | } | ||
38 | |||
39 | export interface RequestVideoQaduInstance | ||
40 | extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance<RequestVideoQaduAttributes> { | ||
41 | id: number | ||
42 | |||
43 | Pod: PodInstance | ||
44 | Video: VideoInstance | ||
45 | } | ||
46 | |||
47 | export interface RequestVideoQaduModel | ||
48 | extends RequestVideoQaduClass, Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> {} | ||
diff --git a/server/models/request/request-video-qadu.ts b/server/models/request/request-video-qadu.ts deleted file mode 100644 index 93cf249b3..000000000 --- a/server/models/request/request-video-qadu.ts +++ /dev/null | |||
@@ -1,159 +0,0 @@ | |||
1 | /* | ||
2 | Request Video for Quick And Dirty Updates like: | ||
3 | - views | ||
4 | - likes | ||
5 | - dislikes | ||
6 | |||
7 | We can't put it in the same system than basic requests for efficiency. | ||
8 | Moreover we don't want to slow down the basic requests with a lot of views/likes/dislikes requests. | ||
9 | So we put it an independant request scheduler. | ||
10 | */ | ||
11 | |||
12 | import { values } from 'lodash' | ||
13 | import * as Sequelize from 'sequelize' | ||
14 | |||
15 | import { database as db } from '../../initializers/database' | ||
16 | import { REQUEST_VIDEO_QADU_TYPES } from '../../initializers' | ||
17 | import { addMethodsToModel } from '../utils' | ||
18 | import { | ||
19 | RequestVideoQaduInstance, | ||
20 | RequestVideoQaduAttributes, | ||
21 | |||
22 | RequestVideoQaduMethods | ||
23 | } from './request-video-qadu-interface' | ||
24 | |||
25 | let RequestVideoQadu: Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> | ||
26 | let countTotalRequests: RequestVideoQaduMethods.CountTotalRequests | ||
27 | let listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom | ||
28 | let removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod | ||
29 | let removeAll: RequestVideoQaduMethods.RemoveAll | ||
30 | |||
31 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
32 | RequestVideoQadu = sequelize.define<RequestVideoQaduInstance, RequestVideoQaduAttributes>('RequestVideoQadu', | ||
33 | { | ||
34 | type: { | ||
35 | type: DataTypes.ENUM(values(REQUEST_VIDEO_QADU_TYPES)), | ||
36 | allowNull: false | ||
37 | } | ||
38 | }, | ||
39 | { | ||
40 | timestamps: false, | ||
41 | indexes: [ | ||
42 | { | ||
43 | fields: [ 'podId' ] | ||
44 | }, | ||
45 | { | ||
46 | fields: [ 'videoId' ] | ||
47 | } | ||
48 | ] | ||
49 | } | ||
50 | ) | ||
51 | |||
52 | const classMethods = [ | ||
53 | associate, | ||
54 | |||
55 | listWithLimitAndRandom, | ||
56 | countTotalRequests, | ||
57 | removeAll, | ||
58 | removeByRequestIdsAndPod | ||
59 | ] | ||
60 | addMethodsToModel(RequestVideoQadu, classMethods) | ||
61 | |||
62 | return RequestVideoQadu | ||
63 | } | ||
64 | |||
65 | // ------------------------------ STATICS ------------------------------ | ||
66 | |||
67 | function associate (models) { | ||
68 | RequestVideoQadu.belongsTo(models.Pod, { | ||
69 | foreignKey: { | ||
70 | name: 'podId', | ||
71 | allowNull: false | ||
72 | }, | ||
73 | onDelete: 'CASCADE' | ||
74 | }) | ||
75 | |||
76 | RequestVideoQadu.belongsTo(models.Video, { | ||
77 | foreignKey: { | ||
78 | name: 'videoId', | ||
79 | allowNull: false | ||
80 | }, | ||
81 | onDelete: 'CASCADE' | ||
82 | }) | ||
83 | } | ||
84 | |||
85 | countTotalRequests = function () { | ||
86 | const query = {} | ||
87 | return RequestVideoQadu.count(query) | ||
88 | } | ||
89 | |||
90 | listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) { | ||
91 | const Pod = db.Pod | ||
92 | const tableJoin = '' | ||
93 | |||
94 | return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', tableJoin).then(podIds => { | ||
95 | // We don't have friends that have requests | ||
96 | if (podIds.length === 0) return [] | ||
97 | |||
98 | const query = { | ||
99 | include: [ | ||
100 | { | ||
101 | model: RequestVideoQadu['sequelize'].models.Pod, | ||
102 | where: { | ||
103 | id: { | ||
104 | [Sequelize.Op.in]: podIds | ||
105 | } | ||
106 | } | ||
107 | }, | ||
108 | { | ||
109 | model: RequestVideoQadu['sequelize'].models.Video | ||
110 | } | ||
111 | ] | ||
112 | } | ||
113 | |||
114 | return RequestVideoQadu.findAll(query).then(requests => { | ||
115 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | ||
116 | return requestsGrouped | ||
117 | }) | ||
118 | }) | ||
119 | } | ||
120 | |||
121 | removeByRequestIdsAndPod = function (ids: number[], podId: number) { | ||
122 | const query = { | ||
123 | where: { | ||
124 | id: { | ||
125 | [Sequelize.Op.in]: ids | ||
126 | }, | ||
127 | podId | ||
128 | } | ||
129 | } | ||
130 | |||
131 | return RequestVideoQadu.destroy(query) | ||
132 | } | ||
133 | |||
134 | removeAll = function () { | ||
135 | // Delete all requests | ||
136 | return RequestVideoQadu.truncate({ cascade: true }) | ||
137 | } | ||
138 | |||
139 | // --------------------------------------------------------------------------- | ||
140 | |||
141 | function groupAndTruncateRequests (requests: RequestVideoQaduInstance[], limitRequestsPerPod: number) { | ||
142 | const requestsGrouped = {} | ||
143 | |||
144 | requests.forEach(request => { | ||
145 | const pod = request.Pod | ||
146 | |||
147 | if (!requestsGrouped[pod.id]) requestsGrouped[pod.id] = [] | ||
148 | |||
149 | if (requestsGrouped[pod.id].length < limitRequestsPerPod) { | ||
150 | requestsGrouped[pod.id].push({ | ||
151 | request: request, | ||
152 | video: request.Video, | ||
153 | pod | ||
154 | }) | ||
155 | } | ||
156 | }) | ||
157 | |||
158 | return requestsGrouped | ||
159 | } | ||
diff --git a/server/models/request/request.ts b/server/models/request/request.ts deleted file mode 100644 index 71118a947..000000000 --- a/server/models/request/request.ts +++ /dev/null | |||
@@ -1,144 +0,0 @@ | |||
1 | import { values } from 'lodash' | ||
2 | import * as Sequelize from 'sequelize' | ||
3 | |||
4 | import { database as db } from '../../initializers/database' | ||
5 | import { REQUEST_ENDPOINTS } from '../../initializers' | ||
6 | import { addMethodsToModel } from '../utils' | ||
7 | import { | ||
8 | RequestInstance, | ||
9 | RequestAttributes, | ||
10 | |||
11 | RequestMethods, | ||
12 | RequestsGrouped | ||
13 | } from './request-interface' | ||
14 | |||
15 | let Request: Sequelize.Model<RequestInstance, RequestAttributes> | ||
16 | let countTotalRequests: RequestMethods.CountTotalRequests | ||
17 | let listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom | ||
18 | let removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo | ||
19 | let removeAll: RequestMethods.RemoveAll | ||
20 | |||
21 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | ||
22 | Request = sequelize.define<RequestInstance, RequestAttributes>('Request', | ||
23 | { | ||
24 | request: { | ||
25 | type: DataTypes.JSON, | ||
26 | allowNull: false | ||
27 | }, | ||
28 | endpoint: { | ||
29 | type: DataTypes.ENUM(values(REQUEST_ENDPOINTS)), | ||
30 | allowNull: false | ||
31 | } | ||
32 | } | ||
33 | ) | ||
34 | |||
35 | const classMethods = [ | ||
36 | associate, | ||
37 | |||
38 | listWithLimitAndRandom, | ||
39 | |||
40 | countTotalRequests, | ||
41 | removeAll, | ||
42 | removeWithEmptyTo | ||
43 | ] | ||
44 | addMethodsToModel(Request, classMethods) | ||
45 | |||
46 | return Request | ||
47 | } | ||
48 | |||
49 | // ------------------------------ STATICS ------------------------------ | ||
50 | |||
51 | function associate (models) { | ||
52 | Request.belongsToMany(models.Pod, { | ||
53 | foreignKey: { | ||
54 | name: 'requestId', | ||
55 | allowNull: false | ||
56 | }, | ||
57 | through: models.RequestToPod, | ||
58 | onDelete: 'CASCADE' | ||
59 | }) | ||
60 | } | ||
61 | |||
62 | countTotalRequests = function () { | ||
63 | // We need to include Pod because there are no cascade delete when a pod is removed | ||
64 | // So we could count requests that do not have existing pod anymore | ||
65 | const query = { | ||
66 | include: [ Request['sequelize'].models.Pod ] | ||
67 | } | ||
68 | |||
69 | return Request.count(query) | ||
70 | } | ||
71 | |||
72 | listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number) { | ||
73 | const Pod = db.Pod | ||
74 | const tableJoin = '' | ||
75 | |||
76 | return Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', tableJoin).then(podIds => { | ||
77 | // We don't have friends that have requests | ||
78 | if (podIds.length === 0) return [] | ||
79 | |||
80 | // The first x requests of these pods | ||
81 | // It is very important to sort by id ASC to keep the requests order! | ||
82 | const query = { | ||
83 | order: [ | ||
84 | [ 'id', 'ASC' ] | ||
85 | ], | ||
86 | include: [ | ||
87 | { | ||
88 | model: Request['sequelize'].models.Pod, | ||
89 | where: { | ||
90 | id: { | ||
91 | [Sequelize.Op.in]: podIds | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | ] | ||
96 | } | ||
97 | |||
98 | return Request.findAll(query).then(requests => { | ||
99 | |||
100 | const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) | ||
101 | return requestsGrouped | ||
102 | }) | ||
103 | }) | ||
104 | } | ||
105 | |||
106 | removeAll = function () { | ||
107 | // Delete all requests | ||
108 | return Request.truncate({ cascade: true }) | ||
109 | } | ||
110 | |||
111 | removeWithEmptyTo = function () { | ||
112 | const query = { | ||
113 | where: { | ||
114 | id: { | ||
115 | [Sequelize.Op.notIn]: [ | ||
116 | Sequelize.literal('SELECT "requestId" FROM "RequestToPods"') | ||
117 | ] | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | return Request.destroy(query) | ||
123 | } | ||
124 | |||
125 | // --------------------------------------------------------------------------- | ||
126 | |||
127 | function groupAndTruncateRequests (requests: RequestInstance[], limitRequestsPerPod: number) { | ||
128 | const requestsGrouped: RequestsGrouped = {} | ||
129 | |||
130 | requests.forEach(request => { | ||
131 | request.Pods.forEach(pod => { | ||
132 | if (!requestsGrouped[pod.id]) requestsGrouped[pod.id] = [] | ||
133 | |||
134 | if (requestsGrouped[pod.id].length < limitRequestsPerPod) { | ||
135 | requestsGrouped[pod.id].push({ | ||
136 | request, | ||
137 | pod | ||
138 | }) | ||
139 | } | ||
140 | }) | ||
141 | }) | ||
142 | |||
143 | return requestsGrouped | ||
144 | } | ||
diff --git a/server/models/video/index.ts b/server/models/video/index.ts index dba6a5590..20d97931f 100644 --- a/server/models/video/index.ts +++ b/server/models/video/index.ts | |||
@@ -1,4 +1,3 @@ | |||
1 | export * from './author-interface' | ||
2 | export * from './tag-interface' | 1 | export * from './tag-interface' |
3 | export * from './video-abuse-interface' | 2 | export * from './video-abuse-interface' |
4 | export * from './video-blacklist-interface' | 3 | export * from './video-blacklist-interface' |