aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/videos
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api/videos')
-rw-r--r--server/controllers/api/videos/abuse.ts62
-rw-r--r--server/controllers/api/videos/blacklist.ts48
-rw-r--r--server/controllers/api/videos/channel.ts153
-rw-r--r--server/controllers/api/videos/index.ts354
-rw-r--r--server/controllers/api/videos/rate.ts205
5 files changed, 361 insertions, 461 deletions
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts
index c9313d5f5..4c7abf395 100644
--- a/server/controllers/api/videos/abuse.ts
+++ b/server/controllers/api/videos/abuse.ts
@@ -14,7 +14,8 @@ import {
14 videoAbuseReportValidator, 14 videoAbuseReportValidator,
15 videoAbusesSortValidator, 15 videoAbusesSortValidator,
16 setVideoAbusesSort, 16 setVideoAbusesSort,
17 setPagination 17 setPagination,
18 asyncMiddleware
18} from '../../../middlewares' 19} from '../../../middlewares'
19import { VideoInstance } from '../../../models' 20import { VideoInstance } from '../../../models'
20import { VideoAbuseCreate } from '../../../../shared' 21import { VideoAbuseCreate } from '../../../../shared'
@@ -28,12 +29,12 @@ abuseVideoRouter.get('/abuse',
28 videoAbusesSortValidator, 29 videoAbusesSortValidator,
29 setVideoAbusesSort, 30 setVideoAbusesSort,
30 setPagination, 31 setPagination,
31 listVideoAbuses 32 asyncMiddleware(listVideoAbuses)
32) 33)
33abuseVideoRouter.post('/:id/abuse', 34abuseVideoRouter.post('/:id/abuse',
34 authenticate, 35 authenticate,
35 videoAbuseReportValidator, 36 videoAbuseReportValidator,
36 reportVideoAbuseRetryWrapper 37 asyncMiddleware(reportVideoAbuseRetryWrapper)
37) 38)
38 39
39// --------------------------------------------------------------------------- 40// ---------------------------------------------------------------------------
@@ -44,55 +45,48 @@ export {
44 45
45// --------------------------------------------------------------------------- 46// ---------------------------------------------------------------------------
46 47
47function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) { 48async function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) {
48 db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort) 49 const resultList = await db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort)
49 .then(result => res.json(getFormattedObjects(result.data, result.total))) 50
50 .catch(err => next(err)) 51 return res.json(getFormattedObjects(resultList.data, resultList.total))
51} 52}
52 53
53function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 54async function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
54 const options = { 55 const options = {
55 arguments: [ req, res ], 56 arguments: [ req, res ],
56 errorMessage: 'Cannot report abuse to the video with many retries.' 57 errorMessage: 'Cannot report abuse to the video with many retries.'
57 } 58 }
58 59
59 retryTransactionWrapper(reportVideoAbuse, options) 60 await retryTransactionWrapper(reportVideoAbuse, options)
60 .then(() => res.type('json').status(204).end()) 61
61 .catch(err => next(err)) 62 return res.type('json').status(204).end()
62} 63}
63 64
64function reportVideoAbuse (req: express.Request, res: express.Response) { 65async function reportVideoAbuse (req: express.Request, res: express.Response) {
65 const videoInstance = res.locals.video as VideoInstance 66 const videoInstance = res.locals.video as VideoInstance
66 const reporterUsername = res.locals.oauth.token.User.username 67 const reporterUsername = res.locals.oauth.token.User.username
67 const body: VideoAbuseCreate = req.body 68 const body: VideoAbuseCreate = req.body
68 69
69 const abuse = { 70 const abuseToCreate = {
70 reporterUsername, 71 reporterUsername,
71 reason: body.reason, 72 reason: body.reason,
72 videoId: videoInstance.id, 73 videoId: videoInstance.id,
73 reporterPodId: null // This is our pod that reported this abuse 74 reporterPodId: null // This is our pod that reported this abuse
74 } 75 }
75 76
76 return db.sequelize.transaction(t => { 77 await db.sequelize.transaction(async t => {
77 return db.VideoAbuse.create(abuse, { transaction: t }) 78 const abuse = await db.VideoAbuse.create(abuseToCreate, { transaction: t })
78 .then(abuse => { 79 // We send the information to the destination pod
79 // We send the information to the destination pod 80 if (videoInstance.isOwned() === false) {
80 if (videoInstance.isOwned() === false) { 81 const reportData = {
81 const reportData = { 82 reporterUsername,
82 reporterUsername, 83 reportReason: abuse.reason,
83 reportReason: abuse.reason, 84 videoUUID: videoInstance.uuid
84 videoUUID: videoInstance.uuid 85 }
85 } 86
86 87 await friends.reportAbuseVideoToFriend(reportData, videoInstance, t)
87 return friends.reportAbuseVideoToFriend(reportData, videoInstance, t).then(() => videoInstance) 88 }
88 }
89
90 return videoInstance
91 })
92 })
93 .then((videoInstance: VideoInstance) => logger.info('Abuse report for video %s created.', videoInstance.name))
94 .catch(err => {
95 logger.debug('Cannot update the video.', err)
96 throw err
97 }) 89 })
90
91 logger.info('Abuse report for video %s created.', videoInstance.name)
98} 92}
diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts
index 66311598e..5a2c3fd80 100644
--- a/server/controllers/api/videos/blacklist.ts
+++ b/server/controllers/api/videos/blacklist.ts
@@ -10,7 +10,8 @@ import {
10 paginationValidator, 10 paginationValidator,
11 blacklistSortValidator, 11 blacklistSortValidator,
12 setBlacklistSort, 12 setBlacklistSort,
13 setPagination 13 setPagination,
14 asyncMiddleware
14} from '../../../middlewares' 15} from '../../../middlewares'
15import { BlacklistedVideoInstance } from '../../../models' 16import { BlacklistedVideoInstance } from '../../../models'
16import { BlacklistedVideo } from '../../../../shared' 17import { BlacklistedVideo } from '../../../../shared'
@@ -21,7 +22,7 @@ blacklistRouter.post('/:videoId/blacklist',
21 authenticate, 22 authenticate,
22 ensureIsAdmin, 23 ensureIsAdmin,
23 videosBlacklistAddValidator, 24 videosBlacklistAddValidator,
24 addVideoToBlacklist 25 asyncMiddleware(addVideoToBlacklist)
25) 26)
26 27
27blacklistRouter.get('/blacklist', 28blacklistRouter.get('/blacklist',
@@ -31,14 +32,14 @@ blacklistRouter.get('/blacklist',
31 blacklistSortValidator, 32 blacklistSortValidator,
32 setBlacklistSort, 33 setBlacklistSort,
33 setPagination, 34 setPagination,
34 listBlacklist 35 asyncMiddleware(listBlacklist)
35) 36)
36 37
37blacklistRouter.delete('/:videoId/blacklist', 38blacklistRouter.delete('/:videoId/blacklist',
38 authenticate, 39 authenticate,
39 ensureIsAdmin, 40 ensureIsAdmin,
40 videosBlacklistRemoveValidator, 41 videosBlacklistRemoveValidator,
41 removeVideoFromBlacklistController 42 asyncMiddleware(removeVideoFromBlacklistController)
42) 43)
43 44
44// --------------------------------------------------------------------------- 45// ---------------------------------------------------------------------------
@@ -49,37 +50,34 @@ export {
49 50
50// --------------------------------------------------------------------------- 51// ---------------------------------------------------------------------------
51 52
52function addVideoToBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) { 53async function addVideoToBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
53 const videoInstance = res.locals.video 54 const videoInstance = res.locals.video
54 55
55 const toCreate = { 56 const toCreate = {
56 videoId: videoInstance.id 57 videoId: videoInstance.id
57 } 58 }
58 59
59 db.BlacklistedVideo.create(toCreate) 60 await db.BlacklistedVideo.create(toCreate)
60 .then(() => res.type('json').status(204).end()) 61 return res.type('json').status(204).end()
61 .catch(err => {
62 logger.error('Errors when blacklisting video ', err)
63 return next(err)
64 })
65} 62}
66 63
67function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) { 64async function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
68 db.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort) 65 const resultList = await db.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort)
69 .then(resultList => res.json(getFormattedObjects<BlacklistedVideo, BlacklistedVideoInstance>(resultList.data, resultList.total))) 66
70 .catch(err => next(err)) 67 return res.json(getFormattedObjects<BlacklistedVideo, BlacklistedVideoInstance>(resultList.data, resultList.total))
71} 68}
72 69
73function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { 70async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) {
74 const blacklistedVideo = res.locals.blacklistedVideo as BlacklistedVideoInstance 71 const blacklistedVideo = res.locals.blacklistedVideo as BlacklistedVideoInstance
75 72
76 blacklistedVideo.destroy() 73 try {
77 .then(() => { 74 await blacklistedVideo.destroy()
78 logger.info('Video %s removed from blacklist.', res.locals.video.uuid) 75
79 res.sendStatus(204) 76 logger.info('Video %s removed from blacklist.', res.locals.video.uuid)
80 }) 77
81 .catch(err => { 78 return res.sendStatus(204)
82 logger.error('Some error while removing video %s from blacklist.', res.locals.video.uuid, err) 79 } catch (err) {
83 next(err) 80 logger.error('Some error while removing video %s from blacklist.', res.locals.video.uuid, err)
84 }) 81 throw err
82 }
85} 83}
diff --git a/server/controllers/api/videos/channel.ts b/server/controllers/api/videos/channel.ts
index 630fc4f53..ab54eedee 100644
--- a/server/controllers/api/videos/channel.ts
+++ b/server/controllers/api/videos/channel.ts
@@ -4,7 +4,8 @@ import { database as db } from '../../../initializers'
4import { 4import {
5 logger, 5 logger,
6 getFormattedObjects, 6 getFormattedObjects,
7 retryTransactionWrapper 7 retryTransactionWrapper,
8 resetSequelizeInstance
8} from '../../../helpers' 9} from '../../../helpers'
9import { 10import {
10 authenticate, 11 authenticate,
@@ -16,7 +17,8 @@ import {
16 videoChannelsRemoveValidator, 17 videoChannelsRemoveValidator,
17 videoChannelGetValidator, 18 videoChannelGetValidator,
18 videoChannelsUpdateValidator, 19 videoChannelsUpdateValidator,
19 listVideoAuthorChannelsValidator 20 listVideoAuthorChannelsValidator,
21 asyncMiddleware
20} from '../../../middlewares' 22} from '../../../middlewares'
21import { 23import {
22 createVideoChannel, 24 createVideoChannel,
@@ -32,18 +34,18 @@ videoChannelRouter.get('/channels',
32 videoChannelsSortValidator, 34 videoChannelsSortValidator,
33 setVideoChannelsSort, 35 setVideoChannelsSort,
34 setPagination, 36 setPagination,
35 listVideoChannels 37 asyncMiddleware(listVideoChannels)
36) 38)
37 39
38videoChannelRouter.get('/authors/:authorId/channels', 40videoChannelRouter.get('/authors/:authorId/channels',
39 listVideoAuthorChannelsValidator, 41 listVideoAuthorChannelsValidator,
40 listVideoAuthorChannels 42 asyncMiddleware(listVideoAuthorChannels)
41) 43)
42 44
43videoChannelRouter.post('/channels', 45videoChannelRouter.post('/channels',
44 authenticate, 46 authenticate,
45 videoChannelsAddValidator, 47 videoChannelsAddValidator,
46 addVideoChannelRetryWrapper 48 asyncMiddleware(addVideoChannelRetryWrapper)
47) 49)
48 50
49videoChannelRouter.put('/channels/:id', 51videoChannelRouter.put('/channels/:id',
@@ -55,12 +57,12 @@ videoChannelRouter.put('/channels/:id',
55videoChannelRouter.delete('/channels/:id', 57videoChannelRouter.delete('/channels/:id',
56 authenticate, 58 authenticate,
57 videoChannelsRemoveValidator, 59 videoChannelsRemoveValidator,
58 removeVideoChannelRetryWrapper 60 asyncMiddleware(removeVideoChannelRetryWrapper)
59) 61)
60 62
61videoChannelRouter.get('/channels/:id', 63videoChannelRouter.get('/channels/:id',
62 videoChannelGetValidator, 64 videoChannelGetValidator,
63 getVideoChannel 65 asyncMiddleware(getVideoChannel)
64) 66)
65 67
66// --------------------------------------------------------------------------- 68// ---------------------------------------------------------------------------
@@ -71,126 +73,113 @@ export {
71 73
72// --------------------------------------------------------------------------- 74// ---------------------------------------------------------------------------
73 75
74function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) { 76async function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
75 db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort) 77 const resultList = await db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort)
76 .then(result => res.json(getFormattedObjects(result.data, result.total))) 78
77 .catch(err => next(err)) 79 return res.json(getFormattedObjects(resultList.data, resultList.total))
78} 80}
79 81
80function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) { 82async function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
81 db.VideoChannel.listByAuthor(res.locals.author.id) 83 const resultList = await db.VideoChannel.listByAuthor(res.locals.author.id)
82 .then(result => res.json(getFormattedObjects(result.data, result.total))) 84
83 .catch(err => next(err)) 85 return res.json(getFormattedObjects(resultList.data, resultList.total))
84} 86}
85 87
86// Wrapper to video channel add that retry the function if there is a database error 88// Wrapper to video channel add that retry the async function if there is a database error
87// We need this because we run the transaction in SERIALIZABLE isolation that can fail 89// We need this because we run the transaction in SERIALIZABLE isolation that can fail
88function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 90async function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
89 const options = { 91 const options = {
90 arguments: [ req, res ], 92 arguments: [ req, res ],
91 errorMessage: 'Cannot insert the video video channel with many retries.' 93 errorMessage: 'Cannot insert the video video channel with many retries.'
92 } 94 }
93 95
94 retryTransactionWrapper(addVideoChannel, options) 96 await retryTransactionWrapper(addVideoChannel, options)
95 .then(() => { 97
96 // TODO : include Location of the new video channel -> 201 98 // TODO : include Location of the new video channel -> 201
97 res.type('json').status(204).end() 99 return res.type('json').status(204).end()
98 })
99 .catch(err => next(err))
100} 100}
101 101
102function addVideoChannel (req: express.Request, res: express.Response) { 102async 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 author: AuthorInstance = res.locals.oauth.token.User.Author
105 let videoChannelCreated: VideoChannelInstance
105 106
106 return db.sequelize.transaction(t => { 107 await db.sequelize.transaction(async t => {
107 return createVideoChannel(videoChannelInfo, author, t) 108 videoChannelCreated = await createVideoChannel(videoChannelInfo, author, t)
108 })
109 .then(videoChannelUUID => logger.info('Video channel with uuid %s created.', videoChannelUUID))
110 .catch((err: Error) => {
111 logger.debug('Cannot insert the video channel.', err)
112 throw err
113 }) 109 })
110
111 logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid)
114} 112}
115 113
116function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 114async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
117 const options = { 115 const options = {
118 arguments: [ req, res ], 116 arguments: [ req, res ],
119 errorMessage: 'Cannot update the video with many retries.' 117 errorMessage: 'Cannot update the video with many retries.'
120 } 118 }
121 119
122 retryTransactionWrapper(updateVideoChannel, options) 120 await retryTransactionWrapper(updateVideoChannel, options)
123 .then(() => res.type('json').status(204).end()) 121
124 .catch(err => next(err)) 122 return res.type('json').status(204).end()
125} 123}
126 124
127function updateVideoChannel (req: express.Request, res: express.Response) { 125async function updateVideoChannel (req: express.Request, res: express.Response) {
128 const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel 126 const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
129 const videoChannelFieldsSave = videoChannelInstance.toJSON() 127 const videoChannelFieldsSave = videoChannelInstance.toJSON()
130 const videoChannelInfoToUpdate: VideoChannelUpdate = req.body 128 const videoChannelInfoToUpdate: VideoChannelUpdate = req.body
131 129
132 return db.sequelize.transaction(t => { 130 try {
133 const options = { 131 await db.sequelize.transaction(async t => {
134 transaction: t 132 const sequelizeOptions = {
135 } 133 transaction: t
134 }
136 135
137 if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name) 136 if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
138 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description) 137 if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
139 138
140 return videoChannelInstance.save(options) 139 await videoChannelInstance.save(sequelizeOptions)
141 .then(() => { 140 const json = videoChannelInstance.toUpdateRemoteJSON()
142 const json = videoChannelInstance.toUpdateRemoteJSON() 141
142 // Now we'll update the video channel's meta data to our friends
143 return updateVideoChannelToFriends(json, t)
143 144
144 // Now we'll update the video channel's meta data to our friends
145 return updateVideoChannelToFriends(json, t)
146 })
147 })
148 .then(() => {
149 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
150 })
151 .catch(err => {
152 logger.debug('Cannot update the video channel.', err)
153
154 // Force fields we want to update
155 // If the transaction is retried, sequelize will think the object has not changed
156 // So it will skip the SQL request, even if the last one was ROLLBACKed!
157 Object.keys(videoChannelFieldsSave).forEach(key => {
158 const value = videoChannelFieldsSave[key]
159 videoChannelInstance.set(key, value)
160 })
161
162 throw err
163 }) 145 })
146
147 logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
148 } catch (err) {
149 logger.debug('Cannot update the video channel.', err)
150
151 // Force fields we want to update
152 // If the transaction is retried, sequelize will think the object has not changed
153 // So it will skip the SQL request, even if the last one was ROLLBACKed!
154 resetSequelizeInstance(videoChannelInstance, videoChannelFieldsSave)
155
156 throw err
157 }
164} 158}
165 159
166function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 160async function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
167 const options = { 161 const options = {
168 arguments: [ req, res ], 162 arguments: [ req, res ],
169 errorMessage: 'Cannot remove the video channel with many retries.' 163 errorMessage: 'Cannot remove the video channel with many retries.'
170 } 164 }
171 165
172 retryTransactionWrapper(removeVideoChannel, options) 166 await retryTransactionWrapper(removeVideoChannel, options)
173 .then(() => res.type('json').status(204).end()) 167
174 .catch(err => next(err)) 168 return res.type('json').status(204).end()
175} 169}
176 170
177function removeVideoChannel (req: express.Request, res: express.Response) { 171async function removeVideoChannel (req: express.Request, res: express.Response) {
178 const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel 172 const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
179 173
180 return db.sequelize.transaction(t => { 174 await db.sequelize.transaction(async t => {
181 return videoChannelInstance.destroy({ transaction: t }) 175 await videoChannelInstance.destroy({ transaction: t })
182 })
183 .then(() => {
184 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
185 })
186 .catch(err => {
187 logger.error('Errors when removed the video channel.', err)
188 throw err
189 }) 176 })
177
178 logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
190} 179}
191 180
192function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) { 181async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
193 db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id) 182 const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id)
194 .then(videoChannelWithVideos => res.json(videoChannelWithVideos.toFormattedJSON())) 183
195 .catch(err => next(err)) 184 return res.json(videoChannelWithVideos.toFormattedJSON())
196} 185}
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index ec855ee8e..7ebbf4d6e 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -1,5 +1,4 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as Promise from 'bluebird'
3import * as multer from 'multer' 2import * as multer from 'multer'
4import { extname, join } from 'path' 3import { extname, join } from 'path'
5 4
@@ -30,7 +29,8 @@ import {
30 videosSearchValidator, 29 videosSearchValidator,
31 videosAddValidator, 30 videosAddValidator,
32 videosGetValidator, 31 videosGetValidator,
33 videosRemoveValidator 32 videosRemoveValidator,
33 asyncMiddleware
34} from '../../../middlewares' 34} from '../../../middlewares'
35import { 35import {
36 logger, 36 logger,
@@ -38,7 +38,8 @@ import {
38 generateRandomString, 38 generateRandomString,
39 getFormattedObjects, 39 getFormattedObjects,
40 renamePromise, 40 renamePromise,
41 getVideoFileHeight 41 getVideoFileHeight,
42 resetSequelizeInstance
42} from '../../../helpers' 43} from '../../../helpers'
43import { TagInstance, VideoInstance } from '../../../models' 44import { TagInstance, VideoInstance } from '../../../models'
44import { VideoCreate, VideoUpdate } from '../../../../shared' 45import { VideoCreate, VideoUpdate } from '../../../../shared'
@@ -88,18 +89,18 @@ videosRouter.get('/',
88 videosSortValidator, 89 videosSortValidator,
89 setVideosSort, 90 setVideosSort,
90 setPagination, 91 setPagination,
91 listVideos 92 asyncMiddleware(listVideos)
92) 93)
93videosRouter.put('/:id', 94videosRouter.put('/:id',
94 authenticate, 95 authenticate,
95 videosUpdateValidator, 96 videosUpdateValidator,
96 updateVideoRetryWrapper 97 asyncMiddleware(updateVideoRetryWrapper)
97) 98)
98videosRouter.post('/upload', 99videosRouter.post('/upload',
99 authenticate, 100 authenticate,
100 reqFiles, 101 reqFiles,
101 videosAddValidator, 102 videosAddValidator,
102 addVideoRetryWrapper 103 asyncMiddleware(addVideoRetryWrapper)
103) 104)
104videosRouter.get('/:id', 105videosRouter.get('/:id',
105 videosGetValidator, 106 videosGetValidator,
@@ -109,7 +110,7 @@ videosRouter.get('/:id',
109videosRouter.delete('/:id', 110videosRouter.delete('/:id',
110 authenticate, 111 authenticate,
111 videosRemoveValidator, 112 videosRemoveValidator,
112 removeVideoRetryWrapper 113 asyncMiddleware(removeVideoRetryWrapper)
113) 114)
114 115
115videosRouter.get('/search/:value', 116videosRouter.get('/search/:value',
@@ -119,7 +120,7 @@ videosRouter.get('/search/:value',
119 setVideosSort, 120 setVideosSort,
120 setPagination, 121 setPagination,
121 setVideosSearch, 122 setVideosSearch,
122 searchVideos 123 asyncMiddleware(searchVideos)
123) 124)
124 125
125// --------------------------------------------------------------------------- 126// ---------------------------------------------------------------------------
@@ -144,220 +145,157 @@ function listVideoLanguages (req: express.Request, res: express.Response) {
144 145
145// Wrapper to video add that retry the function if there is a database error 146// Wrapper to video add that retry the function if there is a database error
146// We need this because we run the transaction in SERIALIZABLE isolation that can fail 147// We need this because we run the transaction in SERIALIZABLE isolation that can fail
147function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 148async function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
148 const options = { 149 const options = {
149 arguments: [ req, res, req.files['videofile'][0] ], 150 arguments: [ req, res, req.files['videofile'][0] ],
150 errorMessage: 'Cannot insert the video with many retries.' 151 errorMessage: 'Cannot insert the video with many retries.'
151 } 152 }
152 153
153 retryTransactionWrapper(addVideo, options) 154 await retryTransactionWrapper(addVideo, options)
154 .then(() => { 155
155 // TODO : include Location of the new video -> 201 156 // TODO : include Location of the new video -> 201
156 res.type('json').status(204).end() 157 res.type('json').status(204).end()
157 })
158 .catch(err => next(err))
159} 158}
160 159
161function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) { 160async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
162 const videoInfo: VideoCreate = req.body 161 const videoInfo: VideoCreate = req.body
163 let videoUUID = '' 162 let videoUUID = ''
164 163
165 return db.sequelize.transaction(t => { 164 await db.sequelize.transaction(async t => {
166 let p: Promise<TagInstance[]> 165 const sequelizeOptions = { transaction: t }
167 166
168 if (!videoInfo.tags) p = Promise.resolve(undefined) 167 const videoData = {
169 else p = db.Tag.findOrCreateTags(videoInfo.tags, t) 168 name: videoInfo.name,
170 169 remote: false,
171 return p 170 extname: extname(videoPhysicalFile.filename),
172 .then(tagInstances => { 171 category: videoInfo.category,
173 const videoData = { 172 licence: videoInfo.licence,
174 name: videoInfo.name, 173 language: videoInfo.language,
175 remote: false, 174 nsfw: videoInfo.nsfw,
176 extname: extname(videoPhysicalFile.filename), 175 description: videoInfo.description,
177 category: videoInfo.category, 176 duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
178 licence: videoInfo.licence, 177 channelId: res.locals.videoChannel.id
179 language: videoInfo.language, 178 }
180 nsfw: videoInfo.nsfw, 179 const video = db.Video.build(videoData)
181 description: videoInfo.description,
182 duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
183 channelId: res.locals.videoChannel.id
184 }
185 180
186 const video = db.Video.build(videoData) 181 const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
187 return { tagInstances, video } 182 const videoFileHeight = await getVideoFileHeight(videoFilePath)
188 })
189 .then(({ tagInstances, video }) => {
190 const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
191 return getVideoFileHeight(videoFilePath)
192 .then(height => ({ tagInstances, video, videoFileHeight: height }))
193 })
194 .then(({ tagInstances, video, videoFileHeight }) => {
195 const videoFileData = {
196 extname: extname(videoPhysicalFile.filename),
197 resolution: videoFileHeight,
198 size: videoPhysicalFile.size
199 }
200 183
201 const videoFile = db.VideoFile.build(videoFileData) 184 const videoFileData = {
202 return { tagInstances, video, videoFile } 185 extname: extname(videoPhysicalFile.filename),
203 }) 186 resolution: videoFileHeight,
204 .then(({ tagInstances, video, videoFile }) => { 187 size: videoPhysicalFile.size
205 const videoDir = CONFIG.STORAGE.VIDEOS_DIR 188 }
206 const source = join(videoDir, videoPhysicalFile.filename) 189 const videoFile = db.VideoFile.build(videoFileData)
207 const destination = join(videoDir, video.getVideoFilename(videoFile)) 190 const videoDir = CONFIG.STORAGE.VIDEOS_DIR
208 191 const source = join(videoDir, videoPhysicalFile.filename)
209 return renamePromise(source, destination) 192 const destination = join(videoDir, video.getVideoFilename(videoFile))
210 .then(() => { 193
211 // This is important in case if there is another attempt in the retry process 194 await renamePromise(source, destination)
212 videoPhysicalFile.filename = video.getVideoFilename(videoFile) 195 // This is important in case if there is another attempt in the retry process
213 return { tagInstances, video, videoFile } 196 videoPhysicalFile.filename = video.getVideoFilename(videoFile)
214 }) 197
215 }) 198 const tasks = []
216 .then(({ tagInstances, video, videoFile }) => { 199
217 const tasks = [] 200 tasks.push(
218 201 video.createTorrentAndSetInfoHash(videoFile),
219 tasks.push( 202 video.createThumbnail(videoFile),
220 video.createTorrentAndSetInfoHash(videoFile), 203 video.createPreview(videoFile)
221 video.createThumbnail(videoFile), 204 )
222 video.createPreview(videoFile) 205
223 ) 206 if (CONFIG.TRANSCODING.ENABLED === true) {
224 207 // Put uuid because we don't have id auto incremented for now
225 if (CONFIG.TRANSCODING.ENABLED === true) { 208 const dataInput = {
226 // Put uuid because we don't have id auto incremented for now 209 videoUUID: video.uuid
227 const dataInput = { 210 }
228 videoUUID: video.uuid 211
229 } 212 tasks.push(
230 213 JobScheduler.Instance.createJob(t, 'videoFileOptimizer', dataInput)
231 tasks.push( 214 )
232 JobScheduler.Instance.createJob(t, 'videoFileOptimizer', dataInput) 215 }
233 ) 216 await Promise.all(tasks)
234 }
235 217
236 return Promise.all(tasks).then(() => ({ tagInstances, video, videoFile })) 218 const videoCreated = await video.save(sequelizeOptions)
237 }) 219 // Do not forget to add video channel information to the created video
238 .then(({ tagInstances, video, videoFile }) => { 220 videoCreated.VideoChannel = res.locals.videoChannel
239 const options = { transaction: t } 221 videoUUID = videoCreated.uuid
240 222
241 return video.save(options) 223 videoFile.videoId = video.id
242 .then(videoCreated => {
243 // Do not forget to add video channel information to the created video
244 videoCreated.VideoChannel = res.locals.videoChannel
245 videoUUID = videoCreated.uuid
246 224
247 return { tagInstances, video: videoCreated, videoFile } 225 await videoFile.save(sequelizeOptions)
248 }) 226 video.VideoFiles = [videoFile]
249 })
250 .then(({ tagInstances, video, videoFile }) => {
251 const options = { transaction: t }
252 videoFile.videoId = video.id
253 227
254 return videoFile.save(options) 228 if (videoInfo.tags) {
255 .then(() => video.VideoFiles = [ videoFile ]) 229 const tagInstances = await db.Tag.findOrCreateTags(videoInfo.tags, t)
256 .then(() => ({ tagInstances, video })) 230
257 }) 231 await video.setTags(tagInstances, sequelizeOptions)
258 .then(({ tagInstances, video }) => { 232 video.Tags = tagInstances
259 if (!tagInstances) return video 233 }
260 234
261 const options = { transaction: t } 235 // Let transcoding job send the video to friends because the video file extension might change
262 return video.setTags(tagInstances, options) 236 if (CONFIG.TRANSCODING.ENABLED === true) return undefined
263 .then(() => { 237
264 video.Tags = tagInstances 238 const remoteVideo = await video.toAddRemoteJSON()
265 return video 239 // Now we'll add the video's meta data to our friends
266 }) 240 return addVideoToFriends(remoteVideo, t)
267 })
268 .then(video => {
269 // Let transcoding job send the video to friends because the video file extension might change
270 if (CONFIG.TRANSCODING.ENABLED === true) return undefined
271
272 return video.toAddRemoteJSON()
273 .then(remoteVideo => {
274 // Now we'll add the video's meta data to our friends
275 return addVideoToFriends(remoteVideo, t)
276 })
277 })
278 })
279 .then(() => logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID))
280 .catch((err: Error) => {
281 logger.debug('Cannot insert the video.', err)
282 throw err
283 }) 241 })
242
243 logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID)
284} 244}
285 245
286function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 246async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
287 const options = { 247 const options = {
288 arguments: [ req, res ], 248 arguments: [ req, res ],
289 errorMessage: 'Cannot update the video with many retries.' 249 errorMessage: 'Cannot update the video with many retries.'
290 } 250 }
291 251
292 retryTransactionWrapper(updateVideo, options) 252 await retryTransactionWrapper(updateVideo, options)
293 .then(() => { 253
294 return res.type('json').status(204).end() 254 return res.type('json').status(204).end()
295 })
296 .catch(err => next(err))
297} 255}
298 256
299function updateVideo (req: express.Request, res: express.Response) { 257async function updateVideo (req: express.Request, res: express.Response) {
300 const videoInstance = res.locals.video 258 const videoInstance = res.locals.video
301 const videoFieldsSave = videoInstance.toJSON() 259 const videoFieldsSave = videoInstance.toJSON()
302 const videoInfoToUpdate: VideoUpdate = req.body 260 const videoInfoToUpdate: VideoUpdate = req.body
303 261
304 return db.sequelize.transaction(t => { 262 try {
305 let tagsPromise: Promise<TagInstance[]> 263 await db.sequelize.transaction(async t => {
306 if (!videoInfoToUpdate.tags) { 264 const sequelizeOptions = {
307 tagsPromise = Promise.resolve(null) 265 transaction: t
308 } else { 266 }
309 tagsPromise = db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t)
310 }
311 267
312 return tagsPromise 268 if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name)
313 .then(tagInstances => { 269 if (videoInfoToUpdate.category !== undefined) videoInstance.set('category', videoInfoToUpdate.category)
314 const options = { 270 if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
315 transaction: t 271 if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
316 } 272 if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
273 if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
317 274
318 if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name) 275 await videoInstance.save(sequelizeOptions)
319 if (videoInfoToUpdate.category !== undefined) videoInstance.set('category', videoInfoToUpdate.category)
320 if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
321 if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
322 if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
323 if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
324 276
325 return videoInstance.save(options).then(() => tagInstances) 277 if (videoInfoToUpdate.tags) {
326 }) 278 const tagInstances = await db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t)
327 .then(tagInstances => {
328 if (!tagInstances) return
329 279
330 const options = { transaction: t } 280 await videoInstance.setTags(tagInstances, sequelizeOptions)
331 return videoInstance.setTags(tagInstances, options) 281 videoInstance.Tags = tagInstances
332 .then(() => { 282 }
333 videoInstance.Tags = tagInstances
334 283
335 return 284 const json = videoInstance.toUpdateRemoteJSON()
336 })
337 })
338 .then(() => {
339 const json = videoInstance.toUpdateRemoteJSON()
340 285
341 // Now we'll update the video's meta data to our friends 286 // Now we'll update the video's meta data to our friends
342 return updateVideoToFriends(json, t) 287 return updateVideoToFriends(json, t)
343 }) 288 })
344 })
345 .then(() => {
346 logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
347 })
348 .catch(err => {
349 logger.debug('Cannot update the video.', err)
350 289
290 logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
291 } catch (err) {
351 // Force fields we want to update 292 // Force fields we want to update
352 // If the transaction is retried, sequelize will think the object has not changed 293 // If the transaction is retried, sequelize will think the object has not changed
353 // So it will skip the SQL request, even if the last one was ROLLBACKed! 294 // So it will skip the SQL request, even if the last one was ROLLBACKed!
354 Object.keys(videoFieldsSave).forEach(key => { 295 resetSequelizeInstance(videoInstance, videoFieldsSave)
355 const value = videoFieldsSave[key]
356 videoInstance.set(key, value)
357 })
358 296
359 throw err 297 throw err
360 }) 298 }
361} 299}
362 300
363function getVideo (req: express.Request, res: express.Response) { 301function getVideo (req: express.Request, res: express.Response) {
@@ -365,17 +303,17 @@ function getVideo (req: express.Request, res: express.Response) {
365 303
366 if (videoInstance.isOwned()) { 304 if (videoInstance.isOwned()) {
367 // The increment is done directly in the database, not using the instance value 305 // The increment is done directly in the database, not using the instance value
306 // FIXME: make a real view system
307 // For example, only add a view when a user watch a video during 30s etc
368 videoInstance.increment('views') 308 videoInstance.increment('views')
369 .then(() => { 309 .then(() => {
370 // FIXME: make a real view system
371 // For example, only add a view when a user watch a video during 30s etc
372 const qaduParams = { 310 const qaduParams = {
373 videoId: videoInstance.id, 311 videoId: videoInstance.id,
374 type: REQUEST_VIDEO_QADU_TYPES.VIEWS 312 type: REQUEST_VIDEO_QADU_TYPES.VIEWS
375 } 313 }
376 return quickAndDirtyUpdateVideoToFriends(qaduParams) 314 return quickAndDirtyUpdateVideoToFriends(qaduParams)
377 }) 315 })
378 .catch(err => logger.error('Cannot add view to video %d.', videoInstance.id, err)) 316 .catch(err => logger.error('Cannot add view to video %s.', videoInstance.uuid, err))
379 } else { 317 } else {
380 // Just send the event to our friends 318 // Just send the event to our friends
381 const eventParams = { 319 const eventParams = {
@@ -383,48 +321,48 @@ function getVideo (req: express.Request, res: express.Response) {
383 type: REQUEST_VIDEO_EVENT_TYPES.VIEWS 321 type: REQUEST_VIDEO_EVENT_TYPES.VIEWS
384 } 322 }
385 addEventToRemoteVideo(eventParams) 323 addEventToRemoteVideo(eventParams)
324 .catch(err => logger.error('Cannot add event to remote video %s.', videoInstance.uuid, err))
386 } 325 }
387 326
388 // Do not wait the view system 327 // Do not wait the view system
389 res.json(videoInstance.toFormattedDetailsJSON()) 328 return res.json(videoInstance.toFormattedDetailsJSON())
390} 329}
391 330
392function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { 331async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
393 db.Video.listForApi(req.query.start, req.query.count, req.query.sort) 332 const resultList = await db.Video.listForApi(req.query.start, req.query.count, req.query.sort)
394 .then(result => res.json(getFormattedObjects(result.data, result.total))) 333
395 .catch(err => next(err)) 334 return res.json(getFormattedObjects(resultList.data, resultList.total))
396} 335}
397 336
398function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 337async function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
399 const options = { 338 const options = {
400 arguments: [ req, res ], 339 arguments: [ req, res ],
401 errorMessage: 'Cannot remove the video with many retries.' 340 errorMessage: 'Cannot remove the video with many retries.'
402 } 341 }
403 342
404 retryTransactionWrapper(removeVideo, options) 343 await retryTransactionWrapper(removeVideo, options)
405 .then(() => { 344
406 return res.type('json').status(204).end() 345 return res.type('json').status(204).end()
407 })
408 .catch(err => next(err))
409} 346}
410 347
411function removeVideo (req: express.Request, res: express.Response) { 348async function removeVideo (req: express.Request, res: express.Response) {
412 const videoInstance: VideoInstance = res.locals.video 349 const videoInstance: VideoInstance = res.locals.video
413 350
414 return db.sequelize.transaction(t => { 351 await db.sequelize.transaction(async t => {
415 return videoInstance.destroy({ transaction: t }) 352 await videoInstance.destroy({ transaction: t })
416 })
417 .then(() => {
418 logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
419 })
420 .catch(err => {
421 logger.error('Errors when removed the video.', err)
422 throw err
423 }) 353 })
354
355 logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
424} 356}
425 357
426function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { 358async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
427 db.Video.searchAndPopulateAuthorAndPodAndTags(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort) 359 const resultList = await db.Video.searchAndPopulateAuthorAndPodAndTags(
428 .then(result => res.json(getFormattedObjects(result.data, result.total))) 360 req.params.value,
429 .catch(err => next(err)) 361 req.query.field,
362 req.query.start,
363 req.query.count,
364 req.query.sort
365 )
366
367 return res.json(getFormattedObjects(resultList.data, resultList.total))
430} 368}
diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts
index 6ddc69817..354c3d8f9 100644
--- a/server/controllers/api/videos/rate.ts
+++ b/server/controllers/api/videos/rate.ts
@@ -1,5 +1,4 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as Promise from 'bluebird'
3 2
4import { database as db } from '../../../initializers/database' 3import { database as db } from '../../../initializers/database'
5import { 4import {
@@ -17,7 +16,8 @@ import {
17} from '../../../lib' 16} from '../../../lib'
18import { 17import {
19 authenticate, 18 authenticate,
20 videoRateValidator 19 videoRateValidator,
20 asyncMiddleware
21} from '../../../middlewares' 21} from '../../../middlewares'
22import { UserVideoRateUpdate, VideoRateType } from '../../../../shared' 22import { UserVideoRateUpdate, VideoRateType } from '../../../../shared'
23 23
@@ -26,7 +26,7 @@ const rateVideoRouter = express.Router()
26rateVideoRouter.put('/:id/rate', 26rateVideoRouter.put('/:id/rate',
27 authenticate, 27 authenticate,
28 videoRateValidator, 28 videoRateValidator,
29 rateVideoRetryWrapper 29 asyncMiddleware(rateVideoRetryWrapper)
30) 30)
31 31
32// --------------------------------------------------------------------------- 32// ---------------------------------------------------------------------------
@@ -37,126 +37,107 @@ export {
37 37
38// --------------------------------------------------------------------------- 38// ---------------------------------------------------------------------------
39 39
40function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { 40async function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
41 const options = { 41 const options = {
42 arguments: [ req, res ], 42 arguments: [ req, res ],
43 errorMessage: 'Cannot update the user video rate.' 43 errorMessage: 'Cannot update the user video rate.'
44 } 44 }
45 45
46 retryTransactionWrapper(rateVideo, options) 46 await retryTransactionWrapper(rateVideo, options)
47 .then(() => res.type('json').status(204).end()) 47
48 .catch(err => next(err)) 48 return res.type('json').status(204).end()
49} 49}
50 50
51function rateVideo (req: express.Request, res: express.Response) { 51async function rateVideo (req: express.Request, res: express.Response) {
52 const body: UserVideoRateUpdate = req.body 52 const body: UserVideoRateUpdate = req.body
53 const rateType = body.rating 53 const rateType = body.rating
54 const videoInstance = res.locals.video 54 const videoInstance = res.locals.video
55 const userInstance = res.locals.oauth.token.User 55 const userInstance = res.locals.oauth.token.User
56 56
57 return db.sequelize.transaction(t => { 57 await db.sequelize.transaction(async t => {
58 return db.UserVideoRate.load(userInstance.id, videoInstance.id, t) 58 const sequelizeOptions = { transaction: t }
59 .then(previousRate => { 59 const previousRate = await db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
60 const options = { transaction: t } 60
61 61 let likesToIncrement = 0
62 let likesToIncrement = 0 62 let dislikesToIncrement = 0
63 let dislikesToIncrement = 0 63
64 64 if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
65 if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++ 65 else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
66 else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++ 66
67 67 // There was a previous rate, update it
68 let promise: Promise<any> 68 if (previousRate) {
69 69 // We will remove the previous rate, so we will need to update the video count attribute
70 // There was a previous rate, update it 70 if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
71 if (previousRate) { 71 else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
72 // We will remove the previous rate, so we will need to update the video count attribute 72
73 if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement-- 73 if (rateType === 'none') { // Destroy previous rate
74 else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- 74 await previousRate.destroy()
75 75 } else { // Update previous rate
76 if (rateType === 'none') { // Destroy previous rate 76 previousRate.type = rateType as VideoRateType
77 promise = previousRate.destroy() 77
78 } else { // Update previous rate 78 await previousRate.save()
79 previousRate.type = rateType as VideoRateType 79 }
80 80 } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
81 promise = previousRate.save() 81 const query = {
82 } 82 userId: userInstance.id,
83 } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate 83 videoId: videoInstance.id,
84 const query = { 84 type: rateType
85 userId: userInstance.id, 85 }
86 videoId: videoInstance.id, 86
87 type: rateType 87 await db.UserVideoRate.create(query, sequelizeOptions)
88 } 88 }
89 89
90 promise = db.UserVideoRate.create(query, options) 90 const incrementQuery = {
91 } else { 91 likes: likesToIncrement,
92 promise = Promise.resolve() 92 dislikes: dislikesToIncrement
93 } 93 }
94 94
95 return promise.then(() => ({ likesToIncrement, dislikesToIncrement })) 95 // Even if we do not own the video we increment the attributes
96 }) 96 // It is useful for the user to have a feedback
97 .then(({ likesToIncrement, dislikesToIncrement }) => { 97 await videoInstance.increment(incrementQuery, sequelizeOptions)
98 const options = { transaction: t } 98
99 const incrementQuery = { 99 // Send a event to original pod
100 likes: likesToIncrement, 100 if (videoInstance.isOwned() === false) {
101 dislikes: dislikesToIncrement 101
102 } 102 const eventsParams = []
103 103
104 // Even if we do not own the video we increment the attributes 104 if (likesToIncrement !== 0) {
105 // It is usefull for the user to have a feedback 105 eventsParams.push({
106 return videoInstance.increment(incrementQuery, options).then(() => ({ likesToIncrement, dislikesToIncrement })) 106 videoId: videoInstance.id,
107 }) 107 type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
108 .then(({ likesToIncrement, dislikesToIncrement }) => { 108 count: likesToIncrement
109 // No need for an event type, we own the video 109 })
110 if (videoInstance.isOwned()) return { likesToIncrement, dislikesToIncrement } 110 }
111 111
112 const eventsParams = [] 112 if (dislikesToIncrement !== 0) {
113 113 eventsParams.push({
114 if (likesToIncrement !== 0) { 114 videoId: videoInstance.id,
115 eventsParams.push({ 115 type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
116 videoId: videoInstance.id, 116 count: dislikesToIncrement
117 type: REQUEST_VIDEO_EVENT_TYPES.LIKES, 117 })
118 count: likesToIncrement 118 }
119 }) 119
120 } 120 await addEventsToRemoteVideo(eventsParams, t)
121 121 } else { // We own the video, we need to send a quick and dirty update to friends to notify the counts changed
122 if (dislikesToIncrement !== 0) { 122 const qadusParams = []
123 eventsParams.push({ 123
124 videoId: videoInstance.id, 124 if (likesToIncrement !== 0) {
125 type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES, 125 qadusParams.push({
126 count: dislikesToIncrement 126 videoId: videoInstance.id,
127 }) 127 type: REQUEST_VIDEO_QADU_TYPES.LIKES
128 } 128 })
129 129 }
130 return addEventsToRemoteVideo(eventsParams, t).then(() => ({ likesToIncrement, dislikesToIncrement })) 130
131 }) 131 if (dislikesToIncrement !== 0) {
132 .then(({ likesToIncrement, dislikesToIncrement }) => { 132 qadusParams.push({
133 // We do not own the video, there is no need to send a quick and dirty update to friends 133 videoId: videoInstance.id,
134 // Our rate was already sent by the addEvent function 134 type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
135 if (videoInstance.isOwned() === false) return undefined 135 })
136 136 }
137 const qadusParams = [] 137
138 138 await quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
139 if (likesToIncrement !== 0) { 139 }
140 qadusParams.push({
141 videoId: videoInstance.id,
142 type: REQUEST_VIDEO_QADU_TYPES.LIKES
143 })
144 }
145
146 if (dislikesToIncrement !== 0) {
147 qadusParams.push({
148 videoId: videoInstance.id,
149 type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
150 })
151 }
152
153 return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
154 })
155 })
156 .then(() => logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username))
157 .catch(err => {
158 // This is just a debug because we will retry the insert
159 logger.debug('Cannot add the user video rate.', err)
160 throw err
161 }) 140 })
141
142 logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
162} 143}