diff --git a/server/controllers/api/bulk.ts b/server/controllers/api/bulk.ts index d27c3c73e..51292175b 100644 --- a/server/controllers/api/bulk.ts +++ b/server/controllers/api/bulk.ts @@ -37,6 +37,6 @@ async function bulkRemoveCommentsOf (req: express.Request, res: express.Response res.status(HttpStatusCode.NO_CONTENT_204).end() for (const comment of comments) { - await removeComment(comment) + await removeComment(comment, req, res) } } diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts index bc47e5fec..11d3525e4 100644 --- a/server/controllers/api/users/index.ts +++ b/server/controllers/api/users/index.ts @@ -212,7 +212,7 @@ async function createUser (req: express.Request, res: express.Response) { await Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url) } - Hooks.runAction('action:api.user.created', { body, user, account, videoChannel }) + Hooks.runAction('action:api.user.created', { body, user, account, videoChannel, req, res }) return res.json({ user: { @@ -254,7 +254,7 @@ async function registerUser (req: express.Request, res: express.Response) { Notifier.Instance.notifyOnNewUserRegistration(user) - Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel }) + Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel, req, res }) return res.type('json').status(HttpStatusCode.NO_CONTENT_204).end() } @@ -264,7 +264,7 @@ async function unblockUser (req: express.Request, res: express.Response) { await changeUserBlock(res, user, false) - Hooks.runAction('action:api.user.unblocked', { user }) + Hooks.runAction('action:api.user.unblocked', { user, req, res }) return res.status(HttpStatusCode.NO_CONTENT_204).end() } @@ -275,7 +275,7 @@ async function blockUser (req: express.Request, res: express.Response) { await changeUserBlock(res, user, true, reason) - Hooks.runAction('action:api.user.blocked', { user }) + Hooks.runAction('action:api.user.blocked', { user, req, res }) return res.status(HttpStatusCode.NO_CONTENT_204).end() } @@ -312,7 +312,7 @@ async function removeUser (req: express.Request, res: express.Response) { await user.destroy({ transaction: t }) }) - Hooks.runAction('action:api.user.deleted', { user }) + Hooks.runAction('action:api.user.deleted', { user, req, res }) return res.status(HttpStatusCode.NO_CONTENT_204).end() } @@ -345,7 +345,7 @@ async function updateUser (req: express.Request, res: express.Response) { auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) - Hooks.runAction('action:api.user.updated', { user }) + Hooks.runAction('action:api.user.updated', { user, req, res }) // Don't need to send this update to followers, these attributes are not federated diff --git a/server/controllers/api/users/token.ts b/server/controllers/api/users/token.ts index d5dbe921c..1d4004ce0 100644 --- a/server/controllers/api/users/token.ts +++ b/server/controllers/api/users/token.ts @@ -66,7 +66,7 @@ async function handleToken (req: express.Request, res: express.Response, next: e res.set('Cache-Control', 'no-store') res.set('Pragma', 'no-cache') - Hooks.runAction('action:api.user.oauth2-got-token', { username: token.user.username, ip: req.ip }) + Hooks.runAction('action:api.user.oauth2-got-token', { username: token.user.username, ip: req.ip, req, res }) return res.json({ token_type: 'Bearer', diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts index 2347e18d2..8b7a76718 100644 --- a/server/controllers/api/video-playlist.ts +++ b/server/controllers/api/video-playlist.ts @@ -334,7 +334,7 @@ async function addVideoInPlaylist (req: express.Request, res: express.Response) logger.info('Video added in playlist %s at position %d.', videoPlaylist.uuid, playlistElement.position) - Hooks.runAction('action:api.video-playlist-element.created', { playlistElement }) + Hooks.runAction('action:api.video-playlist-element.created', { playlistElement, req, res }) return res.json({ videoPlaylistElement: { diff --git a/server/controllers/api/videos/comment.ts b/server/controllers/api/videos/comment.ts index 23bba9089..47fa2f2e2 100644 --- a/server/controllers/api/videos/comment.ts +++ b/server/controllers/api/videos/comment.ts @@ -192,7 +192,7 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons Notifier.Instance.notifyOnNewComment(comment) auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) - Hooks.runAction('action:api.video-thread.created', { comment }) + Hooks.runAction('action:api.video-thread.created', { comment, req, res }) return res.json({ comment: comment.toFormattedJSON() }) } @@ -214,7 +214,7 @@ async function addVideoCommentReply (req: express.Request, res: express.Response Notifier.Instance.notifyOnNewComment(comment) auditLogger.create(getAuditIdFromRes(res), new CommentAuditView(comment.toFormattedJSON())) - Hooks.runAction('action:api.video-comment-reply.created', { comment }) + Hooks.runAction('action:api.video-comment-reply.created', { comment, req, res }) return res.json({ comment: comment.toFormattedJSON() }) } @@ -222,7 +222,7 @@ async function addVideoCommentReply (req: express.Request, res: express.Response async function removeVideoComment (req: express.Request, res: express.Response) { const videoCommentInstance = res.locals.videoCommentFull - await removeComment(videoCommentInstance) + await removeComment(videoCommentInstance, req, res) auditLogger.delete(getAuditIdFromRes(res), new CommentAuditView(videoCommentInstance.toFormattedJSON())) diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index fc1bcc73d..61a030ba1 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -158,7 +158,7 @@ async function viewVideo (req: express.Request, res: express.Response) { const serverActor = await getServerActor() await sendView(serverActor, video, undefined) - Hooks.runAction('action:api.video.viewed', { video: video, ip }) + Hooks.runAction('action:api.video.viewed', { video: video, ip, req, res }) } return res.status(HttpStatusCode.NO_CONTENT_204).end() @@ -201,7 +201,7 @@ async function listVideos (req: express.Request, res: express.Response) { return res.json(getFormattedObjects(resultList.data, resultList.total, guessAdditionalAttributesFromQuery(query))) } -async function removeVideo (_req: express.Request, res: express.Response) { +async function removeVideo (req: express.Request, res: express.Response) { const videoInstance = res.locals.videoAll await sequelizeTypescript.transaction(async t => { @@ -211,7 +211,7 @@ async function removeVideo (_req: express.Request, res: express.Response) { auditLogger.delete(getAuditIdFromRes(res), new VideoAuditView(videoInstance.toFormattedDetailsJSON())) logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid) - Hooks.runAction('action:api.video.deleted', { video: videoInstance }) + Hooks.runAction('action:api.video.deleted', { video: videoInstance, req, res }) return res.type('json') .status(HttpStatusCode.NO_CONTENT_204) diff --git a/server/controllers/api/videos/live.ts b/server/controllers/api/videos/live.ts index efafe64e9..e29615ff5 100644 --- a/server/controllers/api/videos/live.ts +++ b/server/controllers/api/videos/live.ts @@ -133,7 +133,7 @@ async function addLiveVideo (req: express.Request, res: express.Response) { return { videoCreated } }) - Hooks.runAction('action:api.live-video.created', { video: videoCreated }) + Hooks.runAction('action:api.live-video.created', { video: videoCreated, req, res }) return res.json({ video: { diff --git a/server/controllers/api/videos/update.ts b/server/controllers/api/videos/update.ts index de5d94d55..3fcff3e86 100644 --- a/server/controllers/api/videos/update.ts +++ b/server/controllers/api/videos/update.ts @@ -153,7 +153,7 @@ async function updateVideo (req: express.Request, res: express.Response) { Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated) } - Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body }) + Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res }) } catch (err) { // Force fields we want to update // If the transaction is retried, sequelize will think the object has not changed diff --git a/server/controllers/api/videos/upload.ts b/server/controllers/api/videos/upload.ts index 3e9979330..6773b500f 100644 --- a/server/controllers/api/videos/upload.ts +++ b/server/controllers/api/videos/upload.ts @@ -129,7 +129,7 @@ async function addVideoLegacy (req: express.Request, res: express.Response) { const videoInfo: VideoCreate = req.body const files = req.files - const response = await addVideo({ res, videoPhysicalFile, videoInfo, files }) + const response = await addVideo({ req, res, videoPhysicalFile, videoInfo, files }) return res.json(response) } @@ -139,19 +139,20 @@ async function addVideoResumable (req: express.Request, res: express.Response) { const videoInfo = videoPhysicalFile.metadata const files = { previewfile: videoInfo.previewfile } - const response = await addVideo({ res, videoPhysicalFile, videoInfo, files }) + const response = await addVideo({ req, res, videoPhysicalFile, videoInfo, files }) await Redis.Instance.setUploadSession(req.query.upload_id, response) return res.json(response) } async function addVideo (options: { + req: express.Request res: express.Response videoPhysicalFile: express.VideoUploadFile videoInfo: VideoCreate files: express.UploadFiles }) { - const { res, videoPhysicalFile, videoInfo, files } = options + const { req, res, videoPhysicalFile, videoInfo, files } = options const videoChannel = res.locals.videoChannel const user = res.locals.oauth.token.User @@ -235,7 +236,7 @@ async function addVideo (options: { }) .catch(err => logger.error('Cannot add optimize/merge audio job for %s.', videoCreated.uuid, { err, ...lTags(videoCreated.uuid) })) - Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) + Hooks.runAction('action:api.video.uploaded', { video: videoCreated, req, res }) return { video: { diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index c76570a5d..02f160fe8 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts @@ -1,5 +1,6 @@ import { cloneDeep } from 'lodash' import * as Sequelize from 'sequelize' +import express from 'express' import { logger } from '@server/helpers/logger' import { sequelizeTypescript } from '@server/initializers/database' import { ResultList } from '../../shared/models' @@ -10,7 +11,7 @@ import { sendCreateVideoComment, sendDeleteVideoComment } from './activitypub/se import { getLocalVideoCommentActivityPubUrl } from './activitypub/url' import { Hooks } from './plugins/hooks' -async function removeComment (videoCommentInstance: MCommentOwnerVideo) { +async function removeComment (videoCommentInstance: MCommentOwnerVideo, req: express.Request, res: express.Response) { const videoCommentInstanceBefore = cloneDeep(videoCommentInstance) await sequelizeTypescript.transaction(async t => { @@ -25,7 +26,7 @@ async function removeComment (videoCommentInstance: MCommentOwnerVideo) { logger.info('Video comment %d deleted.', videoCommentInstance.id) - Hooks.runAction('action:api.video-comment.deleted', { comment: videoCommentInstanceBefore }) + Hooks.runAction('action:api.video-comment.deleted', { comment: videoCommentInstanceBefore, req, res }) } async function createVideoComment (obj: { diff --git a/shared/models/plugins/server/server-hook.model.ts b/shared/models/plugins/server/server-hook.model.ts index 562c6eb12..3ab910197 100644 --- a/shared/models/plugins/server/server-hook.model.ts +++ b/shared/models/plugins/server/server-hook.model.ts @@ -85,6 +85,8 @@ export const serverActionHookObject = { // Fired when the application has been loaded and is listening HTTP requests 'action:application.listening': true, + // API actions hooks give access to the original express `req` and `res` parameters + // Fired when a local video is updated 'action:api.video.updated': true, // Fired when a local video is deleted diff --git a/support/doc/plugins/guide.md b/support/doc/plugins/guide.md index 072c7c6ca..acf4718e4 100644 --- a/support/doc/plugins/guide.md +++ b/support/doc/plugins/guide.md @@ -108,6 +108,20 @@ async function register ({ } ``` +Hooks prefixed by `action:api` also give access the original **express** [Request](http://expressjs.com/en/api.html#req) and [Response](http://expressjs.com/en/api.html#res): + +```js +async function register ({ + registerHook, + peertubeHelpers: { logger } +}) { + registerHook({ + target: 'action:api.video.updated', + handler: ({ req, res }) => logger.debug('original request parameters', { params: req.params }) + }) +} +``` + On client side, these hooks are registered by the `clientScripts` files defined in `package.json`. All client scripts have scopes so PeerTube client only loads scripts it needs: