Addressing CSRF and user status issues.

This commit is contained in:
David Jay
2017-01-09 15:39:08 -05:00
parent 0f24ab6b28
commit b8fc2c9cc7
8 changed files with 29 additions and 25 deletions
+4 -6
View File
@@ -6,10 +6,9 @@ import * as userTypes from '../constants/users';
*/
// change status of a user
export const userStatusUpdate = (status, userId, commentId) => {
return (dispatch, getState) => {
return (dispatch) => {
dispatch({type: userTypes.UPDATE_STATUS_REQUEST});
const _csrf = getState().auth.get('_csrf');
return coralApi(`/users/${userId}/status`, {method: 'POST', body: {status: status, comment_id: commentId}, _csrf})
return coralApi(`/users/${userId}/status`, {method: 'POST', body: {status: status, comment_id: commentId}})
.then(res => dispatch({type: userTypes.UPDATE_STATUS_SUCCESS, res}))
.catch(error => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
};
@@ -17,9 +16,8 @@ export const userStatusUpdate = (status, userId, commentId) => {
// change status of a user
export const sendNotificationEmail = (userId, subject, body) => {
return (dispatch, getState) => {
const _csrf = getState().auth.get('_csrf');
return coralApi(`/users/${userId}/email`, {method: 'POST', body: {subject, body}, _csrf})
return (dispatch) => {
return coralApi(`/users/${userId}/email`, {method: 'POST', body: {subject, body}})
.catch(error => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
};
};
@@ -35,7 +35,7 @@ const BanUserDialog = ({open, handleClose, onClickBanUser, user = {}}) => (
<Button cStyle="cancel" className={styles.cancel} onClick={() => handleClose()} full>
{lang.t('bandialog.cancel')}
</Button>
<Button cStyle="black" onClick={() => onClickBanUser(user.userId, user.commentId)} full>
<Button cStyle="black" onClick={() => onClickBanUser('banned', user.userId, user.commentId)} full>
{lang.t('bandialog.yes_ban_user')}
</Button>
</div>
+2 -2
View File
@@ -55,7 +55,7 @@ const Comment = props => {
// Get the button of the action performed over a comment if any
const getActionButton = (option, i, props) => {
const {comment, author, menuOptionsMap, action} = props;
const {comment, author, menuOptionsMap} = props;
const status = comment.status;
const flagged = comment.flagged;
const banned = (author.status === 'banned');
@@ -83,7 +83,7 @@ const getActionButton = (option, i, props) => {
cStyle={option}
icon={menuOption.icon}
key={i}
onClick={() => props.onClickAction(menuOption.status, comment, action)}
onClick={() => props.onClickAction(menuOption.status, comment, {item_type: 'comment'})}
/>
);
};
@@ -137,8 +137,8 @@ export default class ModerationList extends React.Component {
// If a user bio or name is rejected, bring up a dialog before suspending them.
if (menuOption === 'rejected') {
this.setState({suspendUserModal: action});
} else {
this.props.userStatusUpdate(menuOption, action.item_id);
} else if (menuOption === 'accepted') {
this.props.userStatusUpdate('active', action.item_id);
}
}
}
@@ -18,7 +18,9 @@ const UserAction = props => {
let userStatus = user.status;
const links = user.settings.bio ? linkify.getMatches(user.settings.bio) : [];
return (
//Do not display if the user status is 'active'. This means that they have already been reviewed and approved.
return userStatus !== 'active' &&
<li tabIndex={props.index} className={`${styles.listItem} ${props.isActive && !props.hideActive ? styles.activeItem : ''}`}>
<div className={styles.itemHeader}>
<div className={styles.author}>
@@ -55,8 +57,7 @@ const UserAction = props => {
<div className={styles.flagCount}>
{`${action.count} ${action.action_type === 'flag_bio' ? lang.t('user.bio_flags') : lang.t('user.username_flags')}`}
</div>
</li>
);
</li>;
};
export default UserAction;
@@ -71,17 +72,14 @@ const getActionButton = (option, i, props) => {
return null;
}
if (option === 'ban') {
return (
<Button
return <Button
className='ban'
cStyle='black'
disabled={banned ? 'disabled' : ''}
onClick={() => onClickShowBanDialog(user.id, user.displayName)}
key={i}
>
key={i}>
{lang.t('comment.ban_user')}
</Button>
);
</Button>;
}
const menuOption = menuOptionsMap[option];
return (
@@ -96,10 +96,9 @@ const mapDispatchToProps = dispatch => {
fetchModerationQueueComments: () => dispatch(fetchModerationQueueComments()),
showBanUserDialog: (userId, userName, commentId) => dispatch(showBanUserDialog(userId, userName, commentId)),
hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
banUser: (userId, commentId) => dispatch(userStatusUpdate('banned', userId, commentId)).then(() => {
userStatusUpdate: (status, userId, commentId) => dispatch(userStatusUpdate(status, userId, commentId)).then(() => {
dispatch(fetchModerationQueueComments());
}),
userStatusUpdate: (status, userId, commentId) => dispatch(userStatusUpdate(status, userId, commentId)),
suspendUser: (userId, subject, text) => dispatch(userStatusUpdate('suspended', userId))
.then(() => dispatch(sendNotificationEmail(userId, subject, text)))
.then(() => dispatch(fetchModerationQueueComments()))
@@ -42,7 +42,7 @@ export default (props) => (
<BanUserDialog
open={props.comments.showBanUserDialog}
handleClose={props.hideBanUserDialog}
onClickBanUser={props.banUser}
onClickBanUser={props.userStatusUpdate}
user={props.comments.banUser}
/>
</div>
@@ -78,7 +78,7 @@ export default (props) => (
<BanUserDialog
open={props.comments.showBanUserDialog}
handleClose={props.hideBanUserDialog}
onClickBanUser={props.banUser}
onClickBanUser={props.userStatusUpdate}
user={props.comments.banUser}
/>
</div>
+10 -1
View File
@@ -125,7 +125,6 @@ router.post('/', (req, res, next) => {
});
router.post('/:user_id/actions', authorization.needed(), (req, res, next) => {
const {
action_type,
metadata
@@ -133,6 +132,16 @@ router.post('/:user_id/actions', authorization.needed(), (req, res, next) => {
User
.addAction(req.params.user_id, req.user.id, action_type, metadata)
.then((action) => {
// Set the user status to "pending" for review by moderators
if (action_type.slice(0, 4) === 'flag') {
return User.setStatus(req.user.id, 'pending')
.then(() => action);
} else {
return action;
}
})
.then((action) => {
res.status(201).json(action);
})