]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add channel server hooks
authorChocobozzz <me@florianbigard.com>
Wed, 3 Aug 2022 09:17:57 +0000 (11:17 +0200)
committerChocobozzz <me@florianbigard.com>
Wed, 3 Aug 2022 09:24:42 +0000 (11:24 +0200)
server/controllers/api/video-channel.ts
server/controllers/api/videos/index.ts
server/lib/model-loaders/video.ts
server/tests/fixtures/peertube-plugin-test/main.js
server/tests/plugins/action-hooks.ts
server/tests/plugins/filter-hooks.ts
shared/models/plugins/server/server-hook.model.ts

index 2454b1ec9342cb945fb4742588deb763f5e5b9fd..411ec86304ff74f49b23582765dfd1ac5ae2b31e 100644 (file)
@@ -126,7 +126,7 @@ videoChannelRouter.delete('/:nameWithHost',
 
 videoChannelRouter.get('/:nameWithHost',
   asyncMiddleware(videoChannelsNameWithHostValidator),
-  getVideoChannel
+  asyncMiddleware(getVideoChannel)
 )
 
 videoChannelRouter.get('/:nameWithHost/video-playlists',
@@ -171,12 +171,19 @@ export {
 
 async function listVideoChannels (req: express.Request, res: express.Response) {
   const serverActor = await getServerActor()
-  const resultList = await VideoChannelModel.listForApi({
+
+  const apiOptions = await Hooks.wrapObject({
     actorId: serverActor.id,
     start: req.query.start,
     count: req.query.count,
     sort: req.query.sort
-  })
+  }, 'filter:api.video-channels.list.params')
+
+  const resultList = await Hooks.wrapPromiseFun(
+    VideoChannelModel.listForApi,
+    apiOptions,
+    'filter:api.video-channels.list.result'
+  )
 
   return res.json(getFormattedObjects(resultList.data, resultList.total))
 }
@@ -243,6 +250,8 @@ async function addVideoChannel (req: express.Request, res: express.Response) {
   auditLogger.create(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelCreated.toFormattedJSON()))
   logger.info('Video channel %s created.', videoChannelCreated.Actor.url)
 
+  Hooks.runAction('action:api.video-channel.created', { videoChannel: videoChannelCreated, req, res })
+
   return res.json({
     videoChannel: {
       id: videoChannelCreated.id
@@ -281,6 +290,8 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
         oldVideoChannelAuditKeys
       )
 
+      Hooks.runAction('action:api.video-channel.updated', { videoChannel: videoChannelInstanceUpdated, req, res })
+
       logger.info('Video channel %s updated.', videoChannelInstance.Actor.url)
     })
   } catch (err) {
@@ -310,6 +321,8 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
 
     await videoChannelInstance.destroy({ transaction: t })
 
+    Hooks.runAction('action:api.video-channel.deleted', { videoChannel: videoChannelInstance, req, res })
+
     auditLogger.delete(getAuditIdFromRes(res), new VideoChannelAuditView(videoChannelInstance.toFormattedJSON()))
     logger.info('Video channel %s deleted.', videoChannelInstance.Actor.url)
   })
@@ -317,8 +330,9 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
   return res.type('json').status(HttpStatusCode.NO_CONTENT_204).end()
 }
 
-function getVideoChannel (req: express.Request, res: express.Response) {
-  const videoChannel = res.locals.videoChannel
+async function getVideoChannel (req: express.Request, res: express.Response) {
+  const id = res.locals.videoChannel.id
+  const videoChannel = await Hooks.wrapObject(res.locals.videoChannel, 'filter:api.video-channel.get.result', { id })
 
   if (videoChannel.isOutdated()) {
     JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannel.Actor.url } })
