X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fcontrollers%2Fapi%2Fabuse.ts;h=d6211cc83e807a0c7591b61564f841c9fbf062ee;hb=bd09dfaf8dcb0ca4cd5dac9f13e3117486f3bcce;hp=04a0c06e33cf62c79b24238dbe02385287dcdbc8;hpb=17aa80ed016bafa3ccb071af3f86054033823284;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts index 04a0c06e3..d6211cc83 100644 --- a/server/controllers/api/abuse.ts +++ b/server/controllers/api/abuse.ts @@ -1,20 +1,29 @@ -import * as express from 'express' +import express from 'express' +import { logger } from '@server/helpers/logger' import { createAccountAbuse, createVideoAbuse, createVideoCommentAbuse } from '@server/lib/moderation' +import { Notifier } from '@server/lib/notifier' import { AbuseModel } from '@server/models/abuse/abuse' +import { AbuseMessageModel } from '@server/models/abuse/abuse-message' import { getServerActor } from '@server/models/application/application' -import { AbuseCreate, abusePredefinedReasonsMap, AbuseState, UserRight } from '../../../shared' +import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' +import { AbuseCreate, AbuseState, HttpStatusCode, UserRight } from '@shared/models' import { getFormattedObjects } from '../../helpers/utils' import { sequelizeTypescript } from '../../initializers/database' import { abuseGetValidator, - abuseListValidator, + abuseListForAdminsValidator, abuseReportValidator, abusesSortValidator, abuseUpdateValidator, + addAbuseMessageValidator, asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, + checkAbuseValidForMessagesValidator, + deleteAbuseMessageValidator, ensureUserHasRight, + getAbuseValidator, + openapiOperationDoc, paginationValidator, setDefaultPagination, setDefaultSort @@ -24,14 +33,15 @@ import { AccountModel } from '../../models/account/account' const abuseRouter = express.Router() abuseRouter.get('/', + openapiOperationDoc({ operationId: 'getAbuses' }), authenticate, ensureUserHasRight(UserRight.MANAGE_ABUSES), paginationValidator, abusesSortValidator, setDefaultSort, setDefaultPagination, - abuseListValidator, - asyncMiddleware(listAbuses) + abuseListForAdminsValidator, + asyncMiddleware(listAbusesForAdmins) ) abuseRouter.put('/:id', authenticate, @@ -51,25 +61,42 @@ abuseRouter.delete('/:id', asyncRetryTransactionMiddleware(deleteAbuse) ) +abuseRouter.get('/:id/messages', + authenticate, + asyncMiddleware(getAbuseValidator), + checkAbuseValidForMessagesValidator, + asyncRetryTransactionMiddleware(listAbuseMessages) +) + +abuseRouter.post('/:id/messages', + authenticate, + asyncMiddleware(getAbuseValidator), + checkAbuseValidForMessagesValidator, + addAbuseMessageValidator, + asyncRetryTransactionMiddleware(addAbuseMessage) +) + +abuseRouter.delete('/:id/messages/:messageId', + authenticate, + asyncMiddleware(getAbuseValidator), + checkAbuseValidForMessagesValidator, + asyncMiddleware(deleteAbuseMessageValidator), + asyncRetryTransactionMiddleware(deleteAbuseMessage) +) + // --------------------------------------------------------------------------- export { - abuseRouter, - - // FIXME: deprecated in 2.3. Remove these exports - listAbuses, - updateAbuse, - deleteAbuse, - reportAbuse + abuseRouter } // --------------------------------------------------------------------------- -async function listAbuses (req: express.Request, res: express.Response) { +async function listAbusesForAdmins (req: express.Request, res: express.Response) { const user = res.locals.oauth.token.user const serverActor = await getServerActor() - const resultList = await AbuseModel.listForApi({ + const resultList = await AbuseModel.listForAdminApi({ start: req.query.start, count: req.query.count, sort: req.query.sort, @@ -87,22 +114,36 @@ async function listAbuses (req: express.Request, res: express.Response) { user }) - return res.json(getFormattedObjects(resultList.data, resultList.total)) + return res.json({ + total: resultList.total, + data: resultList.data.map(d => d.toFormattedAdminJSON()) + }) } async function updateAbuse (req: express.Request, res: express.Response) { const abuse = res.locals.abuse + let stateUpdated = false if (req.body.moderationComment !== undefined) abuse.moderationComment = req.body.moderationComment - if (req.body.state !== undefined) abuse.state = req.body.state + + if (req.body.state !== undefined) { + abuse.state = req.body.state + stateUpdated = true + } await sequelizeTypescript.transaction(t => { return abuse.save({ transaction: t }) }) + if (stateUpdated === true) { + AbuseModel.loadFull(abuse.id) + .then(abuseFull => Notifier.Instance.notifyOnAbuseStateChange(abuseFull)) + .catch(err => logger.error('Cannot notify on abuse state change', { err })) + } + // Do not send the delete to other instances, we updated OUR copy of this abuse - return res.type('json').status(204).end() + return res.status(HttpStatusCode.NO_CONTENT_204).end() } async function deleteAbuse (req: express.Request, res: express.Response) { @@ -114,7 +155,7 @@ async function deleteAbuse (req: express.Request, res: express.Response) { // Do not send the delete to other instances, we delete OUR copy of this abuse - return res.type('json').status(204).end() + return res.status(HttpStatusCode.NO_CONTENT_204).end() } async function reportAbuse (req: express.Request, res: express.Response) { @@ -125,7 +166,11 @@ async function reportAbuse (req: express.Request, res: express.Response) { const body: AbuseCreate = req.body const { id } = await sequelizeTypescript.transaction(async t => { - const reporterAccount = await AccountModel.load(res.locals.oauth.token.User.Account.id, t) + const user = res.locals.oauth.token.User + // Don't send abuse notification if reporter is an admin/moderator + const skipNotification = user.hasRight(UserRight.MANAGE_ABUSES) + + const reporterAccount = await AccountModel.load(user.Account.id, t) const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) const baseAbuse = { @@ -142,7 +187,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { reporterAccount, transaction: t, startAt: body.video.startAt, - endAt: body.video.endAt + endAt: body.video.endAt, + skipNotification }) } @@ -151,7 +197,8 @@ async function reportAbuse (req: express.Request, res: express.Response) { baseAbuse, commentInstance, reporterAccount, - transaction: t + transaction: t, + skipNotification }) } @@ -160,9 +207,50 @@ async function reportAbuse (req: express.Request, res: express.Response) { baseAbuse, accountInstance, reporterAccount, - transaction: t + transaction: t, + skipNotification }) }) return res.json({ abuse: { id } }) } + +async function listAbuseMessages (req: express.Request, res: express.Response) { + const abuse = res.locals.abuse + + const resultList = await AbuseMessageModel.listForApi(abuse.id) + + return res.json(getFormattedObjects(resultList.data, resultList.total)) +} + +async function addAbuseMessage (req: express.Request, res: express.Response) { + const abuse = res.locals.abuse + const user = res.locals.oauth.token.user + + const abuseMessage = await AbuseMessageModel.create({ + message: req.body.message, + byModerator: abuse.reporterAccountId !== user.Account.id, + accountId: user.Account.id, + abuseId: abuse.id + }) + + AbuseModel.loadFull(abuse.id) + .then(abuseFull => Notifier.Instance.notifyOnAbuseMessage(abuseFull, abuseMessage)) + .catch(err => logger.error('Cannot notify on new abuse message', { err })) + + return res.json({ + abuseMessage: { + id: abuseMessage.id + } + }) +} + +async function deleteAbuseMessage (req: express.Request, res: express.Response) { + const abuseMessage = res.locals.abuseMessage + + await sequelizeTypescript.transaction(t => { + return abuseMessage.destroy({ transaction: t }) + }) + + return res.status(HttpStatusCode.NO_CONTENT_204).end() +}