mirror of
https://github.com/wassname/talk.git
synced 2026-07-17 11:33:39 +08:00
Adds status to the user.
This commit is contained in:
@@ -6,13 +6,15 @@ import {
|
||||
FETCH_COMMENTERS_FAILURE,
|
||||
SORT_UPDATE,
|
||||
COMMENTERS_NEW_PAGE,
|
||||
SET_ROLE
|
||||
SET_ROLE,
|
||||
SET_STATUS
|
||||
} from '../constants/community';
|
||||
|
||||
import {base, getInit, handleResp} from '../helpers/response';
|
||||
|
||||
export const fetchCommenters = (query = {}) => dispatch => {
|
||||
dispatch(requestFetchCommenters());
|
||||
console.log('DEBUG ', query);
|
||||
fetch(`${base}/user?${qs.stringify(query)}`, getInit('GET'))
|
||||
.then(handleResp)
|
||||
.then(({result, page, count, limit, totalPages}) =>
|
||||
@@ -47,3 +49,10 @@ export const setRole = (id, role) => dispatch => {
|
||||
return dispatch({type: SET_ROLE, id, role});
|
||||
});
|
||||
};
|
||||
|
||||
export const setStatus = (id, status) => dispatch => {
|
||||
return fetch(`${base}/user/${id}/status`, getInit('POST', {status}))
|
||||
.then(() => {
|
||||
return dispatch({type: SET_STATUS, id, status});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Action disptacher related to users
|
||||
*/
|
||||
|
||||
export const updateUserStatus = (status, id) => (dispatch, getState) => {
|
||||
dispatch({type: 'USER_STATUS_UPDATE', id, status});
|
||||
dispatch({type: 'USER_UPDATE', user: getState().comments.get('byId').get(id)});
|
||||
};
|
||||
@@ -9,7 +9,8 @@ import Comment from 'components/Comment';
|
||||
const actions = {
|
||||
'reject': {status: 'rejected', icon: 'close', key: 'r'},
|
||||
'approve': {status: 'accepted', icon: 'done', key: 't'},
|
||||
'flag': {status: 'flagged', icon: 'flag', filter: 'Untouched'}
|
||||
'flag': {status: 'flagged', icon: 'flag', filter: 'Untouched'},
|
||||
'ban': {status: 'banned', icon: ''}
|
||||
};
|
||||
|
||||
// Renders a comment list and allow performing actions
|
||||
|
||||
@@ -4,3 +4,4 @@ export const FETCH_COMMENTERS_FAILURE = 'FETCH_COMMENTERS_FAILURE';
|
||||
export const SORT_UPDATE = 'SORT_UPDATE';
|
||||
export const COMMENTERS_NEW_PAGE = 'COMMENTERS_NEW_PAGE';
|
||||
export const SET_ROLE = 'SET_ROLE';
|
||||
export const SET_STATUS = 'SET_STATUS';
|
||||
|
||||
@@ -15,8 +15,13 @@
|
||||
.searchBox {
|
||||
/*border: 1px solid rgba(0,0,0,.12);*/
|
||||
background: white;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.statusBox {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.email {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,11 @@ const tableHeaders = [
|
||||
];
|
||||
|
||||
const Community = ({isFetching, commenters, ...props}) => {
|
||||
console.log(commenters);
|
||||
const hasResults = !isFetching && !!commenters.length;
|
||||
return (
|
||||
<Grid>
|
||||
<Cell col={4}>
|
||||
<Cell col={3}>
|
||||
<form action="">
|
||||
<div className={`mdl-textfield ${styles.searchBox}`}>
|
||||
<label className="mdl-button mdl-js-button mdl-button--icon" htmlFor="commenters-search">
|
||||
@@ -54,8 +55,8 @@ const Community = ({isFetching, commenters, ...props}) => {
|
||||
</form>
|
||||
</Cell>
|
||||
<Cell col={8}>
|
||||
{ isFetching && <Loading /> }
|
||||
{ !hasResults && <NoResults /> }
|
||||
{ isFetching && <Loading/> }
|
||||
{ !hasResults && <NoResults/> }
|
||||
{ hasResults &&
|
||||
<Table
|
||||
headers={tableHeaders}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../../translations.json';
|
||||
|
||||
const Loading = () => (
|
||||
<h1> Loading results </h1>
|
||||
<h1> {lang.t('community.loading')} </h1>
|
||||
);
|
||||
|
||||
export default Loading;
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import I18n from 'coral-framework/i18n/i18n';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../../translations.json';
|
||||
|
||||
const NoResults = () => (
|
||||
<div>
|
||||
{lang.t('community.no-results')}</div>
|
||||
{lang.t('community.no-results')}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default NoResults;
|
||||
|
||||
@@ -4,7 +4,7 @@ import {SelectField, Option} from 'react-mdl-selectfield';
|
||||
import styles from './Community.css';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../../translations';
|
||||
import {setRole} from '../../actions/community';
|
||||
import {setRole, setStatus} from '../../actions/community';
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
@@ -13,12 +13,17 @@ class Table extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.onRoleChange = this.onRoleChange.bind(this);
|
||||
this.onStatusChange = this.onStatusChange.bind(this);
|
||||
}
|
||||
|
||||
onRoleChange (id, role) {
|
||||
this.props.dispatch(setRole(id, role));
|
||||
}
|
||||
|
||||
onStatusChange (id, status) {
|
||||
this.props.dispatch(setStatus(id, status));
|
||||
}
|
||||
|
||||
render () {
|
||||
const {headers, commenters, onHeaderClickHandler} = this.props;
|
||||
|
||||
@@ -46,6 +51,15 @@ class Table extends Component {
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
{row.created_at}
|
||||
</td>
|
||||
<td className={`mdl-data-table__cell--non-numeric ${styles.statusBox}`}>
|
||||
<SelectField label={'Select me'} value={row.status}
|
||||
label={lang.t('community.select-status')}
|
||||
onChange={status => this.onStatusChange(row.id, status)}>
|
||||
<Option value={''}>.</Option>
|
||||
<Option value={'active'}>{lang.t('community.active')}</Option>
|
||||
<Option value={'banned'}>{lang.t('community.banned')}</Option>
|
||||
</SelectField>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<SelectField label={'Select me'} value={row.roles[0] || ''}
|
||||
label={lang.t('community.role')}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {connect} from 'react-redux';
|
||||
import ModerationKeysModal from 'components/ModerationKeysModal';
|
||||
import CommentList from 'components/CommentList';
|
||||
import {updateStatus} from 'actions/comments';
|
||||
import {updateUserStatus} from 'actions/users';
|
||||
import styles from './ModerationQueue.css';
|
||||
import key from 'keymaster';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
@@ -11,6 +12,7 @@ import translations from '../translations.json';
|
||||
/*
|
||||
* Renders the moderation queue as a tabbed layout with 3 moderation
|
||||
* queues filtered by status (Untouched, Rejected and Approved)
|
||||
* Pending queue also includes the comments that are flagged in the post-moderation setting.
|
||||
*/
|
||||
|
||||
class ModerationQueue extends React.Component {
|
||||
@@ -44,11 +46,16 @@ class ModerationQueue extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch the update status action
|
||||
// Dispatch the update comment status action
|
||||
onCommentAction (status, id) {
|
||||
this.props.dispatch(updateStatus(status, id));
|
||||
}
|
||||
|
||||
// Dispatch the update user status action
|
||||
onUserAction (status, id) {
|
||||
this.props.dispatch(updateUserStatus(status, id));
|
||||
}
|
||||
|
||||
onTabClick (activeTab) {
|
||||
this.setState({activeTab});
|
||||
}
|
||||
@@ -112,7 +119,7 @@ class ModerationQueue extends React.Component {
|
||||
})}
|
||||
comments={comments.get('byId')}
|
||||
onClickAction={(action, id) => this.onCommentAction(action, id)}
|
||||
actions={['reject', 'approve']}
|
||||
actions={['reject', 'approve', 'ban']}
|
||||
loading={comments.loading} />
|
||||
</div>
|
||||
<ModerationKeysModal open={modalOpen}
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
"moderator": "Moderator",
|
||||
"role": "Select role...",
|
||||
"no-results": "No users found with that user name or email address.",
|
||||
"status": "Status"
|
||||
"status": "Status",
|
||||
"select-status": "Select status...",
|
||||
"active": "Active",
|
||||
"banned": "Banned",
|
||||
"loading": "Loading results"
|
||||
},
|
||||
"modqueue": {
|
||||
"pending": "pending",
|
||||
@@ -53,9 +57,13 @@
|
||||
"newsroom_role": "Rol en la redacción",
|
||||
"admin": "Administrador",
|
||||
"moderator": "Moderador",
|
||||
"role": "Select role...",
|
||||
"role": "Seleccionar rol...",
|
||||
"no-results": "No se encontraron usuarios con ese nombre de usuario o correo electronico.",
|
||||
"status": "Estado"
|
||||
"status": "Estado",
|
||||
"select-status": "Seleccionar estado...",
|
||||
"active": "Activa",
|
||||
"banned": "Suspendido",
|
||||
"loading": "Cargando resultados"
|
||||
},
|
||||
"modqueue": {
|
||||
"pending": "pendiente",
|
||||
|
||||
+6
-3
@@ -13,7 +13,7 @@ const USER_ROLES = [
|
||||
];
|
||||
|
||||
// USER_STATUSES is the list of statuses that are permitted for the user status.
|
||||
const USER_STATUSES = [
|
||||
const USER_STATUS = [
|
||||
'active',
|
||||
'banned'
|
||||
];
|
||||
@@ -74,7 +74,7 @@ const UserSchema = new mongoose.Schema({
|
||||
|
||||
// Status provides a string that says in which state the account is.
|
||||
// When the account is banned, the user login is disabled.
|
||||
status: {type: String, enum: USER_STATUSES, default: 'active'}
|
||||
status: {type: String, enum: USER_STATUS, default: 'active'}
|
||||
}, {
|
||||
|
||||
// This will ensure that we have proper timestamps available on this model.
|
||||
@@ -394,12 +394,15 @@ UserService.removeRoleFromUser = (id, role) => {
|
||||
UserService.setStatus = (id, status) => {
|
||||
|
||||
// Check to see if the user role is in the allowable set of roles.
|
||||
if (USER_STATUSES.indexOf(status) === -1) {
|
||||
if (USER_STATUS.indexOf(status) === -1) {
|
||||
|
||||
// User status is not supported! Error out here.
|
||||
return Promise.reject(new Error(`status ${status} is not supported`));
|
||||
}
|
||||
|
||||
// If we are banning the user
|
||||
// disable their account
|
||||
|
||||
return UserModel.update({
|
||||
id: id
|
||||
}, {
|
||||
|
||||
@@ -21,11 +21,12 @@ router.get('/', (req, res, next) => {
|
||||
])
|
||||
.then(([data, count]) => {
|
||||
const users = data.map((user) => {
|
||||
const {id, displayName, created_at} = user;
|
||||
const {id, displayName, created_at, status} = user;
|
||||
return {
|
||||
id,
|
||||
displayName,
|
||||
created_at,
|
||||
status,
|
||||
profiles: user.toObject().profiles,
|
||||
roles: user.toObject().roles
|
||||
};
|
||||
@@ -52,6 +53,15 @@ router.post('/:user_id/role', (req, res, next) => {
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router.post('/:user_id/status', (req, res, next) => {
|
||||
User
|
||||
.setStatus(req.params.user_id, req.body.status)
|
||||
.then(status => {
|
||||
res.send(status);
|
||||
})
|
||||
.catch(next);
|
||||
});
|
||||
|
||||
router.post('/', (req, res, next) => {
|
||||
const {email, password, displayName} = req.body;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user