index d4e08293e85f597975d8294442d1c3eb8442fe8b..eca72c397a85492f82a688fa516dc0233ddeb6a5 100644 (file)
@@ -110,7 +110,7 @@ videosRouter.get('/:id',
   optionalAuthenticate,
   asyncMiddleware(videosCustomGetValidator('for-api')),
   asyncMiddleware(checkVideoFollowConstraints),
-  getVideo
+  asyncMiddleware(getVideo)
 )
 
 videosRouter.delete('/:id',
@@ -144,8 +144,11 @@ function listVideoPrivacies (_req: express.Request, res: express.Response) {
   res.json(VIDEO_PRIVACIES)
 }
 
-function getVideo (_req: express.Request, res: express.Response) {
-  const video = res.locals.videoAPI
+async function getVideo (_req: express.Request, res: express.Response) {
+  const videoId = res.locals.videoAPI.id
+  const userId = res.locals.oauth?.token.User.id
+
+  const video = await Hooks.wrapObject(res.locals.videoAPI, 'filter:api.video.get.result', { id: videoId, userId })
 
   if (video.isOutdated()) {
     JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
index cef6a367c1c05e960cdeac0db4bd9a7a72facadd..a64389a895785ed50802ef7b8be4db2bd9e87f80 100644 (file)
@@ -7,7 +7,7 @@ import {
   MVideoImmutable,
   MVideoThumbnail
 } from '@server/types/models'
-import { Hooks } from '../plugins/hooks'
+
 
 type VideoLoadType = 'for-api' | 'all' | 'only-video' | 'id' | 'none' | 'only-immutable-attributes'
 
@@ -27,13 +27,7 @@ function loadVideo (
   userId?: number
 ): Promise<MVideoFullLight | MVideoThumbnail | MVideoId | MVideoImmutable> {
 
-  if (fetchType === 'for-api') {
-    return Hooks.wrapPromiseFun(
-      VideoModel.loadForGetAPI,
-      { id, userId },
-      'filter:api.video.get.result'
-    )
-  }
+  if (fetchType === 'for-api') return VideoModel.loadForGetAPI({ id, userId })
 
   if (fetchType === 'all') return VideoModel.loadFull(id, undefined, userId)
 
index c395ac7aa548e6cd46cfebb5c360f584da487a27..8d7584eba2ea40d61fb0c7170c7b26953182c387 100644 (file)
@@ -7,6 +7,10 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
     'action:api.video.uploaded',
     'action:api.video.viewed',
 
+    'action:api.video-channel.created',
+    'action:api.video-channel.updated',
+    'action:api.video-channel.deleted',
+
     'action:api.live-video.created',
 
     'action:api.video-thread.created',
@@ -93,6 +97,29 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
     }
   })
 
+  // ---------------------------------------------------------------------------
+
+  registerHook({
+    target: 'filter:api.video-channels.list.params',
+    handler: obj => addToCount(obj, 1)
+  })
+
+  registerHook({
+    target: 'filter:api.video-channels.list.result',
+    handler: obj => addToTotal(obj, 1)
+  })
+
+  registerHook({
+    target: 'filter:api.video-channel.get.result',
+    handler: channel => {
+      channel.name += ' <3'
+
+      return channel
+    }
+  })
+
+  // ---------------------------------------------------------------------------
+
   for (const hook of [ 'filter:api.video.upload.accept.result', 'filter:api.live-video.create.accept.result' ]) {
     registerHook({
       target: hook,
index 57ede270113e4403323019d74f881e84e148acc0..209db95a44b835c4bab13ca9fdcf1d0711fabc74 100644 (file)
@@ -65,6 +65,39 @@ describe('Test plugin action hooks', function () {
 
       await checkHook('action:api.video.viewed')
     })
+
+    it('Should run action:api.video.deleted', async function () {
+      await servers[0].videos.remove({ id: videoUUID })
+
+      await checkHook('action:api.video.deleted')
+    })
+
+    after(async function () {
+      const { uuid } = await servers[0].videos.quickUpload({ name: 'video' })
+      videoUUID = uuid
+    })
+  })
+
+  describe('Video channel hooks', function () {
+    const channelName = 'my_super_channel'
+
+    it('Should run action:api.video-channel.created', async function () {
+      await servers[0].channels.create({ attributes: { name: channelName } })
+
+      await checkHook('action:api.video-channel.created')
+    })
+
+    it('Should run action:api.video-channel.updated', async function () {
+      await servers[0].channels.update({ channelName, attributes: { displayName: 'my display name' } })
+
+      await checkHook('action:api.video-channel.updated')
+    })
+
+    it('Should run action:api.video-channel.deleted', async function () {
+      await servers[0].channels.delete({ channelName })
+
+      await checkHook('action:api.video-channel.deleted')
+    })
   })
 
   describe('Live hooks', function () {
index 5ed24a58e695430945e20ef65293654d0e5a0c63..015459ead183bd0edc9896b522c838cee5d670ed 100644 (file)
@@ -295,7 +295,7 @@ describe('Test plugin filter hooks', function () {
     await servers[0].servers.waitUntilLog('Run hook filter:api.overviews.videos.list.result', 3)
   })
 
-  describe('Should run filter:video.auto-blacklist.result', function () {
+  describe('filter:video.auto-blacklist.result', function () {
 
     async function checkIsBlacklisted (id: number | string, value: boolean) {
       const video = await servers[0].videos.getWithToken({ id })
@@ -691,6 +691,28 @@ describe('Test plugin filter hooks', function () {
     })
   })
 
+  describe('Video channel filters', async function () {
+
+    it('Should run filter:api.video-channels.list.params', async function () {
+      const { data } = await servers[0].channels.list({ start: 0, count: 0 })
+
+      // plugin do +1 to the count parameter
+      expect(data).to.have.lengthOf(1)
+    })
+
+    it('Should run filter:api.video-channels.list.result', async function () {
+      const { total } = await servers[0].channels.list({ start: 0, count: 1 })
+
+      // plugin do +1 to the total parameter
+      expect(total).to.equal(4)
+    })
+
+    it('Should run filter:api.video-channel.get.result', async function () {
+      const channel = await servers[0].channels.get({ channelName: 'root_channel' })
+      expect(channel.displayName).to.equal('Main root channel <3')
+    })
+  })
+
   after(async function () {
     await cleanupTests(servers)
   })
index 08da95177eed7aee8b0513b06c400efdcc712310..5f3a5be10dd29614b5ac0317005a60824fbfd594 100644 (file)
@@ -45,6 +45,13 @@ export const serverFilterHookObject = {
   // Used to get detailed video information (video watch page for example)
   'filter:api.video.get.result': true,
 
+  // Filter params/results when listing video channels
+  'filter:api.video-channels.list.params': true,
+  'filter:api.video-channels.list.result': true,
+
+  // Filter the result when getting a video channel
+  'filter:api.video-channel.get.result': true,
+
   // Filter the result of the accept upload/live, import via torrent/url functions
   // If this function returns false then the upload is aborted with an error
   'filter:api.video.upload.accept.result': true,
@@ -116,6 +123,13 @@ export const serverActionHookObject = {
   // Fired when a local video is viewed
   'action:api.video.viewed': true,
 
+  // Fired when a video channel is created
+  'action:api.video-channel.created': true,
+  // Fired when a video channel is updated
+  'action:api.video-channel.updated': true,
+  // Fired when a video channel is deleted
+  'action:api.video-channel.deleted': true,
+
   // Fired when a live video is created
   'action:api.live-video.created': true,