diff --git a/client/coral-admin/src/actions/assets.js b/client/coral-admin/src/actions/assets.js
index f431f1ad6..a4a3513a8 100644
--- a/client/coral-admin/src/actions/assets.js
+++ b/client/coral-admin/src/actions/assets.js
@@ -4,8 +4,10 @@ import {
FETCH_ASSETS_FAILURE,
UPDATE_ASSET_STATE_REQUEST,
UPDATE_ASSET_STATE_SUCCESS,
- UPDATE_ASSET_STATE_FAILURE
+ UPDATE_ASSET_STATE_FAILURE,
+ UPDATE_ASSETS
} from '../constants/assets';
+
import coralApi from '../../../coral-framework/helpers/response';
/**
@@ -34,3 +36,7 @@ export const updateAssetState = (id, closedAt) => (dispatch) => {
dispatch({type: UPDATE_ASSET_STATE_SUCCESS}))
.catch(error => dispatch({type: UPDATE_ASSET_STATE_FAILURE, error}));
};
+
+export const updateAssets = assets => dispatch => {
+ dispatch({type: UPDATE_ASSETS, assets});
+};
diff --git a/client/coral-admin/src/actions/comments.js b/client/coral-admin/src/actions/comments.js
index ac7af12fd..14f33bf36 100644
--- a/client/coral-admin/src/actions/comments.js
+++ b/client/coral-admin/src/actions/comments.js
@@ -101,12 +101,3 @@ export const flagComment = id => (dispatch, getState) => {
dispatch({type: commentTypes.COMMENT_FLAG, id});
dispatch({type: 'COMMENT_UPDATE', comment: getState().comments.get('byId').get(id)});
};
-
-// Dialog Actions
-export const showBanUserDialog = (userId, userName, commentId) => {
- return {type: commentTypes.SHOW_BANUSER_DIALOG, userId, userName, commentId};
-};
-
-export const hideBanUserDialog = (showDialog) => {
- return {type: commentTypes.HIDE_BANUSER_DIALOG, showDialog};
-};
diff --git a/client/coral-admin/src/actions/moderation.js b/client/coral-admin/src/actions/moderation.js
index 425628abe..7d34a14ed 100644
--- a/client/coral-admin/src/actions/moderation.js
+++ b/client/coral-admin/src/actions/moderation.js
@@ -3,3 +3,12 @@ import * as actions from 'constants/moderation';
export const setActiveTab = activeTab => ({type: actions.SET_ACTIVE_TAB, activeTab});
export const toggleModal = open => ({type: actions.TOGGLE_MODAL, open});
export const singleView = () => ({type: actions.SINGLE_VIEW});
+
+// Ban User Dialog
+export const showBanUserDialog = (userId, userName, commentId) => {
+ return {type: actions.SHOW_BANUSER_DIALOG, userId, userName, commentId};
+};
+
+export const hideBanUserDialog = (showDialog) => {
+ return {type: actions.HIDE_BANUSER_DIALOG, showDialog};
+};
diff --git a/client/coral-admin/src/components/ui/Header.css b/client/coral-admin/src/components/ui/Header.css
index 8fbdedc0a..e6cf85d23 100644
--- a/client/coral-admin/src/components/ui/Header.css
+++ b/client/coral-admin/src/components/ui/Header.css
@@ -16,6 +16,7 @@
.rightPanel {
position: absolute;
+ top: 0;
right: 0;
width: 170px;
height: 100%;
diff --git a/client/coral-admin/src/constants/assets.js b/client/coral-admin/src/constants/assets.js
index 0a2ecf73c..20ec0a9c3 100644
--- a/client/coral-admin/src/constants/assets.js
+++ b/client/coral-admin/src/constants/assets.js
@@ -1,6 +1,9 @@
export const FETCH_ASSETS_REQUEST = 'FETCH_ASSETS_REQUEST';
export const FETCH_ASSETS_SUCCESS = 'FETCH_ASSETS_SUCCESS';
export const FETCH_ASSETS_FAILURE = 'FETCH_ASSETS_FAILURE';
+
export const UPDATE_ASSET_STATE_REQUEST = 'UPDATE_ASSET_STATE_REQUEST';
export const UPDATE_ASSET_STATE_SUCCESS = 'UPDATE_ASSET_STATE_SUCCESS';
export const UPDATE_ASSET_STATE_FAILURE = 'UPDATE_ASSET_STATE_FAILURE';
+
+export const UPDATE_ASSETS = 'UPDATE_ASSETS';
diff --git a/client/coral-admin/src/constants/moderation.js b/client/coral-admin/src/constants/moderation.js
index 0fa51dc7b..10c6a7c4c 100644
--- a/client/coral-admin/src/constants/moderation.js
+++ b/client/coral-admin/src/constants/moderation.js
@@ -1,3 +1,5 @@
export const SET_ACTIVE_TAB = 'SET_ACTIVE_TAB';
export const TOGGLE_MODAL = 'TOGGLE_MODAL';
export const SINGLE_VIEW = 'SINGLE_VIEW';
+export const SHOW_BANUSER_DIALOG = 'SHOW_BANUSER_DIALOG';
+export const HIDE_BANUSER_DIALOG = 'HIDE_BANUSER_DIALOG';
diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
index 277a0344b..ae78d1b8e 100644
--- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
+++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js
@@ -1,28 +1,20 @@
import React, {Component} from 'react';
-import key from 'keymaster';
import {connect} from 'react-redux';
import {compose} from 'react-apollo';
-import {Spinner} from 'coral-ui';
-import {withRouter} from 'react-router';
+import key from 'keymaster';
+import isEqual from 'lodash/isEqual';
import {modQueueQuery} from '../../graphql/queries';
-import {
- updateStatus,
- showBanUserDialog,
- hideBanUserDialog,
- fetchPremodQueue,
- fetchRejectedQueue,
- fetchFlaggedQueue,
- fetchModerationQueueComments,
-} from 'actions/comments';
-
import {fetchSettings} from 'actions/settings';
-import {userStatusUpdate, sendNotificationEmail} from 'actions/users';
+import {updateAssets} from 'actions/assets';
import {setActiveTab, toggleModal, singleView} from 'actions/moderation';
+import {Spinner} from 'coral-ui';
import ModerationQueue from './ModerationQueue';
-import ModerationQueueHeader from './components/ModerationQueueHeader';
+import ModerationMenu from './components/ModerationMenu';
+import ModerationHeader from './components/ModerationHeader';
+import NotFoundAsset from './components/NotFoundAsset';
class ModerationContainer extends Component {
@@ -42,29 +34,37 @@ class ModerationContainer extends Component {
key.unbind('esc');
}
- onTabClick = (activeTab) => {
- const {setActiveTab} = this.props;
- setActiveTab(activeTab);
- }
-
- onClose = () => {
- const {toggleModal} = this.props;
- toggleModal(false);
+ componentWillReceiveProps(nextProps) {
+ const {updateAssets} = this.props;
+ if(!isEqual(nextProps.data.assets, this.props.data.assets)) {
+ updateAssets(nextProps.data.assets);
+ }
}
render () {
- const {data, moderation, settings} = this.props;
+ const {data, moderation, settings, assets} = this.props;
+ const providedAssetId = this.props.params.id;
+ let asset;
if (data.loading) {
return
;
}
- const enablePremodTab = data.premod.length;
+ if (providedAssetId) {
+ asset = assets.find(asset => asset.id === this.props.params.id);
+
+ if (!asset) {
+ return ;
+ }
+ }
+
+ const enablePremodTab = !!data.premod.length;
return (
-
+
({
moderation: state.moderation.toJS(),
- settings: state.settings.toJS()
+ settings: state.settings.toJS(),
+ assets: state.assets.get('assets')
});
const mapDispatchToProps = dispatch => ({
- setActiveTab: tab => dispatch(setActiveTab(tab)),
- toggleModal: open => dispatch(toggleModal(open)),
+ onTabClick: activeTab => dispatch(setActiveTab(activeTab)),
+ toggleModal: toggle => dispatch(toggleModal(toggle)),
+ onClose: () => dispatch(toggleModal(false)),
singleView: () => dispatch(singleView()),
-
- fetchSettings: () => dispatch(fetchSettings()),
- fetchModerationQueueComments: () => dispatch(fetchModerationQueueComments()),
- fetchPremodQueue: () => dispatch(fetchPremodQueue()),
- fetchRejectedQueue: () => dispatch(fetchRejectedQueue()),
- fetchFlaggedQueue: () => dispatch(fetchFlaggedQueue()),
- showBanUserDialog: (userId, userName, commentId) => dispatch(showBanUserDialog(userId, userName, commentId)),
- hideBanUserDialog: () => dispatch(hideBanUserDialog(false)),
- userStatusUpdate: (status, userId, commentId) => dispatch(userStatusUpdate(status, userId, commentId)).then(() => {
- dispatch(fetchModerationQueueComments());
- }),
- suspendUser: (userId, subject, text) => dispatch(userStatusUpdate('suspended', userId))
- .then(() => dispatch(sendNotificationEmail(userId, subject, text)))
- .then(() => dispatch(fetchModerationQueueComments()))
- ,
- updateStatus: (action, comment) => dispatch(updateStatus(action, comment))
+ updateAssets: assets => dispatch(updateAssets(assets)),
+ fetchSettings: () => dispatch(fetchSettings())
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
- withRouter,
modQueueQuery
)(ModerationContainer);
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
index 771d6fe55..881675d6a 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
+++ b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js
@@ -14,7 +14,6 @@ import translations from '../../../translations.json';
const Comment = props => {
const links = linkify.getMatches(props.body);
-
return (
@@ -50,14 +49,24 @@ const Comment = props => {
: null}
+
+ {/* */}
+
- View context
+
+ {/* */}
+ {/* View context */}
+ {/* */}
+
);
};
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/ModerationHeader.js b/client/coral-admin/src/containers/ModerationQueue/components/ModerationHeader.js
new file mode 100644
index 000000000..474d8fd27
--- /dev/null
+++ b/client/coral-admin/src/containers/ModerationQueue/components/ModerationHeader.js
@@ -0,0 +1,25 @@
+import React from 'react';
+import {Link} from 'react-router';
+import styles from './styles.css';
+
+const ModerationHeader = props => (
+
+
+ {
+ props.asset ?
+
+ :
+
+ }
+
+
+);
+export default ModerationHeader;
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/ModerationQueueHeader.js b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js
similarity index 80%
rename from client/coral-admin/src/containers/ModerationQueue/components/ModerationQueueHeader.js
rename to client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js
index 06540537b..803f62ecd 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/ModerationQueueHeader.js
+++ b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js
@@ -5,7 +5,7 @@ import translations from '../../../translations.json';
const lang = new I18n(translations);
-const ModerationQueueHeader = (props) => (
+const ModerationMenu = (props) => (
);
-ModerationQueueHeader.propTypes = {
+ModerationMenu.propTypes = {
activeTab: PropTypes.string.isRequired,
enablePremodTab: PropTypes.bool
};
-export default ModerationQueueHeader;
+export default ModerationMenu;
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/NotFoundAsset.js b/client/coral-admin/src/containers/ModerationQueue/components/NotFoundAsset.js
new file mode 100644
index 000000000..ffa1adfcd
--- /dev/null
+++ b/client/coral-admin/src/containers/ModerationQueue/components/NotFoundAsset.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import {Link} from 'react-router';
+import styles from './styles.css';
+
+const NotFound = props => (
+
+
+ The provided asset id {props.assetId} does not exist.
+ Go to Streams
+
+
+);
+
+export default NotFound;
diff --git a/client/coral-admin/src/containers/ModerationQueue/components/styles.css b/client/coral-admin/src/containers/ModerationQueue/components/styles.css
index a1e918459..cc40b03a3 100644
--- a/client/coral-admin/src/containers/ModerationQueue/components/styles.css
+++ b/client/coral-admin/src/containers/ModerationQueue/components/styles.css
@@ -1,3 +1,62 @@
+.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: #3949AB;
+ color: white;
+ margin-bottom: -1px;
+
+ .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 {
diff --git a/client/coral-admin/src/containers/Streams/Streams.css b/client/coral-admin/src/containers/Streams/Streams.css
index 26fb4f74f..d8a75a4ce 100644
--- a/client/coral-admin/src/containers/Streams/Streams.css
+++ b/client/coral-admin/src/containers/Streams/Streams.css
@@ -55,6 +55,12 @@
border-left: none;
border-right: none;
+ a {
+ color: rgb(44, 44, 44);
+ font-weight: 500;
+ text-decoration: none;
+ }
+
th {
font-size: 1.1em;
}
diff --git a/client/coral-admin/src/containers/Streams/Streams.js b/client/coral-admin/src/containers/Streams/Streams.js
index 1937f82c0..62f2f009e 100644
--- a/client/coral-admin/src/containers/Streams/Streams.js
+++ b/client/coral-admin/src/containers/Streams/Streams.js
@@ -4,14 +4,10 @@ import {connect} from 'react-redux';
import I18n from 'coral-framework/modules/i18n/i18n';
import {fetchAssets, updateAssetState} from '../../actions/assets';
import translations from '../../translations.json';
-import {
- RadioGroup,
- Radio,
- Icon,
- DataTable,
- TableHeader
-} from 'react-mdl';
-import Pager from 'coral-ui/components/Pager';
+import {Link} from 'react-router';
+
+import {Pager, Icon} from 'coral-ui';
+import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl';
const limit = 25;
@@ -74,6 +70,8 @@ class Streams extends Component {
}
}
+ renderTitle = (title, {id}) =>
{title}
+
renderStatus = (closedAt, {id}) => {
const closed = closedAt && new Date(closedAt).getTime() < Date.now();
const statusMenuOpen = this.state.statusMenus[id];
@@ -104,6 +102,9 @@ class Streams extends Component {
render () {
const {search, sort, filter} = this.state;
const {assets} = this.props;
+
+ const assetsIds = assets.ids.map((id) => assets.byId[id]);
+
return (
@@ -142,16 +143,14 @@ class Streams extends Component {
-
assets.byId[id])}>
- {lang.t('streams.article')}
-
- {lang.t('streams.pubdate')}
-
-
- {lang.t('streams.status')}
-
+
+ {lang.t('streams.article')}
+
+ {lang.t('streams.pubdate')}
+
+
+ {lang.t('streams.status')}
+
{
assets: assets.toJS()
};
};
+
const mapDispatchToProps = (dispatch) => {
return {
fetchAssets: (...args) => {
diff --git a/client/coral-admin/src/containers/Streams/StreamsTable.js b/client/coral-admin/src/containers/Streams/StreamsTable.js
new file mode 100644
index 000000000..a801a3f7b
--- /dev/null
+++ b/client/coral-admin/src/containers/Streams/StreamsTable.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import translations from '../../translations.json';
+import I18n from 'coral-framework/modules/i18n/i18n';
+const lang = new I18n(translations);
+
+const StreamsTable = props => (
+
+
+
+ |
+ {lang.t('streams.article')}
+ |
+
+ {lang.t('streams.pubdate')}
+ |
+
+ {lang.t('streams.status')}
+ |
+
+
+
+ {props.rows.map((row, i)=> (
+
+ |
+ {row.title}
+ |
+
+ {row.publication_date}
+ |
+
+ {lang.t('streams.status')}
+ |
+
+ ))}
+
+
+);
+
+export default StreamsTable;
diff --git a/client/coral-admin/src/graphql/queries/assetsQuery.graphql b/client/coral-admin/src/graphql/queries/assetsQuery.graphql
new file mode 100644
index 000000000..37950692d
--- /dev/null
+++ b/client/coral-admin/src/graphql/queries/assetsQuery.graphql
@@ -0,0 +1,6 @@
+query Assets {
+ assets {
+ id
+ title
+ }
+}
diff --git a/client/coral-admin/src/graphql/queries/modQueueQuery.graphql b/client/coral-admin/src/graphql/queries/modQueueQuery.graphql
index 5d69f6324..a22a6c808 100644
--- a/client/coral-admin/src/graphql/queries/modQueueQuery.graphql
+++ b/client/coral-admin/src/graphql/queries/modQueueQuery.graphql
@@ -1,6 +1,6 @@
#import "../fragments/commentView.graphql"
-query ($asset_id: ID!) {
+query ModQueue ($asset_id: ID!) {
all: comments(query: {
statuses: [ACCEPTED, REJECTED, PREMOD],
asset_id: $asset_id
@@ -25,10 +25,8 @@ query ($asset_id: ID!) {
}) {
...commentView
}
- account: comments(query: {
- statuses: [ACCEPTED],
- asset_id: $asset_id
- }) {
- ...commentView
+ assets: assets {
+ id
+ title
}
}
diff --git a/client/coral-admin/src/reducers/assets.js b/client/coral-admin/src/reducers/assets.js
index 77d0bf081..c9a82f1c5 100644
--- a/client/coral-admin/src/reducers/assets.js
+++ b/client/coral-admin/src/reducers/assets.js
@@ -1,20 +1,26 @@
import {Map, List, fromJS} from 'immutable';
-import {FETCH_ASSETS_SUCCESS, UPDATE_ASSET_STATE_REQUEST} from '../constants/assets';
+import * as actions from '../constants/assets';
const initialState = Map({
byId: Map(),
- ids: List()
+ ids: List(),
+ assets: List()
});
-export default (state = initialState, action) => {
+export default function assets (state = initialState, action) {
switch (action.type) {
- case FETCH_ASSETS_SUCCESS:
+ case actions.FETCH_ASSETS_SUCCESS:
return replaceAssets(action, state);
- case UPDATE_ASSET_STATE_REQUEST:
- return state.setIn(['byId', action.id, 'closedAt'], action.closedAt);
- default: return state;
+ case actions.UPDATE_ASSET_STATE_REQUEST:
+ return state
+ .setIn(['byId', action.id, 'closedAt'], action.closedAt);
+ case actions.UPDATE_ASSETS:
+ return state
+ .set('assets', List(action.assets));
+ default:
+ return state;
}
-};
+}
const replaceAssets = (action, state) => {
const assets = fromJS(action.assets.reduce((prev, curr) => { prev[curr.id] = curr; return prev; }, {}));
diff --git a/graph/mutators/index.js b/graph/mutators/index.js
index 58d0ed62c..b799cf83d 100644
--- a/graph/mutators/index.js
+++ b/graph/mutators/index.js
@@ -2,6 +2,7 @@ const _ = require('lodash');
const Comment = require('./comment');
const Action = require('./action');
+const User = require('./user');
module.exports = (context) => {
@@ -9,6 +10,7 @@ module.exports = (context) => {
return _.merge(...[
Comment,
Action,
+ User,
].map((mutators) => {
// Each set of mutators is a function which takes the context.
diff --git a/graph/mutators/user.js b/graph/mutators/user.js
new file mode 100644
index 000000000..f693195d6
--- /dev/null
+++ b/graph/mutators/user.js
@@ -0,0 +1,34 @@
+const UsersService = require('../../services/users');
+
+const setUserStatus = ({user}, {id, status}) => {
+ console.log('------as-d-asd-a-sads-a-sad-dsa-----');
+ console.log('user', user);
+ console.log('id', id);
+ console.log('status', status);
+
+ return UsersService.setStatus(id, status)
+ .then((user) => {
+ console.log('result', user);
+ return user;
+ });
+};
+
+module.exports = (context) => {
+
+ // TODO: refactor to something that'll return an error in the event an attempt
+ // is made to mutate state while not logged in. There's got to be a better way
+ // to do this.
+ if (context.user && context.user.can('mutation:setUserStatus')) {
+ return {
+ User: {
+ setUserStatus: (action) => setUserStatus(context, action)
+ }
+ };
+ }
+
+ return {
+ User: {
+ setUserStatus: () => {},
+ }
+ };
+};
diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js
index ef46b839a..a1d25189b 100644
--- a/graph/resolvers/root_mutation.js
+++ b/graph/resolvers/root_mutation.js
@@ -8,6 +8,9 @@ const RootMutation = {
deleteAction(_, {id}, {mutators: {Action}}) {
return Action.delete({id});
},
+ setUserStatus(_, {id, status}, {mutators: {User}}) {
+ return User.setUserStatus({id, status});
+ }
};
module.exports = RootMutation;
diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql
index 8369b93c6..a655a77f3 100644
--- a/graph/typeDefs.graphql
+++ b/graph/typeDefs.graphql
@@ -61,6 +61,9 @@ type User {
# returns all comments based on a query.
comments(query: CommentsQuery): [Comment]
+
+ # returns user status
+ status: USER_STATUS
}
type Comment {
@@ -177,6 +180,13 @@ enum COMMENT_STATUS {
PREMOD
}
+enum USER_STATUS {
+ ACTIVE
+ BANNED
+ PENDING
+ APPROVED
+}
+
type RootQuery {
# retrieves site wide settings and defaults.
@@ -216,6 +226,8 @@ type RootMutation {
# delete an action based on the action id.
deleteAction(id: ID!): Boolean
+ # sets user status
+ setUserStatus(id: ID!, status: USER_STATUS!): Boolean
}
schema {
diff --git a/models/user.js b/models/user.js
index 06dc3c7d1..0194ba5f3 100644
--- a/models/user.js
+++ b/models/user.js
@@ -147,7 +147,8 @@ const USER_GRAPH_OPERATIONS = [
'mutation:createComment',
'mutation:createAction',
'mutation:deleteAction',
- 'mutation:editName'
+ 'mutation:editName',
+ 'mutation:setUserStatus'
];
/**