Fix lint
[oweals/peertube.git] / server / controllers / api / videos / channel.ts
1 import * as express from 'express'
2 import { VideoChannelCreate, VideoChannelUpdate } from '../../../../shared'
3 import { getFormattedObjects, logger, resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers'
4 import { database as db } from '../../../initializers'
5 import { createVideoChannel } from '../../../lib'
6 import {
7   asyncMiddleware,
8   authenticate,
9   listVideoAccountChannelsValidator,
10   paginationValidator,
11   setPagination,
12   setVideoChannelsSort,
13   videoChannelsGetValidator,
14   videoChannelsAddValidator,
15   videoChannelsRemoveValidator,
16   videoChannelsSortValidator,
17   videoChannelsUpdateValidator
18 } from '../../../middlewares'
19 import { AccountInstance, VideoChannelInstance } from '../../../models'
20 import { sendUpdateVideoChannel } from '../../../lib/activitypub/send/send-update'
21
22 const videoChannelRouter = express.Router()
23
24 videoChannelRouter.get('/channels',
25   paginationValidator,
26   videoChannelsSortValidator,
27   setVideoChannelsSort,
28   setPagination,
29   asyncMiddleware(listVideoChannels)
30 )
31
32 videoChannelRouter.get('/accounts/:accountId/channels',
33   listVideoAccountChannelsValidator,
34   asyncMiddleware(listVideoAccountChannels)
35 )
36
37 videoChannelRouter.post('/channels',
38   authenticate,
39   videoChannelsAddValidator,
40   asyncMiddleware(addVideoChannelRetryWrapper)
41 )
42
43 videoChannelRouter.put('/channels/:id',
44   authenticate,
45   videoChannelsUpdateValidator,
46   updateVideoChannelRetryWrapper
47 )
48
49 videoChannelRouter.delete('/channels/:id',
50   authenticate,
51   videoChannelsRemoveValidator,
52   asyncMiddleware(removeVideoChannelRetryWrapper)
53 )
54
55 videoChannelRouter.get('/channels/:id',
56   videoChannelsGetValidator,
57   asyncMiddleware(getVideoChannel)
58 )
59
60 // ---------------------------------------------------------------------------
61
62 export {
63   videoChannelRouter
64 }
65
66 // ---------------------------------------------------------------------------
67
68 async function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
69   const resultList = await db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort)
70
71   return res.json(getFormattedObjects(resultList.data, resultList.total))
72 }
73
74 async function listVideoAccountChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
75   const resultList = await db.VideoChannel.listByAccount(res.locals.account.id)
76
77   return res.json(getFormattedObjects(resultList.data, resultList.total))
78 }
79
80 // Wrapper to video channel add that retry the async function if there is a database error
81 // We need this because we run the transaction in SERIALIZABLE isolation that can fail
82 async function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
83   const options = {
84     arguments: [ req, res ],
85     errorMessage: 'Cannot insert the video video channel with many retries.'
86   }
87
88   await retryTransactionWrapper(addVideoChannel, options)
89
90   // TODO : include Location of the new video channel -> 201
91   return res.type('json').status(204).end()
92 }
93
94 async function addVideoChannel (req: express.Request, res: express.Response) {
95   const videoChannelInfo: VideoChannelCreate = req.body
96   const account: AccountInstance = res.locals.oauth.token.User.Account
97   let videoChannelCreated: VideoChannelInstance
98
99   await db.sequelize.transaction(async t => {
100     videoChannelCreated = await createVideoChannel(videoChannelInfo, account, t)
101   })
102
103   logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid)
104 }
105
106 async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
107   const options = {
108     arguments: [ req, res ],
109     errorMessage: 'Cannot update the video with many retries.'
110   }
111
112   await retryTransactionWrapper(updateVideoChannel, options)
113
114   return res.type('json').status(204).end()
115 }
116
117 async function updateVideoChannel (req: express.Request, res: express.Response) {
118   const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
119   const videoChannelFieldsSave = videoChannelInstance.toJSON()
120   const videoChannelInfoToUpdate: VideoChannelUpdate = req.body
121
122   try {
123     await db.sequelize.transaction(async t => {
124       const sequelizeOptions = {
125         transaction: t
126       }
127
128       if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
129       if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
130
131       const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
132
133       await sendUpdateVideoChannel(videoChannelInstanceUpdated, t)
134     })
135
136     logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
137   } catch (err) {
138     logger.debug('Cannot update the video channel.', err)
139
140     // Force fields we want to update
141     // If the transaction is retried, sequelize will think the object has not changed
142     // So it will skip the SQL request, even if the last one was ROLLBACKed!
143     resetSequelizeInstance(videoChannelInstance, videoChannelFieldsSave)
144
145     throw err
146   }
147 }
148
149 async function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
150   const options = {
151     arguments: [ req, res ],
152     errorMessage: 'Cannot remove the video channel with many retries.'
153   }
154
155   await retryTransactionWrapper(removeVideoChannel, options)
156
157   return res.type('json').status(204).end()
158 }
159
160 async function removeVideoChannel (req: express.Request, res: express.Response) {
161   const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
162
163   await db.sequelize.transaction(async t => {
164     await videoChannelInstance.destroy({ transaction: t })
165   })
166
167   logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
168 }
169
170 async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
171   const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAccountAndVideos(res.locals.videoChannel.id)
172
173   return res.json(videoChannelWithVideos.toFormattedJSON())
174 }