diff options
Diffstat (limited to 'server/controllers/api/abuse.ts')
-rw-r--r-- | server/controllers/api/abuse.ts | 259 |
1 files changed, 0 insertions, 259 deletions
diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts deleted file mode 100644 index d582f198d..000000000 --- a/server/controllers/api/abuse.ts +++ /dev/null | |||
@@ -1,259 +0,0 @@ | |||
1 | import express from 'express' | ||
2 | import { logger } from '@server/helpers/logger' | ||
3 | import { createAccountAbuse, createVideoAbuse, createVideoCommentAbuse } from '@server/lib/moderation' | ||
4 | import { Notifier } from '@server/lib/notifier' | ||
5 | import { AbuseModel } from '@server/models/abuse/abuse' | ||
6 | import { AbuseMessageModel } from '@server/models/abuse/abuse-message' | ||
7 | import { getServerActor } from '@server/models/application/application' | ||
8 | import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' | ||
9 | import { AbuseCreate, AbuseState, HttpStatusCode, UserRight } from '@shared/models' | ||
10 | import { getFormattedObjects } from '../../helpers/utils' | ||
11 | import { sequelizeTypescript } from '../../initializers/database' | ||
12 | import { | ||
13 | abuseGetValidator, | ||
14 | abuseListForAdminsValidator, | ||
15 | abuseReportValidator, | ||
16 | abusesSortValidator, | ||
17 | abuseUpdateValidator, | ||
18 | addAbuseMessageValidator, | ||
19 | apiRateLimiter, | ||
20 | asyncMiddleware, | ||
21 | asyncRetryTransactionMiddleware, | ||
22 | authenticate, | ||
23 | checkAbuseValidForMessagesValidator, | ||
24 | deleteAbuseMessageValidator, | ||
25 | ensureUserHasRight, | ||
26 | getAbuseValidator, | ||
27 | openapiOperationDoc, | ||
28 | paginationValidator, | ||
29 | setDefaultPagination, | ||
30 | setDefaultSort | ||
31 | } from '../../middlewares' | ||
32 | import { AccountModel } from '../../models/account/account' | ||
33 | |||
34 | const abuseRouter = express.Router() | ||
35 | |||
36 | abuseRouter.use(apiRateLimiter) | ||
37 | |||
38 | abuseRouter.get('/', | ||
39 | openapiOperationDoc({ operationId: 'getAbuses' }), | ||
40 | authenticate, | ||
41 | ensureUserHasRight(UserRight.MANAGE_ABUSES), | ||
42 | paginationValidator, | ||
43 | abusesSortValidator, | ||
44 | setDefaultSort, | ||
45 | setDefaultPagination, | ||
46 | abuseListForAdminsValidator, | ||
47 | asyncMiddleware(listAbusesForAdmins) | ||
48 | ) | ||
49 | abuseRouter.put('/:id', | ||
50 | authenticate, | ||
51 | ensureUserHasRight(UserRight.MANAGE_ABUSES), | ||
52 | asyncMiddleware(abuseUpdateValidator), | ||
53 | asyncRetryTransactionMiddleware(updateAbuse) | ||
54 | ) | ||
55 | abuseRouter.post('/', | ||
56 | authenticate, | ||
57 | asyncMiddleware(abuseReportValidator), | ||
58 | asyncRetryTransactionMiddleware(reportAbuse) | ||
59 | ) | ||
60 | abuseRouter.delete('/:id', | ||
61 | authenticate, | ||
62 | ensureUserHasRight(UserRight.MANAGE_ABUSES), | ||
63 | asyncMiddleware(abuseGetValidator), | ||
64 | asyncRetryTransactionMiddleware(deleteAbuse) | ||
65 | ) | ||
66 | |||
67 | abuseRouter.get('/:id/messages', | ||
68 | authenticate, | ||
69 | asyncMiddleware(getAbuseValidator), | ||
70 | checkAbuseValidForMessagesValidator, | ||
71 | asyncRetryTransactionMiddleware(listAbuseMessages) | ||
72 | ) | ||
73 | |||
74 | abuseRouter.post('/:id/messages', | ||
75 | authenticate, | ||
76 | asyncMiddleware(getAbuseValidator), | ||
77 | checkAbuseValidForMessagesValidator, | ||
78 | addAbuseMessageValidator, | ||
79 | asyncRetryTransactionMiddleware(addAbuseMessage) | ||
80 | ) | ||
81 | |||
82 | abuseRouter.delete('/:id/messages/:messageId', | ||
83 | authenticate, | ||
84 | asyncMiddleware(getAbuseValidator), | ||
85 | checkAbuseValidForMessagesValidator, | ||
86 | asyncMiddleware(deleteAbuseMessageValidator), | ||
87 | asyncRetryTransactionMiddleware(deleteAbuseMessage) | ||
88 | ) | ||
89 | |||
90 | // --------------------------------------------------------------------------- | ||
91 | |||
92 | export { | ||
93 | abuseRouter | ||
94 | } | ||
95 | |||
96 | // --------------------------------------------------------------------------- | ||
97 | |||
98 | async function listAbusesForAdmins (req: express.Request, res: express.Response) { | ||
99 | const user = res.locals.oauth.token.user | ||
100 | const serverActor = await getServerActor() | ||
101 | |||
102 | const resultList = await AbuseModel.listForAdminApi({ | ||
103 | start: req.query.start, | ||
104 | count: req.query.count, | ||
105 | sort: req.query.sort, | ||
106 | id: req.query.id, | ||
107 | filter: req.query.filter, | ||
108 | predefinedReason: req.query.predefinedReason, | ||
109 | search: req.query.search, | ||
110 | state: req.query.state, | ||
111 | videoIs: req.query.videoIs, | ||
112 | searchReporter: req.query.searchReporter, | ||
113 | searchReportee: req.query.searchReportee, | ||
114 | searchVideo: req.query.searchVideo, | ||
115 | searchVideoChannel: req.query.searchVideoChannel, | ||
116 | serverAccountId: serverActor.Account.id, | ||
117 | user | ||
118 | }) | ||
119 | |||
120 | return res.json({ | ||
121 | total: resultList.total, | ||
122 | data: resultList.data.map(d => d.toFormattedAdminJSON()) | ||
123 | }) | ||
124 | } | ||
125 | |||
126 | async function updateAbuse (req: express.Request, res: express.Response) { | ||
127 | const abuse = res.locals.abuse | ||
128 | let stateUpdated = false | ||
129 | |||
130 | if (req.body.moderationComment !== undefined) abuse.moderationComment = req.body.moderationComment | ||
131 | |||
132 | if (req.body.state !== undefined) { | ||
133 | abuse.state = req.body.state | ||
134 | stateUpdated = true | ||
135 | } | ||
136 | |||
137 | await sequelizeTypescript.transaction(t => { | ||
138 | return abuse.save({ transaction: t }) | ||
139 | }) | ||
140 | |||
141 | if (stateUpdated === true) { | ||
142 | AbuseModel.loadFull(abuse.id) | ||
143 | .then(abuseFull => Notifier.Instance.notifyOnAbuseStateChange(abuseFull)) | ||
144 | .catch(err => logger.error('Cannot notify on abuse state change', { err })) | ||
145 | } | ||
146 | |||
147 | // Do not send the delete to other instances, we updated OUR copy of this abuse | ||
148 | |||
149 | return res.status(HttpStatusCode.NO_CONTENT_204).end() | ||
150 | } | ||
151 | |||
152 | async function deleteAbuse (req: express.Request, res: express.Response) { | ||
153 | const abuse = res.locals.abuse | ||
154 | |||
155 | await sequelizeTypescript.transaction(t => { | ||
156 | return abuse.destroy({ transaction: t }) | ||
157 | }) | ||
158 | |||
159 | // Do not send the delete to other instances, we delete OUR copy of this abuse | ||
160 | |||
161 | return res.status(HttpStatusCode.NO_CONTENT_204).end() | ||
162 | } | ||
163 | |||
164 | async function reportAbuse (req: express.Request, res: express.Response) { | ||
165 | const videoInstance = res.locals.videoAll | ||
166 | const commentInstance = res.locals.videoCommentFull | ||
167 | const accountInstance = res.locals.account | ||
168 | |||
169 | const body: AbuseCreate = req.body | ||
170 | |||
171 | const { id } = await sequelizeTypescript.transaction(async t => { | ||
172 | const user = res.locals.oauth.token.User | ||
173 | // Don't send abuse notification if reporter is an admin/moderator | ||
174 | const skipNotification = user.hasRight(UserRight.MANAGE_ABUSES) | ||
175 | |||
176 | const reporterAccount = await AccountModel.load(user.Account.id, t) | ||
177 | const predefinedReasons = body.predefinedReasons?.map(r => abusePredefinedReasonsMap[r]) | ||
178 | |||
179 | const baseAbuse = { | ||
180 | reporterAccountId: reporterAccount.id, | ||
181 | reason: body.reason, | ||
182 | state: AbuseState.PENDING, | ||
183 | predefinedReasons | ||
184 | } | ||
185 | |||
186 | if (body.video) { | ||
187 | return createVideoAbuse({ | ||
188 | baseAbuse, | ||
189 | videoInstance, | ||
190 | reporterAccount, | ||
191 | transaction: t, | ||
192 | startAt: body.video.startAt, | ||
193 | endAt: body.video.endAt, | ||
194 | skipNotification | ||
195 | }) | ||
196 | } | ||
197 | |||
198 | if (body.comment) { | ||
199 | return createVideoCommentAbuse({ | ||
200 | baseAbuse, | ||
201 | commentInstance, | ||
202 | reporterAccount, | ||
203 | transaction: t, | ||
204 | skipNotification | ||
205 | }) | ||
206 | } | ||
207 | |||
208 | // Account report | ||
209 | return createAccountAbuse({ | ||
210 | baseAbuse, | ||
211 | accountInstance, | ||
212 | reporterAccount, | ||
213 | transaction: t, | ||
214 | skipNotification | ||
215 | }) | ||
216 | }) | ||
217 | |||
218 | return res.json({ abuse: { id } }) | ||
219 | } | ||
220 | |||
221 | async function listAbuseMessages (req: express.Request, res: express.Response) { | ||
222 | const abuse = res.locals.abuse | ||
223 | |||
224 | const resultList = await AbuseMessageModel.listForApi(abuse.id) | ||
225 | |||
226 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
227 | } | ||
228 | |||
229 | async function addAbuseMessage (req: express.Request, res: express.Response) { | ||
230 | const abuse = res.locals.abuse | ||
231 | const user = res.locals.oauth.token.user | ||
232 | |||
233 | const abuseMessage = await AbuseMessageModel.create({ | ||
234 | message: req.body.message, | ||
235 | byModerator: abuse.reporterAccountId !== user.Account.id, | ||
236 | accountId: user.Account.id, | ||
237 | abuseId: abuse.id | ||
238 | }) | ||
239 | |||
240 | AbuseModel.loadFull(abuse.id) | ||
241 | .then(abuseFull => Notifier.Instance.notifyOnAbuseMessage(abuseFull, abuseMessage)) | ||
242 | .catch(err => logger.error('Cannot notify on new abuse message', { err })) | ||
243 | |||
244 | return res.json({ | ||
245 | abuseMessage: { | ||
246 | id: abuseMessage.id | ||
247 | } | ||
248 | }) | ||
249 | } | ||
250 | |||
251 | async function deleteAbuseMessage (req: express.Request, res: express.Response) { | ||
252 | const abuseMessage = res.locals.abuseMessage | ||
253 | |||
254 | await sequelizeTypescript.transaction(t => { | ||
255 | return abuseMessage.destroy({ transaction: t }) | ||
256 | }) | ||
257 | |||
258 | return res.status(HttpStatusCode.NO_CONTENT_204).end() | ||
259 | } | ||