]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/remote/videos.ts
c8f531490c371e6d2b34067068c76da058e0f40c
[github/Chocobozzz/PeerTube.git] / server / controllers / api / remote / videos.ts
1 import * as express from 'express'
2 import * as Promise from 'bluebird'
3 import * as Sequelize from 'sequelize'
4
5 import { database as db } from '../../../initializers/database'
6 import {
7 REQUEST_ENDPOINT_ACTIONS,
8 REQUEST_ENDPOINTS,
9 REQUEST_VIDEO_EVENT_TYPES,
10 REQUEST_VIDEO_QADU_TYPES
11 } from '../../../initializers'
12 import {
13 checkSignature,
14 signatureValidator,
15 remoteVideosValidator,
16 remoteQaduVideosValidator,
17 remoteEventsVideosValidator
18 } from '../../../middlewares'
19 import { logger, retryTransactionWrapper } from '../../../helpers'
20 import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib'
21 import { PodInstance, VideoFileInstance } from '../../../models'
22 import {
23 RemoteVideoRequest,
24 RemoteVideoCreateData,
25 RemoteVideoUpdateData,
26 RemoteVideoRemoveData,
27 RemoteVideoReportAbuseData,
28 RemoteQaduVideoRequest,
29 RemoteQaduVideoData,
30 RemoteVideoEventRequest,
31 RemoteVideoEventData,
32 RemoteVideoChannelCreateData,
33 RemoteVideoChannelUpdateData,
34 RemoteVideoChannelRemoveData,
35 RemoteVideoAuthorRemoveData,
36 RemoteVideoAuthorCreateData
37 } from '../../../../shared'
38
39 const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
40
41 // Functions to call when processing a remote request
42 // FIXME: use RemoteVideoRequestType as id type
43 const functionsHash: { [ id: string ]: (...args) => Promise<any> } = {}
44 functionsHash[ENDPOINT_ACTIONS.ADD_VIDEO] = addRemoteVideoRetryWrapper
45 functionsHash[ENDPOINT_ACTIONS.UPDATE_VIDEO] = updateRemoteVideoRetryWrapper
46 functionsHash[ENDPOINT_ACTIONS.REMOVE_VIDEO] = removeRemoteVideoRetryWrapper
47 functionsHash[ENDPOINT_ACTIONS.ADD_CHANNEL] = addRemoteVideoChannelRetryWrapper
48 functionsHash[ENDPOINT_ACTIONS.UPDATE_CHANNEL] = updateRemoteVideoChannelRetryWrapper
49 functionsHash[ENDPOINT_ACTIONS.REMOVE_CHANNEL] = removeRemoteVideoChannelRetryWrapper
50 functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideoRetryWrapper
51 functionsHash[ENDPOINT_ACTIONS.ADD_AUTHOR] = addRemoteVideoAuthorRetryWrapper
52 functionsHash[ENDPOINT_ACTIONS.REMOVE_AUTHOR] = removeRemoteVideoAuthorRetryWrapper
53
54 const remoteVideosRouter = express.Router()
55
56 remoteVideosRouter.post('/',
57 signatureValidator,
58 checkSignature,
59 remoteVideosValidator,
60 remoteVideos
61 )
62
63 remoteVideosRouter.post('/qadu',
64 signatureValidator,
65 checkSignature,
66 remoteQaduVideosValidator,
67 remoteVideosQadu
68 )
69
70 remoteVideosRouter.post('/events',
71 signatureValidator,
72 checkSignature,
73 remoteEventsVideosValidator,
74 remoteVideosEvents
75 )
76
77 // ---------------------------------------------------------------------------
78
79 export {
80 remoteVideosRouter
81 }
82
83 // ---------------------------------------------------------------------------
84
85 function remoteVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
86 const requests: RemoteVideoRequest[] = req.body.data
87 const fromPod = res.locals.secure.pod
88
89 // We need to process in the same order to keep consistency
90 Promise.each(requests, request => {
91 const data = request.data
92
93 // Get the function we need to call in order to process the request
94 const fun = functionsHash[request.type]
95 if (fun === undefined) {
96 logger.error('Unknown remote request type %s.', request.type)
97 return
98 }
99
100 return fun.call(this, data, fromPod)
101 })
102 .catch(err => logger.error('Error managing remote videos.', err))
103
104 // Don't block the other pod
105 return res.type('json').status(204).end()
106 }
107
108 function remoteVideosQadu (req: express.Request, res: express.Response, next: express.NextFunction) {
109 const requests: RemoteQaduVideoRequest[] = req.body.data
110 const fromPod = res.locals.secure.pod
111
112 Promise.each(requests, request => {
113 const videoData = request.data
114
115 return quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod)
116 })
117 .catch(err => logger.error('Error managing remote videos.', err))
118
119 return res.type('json').status(204).end()
120 }
121
122 function remoteVideosEvents (req: express.Request, res: express.Response, next: express.NextFunction) {
123 const requests: RemoteVideoEventRequest[] = req.body.data
124 const fromPod = res.locals.secure.pod
125
126 Promise.each(requests, request => {
127 const eventData = request.data
128
129 return processVideosEventsRetryWrapper(eventData, fromPod)
130 })
131 .catch(err => logger.error('Error managing remote videos.', err))
132
133 return res.type('json').status(204).end()
134 }
135
136 function processVideosEventsRetryWrapper (eventData: RemoteVideoEventData, fromPod: PodInstance) {
137 const options = {
138 arguments: [ eventData, fromPod ],
139 errorMessage: 'Cannot process videos events with many retries.'
140 }
141
142 return retryTransactionWrapper(processVideosEvents, options)
143 }
144
145 function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) {
146
147 return db.sequelize.transaction(t => {
148 return fetchVideoByUUID(eventData.uuid, t)
149 .then(videoInstance => {
150 const options = { transaction: t }
151
152 let columnToUpdate
153 let qaduType
154
155 switch (eventData.eventType) {
156 case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
157 columnToUpdate = 'views'
158 qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
159 break
160
161 case REQUEST_VIDEO_EVENT_TYPES.LIKES:
162 columnToUpdate = 'likes'
163 qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
164 break
165
166 case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
167 columnToUpdate = 'dislikes'
168 qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
169 break
170
171 default:
172 throw new Error('Unknown video event type.')
173 }
174
175 const query = {}
176 query[columnToUpdate] = eventData.count
177
178 return videoInstance.increment(query, options).then(() => ({ videoInstance, qaduType }))
179 })
180 .then(({ videoInstance, qaduType }) => {
181 const qadusParams = [
182 {
183 videoId: videoInstance.id,
184 type: qaduType
185 }
186 ]
187
188 return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
189 })
190 })
191 .then(() => logger.info('Remote video event processed for video with uuid %s.', eventData.uuid))
192 .catch(err => {
193 logger.debug('Cannot process a video event.', err)
194 throw err
195 })
196 }
197
198 function quickAndDirtyUpdateVideoRetryWrapper (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
199 const options = {
200 arguments: [ videoData, fromPod ],
201 errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
202 }
203
204 return retryTransactionWrapper(quickAndDirtyUpdateVideo, options)
205 }
206
207 function quickAndDirtyUpdateVideo (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
208 let videoUUID = ''
209
210 return db.sequelize.transaction(t => {
211 return fetchVideoByHostAndUUID(fromPod.host, videoData.uuid, t)
212 .then(videoInstance => {
213 const options = { transaction: t }
214
215 videoUUID = videoInstance.uuid
216
217 if (videoData.views) {
218 videoInstance.set('views', videoData.views)
219 }
220
221 if (videoData.likes) {
222 videoInstance.set('likes', videoData.likes)
223 }
224
225 if (videoData.dislikes) {
226 videoInstance.set('dislikes', videoData.dislikes)
227 }
228
229 return videoInstance.save(options)
230 })
231 })
232 .then(() => logger.info('Remote video with uuid %s quick and dirty updated', videoUUID))
233 .catch(err => logger.debug('Cannot quick and dirty update the remote video.', err))
234 }
235
236 // Handle retries on fail
237 function addRemoteVideoRetryWrapper (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
238 const options = {
239 arguments: [ videoToCreateData, fromPod ],
240 errorMessage: 'Cannot insert the remote video with many retries.'
241 }
242
243 return retryTransactionWrapper(addRemoteVideo, options)
244 }
245
246 function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
247 logger.debug('Adding remote video "%s".', videoToCreateData.uuid)
248
249 return db.sequelize.transaction(t => {
250 return db.Video.loadByUUID(videoToCreateData.uuid)
251 .then(video => {
252 if (video) throw new Error('UUID already exists.')
253
254 return db.VideoChannel.loadByHostAndUUID(fromPod.host, videoToCreateData.channelUUID, t)
255 })
256 .then(videoChannel => {
257 if (!videoChannel) throw new Error('Video channel ' + videoToCreateData.channelUUID + ' not found.')
258
259 const tags = videoToCreateData.tags
260
261 return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ videoChannel, tagInstances }))
262 })
263 .then(({ videoChannel, tagInstances }) => {
264 const videoData = {
265 name: videoToCreateData.name,
266 uuid: videoToCreateData.uuid,
267 category: videoToCreateData.category,
268 licence: videoToCreateData.licence,
269 language: videoToCreateData.language,
270 nsfw: videoToCreateData.nsfw,
271 description: videoToCreateData.description,
272 channelId: videoChannel.id,
273 duration: videoToCreateData.duration,
274 createdAt: videoToCreateData.createdAt,
275 // FIXME: updatedAt does not seems to be considered by Sequelize
276 updatedAt: videoToCreateData.updatedAt,
277 views: videoToCreateData.views,
278 likes: videoToCreateData.likes,
279 dislikes: videoToCreateData.dislikes,
280 remote: true
281 }
282
283 const video = db.Video.build(videoData)
284 return { tagInstances, video }
285 })
286 .then(({ tagInstances, video }) => {
287 return db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData).then(() => ({ tagInstances, video }))
288 })
289 .then(({ tagInstances, video }) => {
290 const options = {
291 transaction: t
292 }
293
294 return video.save(options).then(videoCreated => ({ tagInstances, videoCreated }))
295 })
296 .then(({ tagInstances, videoCreated }) => {
297 const tasks = []
298 const options = {
299 transaction: t
300 }
301
302 videoToCreateData.files.forEach(fileData => {
303 const videoFileInstance = db.VideoFile.build({
304 extname: fileData.extname,
305 infoHash: fileData.infoHash,
306 resolution: fileData.resolution,
307 size: fileData.size,
308 videoId: videoCreated.id
309 })
310
311 tasks.push(videoFileInstance.save(options))
312 })
313
314 return Promise.all(tasks).then(() => ({ tagInstances, videoCreated }))
315 })
316 .then(({ tagInstances, videoCreated }) => {
317 const options = {
318 transaction: t
319 }
320
321 return videoCreated.setTags(tagInstances, options)
322 })
323 })
324 .then(() => logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid))
325 .catch(err => {
326 logger.debug('Cannot insert the remote video.', err)
327 throw err
328 })
329 }
330
331 // Handle retries on fail
332 function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
333 const options = {
334 arguments: [ videoAttributesToUpdate, fromPod ],
335 errorMessage: 'Cannot update the remote video with many retries'
336 }
337
338 return retryTransactionWrapper(updateRemoteVideo, options)
339 }
340
341 function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
342 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
343
344 return db.sequelize.transaction(t => {
345 return fetchVideoByHostAndUUID(fromPod.host, videoAttributesToUpdate.uuid, t)
346 .then(videoInstance => {
347 const tags = videoAttributesToUpdate.tags
348
349 return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ videoInstance, tagInstances }))
350 })
351 .then(({ videoInstance, tagInstances }) => {
352 const options = { transaction: t }
353
354 videoInstance.set('name', videoAttributesToUpdate.name)
355 videoInstance.set('category', videoAttributesToUpdate.category)
356 videoInstance.set('licence', videoAttributesToUpdate.licence)
357 videoInstance.set('language', videoAttributesToUpdate.language)
358 videoInstance.set('nsfw', videoAttributesToUpdate.nsfw)
359 videoInstance.set('description', videoAttributesToUpdate.description)
360 videoInstance.set('duration', videoAttributesToUpdate.duration)
361 videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
362 videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
363 videoInstance.set('views', videoAttributesToUpdate.views)
364 videoInstance.set('likes', videoAttributesToUpdate.likes)
365 videoInstance.set('dislikes', videoAttributesToUpdate.dislikes)
366
367 return videoInstance.save(options).then(() => ({ videoInstance, tagInstances }))
368 })
369 .then(({ tagInstances, videoInstance }) => {
370 const tasks: Promise<void>[] = []
371
372 // Remove old video files
373 videoInstance.VideoFiles.forEach(videoFile => {
374 tasks.push(videoFile.destroy({ transaction: t }))
375 })
376
377 return Promise.all(tasks).then(() => ({ tagInstances, videoInstance }))
378 })
379 .then(({ tagInstances, videoInstance }) => {
380 const tasks: Promise<VideoFileInstance>[] = []
381 const options = {
382 transaction: t
383 }
384
385 videoAttributesToUpdate.files.forEach(fileData => {
386 const videoFileInstance = db.VideoFile.build({
387 extname: fileData.extname,
388 infoHash: fileData.infoHash,
389 resolution: fileData.resolution,
390 size: fileData.size,
391 videoId: videoInstance.id
392 })
393
394 tasks.push(videoFileInstance.save(options))
395 })
396
397 return Promise.all(tasks).then(() => ({ tagInstances, videoInstance }))
398 })
399 .then(({ videoInstance, tagInstances }) => {
400 const options = { transaction: t }
401
402 return videoInstance.setTags(tagInstances, options)
403 })
404 })
405 .then(() => logger.info('Remote video with uuid %s updated', videoAttributesToUpdate.uuid))
406 .catch(err => {
407 // This is just a debug because we will retry the insert
408 logger.debug('Cannot update the remote video.', err)
409 throw err
410 })
411 }
412
413 function removeRemoteVideoRetryWrapper (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
414 const options = {
415 arguments: [ videoToRemoveData, fromPod ],
416 errorMessage: 'Cannot remove the remote video channel with many retries.'
417 }
418
419 return retryTransactionWrapper(removeRemoteVideo, options)
420 }
421
422 function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
423 logger.debug('Removing remote video "%s".', videoToRemoveData.uuid)
424
425 return db.sequelize.transaction(t => {
426 // We need the instance because we have to remove some other stuffs (thumbnail etc)
427 return fetchVideoByHostAndUUID(fromPod.host, videoToRemoveData.uuid, t)
428 .then(video => video.destroy({ transaction: t }))
429 })
430 .then(() => logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid))
431 .catch(err => {
432 logger.debug('Cannot remove the remote video.', err)
433 throw err
434 })
435 }
436
437 function addRemoteVideoAuthorRetryWrapper (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
438 const options = {
439 arguments: [ authorToCreateData, fromPod ],
440 errorMessage: 'Cannot insert the remote video author with many retries.'
441 }
442
443 return retryTransactionWrapper(addRemoteVideoAuthor, options)
444 }
445
446 function addRemoteVideoAuthor (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
447 logger.debug('Adding remote video author "%s".', authorToCreateData.uuid)
448
449 return db.sequelize.transaction(t => {
450 return db.Author.loadAuthorByPodAndUUID(authorToCreateData.uuid, fromPod.id, t)
451 .then(author => {
452 if (author) throw new Error('UUID already exists.')
453
454 return undefined
455 })
456 .then(() => {
457 const videoAuthorData = {
458 name: authorToCreateData.name,
459 uuid: authorToCreateData.uuid,
460 userId: null, // Not on our pod
461 podId: fromPod.id
462 }
463
464 const author = db.Author.build(videoAuthorData)
465 return author.save({ transaction: t })
466 })
467 })
468 .then(() => logger.info('Remote video author with uuid %s inserted.', authorToCreateData.uuid))
469 .catch(err => {
470 logger.debug('Cannot insert the remote video author.', err)
471 throw err
472 })
473 }
474
475 function removeRemoteVideoAuthorRetryWrapper (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
476 const options = {
477 arguments: [ authorAttributesToRemove, fromPod ],
478 errorMessage: 'Cannot remove the remote video author with many retries.'
479 }
480
481 return retryTransactionWrapper(removeRemoteVideoAuthor, options)
482 }
483
484 function removeRemoteVideoAuthor (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
485 logger.debug('Removing remote video author "%s".', authorAttributesToRemove.uuid)
486
487 return db.sequelize.transaction(t => {
488 return db.Author.loadAuthorByPodAndUUID(authorAttributesToRemove.uuid, fromPod.id, t)
489 .then(videoAuthor => videoAuthor.destroy({ transaction: t }))
490 })
491 .then(() => logger.info('Remote video author with uuid %s removed.', authorAttributesToRemove.uuid))
492 .catch(err => {
493 logger.debug('Cannot remove the remote video author.', err)
494 throw err
495 })
496 }
497
498 function addRemoteVideoChannelRetryWrapper (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
499 const options = {
500 arguments: [ videoChannelToCreateData, fromPod ],
501 errorMessage: 'Cannot insert the remote video channel with many retries.'
502 }
503
504 return retryTransactionWrapper(addRemoteVideoChannel, options)
505 }
506
507 function addRemoteVideoChannel (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
508 logger.debug('Adding remote video channel "%s".', videoChannelToCreateData.uuid)
509
510 return db.sequelize.transaction(t => {
511 return db.VideoChannel.loadByUUID(videoChannelToCreateData.uuid)
512 .then(videoChannel => {
513 if (videoChannel) throw new Error('UUID already exists.')
514
515 return undefined
516 })
517 .then(() => {
518 const authorUUID = videoChannelToCreateData.ownerUUID
519 const podId = fromPod.id
520
521 return db.Author.loadAuthorByPodAndUUID(authorUUID, podId, t)
522 })
523 .then(author => {
524 if (!author) throw new Error('Unknown author UUID.')
525
526 const videoChannelData = {
527 name: videoChannelToCreateData.name,
528 description: videoChannelToCreateData.description,
529 uuid: videoChannelToCreateData.uuid,
530 createdAt: videoChannelToCreateData.createdAt,
531 updatedAt: videoChannelToCreateData.updatedAt,
532 remote: true,
533 authorId: author.id
534 }
535
536 const videoChannel = db.VideoChannel.build(videoChannelData)
537 return videoChannel.save({ transaction: t })
538 })
539 })
540 .then(() => logger.info('Remote video channel with uuid %s inserted.', videoChannelToCreateData.uuid))
541 .catch(err => {
542 logger.debug('Cannot insert the remote video channel.', err)
543 throw err
544 })
545 }
546
547 function updateRemoteVideoChannelRetryWrapper (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
548 const options = {
549 arguments: [ videoChannelAttributesToUpdate, fromPod ],
550 errorMessage: 'Cannot update the remote video channel with many retries.'
551 }
552
553 return retryTransactionWrapper(updateRemoteVideoChannel, options)
554 }
555
556 function updateRemoteVideoChannel (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
557 logger.debug('Updating remote video channel "%s".', videoChannelAttributesToUpdate.uuid)
558
559 return db.sequelize.transaction(t => {
560 return fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToUpdate.uuid, t)
561 .then(videoChannelInstance => {
562 const options = { transaction: t }
563
564 videoChannelInstance.set('name', videoChannelAttributesToUpdate.name)
565 videoChannelInstance.set('description', videoChannelAttributesToUpdate.description)
566 videoChannelInstance.set('createdAt', videoChannelAttributesToUpdate.createdAt)
567 videoChannelInstance.set('updatedAt', videoChannelAttributesToUpdate.updatedAt)
568
569 return videoChannelInstance.save(options)
570 })
571 })
572 .then(() => logger.info('Remote video channel with uuid %s updated', videoChannelAttributesToUpdate.uuid))
573 .catch(err => {
574 // This is just a debug because we will retry the insert
575 logger.debug('Cannot update the remote video channel.', err)
576 throw err
577 })
578 }
579
580 function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
581 const options = {
582 arguments: [ videoChannelAttributesToRemove, fromPod ],
583 errorMessage: 'Cannot remove the remote video channel with many retries.'
584 }
585
586 return retryTransactionWrapper(removeRemoteVideoChannel, options)
587 }
588
589 function removeRemoteVideoChannel (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
590 logger.debug('Removing remote video channel "%s".', videoChannelAttributesToRemove.uuid)
591
592 return db.sequelize.transaction(t => {
593 return fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToRemove.uuid, t)
594 .then(videoChannel => videoChannel.destroy({ transaction: t }))
595 })
596 .then(() => logger.info('Remote video channel with uuid %s removed.', videoChannelAttributesToRemove.uuid))
597 .catch(err => {
598 logger.debug('Cannot remove the remote video channel.', err)
599 throw err
600 })
601 }
602
603 function reportAbuseRemoteVideoRetryWrapper (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
604 const options = {
605 arguments: [ reportData, fromPod ],
606 errorMessage: 'Cannot create remote abuse video with many retries.'
607 }
608
609 return retryTransactionWrapper(reportAbuseRemoteVideo, options)
610 }
611
612 function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
613 logger.debug('Reporting remote abuse for video %s.', reportData.videoUUID)
614
615 return db.sequelize.transaction(t => {
616 return fetchVideoByUUID(reportData.videoUUID, t)
617 .then(video => {
618 const videoAbuseData = {
619 reporterUsername: reportData.reporterUsername,
620 reason: reportData.reportReason,
621 reporterPodId: fromPod.id,
622 videoId: video.id
623 }
624
625 return db.VideoAbuse.create(videoAbuseData)
626 })
627 })
628 .then(() => logger.info('Remote abuse for video uuid %s created', reportData.videoUUID))
629 .catch(err => {
630 // This is just a debug because we will retry the insert
631 logger.debug('Cannot create remote abuse video', err)
632 throw err
633 })
634 }
635
636 function fetchVideoByUUID (id: string, t: Sequelize.Transaction) {
637 return db.Video.loadByUUID(id, t)
638 .then(video => {
639 if (!video) throw new Error('Video not found')
640
641 return video
642 })
643 .catch(err => {
644 logger.error('Cannot load owned video from id.', { error: err.stack, id })
645 throw err
646 })
647 }
648
649 function fetchVideoByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
650 return db.Video.loadByHostAndUUID(podHost, uuid, t)
651 .then(video => {
652 if (!video) throw new Error('Video not found')
653
654 return video
655 })
656 .catch(err => {
657 logger.error('Cannot load video from host and uuid.', { error: err.stack, podHost, uuid })
658 throw err
659 })
660 }
661
662 function fetchVideoChannelByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
663 return db.VideoChannel.loadByHostAndUUID(podHost, uuid, t)
664 .then(videoChannel => {
665 if (!videoChannel) throw new Error('Video channel not found')
666
667 return videoChannel
668 })
669 .catch(err => {
670 logger.error('Cannot load video channel from host and uuid.', { error: err.stack, podHost, uuid })
671 throw err
672 })
673 }