mirror of
https://github.com/wassname/talk.git
synced 2026-07-20 12:40:47 +08:00
Adding actions to suspend users and send e-mail.
This commit is contained in:
@@ -14,3 +14,12 @@ export const userStatusUpdate = (status, userId, commentId) => {
|
||||
.catch(error => dispatch({type: userTypes.UPDATE_STATUS_FAILURE, error}));
|
||||
};
|
||||
};
|
||||
|
||||
// change status of a user
|
||||
export const sendNotificationEmail = (userId, subject, text) => {
|
||||
return (dispatch, getState) => {
|
||||
const _csrf = getState().auth.get('_csrf');
|
||||
return coralApi(`/users/${userId}/email`, {method: 'POST', body: {subject, text}, _csrf})
|
||||
.catch(error => dispatch({type: userTypes.USER_EMAIL_FAILURE, error}));
|
||||
};
|
||||
};
|
||||
|
||||
@@ -24,7 +24,8 @@ export default class ModerationList extends React.Component {
|
||||
comments: PropTypes.object,
|
||||
users: PropTypes.object.isRequired,
|
||||
actions: PropTypes.object,
|
||||
updateCommentStatus: PropTypes.func.isRequired,
|
||||
userStatusUpdate: PropTypes.func.isRequired,
|
||||
suspendUser: PropTypes.func.isRequired,
|
||||
|
||||
// list of actions (flags, etc) associated with the comments
|
||||
modActions: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
@@ -135,32 +136,13 @@ 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: {stage: 0, actionType: action.action_type}});
|
||||
this.setState({suspendUserModal: action});
|
||||
} else {
|
||||
this.props.updateUserStatus(menuOption, action.item_id);
|
||||
this.props.userStatusUpdate(menuOption, action.item_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When an admin clicks to suspend a user a dialog is shown, this function
|
||||
* handles the possible actions for that dialog.
|
||||
*/
|
||||
onClickSuspendModalButton = (stage, menuOption) => () => {
|
||||
const {updateUserStatus, action} = this.props;
|
||||
const cancel = () => this.setState({suspendUserModal: null});
|
||||
const next = () => this.setState((prev) => {
|
||||
prev.suspendUserModal.stage++;
|
||||
return prev;
|
||||
});
|
||||
const suspend = () => updateUserStatus('suspend', action.item_id);
|
||||
const suspendModalActions = [
|
||||
[ cancel, next ],
|
||||
[ cancel, suspend ]
|
||||
];
|
||||
return suspendModalActions[stage][menuOption]();
|
||||
}
|
||||
|
||||
onClickShowBanDialog = (userId, userName, commentId) => {
|
||||
this.props.onClickShowBanDialog(userId, userName, commentId);
|
||||
}
|
||||
@@ -221,7 +203,7 @@ export default class ModerationList extends React.Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const {singleView, key} = this.props;
|
||||
const {singleView, key, suspendUser} = this.props;
|
||||
|
||||
// Combine moderations and actions into a single stream and sort by most recently updated.
|
||||
const moderationIds = this.getModerationIds();
|
||||
@@ -232,9 +214,9 @@ export default class ModerationList extends React.Component {
|
||||
id='moderationList'>
|
||||
{moderationIds.map(this.mapModItems)}
|
||||
<SuspendUserModal
|
||||
{...this.state.suspendUserModal}
|
||||
action = {this.state.suspendUserModal}
|
||||
onClose={() => this.setState({suspendUserModal:null})}
|
||||
onButtonClick={this.onClickSuspendModalButton} />
|
||||
suspendUser={suspendUser} />
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,13 +26,13 @@ const stages = [
|
||||
|
||||
class SuspendUserModal extends Component {
|
||||
|
||||
state = {email: ''}
|
||||
state = {email: '', stage: 0}
|
||||
|
||||
static propTypes = {
|
||||
stage: PropTypes.number,
|
||||
actionType: PropTypes.string,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onButtonClick: PropTypes.func.isRequired
|
||||
suspendUser: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -40,12 +40,36 @@ class SuspendUserModal extends Component {
|
||||
this.setState({email: lang.t('suspenduser.email', about)});
|
||||
}
|
||||
|
||||
/*
|
||||
* When an admin clicks to suspend a user a dialog is shown, this function
|
||||
* handles the possible actions for that dialog.
|
||||
*/
|
||||
onActionClick = (stage, menuOption) => () => {
|
||||
const {suspendUser, action} = this.props;
|
||||
const {stage, email} = this.state;
|
||||
const cancel = this.props.onClose;
|
||||
const next = () => this.setState({stage: stage + 1});
|
||||
const suspend = () => suspendUser(action.item_id, lang.t('suspenduser.email_subject'), email);
|
||||
const suspendModalActions = [
|
||||
[ cancel, next ],
|
||||
[ cancel, suspend ]
|
||||
];
|
||||
return suspendModalActions[stage][menuOption]();
|
||||
}
|
||||
|
||||
onEmailChange = (e) => this.setState({email: e.target.value})
|
||||
|
||||
render () {
|
||||
const {stage, actionType, onClose, onButtonClick} = this.props;
|
||||
const {action, onClose} = this.props;
|
||||
|
||||
if (!action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {stage} = this.state;
|
||||
const actionType = action.actionType;
|
||||
const about = actionType === 'flag_bio' ? lang.t('suspenduser.bio') : lang.t('suspenduser.username');
|
||||
return actionType ? <Modal open={actionType} onClose={onClose}>
|
||||
return <Modal open={true} onClose={onClose}>
|
||||
<div className={styles.title}>{lang.t(stages[stage].title, about)}</div>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.description}>
|
||||
@@ -66,14 +90,13 @@ class SuspendUserModal extends Component {
|
||||
}
|
||||
<div className={styles.modalButtons}>
|
||||
{Object.keys(stages[stage].options).map((key, i) => (
|
||||
<Button key={i} onClick={onButtonClick(stage, i)}>
|
||||
<Button key={i} onClick={this.onActionClick(stage, i)}>
|
||||
{lang.t(stages[stage].options[key], about)}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
: null;
|
||||
</Modal>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export const UPDATE_STATUS_REQUEST = 'UPDATE_STATUS_REQUEST';
|
||||
export const UPDATE_STATUS_SUCCESS = 'UPDATE_STATUS_SUCCESS';
|
||||
export const UPDATE_STATUS_FAILURE = 'UPDATE_STATUS_FAILURE';
|
||||
export const USER_EMAIL_FAILURE = 'USER_EMAIL_FAILURE';
|
||||
export const USERS_MODERATION_QUEUE_FETCH_SUCCESS = 'USERS_MODERATION_QUEUE_FETCH_SUCCESS';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
hideBanUserDialog,
|
||||
fetchModerationQueueComments
|
||||
} from 'actions/comments';
|
||||
import {userStatusUpdate} from 'actions/users';
|
||||
import {userStatusUpdate, sendNotificationEmail} from 'actions/users';
|
||||
import {fetchSettings} from 'actions/settings';
|
||||
|
||||
import ModerationQueue from './ModerationQueue';
|
||||
@@ -62,7 +62,7 @@ class ModerationContainer extends React.Component {
|
||||
|
||||
render () {
|
||||
const {comments, actions} = this.props;
|
||||
|
||||
|
||||
const premodIds = comments.ids.filter(id => comments.byId[id].status === 'premod');
|
||||
const rejectedIds = comments.ids.filter(id => comments.byId[id].status === 'rejected');
|
||||
const flaggedIds = comments.ids.filter(id => comments.byId[id].flagged === true);
|
||||
@@ -99,6 +99,11 @@ const mapDispatchToProps = dispatch => {
|
||||
banUser: (userId, commentId) => dispatch(userStatusUpdate('banned', 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()))
|
||||
,
|
||||
updateStatus: (action, comment) => dispatch(updateStatus(action, comment))
|
||||
};
|
||||
};
|
||||
|
||||
@@ -31,6 +31,8 @@ export default (props) => (
|
||||
users={props.users.byId}
|
||||
actionIds={props.userActionIds}
|
||||
actions={props.actions.byId}
|
||||
userStatusUpdate={props.userStatusUpdate}
|
||||
suspendUser={props.suspendUser}
|
||||
updateCommentStatus={props.updateStatus}
|
||||
onClickShowBanDialog={props.showBanUserDialog}
|
||||
modActions={['reject', 'approve', 'ban']}
|
||||
@@ -48,6 +50,8 @@ export default (props) => (
|
||||
isActive={props.activeTab === 'rejected'}
|
||||
singleView={props.singleView}
|
||||
commentIds={props.rejectedIds}
|
||||
userStatusUpdate={props.userStatusUpdate}
|
||||
suspendUser={props.suspendUser}
|
||||
comments={props.comments.byId}
|
||||
users={props.users.byId}
|
||||
updateCommentStatus={props.updateStatus}
|
||||
@@ -61,6 +65,8 @@ export default (props) => (
|
||||
isActive={props.activeTab === 'rejected'}
|
||||
singleView={props.singleView}
|
||||
commentIds={props.flaggedIds}
|
||||
userStatusUpdate={props.userStatusUpdate}
|
||||
suspendUser={props.suspendUser}
|
||||
comments={props.comments.byId}
|
||||
users={props.users.byId}
|
||||
updateCommentStatus={props.updateStatus}
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
"send": "Send",
|
||||
"bio": "bio",
|
||||
"username": "username",
|
||||
"subject": "Your account has been suspended",
|
||||
"email": "Another member of the community recently flagged your {0} for review. Because of its content your {0} was rejected. This means you can no longer comment, like, or flag content until you rewrite your {0}. Please e-mail moderator@newsorg.com if you have any questions or concerns.",
|
||||
"write_message": "Write a message"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user