@@ -58,7 +58,7 @@ const People = ({isFetching, commenters, ...props}) => {
hasResults
?
:
{lang.t('community.no-results')}
@@ -73,4 +73,4 @@ const People = ({isFetching, commenters, ...props}) => {
);
};
-export default People;
+export default Community;
diff --git a/client/coral-admin/src/containers/Community/CommunityContainer.js b/client/coral-admin/src/containers/Community/CommunityContainer.js
index 4f65303ff..e4263cc06 100644
--- a/client/coral-admin/src/containers/Community/CommunityContainer.js
+++ b/client/coral-admin/src/containers/Community/CommunityContainer.js
@@ -1,29 +1,14 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
-import {compose} from 'react-apollo';
-
-import {modUserFlaggedQuery} from 'coral-admin/src/graphql/queries';
-import {banUser, setUserStatus, suspendUser} from 'coral-admin/src/graphql/mutations';
-
import {
- fetchAccounts,
+ fetchCommenters,
updateSorting,
newPage,
- showBanUserDialog,
- hideBanUserDialog,
- showSuspendUserDialog,
- hideSuspendUserDialog
} from '../../actions/community';
-import CommunityMenu from './components/CommunityMenu';
-import BanUserDialog from './components/BanUserDialog';
-import SuspendUserDialog from './components/SuspendUserDialog';
-
-import People from './People';
-import FlaggedAccounts from './FlaggedAccounts';
+import Community from './Community';
class CommunityContainer extends Component {
-
constructor(props) {
super(props);
@@ -37,10 +22,6 @@ class CommunityContainer extends Component {
this.onNewPageHandler = this.onNewPageHandler.bind(this);
}
- componentWillMount() {
- this.props.fetchAccounts({});
- }
-
onKeyDownHandler(e) {
if (e.key === 'Enter') {
e.preventDefault();
@@ -57,13 +38,16 @@ class CommunityContainer extends Component {
search(query = {}) {
const {community} = this.props;
- this.props.fetchAccounts({
+ this.props.dispatch(fetchCommenters({
value: this.state.searchValue,
- field: community.fieldPeople,
- asc: community.ascPeople,
+ field: community.field,
+ asc: community.asc,
...query
- });
+ }));
+ }
+ componentDidMount() {
+ this.search();
}
onHeaderClickHandler(sort) {
@@ -76,66 +60,19 @@ class CommunityContainer extends Component {
this.search({page});
}
- getTabContent(searchValue, props) {
- const {community, data} = props;
- const activeTab = props.route.path === ':id' ? 'flagged' : props.route.path;
-
- if (activeTab === 'people') {
- return (
-
- );
- }
-
- return (
-
-
-
-
-
- );
- }
-
render() {
const {searchValue} = this.state;
-
- const tab = this.getTabContent(searchValue, this.props);
-
+ const {community} = this.props;
return (
-
+
);
}
}
@@ -144,18 +81,4 @@ const mapStateToProps = state => ({
community: state.community.toJS()
});
-const mapDispatchToProps = dispatch => ({
- fetchAccounts: query => dispatch(fetchAccounts(query)),
- showBanUserDialog: (user) => dispatch(showBanUserDialog(user)),
- hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
- showSuspendUserDialog: (user) => dispatch(showSuspendUserDialog(user)),
- hideSuspendUserDialog: () => dispatch(hideSuspendUserDialog())
-});
-
-export default compose(
- connect(mapStateToProps, mapDispatchToProps),
- modUserFlaggedQuery,
- banUser,
- setUserStatus,
- suspendUser
-)(CommunityContainer);
+export default connect(mapStateToProps)(CommunityContainer);
diff --git a/client/coral-admin/src/containers/Community/CommunityLayout.js b/client/coral-admin/src/containers/Community/CommunityLayout.js
deleted file mode 100644
index d6022fed9..000000000
--- a/client/coral-admin/src/containers/Community/CommunityLayout.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from 'react';
-
-const CommunityLayout = props => (
-
- {props.children}
-
-);
-
-export default CommunityLayout;
diff --git a/client/coral-admin/src/containers/Community/FlaggedAccounts.js b/client/coral-admin/src/containers/Community/FlaggedAccounts.js
deleted file mode 100644
index 1a6d349c8..000000000
--- a/client/coral-admin/src/containers/Community/FlaggedAccounts.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import React from 'react';
-
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from 'coral-admin/src/translations.json';
-const lang = new I18n(translations);
-
-import styles from './Community.css';
-
-import Loading from './Loading';
-import EmptyCard from '../../components/EmptyCard';
-import User from './components/User';
-
-const FlaggedAccounts = ({...props}) => {
- const {commenters, isFetching} = props;
- const hasResults = !isFetching && commenters && !!commenters.length;
-
- return (
-
-
- { isFetching && }
- {
- hasResults
- ? commenters.map((commenter, index) => {
- if (commenter.status === 'PENDING' && commenter.actions.length > 0) {
- return ;
- }
- return null;
- })
- : {lang.t('community.no-flagged-accounts')}
- }
-
-
- );
-};
-
-export default FlaggedAccounts;
diff --git a/client/coral-admin/src/containers/Community/Table.js b/client/coral-admin/src/containers/Community/Table.js
index aacc9c82f..480ce72bf 100644
--- a/client/coral-admin/src/containers/Community/Table.js
+++ b/client/coral-admin/src/containers/Community/Table.js
@@ -77,4 +77,4 @@ class Table extends Component {
}
}
-export default connect(state => ({commenters: state.community.get('accounts')}))(Table);
+export default connect(state => ({commenters: state.community.get('commenters')}))(Table);
diff --git a/client/coral-admin/src/containers/Community/components/ActionButton.js b/client/coral-admin/src/containers/Community/components/ActionButton.js
deleted file mode 100644
index 6352480fd..000000000
--- a/client/coral-admin/src/containers/Community/components/ActionButton.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import styles from '../Community.css';
-import BanUserButton from '../../../components/BanUserButton';
-import {Button} from 'coral-ui';
-import {menuActionsMap} from '../../../containers/ModerationQueue/helpers/moderationQueueActionsMap';
-
-const ActionButton = ({type = '', user, ...props}) => {
- if (type === 'BAN') {
- return
props.showBanUserDialog(user)} />;
- }
-
- return (
- {
- type === 'APPROVE' ? props.approveUser({userId: user.id}) : props.showSuspendUserDialog({user: user});
- }}
- >{menuActionsMap[type].text}
- );
-};
-
-export default ActionButton;
diff --git a/client/coral-admin/src/containers/Community/components/BanUserDialog.css b/client/coral-admin/src/containers/Community/components/BanUserDialog.css
deleted file mode 100644
index a46b9da32..000000000
--- a/client/coral-admin/src/containers/Community/components/BanUserDialog.css
+++ /dev/null
@@ -1,164 +0,0 @@
-.dialog {
- border: none;
- box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2);
- width: 500px;
- top: 50%;
- transform: translateY(-50%);
- height: 184px;
- padding: 20px;
-
- h2 {
- color: black;
- font-size: 1.76em;
- font-weight: 500;
- margin: 0;
- }
-
- h3 {
- color: black;
- font-size: 1.4em;
- font-weight: 500;
- margin: 0;
- }
-}
-
-.textField {
- margin-top: 15px;
-}
-
-.textField label {
- font-size: 1.08em;
- font-weight: bold;
- margin-bottom: 5px;
-}
-
-.textField input {
- width: 100%;
- display: block;
- border: none;
- outline: none;
- border: 1px solid rgba(0,0,0,.12);
- padding: 10px 6px;
- box-sizing: border-box;
- border-radius: 2px;
- margin: 5px auto;
-}
-
-.footer {
- margin: 20px auto 10px;
- text-align: center;
-}
-
-.footer span {
- display: block;
- margin-bottom: 5px;
-}
-
-.footer a {
- color: #2c69b6;
- cursor: pointer;
- margin: 0 5px;
-}
-
-.socialConnections {
- margin-bottom: 20px;
-}
-
-.signInButton {
- margin-top: 10px;
-}
-
-.close {
- font-size: 20px;
- line-height: 14px;
- top: 10px;
- right: 10px;
- position: absolute;
- display: block;
- font-weight: bold;
- color: #363636;
- cursor: pointer;
-}
-
-.close:hover {
- color: #6b6b6b;
-}
-
-input.error{
- border: solid 2px #f44336;
-}
-
-.errorMsg, .hint {
- color: grey;
- font-weight: 600;
- padding: 3px 0 16px;
-}
-
-.alert {
- padding: 10px;
- margin-bottom: 20px;
- border-radius: 2px;
-}
-
-.alert--success {
- border: solid 1px #1ec00e;
- background: #cbf1b8;
- color: #006900;
-}
-
-.alert--error {
- background: #FFEBEE;
- color: #B71C1C;
-}
-
-.userBox a {
- color: #2c69b6;
- cursor: pointer;
- margin: 0px;
-}
-
-.attention {
- display: inline-block;
- width: 15px;
- height: 15px;
- background: #B71C1C;
- color: #FFEBEE;
- font-weight: bolder;
- padding: 4px;
- vertical-align: middle;
- border-radius: 20px;
- box-sizing: border-box;
- font-size: 9px;
- line-height: 7px;
- text-align: center;
- margin-right: 5px;
-}
-
-.action {
- margin-top: 15px;
-}
-
-.passwordRequestSuccess {
- border: 1px solid green;
- background-color: lightgreen;
- padding: 10px;
-}
-
-.passwordRequestFailure {
- border: 1px solid orange;
- background-color: 1px solid coral;
- padding: 10px;
-}
-
-.cancel {
- margin-right: 10px;
- width: 47%;
-}
-
-.ban {
- width: 47%;
-}
-
-.buttons {
- margin: 20px 0;
-}
diff --git a/client/coral-admin/src/containers/Community/components/BanUserDialog.js b/client/coral-admin/src/containers/Community/components/BanUserDialog.js
deleted file mode 100644
index affffcd54..000000000
--- a/client/coral-admin/src/containers/Community/components/BanUserDialog.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React, {PropTypes} from 'react';
-import {Dialog} from 'coral-ui';
-import styles from './BanUserDialog.css';
-
-import Button from 'coral-ui/components/Button';
-
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from 'coral-admin/src/translations.json';
-
-const lang = new I18n(translations);
-
-const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
-
- ×
-
-
-
{lang.t('community.ban_user')}
-
-
-
{lang.t('community.are_you_sure', user.username)}
- {lang.t('community.note')}
-
-
-
- {lang.t('community.cancel')}
-
- {
- handleBanUser({userId: user.id}).then(() => {
- handleClose();
- });
- }}
- raised>
- {lang.t('community.yes_ban_user')}
-
-
-
-
-);
-
-BanUserDialog.propTypes = {
- handleBanUser: PropTypes.func.isRequired,
- handleClose: PropTypes.func.isRequired,
- user: PropTypes.object.isRequired,
-};
-
-export default BanUserDialog;
diff --git a/client/coral-admin/src/containers/Community/components/CommunityMenu.js b/client/coral-admin/src/containers/Community/components/CommunityMenu.js
deleted file mode 100644
index 9a51798ec..000000000
--- a/client/coral-admin/src/containers/Community/components/CommunityMenu.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-
-import styles from './styles.css';
-
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from 'coral-admin/src/translations.json';
-
-import {Link} from 'react-router';
-
-const lang = new I18n(translations);
-
-const CommunityMenu = () => {
- const flaggedPath = '/admin/community/flagged';
- const peoplePath = '/admin/community/people';
- return (
-
-
-
-
- {lang.t('community.flaggedaccounts')}
-
-
- {lang.t('community.people')}
-
-
-
-
- );
-};
-
-export default CommunityMenu;
diff --git a/client/coral-admin/src/containers/Community/components/SuspendUserDialog.js b/client/coral-admin/src/containers/Community/components/SuspendUserDialog.js
deleted file mode 100644
index 44f38f796..000000000
--- a/client/coral-admin/src/containers/Community/components/SuspendUserDialog.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import React, {Component, PropTypes} from 'react';
-
-import {Dialog, Button} from 'coral-ui';
-import styles from './SuspendUserDialog.css';
-
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from 'coral-admin/src/translations.json';
-
-const lang = new I18n(translations);
-
-const stages = [
- {
- title: 'suspenduser.title_0',
- description: 'suspenduser.description_0',
- options: {
- 'j': 'suspenduser.no_cancel',
- 'k': 'suspenduser.yes_suspend'
- }
- },
- {
- title: 'suspenduser.title_1',
- description: 'suspenduser.description_1',
- options: {
- 'j': 'bandialog.cancel',
- 'k': 'suspenduser.send'
- }
- }
-];
-
-class SuspendUserDialog extends Component {
-
- state = {email: '', stage: 0}
-
- static propTypes = {
- stage: PropTypes.number,
- handleClose: PropTypes.func.isRequired,
- suspendUser: PropTypes.func.isRequired
- }
-
- componentDidMount() {
- this.setState({email: lang.t('suspenduser.email'), about: lang.t('suspenduser.username')});
- }
-
- /*
- * 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, user} = this.props;
- const {stage} = this.state;
-
- const cancel = this.props.onClose;
- const next = () => this.setState({stage: stage + 1});
- const suspend = () => {
- suspendUser({userId: user.user.id, message: this.state.email})
- .then(() => {
- this.props.handleClose();
- });
- };
-
- const suspendModalActions = [
- [ cancel, next ],
- [ cancel, suspend ]
- ];
- return suspendModalActions[stage][menuOption]();
- }
-
- onEmailChange = (e) => {
- this.setState({email: e.target.value});
- }
-
- render () {
- const {open, handleClose} = this.props;
- const {stage} = this.state;
-
- return
-
- {lang.t(stages[stage].title, lang.t('suspenduser.username'))}
-
-
-
- {lang.t(stages[stage].description, lang.t('suspenduser.username'))}
-
- {
- stage === 1 &&
-
-
{lang.t('suspenduser.write_message')}
-
-
-
- }
-
- {Object.keys(stages[stage].options).map((key, i) => (
-
- {lang.t(stages[stage].options[key], lang.t('suspenduser.username'))}
-
- ))}
-
-
- ;
- }
-}
-
-export default SuspendUserDialog;
diff --git a/client/coral-admin/src/containers/Community/components/User.js b/client/coral-admin/src/containers/Community/components/User.js
deleted file mode 100644
index 71598e352..000000000
--- a/client/coral-admin/src/containers/Community/components/User.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from 'react';
-import styles from '../Community.css';
-
-import ActionButton from './ActionButton';
-
-import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from '../../../translations.json';
-
-const lang = new I18n(translations);
-
-// Render a single user for the list
-const User = props => {
- const {user, modActionButtons} = props;
- let userStatus = user.status;
-
- // Do not display unless the user status is 'pending' or 'banned'.
- // This means that they have already been reviewed and approved.
- return (userStatus === 'PENDING' || userStatus === 'BANNED') &&
-
-
-
-
-
- {user.username}
-
-
-
-
-
-
-
-
- flag Flags({ user.actions.length }) :
- { user.action_summaries.map(
- (action, i ) => {
- return
- {lang.t(`community.${action.reason}`)} ({action.count})
- ;
- }
- )}
-
-
- { user.action_summaries.map(
- (action_sum, i ) => {
- return
-
- {lang.t(`community.${action_sum.reason}`)} ({action_sum.count})
-
- {user.actions.map(
-
- // find the action by action_sum.reason
- (action, j) => {
- if (action.reason === action_sum.reason) {
- return
- {action.user && action.user.username}: {action.message ? action.message : 'n/a'}
-
;
- }
- return null;
- }
- )}
-
;
- }
- )}
-
-
-
-
-
- {modActionButtons.map((action, i) =>
-
- )}
-
-
-
-
- ;
-};
-
-export default User;
diff --git a/client/coral-admin/src/containers/Community/components/styles.css b/client/coral-admin/src/containers/Community/components/styles.css
deleted file mode 100644
index 2cd3f7b50..000000000
--- a/client/coral-admin/src/containers/Community/components/styles.css
+++ /dev/null
@@ -1,339 +0,0 @@
-@custom-media --big-viewport (min-width: 780px);
-
-.listContainer {
- max-width: 860px;
- margin: 0 auto;
-}
-
-.tabBar {
- background-color: rgba(44, 44, 44, 0.89);
- z-index: 5;
-}
-
-.tab {
- flex: 1;
- color: white;
- text-transform: capitalize;
- font-weight: 500;
- font-size: 15px;
- letter-spacing: 1px;
- transition: border-bottom 200ms;
-}
-
-.active {
- color: white;
- box-sizing: border-box;
- border-bottom: solid 5px #F36451;
-}
-
-.active > span {
- color: white;
-}
-
-.active:after {
- background: transparent !important;
-}
-
-.showShortcuts {
- position: absolute;
- right: 130px;
- display: flex;
- align-items: center;
- font-size: 13px;
-
-span {
- margin-left: 7px;
-}
-}
-
-@media (--big-viewport) {
- .tab {
- flex: none;
- }
-}
-
-.notFound {
- position: relative;
- margin: 20px auto;
- text-align: center;
- padding: 68px 45px;
- vertical-align: middle;
- min-width: 500px;
-
- a {
- color: rgb(244, 126, 107);
- font-weight: 500;
-
- &.goToStreams {
- position: absolute;
- right: 10px;
- bottom: 10px;
- }
- }
-}
-
-.header {
- background-color: #2c2c2c;
- color: white;
- margin-bottom: -1px;
-
- .settingsButton {
- i {
- vertical-align: middle;
- margin-left: 10px;
- margin-top: -4px;
- }
- }
-
- .moderateAsset {
- a {
- -webkit-box-flex: 1;
- -ms-flex: 1;
- flex: 1;
- color: white;
- text-transform: capitalize;
- font-weight: 500;
- font-size: 15px;
- letter-spacing: 1px;
- transition: opacity 200ms;
- opacity: 1;
-
- &:hover {
- opacity: .8;
- cursor: pointer;
- }
-
- &:first-child {
- text-align: left;
- }
-
- &:nth-child(2) {
- text-align: center;
- }
-
- &:last-child {
- text-align: right;
- }
- }
- }
-}
-
-
-@custom-media --big-viewport (min-width: 780px);
-
-.list {
- padding: 8px 0;
- list-style: none;
- display: block;
-
- &.singleView .listItem {
- display: none;
- }
-
- &.singleView .listItem.activeItem {
- display: block;
- height: 100%;
- font-size: 1.5em;
- line-height: 1.5em;
- border: none;
-
- .actions {
- position: fixed;
- bottom: 60px;
- left: 25%;
- display: flex;
- justify-content: space-around;
- width: 50%;
- margin: 0;
- }
-
- .actionButton {
- transform: scale(1.4);
- }
- }
-}
-
-.listItem {
- border-bottom: 1px solid #e0e0e0;
- font-size: 18px;
- width: 100%;
- max-width: 660px;
- min-width: 400px;
- margin: 0 auto;
- position: relative;
- transition: all 200ms;
- padding: 10px 0 0;
- min-height: 220px;
-
- .container {
- padding: 0 14px;
- min-height: 180px;
- }
-
- &:hover {
- box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
- }
-
- &:last-child {
- border-bottom: none;
- }
-
- .context {
- a {
- color: #f36451;
- text-decoration: underline;
- float: right;
- }
- }
-
- .sideActions {
- position: absolute;
- right: 0;
- height: 100%;
- top: 0;
- padding: 40px 18px;
- box-sizing: border-box;
- }
-
- .itemHeader {
- display: flex;
- align-items: center;
- justify-content: space-between;
-
- .author {
- min-width: 230px;
- display: flex;
- align-items: center;
- }
- }
-
- .itemBody {
- display: flex;
- justify-content: space-between;
- }
-
- .avatar {
- margin-right: 16px;
- height: 40px;
- width: 40px;
- border-radius: 50%;
- background-color: #757575;
- font-size: 40px;
- color: #fff;
- }
-
- .created {
- color: #666;
- font-size: 13px;
- margin-left: 40px;
- }
-
- .actionButton {
- transform: scale(.8);
- margin: 0;
- }
-
- .body {
- margin-top: 0px;
- flex: 1;
- color: black;
- max-width: 500px;
- word-wrap: break-word;
- font-weight: 300;
- }
-
- .flagged {
- color: rgba(255, 0, 0, .5);
- padding-top: 15px;
- padding-left: 10px;
- }
-
- .flagCount{
- font-size: 12px;
- color: #d32f2f;
- }
-
-}
-
-.empty {
- color: #444;
- margin-top: 50px;
- text-align: center;
-}
-
-
-@media (--big-viewport) {
- .listItem {
- border: 1px solid #e0e0e0;
- margin-bottom: 30px;
-
- &:last-child {
- border-bottom: 1px solid #e0e0e0;
- }
-
- &.activeItem {
- border: 2px solid #333;
- }
- }
-
-}
-
-.hasLinks {
- color: #f00;
- text-align: right;
- display: flex;
- align-items: center;
-
- i {
- margin-right: 5px;
- }
-}
-
-.banned {
- color: #f00;
- text-align: left;
- display: flex;
- align-items: center;
-
- i {
- margin-right: 5px;
- }
-}
-
-.ban {
- display: block;
- text-align: center;
- margin-top: 5px;
-}
-
-.Comment {
- .moderateArticle {
- font-size: 12px;
- a {
- display: inline-block;
- color: #679af3;
- text-decoration: none;
- font-size: 1em;
- font-weight: 400;
- letter-spacing: .5px;
- font-size: 12px;
- margin-left: 10px;
-
- &:hover {
- text-decoration: underline;
- opacity: .9;
- cursor: pointer;
- }
- }
- }
-}
-
-.flagBox {
- max-width: 480px;
- border-top: 1px solid rgba(66, 66, 66, 0.12);
- h3 {
- font-size: 14px;
- margin: 0;
- font-weight: 500;
- }
-}
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
index f68bab2b7..36ff7763a 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
+++ b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
@@ -21,19 +21,19 @@ const Comment = ({actions = [], ...props}) => {
const links = linkify.getMatches(props.comment.body);
const actionSummaries = props.comment.action_summaries;
return (
-
+
-
- {props.comment.user.name}
-
-
- {timeago().format(props.comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
-
- props.showBanUserDialog(props.comment.user, props.comment.id, props.comment.status !== 'REJECTED')} />
-
-
+
+ {props.comment.user.name}
+
+
+ {timeago().format(props.comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))}
+
+
props.showBanUserDialog(props.comment.user, props.comment.id, props.comment.status !== 'REJECTED')} />
+
+
{props.comment.user.status === 'banned' ?
diff --git a/client/coral-admin/src/graphql/mutations/index.js b/client/coral-admin/src/graphql/mutations/index.js
index 7ca1b078f..884e30e0c 100644
--- a/client/coral-admin/src/graphql/mutations/index.js
+++ b/client/coral-admin/src/graphql/mutations/index.js
@@ -1,7 +1,6 @@
import {graphql} from 'react-apollo';
import SET_USER_STATUS from './setUserStatus.graphql';
import SET_COMMENT_STATUS from './setCommentStatus.graphql';
-import SUSPEND_USER from './suspendUser.graphql';
export const banUser = graphql(SET_USER_STATUS, {
props: ({mutate}) => ({
@@ -10,40 +9,11 @@ export const banUser = graphql(SET_USER_STATUS, {
variables: {
userId,
status: 'BANNED'
- },
- refetchQueries: ['Users']
+ }
});
}}),
});
-export const setUserStatus = graphql(SET_USER_STATUS, {
- props: ({mutate}) => ({
- approveUser: ({userId}) => {
- return mutate({
- variables: {
- userId,
- status: 'APPROVED'
- },
- refetchQueries: ['Users']
- });
- }
- })
-});
-
-export const suspendUser = graphql(SUSPEND_USER, {
- props: ({mutate}) => ({
- suspendUser: ({userId, message}) => {
- return mutate({
- variables: {
- userId,
- message
- },
- refetchQueries: ['Users']
- });
- }
- })
-});
-
export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
props: ({mutate}) => ({
acceptComment: ({commentId}) => {
diff --git a/client/coral-admin/src/graphql/mutations/suspendUser.graphql b/client/coral-admin/src/graphql/mutations/suspendUser.graphql
deleted file mode 100644
index 0d56a3cc0..000000000
--- a/client/coral-admin/src/graphql/mutations/suspendUser.graphql
+++ /dev/null
@@ -1,7 +0,0 @@
-mutation suspendUser($userId: ID!, $message: String) {
- suspendUser(id: $userId, message: $message) {
- errors {
- translation_key
- }
- }
-}
diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js
index 291ea6bc5..13164bca2 100644
--- a/client/coral-admin/src/graphql/queries/index.js
+++ b/client/coral-admin/src/graphql/queries/index.js
@@ -2,7 +2,6 @@ import {graphql} from 'react-apollo';
import MOD_QUEUE_QUERY from './modQueueQuery.graphql';
import MOD_QUEUE_LOAD_MORE from './loadMore.graphql';
-import MOD_USER_FLAGGED_QUERY from './modUserFlaggedQuery.graphql';
import METRICS from './metricsQuery.graphql';
export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
@@ -67,8 +66,6 @@ export const loadMore = (fetchMore) => ({limit, cursor, sort, tab, asset_id}) =>
});
};
-export const modUserFlaggedQuery = graphql(MOD_USER_FLAGGED_QUERY);
-
export const modQueueResort = (id, fetchMore) => (sort) => {
return fetchMore({
query: MOD_QUEUE_QUERY,
diff --git a/client/coral-admin/src/graphql/queries/modUserFlaggedQuery.graphql b/client/coral-admin/src/graphql/queries/modUserFlaggedQuery.graphql
deleted file mode 100644
index 98f2191eb..000000000
--- a/client/coral-admin/src/graphql/queries/modUserFlaggedQuery.graphql
+++ /dev/null
@@ -1,26 +0,0 @@
-query Users ($n: ACTION_TYPE) {
- users (query:{action_type: $n}){
- id
- username
- status
- roles
- actions{
- id
- created_at
- ... on FlagAction {
- reason
- message
- user {
- id
- username
- }
- }
- }
- action_summaries {
- count
- ... on FlagActionSummary {
- reason
- }
- }
- }
-}
diff --git a/client/coral-admin/src/reducers/community.js b/client/coral-admin/src/reducers/community.js
index d051ae0ff..367e67b2a 100644
--- a/client/coral-admin/src/reducers/community.js
+++ b/client/coral-admin/src/reducers/community.js
@@ -6,88 +6,58 @@ import {
FETCH_COMMENTERS_SUCCESS,
SORT_UPDATE,
SET_ROLE,
- SET_COMMENTER_STATUS,
- SHOW_BANUSER_DIALOG,
- HIDE_BANUSER_DIALOG,
- SHOW_SUSPENDUSER_DIALOG,
- HIDE_SUSPENDUSER_DIALOG
+ SET_COMMENTER_STATUS
} from '../constants/community';
const initialState = Map({
community: Map(),
- isFetchingPeople: false,
- errorPeople: '',
- accounts: [],
- fieldPeople: 'created_at',
- ascPeople: false,
- totalPagesPeople: 0,
- pagePeople: 0,
- user: Map({}),
- banDialog: false,
- suspendDialog: false
+ isFetching: false,
+ error: '',
+ commenters: [],
+ field: 'created_at',
+ asc: false,
+ totalPages: 0,
+ page: 0
});
export default function community (state = initialState, action) {
switch (action.type) {
case FETCH_COMMENTERS_REQUEST :
return state
- .set('isFetchingPeople', true);
+ .set('isFetching', true);
case FETCH_COMMENTERS_FAILURE :
return state
- .set('isFetchingPeople', false)
- .set('errorPeople', action.error);
-
+ .set('isFetching', false)
+ .set('error', action.error);
case FETCH_COMMENTERS_SUCCESS : {
- const {accounts, type, page, count, limit, totalPages, ...rest} = action; // eslint-disable-line
+ const {commenters, type, ...rest} = action; // eslint-disable-line
return state
.merge({
- isFetchingPeople: false,
- errorPeople: '',
- pagePeople: page,
- countPeople: count,
- limitPeople: limit,
- totalPagesPeople: totalPages,
+ isFetching: false,
+ error: '',
...rest
})
- .set('accounts', accounts); // Sets to normal array
+ .set('commenters', commenters); // Sets to normal array
}
case SET_ROLE : {
- const commenters = state.get('accounts');
+ const commenters = state.get('commenters');
const idx = commenters.findIndex(el => el.id === action.id);
commenters[idx].roles[0] = action.role;
- return state.set('accounts', commenters.map(id => id));
+ return state.set('commenters', commenters.map(id => id));
}
case SET_COMMENTER_STATUS: {
- const commenters = state.get('accounts');
+ const commenters = state.get('commenters');
const idx = commenters.findIndex(el => el.id === action.id);
commenters[idx].status = action.status;
- return state.set('accounts', commenters.map(id => id));
+ return state.set('commenters', commenters.map(id => id));
}
case SORT_UPDATE :
return state
- .set('fieldPeople', action.sort.field)
- .set('ascPeople', !state.get('ascPeople'));
- case HIDE_BANUSER_DIALOG:
- return state
- .set('banDialog', false);
- case SHOW_BANUSER_DIALOG:
- return state
- .merge({
- user: Map(action.user),
- banDialog: true
- });
- case HIDE_SUSPENDUSER_DIALOG:
- return state
- .set('suspendDialog', false);
- case SHOW_SUSPENDUSER_DIALOG:
- return state
- .merge({
- user: Map(action.user),
- suspendDialog: true
- });
+ .set('field', action.sort.field)
+ .set('asc', !state.get('asc'));
default :
return state;
}
diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json
index f59499e50..13538e224 100644
--- a/client/coral-admin/src/translations.json
+++ b/client/coral-admin/src/translations.json
@@ -17,20 +17,7 @@
"active": "Active",
"banned": "Banned",
"banned-user": "Banned User",
- "loading": "Loading results",
- "flaggedaccounts": "Flagged Usernames",
- "people": "People",
- "no-flagged-accounts": "The Account Flags queue is currently empty.",
- "I don't like this username": "I don't like this username",
- "This user is impersonating": "Impersonation",
- "This looks like an ad/marketing": "Spam/Ads",
- "This username is offensive": "Offensive",
- "Other": "Other",
- "ban_user": "Ban User?",
- "are_you_sure": "Are you sure you would like to ban {0}?",
- "note": "Note: Banning this user will not let them edit, comment or remove anything.",
- "cancel": "Cancel",
- "yes_ban_user": "Yes, Ban User"
+ "loading": "Loading results"
},
"modqueue": {
"likes": "likes",
@@ -117,9 +104,8 @@
"yes_ban_user": "Yes, Ban User"
},
"suspenduser": {
- "title": "Suspend a user",
- "title_0": "We noticed you rejected a username",
- "description_0": "Would you like to temporarily ban this user because of their {0}? Doing so will temporarily hide their comments until they rewrite their {0}.",
+ "title_0": "We noticed you rejected a {0}",
+ "description_0": "Would you like to temporarily ban this user becuase of their {0}? Doing so will temporarily hide their comments until they rewrite their {0}.",
"title_1": "Notify the user of their temporary suspension",
"description_1": "Suspending this user will temporarily disable their account and hide all of their comments on the site.",
"no_cancel": "No, cancel",
@@ -128,7 +114,7 @@
"bio": "bio",
"username": "username",
"email_subject": "Your account has been suspended",
- "email": "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment, like, or flag content until you rewrite your username. Please e-mail us if you have any questions or concerns.",
+ "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"
},
"dashboard": {
@@ -176,34 +162,7 @@
"active": "Activa",
"banned": "Suspendido",
"banned-user": "Usuario Suspendido",
- "loading": "Cargando resultados",
- "flaggedaccounts": "Nombres de Usuario Reportados",
- "people": "Gente",
- "no-flagged-accounts": "No hay ninguna cuenta reportada.",
- "I don't like this username": "No me gusta ese nombre de usuario",
- "This user is impersonating": "Suplantación",
- "This looks like an ad/marketing": "Spam/Propaganda",
- "This username is offensive": "Ofensivo",
- "Other": "Otros",
- "ban_user": "Quieres suspender el Usuario?",
- "are_you_sure": "Estas segura que quieres suspender a {0}?",
- "note": "Nota: Suspender a este usuario no le va a permitir borrar ni editar ni comentar.",
- "cancel": "Cancelar",
- "yes_ban_user": "Si, Suspendan el usuario"
- },
- "suspenduser": {
- "title": "Suspendiendo un usuario",
- "title_0": "Esta queriendo suspender un usuario?",
- "description_0": "Le gustaria suspender a esta usuaria temporarianmente por su nombre de usuario? Si lo hace sus comentarios serán escondidos temporariamente hasta que puedan reescribir su nombre de usuario.",
- "title_1": "Enviarle una nota al usuario sobre su cuenta suspendida",
- "description_1": "Si suspende a este usuario, su cuenta va a ser deshabilitada y todos sus comentarios escondidos del sitio.",
- "no_cancel": "No, cancelar",
- "yes_suspend": "Si, suspender",
- "send": "Enviar",
- "username": "nombre de usuario",
- "email_subject": "Su cuenta ha sido suspendida temporariamente",
- "email": "Otra persona de la comunidad recientemente marcó su nombre de usuario para ser revisado. Por su contenido, el nombre de usuario ha sido rechazado. Esto quiere decir que no puede comentar, gustar o marcar contenido hasta que modifique su nombre de usuario. Por favor, envienos un correo a moderator@newsorg.com si tiene alguna pregunta o preocupación",
- "write_message": "Escribir un mensaje"
+ "loading": "Cargando resultados"
},
"modqueue": {
"likes": "gustos",
diff --git a/client/coral-plugin-flags/FlagComment.js b/client/coral-plugin-flags/FlagComment.js
index 3f3051f28..24fde6b0f 100644
--- a/client/coral-plugin-flags/FlagComment.js
+++ b/client/coral-plugin-flags/FlagComment.js
@@ -23,14 +23,14 @@ const getPopupMenu = [
{val: 'This comment is offensive', text: lang.t('comment-offensive')},
{val: 'This looks like an ad/marketing', text: lang.t('marketing')},
{val: 'I don\'t agree with this comment', text: lang.t('no-agree-comment')},
- {val: 'Other', text: lang.t('other')}
+ {val: 'other', text: lang.t('other')}
]
: [
{val: 'This username is offensive', text: lang.t('username-offensive')},
{val: 'I don\'t like this username', text: lang.t('no-like-username')},
{val: 'This user is impersonating', text: lang.t('user-impersonating')},
{val: 'This looks like an ad/marketing', text: lang.t('marketing')},
- {val: 'Other', text: lang.t('other')}
+ {val: 'other', text: lang.t('other')}
];
return {
header: lang.t('step-2-header'),
diff --git a/graph/loaders/users.js b/graph/loaders/users.js
index 145b0dfdb..90c661f71 100644
--- a/graph/loaders/users.js
+++ b/graph/loaders/users.js
@@ -3,51 +3,11 @@ const DataLoader = require('dataloader');
const util = require('./util');
const UsersService = require('../../services/users');
-const UserModel = require('../../models/user');
const genUserByIDs = (context, ids) => UsersService
.findByIdArray(ids)
.then(util.singleJoinBy(ids, 'id'));
-/**
- * Retrieves users based on the passed in query that is filtered by the
- * current used passed in via the context.
- * @param {Object} context graph context
- * @param {Object} query query terms to apply to the users query
- */
-const getUsersByQuery = ({user}, {ids, limit, cursor, sort}) => {
-
- let users = UserModel.find();
-
- if (ids) {
- users = users.find({
- id: {
- $in: ids
- }
- });
- }
-
- if (cursor) {
- if (sort === 'REVERSE_CHRONOLOGICAL') {
- users = users.where({
- created_at: {
- $lt: cursor
- }
- });
- } else {
- users = users.where({
- created_at: {
- $gt: cursor
- }
- });
- }
- }
-
- return users
- .sort({created_at: sort === 'REVERSE_CHRONOLOGICAL' ? -1 : 1})
- .limit(limit);
-};
-
/**
* Creates a set of loaders based on a GraphQL context.
* @param {Object} context the context of the GraphQL request
@@ -55,7 +15,6 @@ const getUsersByQuery = ({user}, {ids, limit, cursor, sort}) => {
*/
module.exports = (context) => ({
Users: {
- getByQuery: (query) => getUsersByQuery(context, query),
getByID: new DataLoader((ids) => genUserByIDs(context, ids))
}
});
diff --git a/graph/mutators/user.js b/graph/mutators/user.js
index 48966c5e8..3f87c1fb5 100644
--- a/graph/mutators/user.js
+++ b/graph/mutators/user.js
@@ -6,28 +6,18 @@ const setUserStatus = ({user}, {id, status}) => {
.then(res => res);
};
-const suspendUser = ({user}, {id, message}) => {
- return UsersService.suspendUser(id, message)
- .then(res => {
- return res;
- });
-};
-
module.exports = (context) => {
- let mutators = {
+ if (context.user && context.user.can('mutation:setUserStatus')) {
+ return {
+ User: {
+ setUserStatus: (action) => setUserStatus(context, action)
+ }
+ };
+ }
+
+ return {
User: {
- setUserStatus: () => Promise.reject(errors.ErrNotAuthorized),
- suspendUser: () => Promise.reject(errors.ErrNotAuthorized)
+ setUserStatus: () => Promise.reject(errors.ErrNotAuthorized)
}
};
-
- if (context.user && context.user.can('mutation:setUserStatus')) {
- mutators.User.setUserStatus = (action) => setUserStatus(context, action);
- }
-
- if (context.user && context.user.can('mutation:suspendUser')) {
- mutators.User.suspendUser = (action) => suspendUser(context, action);
- }
-
- return mutators;
};
diff --git a/graph/resolvers/flag_action.js b/graph/resolvers/flag_action.js
index 80d1583ad..44cf7a410 100644
--- a/graph/resolvers/flag_action.js
+++ b/graph/resolvers/flag_action.js
@@ -1,15 +1,9 @@
const FlagAction = {
// Stored in the metadata, extract and return.
- message({metadata: {message}}) {
- return message;
- },
- reason({group_id}) {
- return group_id;
- },
- user({user_id}, _, {loaders: {Users}}) {
- return Users.getByID.load(user_id);
- },
+ reason({metadata: {reason}}) {
+ return reason;
+ }
};
module.exports = FlagAction;
diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js
index a474407d2..dc540b202 100644
--- a/graph/resolvers/root_mutation.js
+++ b/graph/resolvers/root_mutation.js
@@ -47,9 +47,6 @@ const RootMutation = {
setUserStatus(_, {id, status}, {mutators: {User}}) {
return wrapResponse(null)(User.setUserStatus({id, status}));
},
- suspendUser(_, {id, message}, {mutators: {User}}) {
- return wrapResponse(null)(User.suspendUser({id, message}));
- },
setCommentStatus(_, {id, status}, {mutators: {Comment}}) {
return wrapResponse(null)(Comment.setCommentStatus({id, status}));
},
diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js
index ce11fcae9..e2836c51d 100644
--- a/graph/resolvers/root_query.js
+++ b/graph/resolvers/root_query.js
@@ -86,28 +86,6 @@ const RootQuery = {
}
return user;
- },
-
- // This endpoint is used for loading the user moderation queues (users whose username has been flagged),
- // so hide it in the event that we aren't an admin.
- users(_, {query: {action_type, limit, cursor, sort}}, {user, loaders: {Users, Actions}}) {
-
- if (user == null || !user.hasRoles('ADMIN')) {
- return null;
- }
-
- const query = {limit, cursor, sort};
-
- if (action_type) {
- return Actions.getByTypes({action_type, item_type: 'USERS'})
- .then((ids) => {
-
- // Perform the query using the available resolver.
- return Users.getByQuery({ids, limit, cursor, sort});
- });
- }
-
- return Users.getByQuery(query);
}
};
diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql
index 8b07c2ab2..e656d0183 100644
--- a/graph/typeDefs.graphql
+++ b/graph/typeDefs.graphql
@@ -45,9 +45,6 @@ type User {
# returns all comments based on a query.
comments(query: CommentsQuery): [Comment]
- # returns all users based on a query.
- users(query: UsersQuery): [User]
-
# returns user status
status: USER_STATUS
}
@@ -63,20 +60,6 @@ type Tag {
created_at: Date!
}
-# UsersQuery allows the ability to query users by a specific fields.
-input UsersQuery {
- action_type: ACTION_TYPE
-
- # Limit the number of results to be returned.
- limit: Int = 10
-
- # Skip results from the last created_at timestamp.
- cursor: Date
-
- # Sort the results by created_at.
- sort: SORT_ORDER = REVERSE_CHRONOLOGICAL
-}
-
################################################################################
## Comments
################################################################################
@@ -537,9 +520,6 @@ type RootQuery {
# role.
me: User
- # Users returned based on a query.
- users(query: UsersQuery): [User]
-
# Asset metrics related to user actions are saturated into the assets
# returned.
assetMetrics(from: Date!, to: Date!, sort: ASSET_METRICS_SORT!, limit: Int = 10): [Asset!]
@@ -673,14 +653,6 @@ type SetUserStatusResponse implements Response {
errors: [UserError]
}
-# SuspendUserResponse is the response returned with possibly some errors
-# relating to the suspend action attempt.
-type SuspendUserResponse implements Response {
-
- # An array of errors relating to the mutation that occurred.
- errors: [UserError]
-}
-
# SetCommentStatusResponse is the response returned with possibly some errors
# relating to the delete action attempt.
type SetCommentStatusResponse implements Response {
@@ -724,9 +696,6 @@ type RootMutation {
# Sets User status. Requires the `ADMIN` role.
setUserStatus(id: ID!, status: USER_STATUS!): SetUserStatusResponse
- # Sets User status to BANNED and canEditName to true. It sends a message to the banned User. Requires the `ADMIN` role.
- suspendUser(id: ID!, message: String): SuspendUserResponse
-
# Sets Comment status. Requires the `ADMIN` role.
setCommentStatus(id: ID!, status: COMMENT_STATUS!): SetCommentStatusResponse
diff --git a/models/user.js b/models/user.js
index e1cbb466b..e23acaa56 100644
--- a/models/user.js
+++ b/models/user.js
@@ -176,10 +176,9 @@ const USER_GRAPH_OPERATIONS = [
'mutation:deleteAction',
'mutation:editName',
'mutation:setUserStatus',
- 'mutation:suspendUser',
'mutation:setCommentStatus',
'mutation:addCommentTag',
- 'mutation:removeCommentTag'
+ 'mutation:removeCommentTag',
];
/**
@@ -195,7 +194,7 @@ UserSchema.method('can', function(...actions) {
return false;
}
- if (actions.some((action) => action === 'mutation:setUserStatus' || action === 'mutation:suspendUser' || action === 'mutation:setCommentStatus') && !this.hasRoles('ADMIN')) {
+ if (actions.some((action) => action === 'mutation:setUserStatus' || action === 'mutation:setCommentStatus') && !this.hasRoles('ADMIN')) {
return false;
}
diff --git a/services/email/suspension.ejs b/services/email/suspension.ejs
deleted file mode 100644
index b36560ec5..000000000
--- a/services/email/suspension.ejs
+++ /dev/null
@@ -1 +0,0 @@
-<%= body %>
diff --git a/services/email/suspension.txt.ejs b/services/email/suspension.txt.ejs
deleted file mode 100644
index b36560ec5..000000000
--- a/services/email/suspension.txt.ejs
+++ /dev/null
@@ -1 +0,0 @@
-<%= body %>
diff --git a/services/users.js b/services/users.js
index 4e1196252..1810cf2a5 100644
--- a/services/users.js
+++ b/services/users.js
@@ -1,11 +1,8 @@
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const Wordlist = require('./wordlist');
-
const errors = require('../errors');
-
const uuid = require('uuid');
-
const redis = require('./redis');
const redisClient = redis.createClient();
@@ -17,7 +14,6 @@ const RECAPTCHA_WINDOW_SECONDS = 60 * 10; // 10 minutes.
const RECAPTCHA_INCORRECT_TRIGGER = 5; // after 3 incorrect attempts, recaptcha will be required.
const ActionsService = require('./actions');
-const MailerService = require('./mailer');
// In the event that the TALK_SESSION_SECRET is missing but we are testing, then
// set the process.env.TALK_SESSION_SECRET.
@@ -450,48 +446,6 @@ module.exports = class UsersService {
});
}
- /**
- * Suspend a user. It changes the status to BANNED and canEditName to True.
- * @param {String} id id of a user
- * @param {Function} done callback after the operation is complete
- */
- static suspendUser(id, message) {
- return UserModel.update({
- id
- }, {
- $set: {
- status: 'BANNED',
- canEditName: true
- }
- })
- .then(() => {
- return UsersService.findById(id)
- .then((user) => {
- if (message) {
- let localProfile = user.profiles.find((profile) => profile.provider === 'local');
-
- if (localProfile) {
- const options =
- {
- template: 'suspension', // needed to know which template to render!
- locals: { // specifies the template locals.
- body: message
- },
- subject: 'Email Suspension',
- to: localProfile.id // This only works if the user has registered via e-mail.
- // We may want a standard way to access a user's e-mail address in the future
- };
-
- return MailerService.sendSimple(options);
- } else {
- return Promise.reject(errors.ErrMissingEmail);
- }
- }
- });
-
- });
- }
-
/**
* Finds a user with the id.
* @param {String} id user id (uuid)
diff --git a/test/graph/mutations/addCommentTag.js b/test/graph/mutations/addCommentTag.js
index 0835e81bc..14a746705 100644
--- a/test/graph/mutations/addCommentTag.js
+++ b/test/graph/mutations/addCommentTag.js
@@ -54,7 +54,7 @@ describe('graph.mutations.addCommentTag', () => {
}
expect(response.errors).to.be.empty;
expect(response.data.addCommentTag.errors).to.deep.equal([{'translation_key':'NOT_AUTHORIZED'}]);
- expect(response.data.addCommentTag.comment).to.be.null;
+ expect(response.data.addCommentTag.comment).to.be.null;
});
});
});