1 import express = require('express')
2 import { waterfall } from 'async'
4 const db = require('../../../initializers/database')
7 retryTransactionWrapper,
8 startSerializableTransaction,
11 } from '../../../helpers'
14 REQUEST_VIDEO_EVENT_TYPES,
15 REQUEST_VIDEO_QADU_TYPES
16 } from '../../../initializers'
18 addEventsToRemoteVideo,
19 quickAndDirtyUpdatesVideoToFriends
24 } from '../../../middlewares'
26 const rateVideoRouter = express.Router()
28 rateVideoRouter.put('/:id/rate',
34 // ---------------------------------------------------------------------------
40 // ---------------------------------------------------------------------------
42 function rateVideoRetryWrapper (req, res, next) {
44 arguments: [ req, res ],
45 errorMessage: 'Cannot update the user video rate.'
48 retryTransactionWrapper(rateVideo, options, function (err) {
49 if (err) return next(err)
51 return res.type('json').status(204).end()
55 function rateVideo (req, res, finalCallback) {
56 const rateType = req.body.rating
57 const videoInstance = res.locals.video
58 const userInstance = res.locals.oauth.token.User
61 startSerializableTransaction,
63 function findPreviousRate (t, callback) {
64 db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) {
65 return callback(err, t, previousRate)
69 function insertUserRateIntoDB (t, previousRate, callback) {
70 const options = { transaction: t }
72 let likesToIncrement = 0
73 let dislikesToIncrement = 0
75 if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
76 else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
78 // There was a previous rate, update it
80 // We will remove the previous rate, so we will need to remove it from the video attribute
81 if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
82 else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
84 previousRate.type = rateType
86 previousRate.save(options).asCallback(function (err) {
87 return callback(err, t, likesToIncrement, dislikesToIncrement)
89 } else { // There was not a previous rate, insert a new one
91 userId: userInstance.id,
92 videoId: videoInstance.id,
96 db.UserVideoRate.create(query, options).asCallback(function (err) {
97 return callback(err, t, likesToIncrement, dislikesToIncrement)
102 function updateVideoAttributeDB (t, likesToIncrement, dislikesToIncrement, callback) {
103 const options = { transaction: t }
104 const incrementQuery = {
105 likes: likesToIncrement,
106 dislikes: dislikesToIncrement
109 // Even if we do not own the video we increment the attributes
110 // It is usefull for the user to have a feedback
111 videoInstance.increment(incrementQuery, options).asCallback(function (err) {
112 return callback(err, t, likesToIncrement, dislikesToIncrement)
116 function sendEventsToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
117 // No need for an event type, we own the video
118 if (videoInstance.isOwned()) return callback(null, t, likesToIncrement, dislikesToIncrement)
120 const eventsParams = []
122 if (likesToIncrement !== 0) {
124 videoId: videoInstance.id,
125 type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
126 count: likesToIncrement
130 if (dislikesToIncrement !== 0) {
132 videoId: videoInstance.id,
133 type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
134 count: dislikesToIncrement
138 addEventsToRemoteVideo(eventsParams, t, function (err) {
139 return callback(err, t, likesToIncrement, dislikesToIncrement)
143 function sendQaduToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
144 // We do not own the video, there is no need to send a quick and dirty update to friends
145 // Our rate was already sent by the addEvent function
146 if (videoInstance.isOwned() === false) return callback(null, t)
148 const qadusParams = []
150 if (likesToIncrement !== 0) {
152 videoId: videoInstance.id,
153 type: REQUEST_VIDEO_QADU_TYPES.LIKES
157 if (dislikesToIncrement !== 0) {
159 videoId: videoInstance.id,
160 type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
164 quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
165 return callback(err, t)
171 ], function (err, t) {
173 // This is just a debug because we will retry the insert
174 logger.debug('Cannot add the user video rate.', { error: err })
175 return rollbackTransaction(err, t, finalCallback)
178 logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
179 return finalCallback(null)