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