From c50cee0d88b9ef1b52513f164f1c4824aef22405 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Wed, 12 Jul 2023 16:32:25 -0500 Subject: [PATCH] fix(flagging): debug params issue Also add and document the "source" body param --- website/server/controllers/api-v3/members.js | 6 +++ .../libs/chatReporting/profileReporter.js | 49 ++++++++++++------- website/server/models/user/schema.js | 4 +- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/website/server/controllers/api-v3/members.js b/website/server/controllers/api-v3/members.js index 93e2173bca..16cccd6501 100644 --- a/website/server/controllers/api-v3/members.js +++ b/website/server/controllers/api-v3/members.js @@ -786,12 +786,18 @@ api.transferGems = { * * @apiParam (Path) {UUID} memberId The unique ID of the user being flagged * @apiParam (Body) {String} [comment] explain why the user was flagged + * @apiParam (Body) {String} [source] URL or view from which the user was flagged * * @apiSuccess {Object} data The flagged user * @apiSuccess {UUID} data.id The id of the flagged user * @apiSuccess {String} data.username The username of the flagged user * @apiSuccess {Object} data.profile The flagged user's profile information * @apiSuccess {String} data.profile.blurb Text of the flagged user's profile bio + * @apiSuccess {Object} data.profile.flags Data about flags the profile has received. + * Restricted to the reporting user's own flag + * unless the reporting user is a moderator. + * Each key is a UUID, and fields are comment, + * source, and timestamp. * @apiSuccess {String} data.profile.imageUrl URL of the flagged user's profile image * @apiSuccess {String} data.profile.name The flagged user's display name * diff --git a/website/server/libs/chatReporting/profileReporter.js b/website/server/libs/chatReporting/profileReporter.js index 7374e24913..e30f1b8099 100644 --- a/website/server/libs/chatReporting/profileReporter.js +++ b/website/server/libs/chatReporting/profileReporter.js @@ -21,27 +21,27 @@ export default class ProfileReporter extends ChatReporter { } async validate () { - this.req.checkParams('memberId', apiError('memberIdRequired')).notEmpty(); + this.req.checkParams('memberId', this.res.t('memberIdRequired')).notEmpty().isUUID(); const validationErrors = this.req.validationErrors(); if (validationErrors) throw validationErrors; const flaggedUser = await User.findOne( - { _id: this.req.query.memberId }, + { _id: this.req.params.memberId }, { auth: 1, profile: 1 }, ).exec(); if (!flaggedUser) { - throw new NotFound(this.res.t('userWithIDNotFound')); + throw new NotFound(this.res.t('userWithIDNotFound', { userId: this.req.params.memberId })); } - if (flaggedUser.profile.flags && flaggedUser.profile.flags.indexOf(this.user._id) !== -1 + if (flaggedUser.profile.flags && flaggedUser.profile.flags[this.user._id] && !this.user.hasPermission('moderator')) { throw new BadRequest('A profile can not be flagged more than once by the same user.'); } - const userComment = this.req.body.comment; + const { comment, source } = this.req.body; - return { flaggedUser, userComment }; + return { flaggedUser, comment, source }; } getEmailVariables (flaggedUser) { @@ -65,21 +65,27 @@ export default class ProfileReporter extends ChatReporter { ]; } - flagProfile (flaggedUser) { + async flagProfile (flaggedUser, comment, source) { + const timestamp = new Date(); // Log user ids that have flagged the account if (!flaggedUser.profile.flags) { - flaggedUser.profile.flags = []; + flaggedUser.profile.flags = {}; } - flaggedUser.profile.flags.push(this.user._id); - - return flaggedUser.save(); + flaggedUser.profile.flags[this.user._id] = { + comment, + source, + timestamp, + }; + flaggedUser.markModified('profile.flags'); + await flaggedUser.save(); + return timestamp; } - async notify (flaggedUser, userComment) { - let emailVariables = await this.getEmailVariables(flaggedUser); + notify (flaggedUser, comment) { + let emailVariables = this.getEmailVariables(flaggedUser); emailVariables = emailVariables.concat([ - { name: 'REPORTER_COMMENT', content: userComment || '' }, + { name: 'REPORTER_COMMENT', content: comment || '' }, ]); sendTxn(FLAG_REPORT_EMAILS, 'profile-report-to-mods-with-comments', emailVariables); @@ -87,16 +93,21 @@ export default class ProfileReporter extends ChatReporter { slack.sendProfileFlagNotification({ reporter: this.user, flaggedUser, - userComment, + comment, }); } async flag () { - const { flaggedUser, userComment } = await this.validate(); - await this.flagProfile(flaggedUser); - await this.notify(flaggedUser, userComment); + const { flaggedUser, comment, source } = await this.validate(); + const timestamp = await this.flagProfile(flaggedUser, comment, source); + this.notify(flaggedUser, comment, source); if (!this.user.hasPermission('moderator')) { - flaggedUser.profile.flags = [this.user._id]; + flaggedUser.profile.flags = {}; + flaggedUser.profile.flags[this.user._id] = { + comment, + source, + timestamp, + }; } return flaggedUser; } diff --git a/website/server/models/user/schema.js b/website/server/models/user/schema.js index ad5b7a1165..35da973b4e 100644 --- a/website/server/models/user/schema.js +++ b/website/server/models/user/schema.js @@ -621,9 +621,7 @@ export default new Schema({ required: true, trim: true, }, - flags: [ - { $type: String, validate: [v => validator.isUUID(v), 'Invalid user UUID.'], ref: 'User' }, - ], + flags: { $type: Schema.Types.Mixed }, }, stats: { hp: { $type: Number, default: shared.maxHealth },