]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/videos/rate.ts
Type models
[github/Chocobozzz/PeerTube.git] / server / controllers / api / videos / rate.ts
1 import express = require('express')
2 import { waterfall } from 'async'
3
4 import { database as db } from '../../../initializers/database'
5 import {
6 logger,
7 retryTransactionWrapper,
8 startSerializableTransaction,
9 commitTransaction,
10 rollbackTransaction
11 } from '../../../helpers'
12 import {
13 VIDEO_RATE_TYPES,
14 REQUEST_VIDEO_EVENT_TYPES,
15 REQUEST_VIDEO_QADU_TYPES
16 } from '../../../initializers'
17 import {
18 addEventsToRemoteVideo,
19 quickAndDirtyUpdatesVideoToFriends
20 } from '../../../lib'
21 import {
22 authenticate,
23 videoRateValidator
24 } from '../../../middlewares'
25
26 const rateVideoRouter = express.Router()
27
28 rateVideoRouter.put('/:id/rate',
29 authenticate,
30 videoRateValidator,
31 rateVideoRetryWrapper
32 )
33
34 // ---------------------------------------------------------------------------
35
36 export {
37 rateVideoRouter
38 }
39
40 // ---------------------------------------------------------------------------
41
42 function rateVideoRetryWrapper (req, res, next) {
43 const options = {
44 arguments: [ req, res ],
45 errorMessage: 'Cannot update the user video rate.'
46 }
47
48 retryTransactionWrapper(rateVideo, options, function (err) {
49 if (err) return next(err)
50
51 return res.type('json').status(204).end()
52 })
53 }
54
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
59
60 waterfall([
61 startSerializableTransaction,
62
63 function findPreviousRate (t, callback) {
64 db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) {
65 return callback(err, t, previousRate)
66 })
67 },
68
69 function insertUserRateIntoDB (t, previousRate, callback) {
70 const options = { transaction: t }
71
72 let likesToIncrement = 0
73 let dislikesToIncrement = 0
74
75 if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
76 else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
77
78 // There was a previous rate, update it
79 if (previousRate) {
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--
83
84 previousRate.type = rateType
85
86 previousRate.save(options).asCallback(function (err) {
87 return callback(err, t, likesToIncrement, dislikesToIncrement)
88 })
89 } else { // There was not a previous rate, insert a new one
90 const query = {
91 userId: userInstance.id,
92 videoId: videoInstance.id,
93 type: rateType
94 }
95
96 db.UserVideoRate.create(query, options).asCallback(function (err) {
97 return callback(err, t, likesToIncrement, dislikesToIncrement)
98 })
99 }
100 },
101
102 function updateVideoAttributeDB (t, likesToIncrement, dislikesToIncrement, callback) {
103 const options = { transaction: t }
104 const incrementQuery = {
105 likes: likesToIncrement,
106 dislikes: dislikesToIncrement
107 }
108
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)
113 })
114 },
115
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)
119
120 const eventsParams = []
121
122 if (likesToIncrement !== 0) {
123 eventsParams.push({
124 videoId: videoInstance.id,
125 type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
126 count: likesToIncrement
127 })
128 }
129
130 if (dislikesToIncrement !== 0) {
131 eventsParams.push({
132 videoId: videoInstance.id,
133 type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
134 count: dislikesToIncrement
135 })
136 }
137
138 addEventsToRemoteVideo(eventsParams, t, function (err) {
139 return callback(err, t, likesToIncrement, dislikesToIncrement)
140 })
141 },
142
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)
147
148 const qadusParams = []
149
150 if (likesToIncrement !== 0) {
151 qadusParams.push({
152 videoId: videoInstance.id,
153 type: REQUEST_VIDEO_QADU_TYPES.LIKES
154 })
155 }
156
157 if (dislikesToIncrement !== 0) {
158 qadusParams.push({
159 videoId: videoInstance.id,
160 type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
161 })
162 }
163
164 quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
165 return callback(err, t)
166 })
167 },
168
169 commitTransaction
170
171 ], function (err, t) {
172 if (err) {
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)
176 }
177
178 logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
179 return finalCallback(null)
180 })
181 }