Merge pull request #12048 from raisedadead/feature/reporting-profiles
feat(user): Report profiles
This commit is contained in:
@ -1184,7 +1184,7 @@ and (max-width : 400px) {
|
|||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset/Delete Account Modal Styles
|
// Account Modal Styles
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
margin: 80px;
|
margin: 80px;
|
||||||
|
|
||||||
@ -1223,6 +1223,14 @@ and (max-width : 400px) {
|
|||||||
background-color: #208e36;
|
background-color: #208e36;
|
||||||
border-color: darkgreen;
|
border-color: darkgreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-textarea {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 590px;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ import {
|
|||||||
import certTypes from '../utils/certTypes.json';
|
import certTypes from '../utils/certTypes.json';
|
||||||
import {
|
import {
|
||||||
ifNoUser401,
|
ifNoUser401,
|
||||||
ifNoUserRedirectTo
|
ifNoUserRedirectTo,
|
||||||
|
ifNotVerifiedRedirectToSettings
|
||||||
} from '../utils/middleware';
|
} from '../utils/middleware';
|
||||||
import { observeQuery } from '../utils/rx';
|
import { observeQuery } from '../utils/rx';
|
||||||
import {
|
import {
|
||||||
@ -140,6 +141,7 @@ module.exports = function(app) {
|
|||||||
const api = app.loopback.Router();
|
const api = app.loopback.Router();
|
||||||
const User = app.models.User;
|
const User = app.models.User;
|
||||||
const Block = app.models.Block;
|
const Block = app.models.Block;
|
||||||
|
const { Email } = app.models;
|
||||||
const map$ = cachedMap(Block);
|
const map$ = cachedMap(Block);
|
||||||
function findUserByUsername$(username, fields) {
|
function findUserByUsername$(username, fields) {
|
||||||
return observeQuery(
|
return observeQuery(
|
||||||
@ -223,6 +225,18 @@ module.exports = function(app) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
router.get('/:username', showUserProfile);
|
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('/:lang', router);
|
||||||
app.use(api);
|
app.use(api);
|
||||||
@ -631,4 +645,55 @@ module.exports = function(app) {
|
|||||||
return res.render('account/forgot');
|
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('/');
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
@ -26,6 +26,30 @@ export default function() {
|
|||||||
// every file has contents
|
// every file has contents
|
||||||
keys.map(key => value[key]).every(file => isPoly(file));
|
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]*?</script\\s*'
|
||||||
|
+ '|style\\b' + tagBody + '>[\\s\\S]*?</style\\s*'
|
||||||
|
// Regular name
|
||||||
|
+ '|/?[a-z]'
|
||||||
|
+ tagBody
|
||||||
|
+ ')>',
|
||||||
|
'gi');
|
||||||
|
let rawValue;
|
||||||
|
do {
|
||||||
|
rawValue = value;
|
||||||
|
value = value.replace(tagOrComment, '');
|
||||||
|
} while (value !== rawValue);
|
||||||
|
return value.replace(/</g, '<');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -29,21 +29,17 @@ export function ifNoUser401(req, res, next) {
|
|||||||
return res.status(401).end();
|
return res.status(401).end();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function flashIfNotVerified(req, res, next) {
|
export function ifNotVerifiedRedirectToSettings(req, res, next) {
|
||||||
return next();
|
const { user } = req;
|
||||||
/*
|
|
||||||
// disabled until authorized required bug is fixed
|
|
||||||
const user = req.user;
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
const email = req.user.email;
|
if (!user.emailVerified) {
|
||||||
const emailVerified = req.user.emailVerified;
|
req.flash('error', {
|
||||||
if (!email || !emailVerified) {
|
msg: 'We do not have your verified email address on record, '
|
||||||
req.flash('info', {
|
+ 'please add it in the settings to continue with your request.'
|
||||||
msg: 'Please verify your email address ' +
|
|
||||||
'<a href="/update-email">here</a>.'
|
|
||||||
});
|
});
|
||||||
|
return res.redirect('/settings');
|
||||||
}
|
}
|
||||||
*/
|
return next();
|
||||||
}
|
}
|
||||||
|
29
server/views/account/report-profile.jade
Normal file
29
server/views/account/report-profile.jade
Normal file
@ -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');
|
||||||
|
});
|
@ -56,6 +56,9 @@ block content
|
|||||||
if isBackEndCert
|
if isBackEndCert
|
||||||
.button-spacer
|
.button-spacer
|
||||||
a.btn.btn-primary.btn-block(href='/' + username + '/back-end-certification') View My Back End Development Certification
|
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
|
.row
|
||||||
.col-xs-12.text-center
|
.col-xs-12.text-center
|
||||||
if (badges.coreTeam && badges.coreTeam.length)
|
if (badges.coreTeam && badges.coreTeam.length)
|
||||||
|
Reference in New Issue
Block a user