From 1f67c72fc6a2bb30fa7bd387c02323e53ec4178c Mon Sep 17 00:00:00 2001 From: Mrugesh Mohapatra Date: Thu, 15 Dec 2016 02:54:59 +0530 Subject: [PATCH] feat(user): Report profiles This adds a simple email-based mechanism to report profiles for abuse. An email with text from the report is sent to Free Code Camp's support account with the reporter's account in copy. This also adds the reporter's details to the report for follow ups. --- client/less/main.less | 10 +++- server/boot/user.js | 67 +++++++++++++++++++++++- server/middlewares/validator.js | 24 +++++++++ server/utils/middleware.js | 20 +++---- server/views/account/report-profile.jade | 29 ++++++++++ server/views/account/show.jade | 3 ++ 6 files changed, 139 insertions(+), 14 deletions(-) create mode 100644 server/views/account/report-profile.jade diff --git a/client/less/main.less b/client/less/main.less index a61a04b9e9..a7cd740b2e 100644 --- a/client/less/main.less +++ b/client/less/main.less @@ -1145,7 +1145,7 @@ and (max-width : 400px) { -webkit-overflow-scrolling: touch; } -// Reset/Delete Account Modal Styles +// Account Modal Styles .modal-dialog { margin: 80px; @@ -1184,6 +1184,14 @@ and (max-width : 400px) { background-color: #208e36; border-color: darkgreen; } + + .modal-textarea { + width: 100%; + max-width: 590px; + border: 2px solid #ccc; + border-radius: 5px; + padding: 5px; + } } } diff --git a/server/boot/user.js b/server/boot/user.js index be7833430b..f3f88e3eeb 100644 --- a/server/boot/user.js +++ b/server/boot/user.js @@ -12,7 +12,8 @@ import { import certTypes from '../utils/certTypes.json'; import { ifNoUser401, - ifNoUserRedirectTo + ifNoUserRedirectTo, + ifNotVerifiedRedirectToSettings } from '../utils/middleware'; import { observeQuery } from '../utils/rx'; import { @@ -140,6 +141,7 @@ module.exports = function(app) { const api = app.loopback.Router(); const User = app.models.User; const Block = app.models.Block; + const { Email } = app.models; const map$ = cachedMap(Block); function findUserByUsername$(username, fields) { return observeQuery( @@ -223,6 +225,18 @@ module.exports = function(app) { ); router.get('/:username', showUserProfile); + router.get( + '/:username/report-user/', + sendNonUserToMap, + ifNotVerifiedRedirectToSettings, + getReportUserProfile + ); + + api.post( + '/:username/report-user/', + ifNoUser401, + postReportUserProfile + ); app.use('/:lang', router); app.use(api); @@ -631,4 +645,55 @@ module.exports = function(app) { return res.render('account/forgot'); }); } + + function getReportUserProfile(req, res) { + const username = req.params.username.toLowerCase(); + return res.render('account/report-profile', { + title: 'Report User', + username + }); + } + + function postReportUserProfile(req, res, next) { + const { user } = req; + const { username } = req.params; + const report = req.sanitize('reportDescription').trimTags(); + + if (!username || !report || report === '') { + req.flash('errors', { + msg: 'Oops, something is not right please re-check your submission.' + }); + return next(); + } + + return Email.send$({ + type: 'email', + to: 'Team@FreeCodeCamp.com', + cc: user.email, + from: 'Team@FreeCodeCamp.com', + subject: 'Abuse Report : Reporting ' + username + '\'s profile.', + text: dedent(` + Hello Team,\n + This is to report the profile of ${username}.\n + Report Details:\n + ${report}\n\n + Reported by: + Username: ${user.username} + Name: ${user.name} + Email: ${user.email}\n + Thanks and regards, + ${user.name} + `) + }, err => { + if (err) { + err.redirectTo = '/' + username; + return next(err); + } + + req.flash('info', { + msg: 'A report was sent to the team with ' + user.email + ' in copy.' + }); + return res.redirect('/'); + }); + } }; diff --git a/server/middlewares/validator.js b/server/middlewares/validator.js index 80a7ede590..bca7b0f8f5 100644 --- a/server/middlewares/validator.js +++ b/server/middlewares/validator.js @@ -26,6 +26,30 @@ export default function() { // every file has contents keys.map(key => value[key]).every(file => isPoly(file)); } + }, + customSanitizers: { + // Refer : http://stackoverflow.com/a/430240/1932901 + trimTags(value) { + const tagBody = '(?:[^"\'>]|"[^"]*"|\'[^\']*\')*'; + const tagOrComment = new RegExp( + '<(?:' + // Comment body. + + '!--(?:(?:-*[^->])*--+|-?)' + // Special "raw text" elements whose content should be elided. + + '|script\\b' + tagBody + '>[\\s\\S]*?[\\s\\S]*?', + 'gi'); + let rawValue; + do { + rawValue = value; + value = value.replace(tagOrComment, ''); + } while (value !== rawValue); + return value.replace(/here.' + if (!user.emailVerified) { + req.flash('error', { + msg: 'We do not have your verified email address on record, ' + + 'please add it in the settings to continue with your request.' }); + return res.redirect('/settings'); } - */ + return next(); } diff --git a/server/views/account/report-profile.jade b/server/views/account/report-profile.jade new file mode 100644 index 0000000000..91d0f7df6d --- /dev/null +++ b/server/views/account/report-profile.jade @@ -0,0 +1,29 @@ +extends ../layout +block content + #modal-dialog.modal + .modal-dialog + .modal-content + .modal-header + a.close(href='/settings', data-dismiss='modal', aria-hidden='true') × + h3 Do you want to report #{username}'s profile for abuse? + .modal-body + p We will notify the community moderators' team, + | and a send copy of this report to your email: + strong #{user.email} + | . We may get back to you for more information, if required. + .modal-footer + form(action='/' + username +'/report-user/', method='POST') + input(type='hidden', name='_csrf', value=_csrf) + div + textarea.modal-textarea(name='reportDescription', cols='40', rows='5') + .spacer + button.btn.btn-danger.btn-block(type='submit') + | Yes, submit my report about this user's profile. + .spacer + a.btn.btn-success.btn-block(href='/settings', data-dismiss='modal', aria-hidden='true') + | Nevermind, I don't want to report this user. + script. + document.addEventListener('DOMContentLoaded', function() { + const modal$ = document.getElementById('modal-dialog'); + modal$.classList.add('show'); + }); diff --git a/server/views/account/show.jade b/server/views/account/show.jade index 964492cf6a..026e52a511 100644 --- a/server/views/account/show.jade +++ b/server/views/account/show.jade @@ -56,6 +56,9 @@ block content if isBackEndCert .button-spacer a.btn.btn-primary.btn-block(href='/' + username + '/back-end-certification') View My Back End Development Certification + if (user && user.username != username) + .button-spacer + a.btn.btn-primary.btn-block(href='/' + username + '/report-user/') Report this user's profile for abuse .row .col-xs-12.text-center if (badges.coreTeam && badges.coreTeam.length)