aboutsummaryrefslogblamecommitdiffhomepage
path: root/server/controllers/api/videos/channel.ts
blob: 630fc4f53d02bce16cad4aed37fee0f044c324c1 (plain) (tree)



































































































































































































                                                                                                                                         
import * as express from 'express'

import { database as db } from '../../../initializers'
import {
  logger,
  getFormattedObjects,
  retryTransactionWrapper
} from '../../../helpers'
import {
  authenticate,
  paginationValidator,
  videoChannelsSortValidator,
  videoChannelsAddValidator,
  setVideoChannelsSort,
  setPagination,
  videoChannelsRemoveValidator,
  videoChannelGetValidator,
  videoChannelsUpdateValidator,
  listVideoAuthorChannelsValidator
} from '../../../middlewares'
import {
  createVideoChannel,
  updateVideoChannelToFriends
} from '../../../lib'
import { VideoChannelInstance, AuthorInstance } from '../../../models'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'

const videoChannelRouter = express.Router()

videoChannelRouter.get('/channels',
  paginationValidator,
  videoChannelsSortValidator,
  setVideoChannelsSort,
  setPagination,
  listVideoChannels
)

videoChannelRouter.get('/authors/:authorId/channels',
  listVideoAuthorChannelsValidator,
  listVideoAuthorChannels
)

videoChannelRouter.post('/channels',
  authenticate,
  videoChannelsAddValidator,
  addVideoChannelRetryWrapper
)

videoChannelRouter.put('/channels/:id',
  authenticate,
  videoChannelsUpdateValidator,
  updateVideoChannelRetryWrapper
)

videoChannelRouter.delete('/channels/:id',
  authenticate,
  videoChannelsRemoveValidator,
  removeVideoChannelRetryWrapper
)

videoChannelRouter.get('/channels/:id',
  videoChannelGetValidator,
  getVideoChannel
)

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

export {
  videoChannelRouter
}

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

function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
  db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort)
    .then(result => res.json(getFormattedObjects(result.data, result.total)))
    .catch(err => next(err))
}

function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
  db.VideoChannel.listByAuthor(res.locals.author.id)
    .then(result => res.json(getFormattedObjects(result.data, result.total)))
    .catch(err => next(err))
}

// Wrapper to video channel add that retry the function if there is a database error
// We need this because we run the transaction in SERIALIZABLE isolation that can fail
function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
  const options = {
    arguments: [ req, res ],
    errorMessage: 'Cannot insert the video video channel with many retries.'
  }

  retryTransactionWrapper(addVideoChannel, options)
    .then(() => {
      // TODO : include Location of the new video channel -> 201
      res.type('json').status(204).end()
    })
    .catch(err => next(err))
}

function addVideoChannel (req: express.Request, res: express.Response) {
  const videoChannelInfo: VideoChannelCreate = req.body
  const author: AuthorInstance = res.locals.oauth.token.User.Author

  return db.sequelize.transaction(t => {
    return createVideoChannel(videoChannelInfo, author, t)
  })
  .then(videoChannelUUID => logger.info('Video channel with uuid %s created.', videoChannelUUID))
  .catch((err: Error) => {
    logger.debug('Cannot insert the video channel.', err)
    throw err
  })
}

function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
  const options = {
    arguments: [ req, res ],
    errorMessage: 'Cannot update the video with many retries.'
  }

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

function updateVideoChannel (req: express.Request, res: express.Response) {
  const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
  const videoChannelFieldsSave = videoChannelInstance.toJSON()
  const videoChannelInfoToUpdate: VideoChannelUpdate = req.body

  return db.sequelize.transaction(t => {
    const options = {
      transaction: t
    }

    if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
    if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)

    return videoChannelInstance.save(options)
      .then(() => {
        const json = videoChannelInstance.toUpdateRemoteJSON()

        // Now we'll update the video channel's meta data to our friends
        return updateVideoChannelToFriends(json, t)
      })
  })
    .then(() => {
      logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
    })
    .catch(err => {
      logger.debug('Cannot update the video channel.', err)

      // Force fields we want to update
      // If the transaction is retried, sequelize will think the object has not changed
      // So it will skip the SQL request, even if the last one was ROLLBACKed!
      Object.keys(videoChannelFieldsSave).forEach(key => {
        const value = videoChannelFieldsSave[key]
        videoChannelInstance.set(key, value)
      })

      throw err
    })
}

function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
  const options = {
    arguments: [ req, res ],
    errorMessage: 'Cannot remove the video channel with many retries.'
  }

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

function removeVideoChannel (req: express.Request, res: express.Response) {
  const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel

  return db.sequelize.transaction(t => {
    return videoChannelInstance.destroy({ transaction: t })
  })
  .then(() => {
    logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
  })
  .catch(err => {
    logger.error('Errors when removed the video channel.', err)
    throw err
  })
}

function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
  db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id)
    .then(videoChannelWithVideos => res.json(videoChannelWithVideos.toFormattedJSON()))
    .catch(err => next(err))
}