aboutsummaryrefslogblamecommitdiffhomepage
path: root/server/controllers/api/videos/rate.ts
blob: 8456cbaf24ec48685b6d2ed0348f57545fdefcaf (plain) (tree)
1
2
3
4
5
6
7
                                  
                                   
 
                                                               

         
                         













                                    
                                                                       





                                        




                                                                              


                 


                                                                              
                                                                                                          




                                                      


                                                   

 
                                                                  

                                            


                                                  



                                                                      
 

                                   
 

                                                                             
 

                                 




                                                                                                    
 



                                                             
 


                                                                                                               




                                      
 


                                                           
         

                                                                              
        









                                                                                                                       
        




















                                                                                     
 














                                                                                                              
 





                                                   
 





                                                                                                                         
                                                        
             

    
import * as express from 'express'
import * as Promise from 'bluebird'

import { database as db } from '../../../initializers/database'
import {
  logger,
  retryTransactionWrapper
} from '../../../helpers'
import {
  VIDEO_RATE_TYPES,
  REQUEST_VIDEO_EVENT_TYPES,
  REQUEST_VIDEO_QADU_TYPES
} from '../../../initializers'
import {
  addEventsToRemoteVideo,
  quickAndDirtyUpdatesVideoToFriends
} from '../../../lib'
import {
  authenticate,
  videoRateValidator
} from '../../../middlewares'
import { UserVideoRateUpdate, VideoRateType } from '../../../../shared'

const rateVideoRouter = express.Router()

rateVideoRouter.put('/:id/rate',
  authenticate,
  videoRateValidator,
  rateVideoRetryWrapper
)

// ---------------------------------------------------------------------------

export {
  rateVideoRouter
}

// ---------------------------------------------------------------------------

function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
  const options = {
    arguments: [ req, res ],
    errorMessage: 'Cannot update the user video rate.'
  }

  retryTransactionWrapper(rateVideo, options)
    .then(() => res.type('json').status(204).end())
    .catch(err => next(err))
}

function rateVideo (req: express.Request, res: express.Response) {
  const body: UserVideoRateUpdate = req.body
  const rateType = body.rating
  const videoInstance = res.locals.video
  const userInstance = res.locals.oauth.token.User

  return db.sequelize.transaction(t => {
    return db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
      .then(previousRate => {
        const options = { transaction: t }

        let likesToIncrement = 0
        let dislikesToIncrement = 0

        if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
        else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++

        let promise: Promise<any>

        // There was a previous rate, update it
        if (previousRate) {
          // We will remove the previous rate, so we will need to remove it from the video attribute
          if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
          else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--

          if (rateType === 'none') { // Destroy previous rate
            promise = previousRate.destroy()
          } else { // Update previous rate
            previousRate.type = rateType as VideoRateType

            promise = previousRate.save()
          }
        } else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
          const query = {
            userId: userInstance.id,
            videoId: videoInstance.id,
            type: rateType
          }

          promise = db.UserVideoRate.create(query, options)
        } else {
          promise = Promise.resolve()
        }

        return promise.then(() => ({ likesToIncrement, dislikesToIncrement }))
      })
      .then(({ likesToIncrement, dislikesToIncrement }) => {
        const options = { transaction: t }
        const incrementQuery = {
          likes: likesToIncrement,
          dislikes: dislikesToIncrement
        }

        // Even if we do not own the video we increment the attributes
        // It is usefull for the user to have a feedback
        return videoInstance.increment(incrementQuery, options).then(() => ({ likesToIncrement, dislikesToIncrement }))
      })
      .then(({ likesToIncrement, dislikesToIncrement }) => {
        // No need for an event type, we own the video
        if (videoInstance.isOwned()) return { likesToIncrement, dislikesToIncrement }

        const eventsParams = []

        if (likesToIncrement !== 0) {
          eventsParams.push({
            videoId: videoInstance.id,
            type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
            count: likesToIncrement
          })
        }

        if (dislikesToIncrement !== 0) {
          eventsParams.push({
            videoId: videoInstance.id,
            type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
            count: dislikesToIncrement
          })
        }

        return addEventsToRemoteVideo(eventsParams, t).then(() => ({ likesToIncrement, dislikesToIncrement }))
      })
      .then(({ likesToIncrement, dislikesToIncrement }) => {
        // We do not own the video, there is no need to send a quick and dirty update to friends
        // Our rate was already sent by the addEvent function
        if (videoInstance.isOwned() === false) return undefined

        const qadusParams = []

        if (likesToIncrement !== 0) {
          qadusParams.push({
            videoId: videoInstance.id,
            type: REQUEST_VIDEO_QADU_TYPES.LIKES
          })
        }

        if (dislikesToIncrement !== 0) {
          qadusParams.push({
            videoId: videoInstance.id,
            type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
          })
        }

        return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
      })
  })
  .then(() => logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username))
  .catch(err => {
    // This is just a debug because we will retry the insert
    logger.debug('Cannot add the user video rate.', err)
    throw err
  })
}