Add action hooks to user routes

This commit is contained in:
Chocobozzz 2019-12-06 15:59:12 +01:00
parent 349be1eaa9
commit 6f3fe96f40
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
6 changed files with 141 additions and 41 deletions

View File

@ -49,6 +49,7 @@ import { sequelizeTypescript } from '../../../initializers/database'
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
import { UserRegister } from '../../../../shared/models/users/user-register.model'
import { MUser, MUserAccountDefault } from '@server/typings/models'
import { Hooks } from '@server/lib/plugins/hooks'
const auditLogger = auditLoggerFactory('users')
@ -172,7 +173,7 @@ usersRouter.post('/:id/verify-email',
usersRouter.post('/token',
loginRateLimiter,
token,
success
tokenSuccess
)
// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
@ -198,11 +199,13 @@ async function createUser (req: express.Request, res: express.Response) {
adminFlags: body.adminFlags || UserAdminFlag.NONE
}) as MUser
const { user, account } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate })
const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate })
auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
logger.info('User %s with its channel and account created.', body.username)
Hooks.runAction('action:api.user.created', { body, user, account, videoChannel })
return res.json({
user: {
id: user.id,
@ -228,7 +231,7 @@ async function registerUser (req: express.Request, res: express.Response) {
emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
})
const { user } = await createUserAccountAndChannelAndPlaylist({
const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({
userToCreate: userToCreate,
userDisplayName: body.displayName || undefined,
channelNames: body.channel
@ -243,6 +246,8 @@ async function registerUser (req: express.Request, res: express.Response) {
Notifier.Instance.notifyOnNewUserRegistration(user)
Hooks.runAction('action:api.user.registered', { body, user, account, videoChannel })
return res.type('json').status(204).end()
}
@ -251,6 +256,8 @@ async function unblockUser (req: express.Request, res: express.Response) {
await changeUserBlock(res, user, false)
Hooks.runAction('action:api.user.unblocked', { user })
return res.status(204).end()
}
@ -260,6 +267,8 @@ async function blockUser (req: express.Request, res: express.Response) {
await changeUserBlock(res, user, true, reason)
Hooks.runAction('action:api.user.blocked', { user })
return res.status(204).end()
}
@ -286,6 +295,8 @@ async function removeUser (req: express.Request, res: express.Response) {
auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
Hooks.runAction('action:api.user.deleted', { user })
return res.sendStatus(204)
}
@ -310,6 +321,8 @@ 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 })
// Don't need to send this update to followers, these attributes are not federated
return res.sendStatus(204)
@ -356,8 +369,10 @@ async function verifyUserEmail (req: express.Request, res: express.Response) {
return res.status(204).end()
}
function success (req: express.Request, res: express.Response) {
res.end()
function tokenSuccess (req: express.Request) {
const username = req.body.username
Hooks.runAction('action:api.user.oauth2-got-token', { username, ip: req.ip })
}
async function changeUserBlock (res: express.Response, user: MUserAccountDefault, block: boolean, reason?: string) {

View File

@ -9,6 +9,7 @@ const oAuthServer = new OAuthServer({
useErrorHandler: true,
accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN,
refreshTokenLifetime: OAUTH_LIFETIME.REFRESH_TOKEN,
continueMiddleware: true,
model: require('../lib/oauth-model')
})

View File

@ -9,7 +9,15 @@ async function register ({ registerHook, registerSetting, settingsManager, stora
'action:api.video-thread.created',
'action:api.video-comment-reply.created',
'action:api.video-comment.deleted'
'action:api.video-comment.deleted',
'action:api.user.blocked',
'action:api.user.unblocked',
'action:api.user.registered',
'action:api.user.created',
'action:api.user.deleted',
'action:api.user.updated',
'action:api.user.oauth2-got-token'
]
for (const h of actionHooks) {

View File

@ -5,19 +5,26 @@ import 'mocha'
import {
cleanupTests,
flushAndRunMultipleServers,
flushAndRunServer, killallServers, reRunServer,
killallServers,
reRunServer,
ServerInfo,
waitUntilLog
} from '../../../shared/extra-utils/server/servers'
import {
addVideoCommentReply,
addVideoCommentThread, deleteVideoComment,
addVideoCommentThread,
blockUser,
createUser,
deleteVideoComment,
getPluginTestPath,
installPlugin, removeVideo,
installPlugin, login,
registerUser, removeUser,
setAccessTokensToServers,
unblockUser, updateUser,
updateVideo,
uploadVideo,
viewVideo
viewVideo,
userLogin
} from '../../../shared/extra-utils'
const expect = chai.expect
@ -48,52 +55,104 @@ describe('Test plugin action hooks', function () {
await reRunServer(servers[0])
})
it('Should run action:application.listening', async function () {
await checkHook('action:application.listening')
describe('Application hooks', function () {
it('Should run action:application.listening', async function () {
await checkHook('action:application.listening')
})
})
it('Should run action:api.video.uploaded', async function () {
const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
videoUUID = res.body.video.uuid
describe('Videos hooks', function () {
it('Should run action:api.video.uploaded', async function () {
const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
videoUUID = res.body.video.uuid
await checkHook('action:api.video.uploaded')
await checkHook('action:api.video.uploaded')
})
it('Should run action:api.video.updated', async function () {
await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video updated' })
await checkHook('action:api.video.updated')
})
it('Should run action:api.video.viewed', async function () {
await viewVideo(servers[0].url, videoUUID)
await checkHook('action:api.video.viewed')
})
})
it('Should run action:api.video.updated', async function () {
await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video updated' })
describe('Comments hooks', function () {
it('Should run action:api.video-thread.created', async function () {
const res = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'thread')
threadId = res.body.comment.id
await checkHook('action:api.video.updated')
await checkHook('action:api.video-thread.created')
})
it('Should run action:api.video-comment-reply.created', async function () {
await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID, threadId, 'reply')
await checkHook('action:api.video-comment-reply.created')
})
it('Should run action:api.video-comment.deleted', async function () {
await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
await checkHook('action:api.video-comment.deleted')
})
})
it('Should run action:api.video.viewed', async function () {
await viewVideo(servers[0].url, videoUUID)
describe('Users hooks', function () {
let userId: number
await checkHook('action:api.video.viewed')
})
it('Should run action:api.user.registered', async function () {
await registerUser(servers[0].url, 'registered_user', 'super_password')
it('Should run action:api.video-thread.created', async function () {
const res = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, 'thread')
threadId = res.body.comment.id
await checkHook('action:api.user.registered')
})
await checkHook('action:api.video-thread.created')
})
it('Should run action:api.user.created', async function () {
const res = await createUser({
url: servers[0].url,
accessToken: servers[0].accessToken,
username: 'created_user',
password: 'super_password'
})
userId = res.body.user.id
it('Should run action:api.video-comment-reply.created', async function () {
await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID, threadId, 'reply')
await checkHook('action:api.user.created')
})
await checkHook('action:api.video-comment-reply.created')
})
it('Should run action:api.user.oauth2-got-token', async function () {
await userLogin(servers[0], { username: 'created_user', password: 'super_password' })
it('Should run action:api.video-comment.deleted', async function () {
await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
await checkHook('action:api.user.oauth2-got-token')
})
await checkHook('action:api.video-comment.deleted')
})
it('Should run action:api.user.blocked', async function () {
await blockUser(servers[0].url, userId, servers[0].accessToken)
it('Should run action:api.video.deleted', async function () {
await removeVideo(servers[0].url, servers[0].accessToken, videoUUID)
await checkHook('action:api.user.blocked')
})
await checkHook('action:api.video.deleted')
it('Should run action:api.user.unblocked', async function () {
await unblockUser(servers[0].url, userId, servers[0].accessToken)
await checkHook('action:api.user.unblocked')
})
it('Should run action:api.user.updated', async function () {
await updateUser({ url: servers[0].url, accessToken: servers[0].accessToken, userId, videoQuota: 50 })
await checkHook('action:api.user.updated')
})
it('Should run action:api.user.deleted', async function () {
await removeUser(servers[0].url, userId, servers[0].accessToken)
await checkHook('action:api.user.deleted')
})
})
after(async function () {

View File

@ -8,7 +8,8 @@ import { userLogin } from './login'
import { UserUpdateMe } from '../../models/users'
import { omit } from 'lodash'
type CreateUserArgs = { url: string,
type CreateUserArgs = {
url: string,
accessToken: string,
username: string,
password: string,

View File

@ -55,7 +55,23 @@ export const serverActionHookObject = {
// Fired when a reply to a thread is created
'action:api.video-comment-reply.created': true,
// Fired when a comment (thread or reply) is deleted
'action:api.video-comment.deleted': true
'action:api.video-comment.deleted': true,
// Fired when a user is blocked (banned)
'action:api.user.blocked': true,
// Fired when a user is unblocked (unbanned)
'action:api.user.unblocked': true,
// Fired when a user registered on the instance
'action:api.user.registered': true,
// Fired when an admin/moderator created a user
'action:api.user.created': true,
// Fired when a user is removed by an admin/moderator
'action:api.user.deleted': true,
// Fired when a user is updated by an admin/moderator
'action:api.user.updated': true,
// Fired when a user got a new oauth2 token
'action:api.user.oauth2-got-token': true
}
export type ServerActionHookName = keyof typeof serverActionHookObject