Add channel server hooks

This commit is contained in:
Chocobozzz 2022-08-03 11:17:57 +02:00
parent 9ca0f688e9
commit 0260dc8aca
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
7 changed files with 124 additions and 17 deletions

View 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 } })

View 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 } })

View 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)

View 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,

View 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 () {

View 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)
})

View 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,