diff --git a/app.js b/app.js index c04e0cb4a..c2601ad5a 100644 --- a/app.js +++ b/app.js @@ -94,6 +94,11 @@ if (app.get('env') !== 'production') { endpointURL: '/api/v1/graph/ql' })); + // GraphQL documention. + app.get('/admin/docs', (req, res) => { + res.render('admin/docs'); + }); + } //============================================================================== diff --git a/client/coral-admin/src/actions/moderation.js b/client/coral-admin/src/actions/moderation.js index 7d34a14ed..b332b9086 100644 --- a/client/coral-admin/src/actions/moderation.js +++ b/client/coral-admin/src/actions/moderation.js @@ -5,10 +5,5 @@ 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}; -}; +export const showBanUserDialog = (user, commentId) => ({type: actions.SHOW_BANUSER_DIALOG, user, commentId}); +export const hideBanUserDialog = (showDialog) => ({type: actions.HIDE_BANUSER_DIALOG, showDialog}); diff --git a/client/coral-admin/src/components/ActionButton.js b/client/coral-admin/src/components/ActionButton.js index 09abdd266..0415b2529 100644 --- a/client/coral-admin/src/components/ActionButton.js +++ b/client/coral-admin/src/components/ActionButton.js @@ -1,44 +1,23 @@ import React from 'react'; import styles from './ModerationList.css'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../translations.json'; -import {FabButton, Button, Icon} from 'coral-ui'; +import BanUserButton from './BanUserButton'; +import {FabButton} from 'coral-ui'; +import {menuActionsMap} from '../containers/ModerationQueue/helpers/moderationQueueActionsMap'; -const ActionButton = ({type, user}) => { - const menuOptionsMap = { - 'reject': {status: 'REJECTED', icon: 'close', key: 'r'}, - 'approve': {status: 'ACCEPTED', icon: 'done', key: 't'}, - 'flag': {status: 'FLAGGED', icon: 'flag', filter: 'Untouched'}, - 'ban': {status: 'BANNED', icon: 'not interested'} - }; - - if (type === 'ban') { - return ( -
- -
- ); +const ActionButton = ({type = '', user, ...props}) => { + if (type === 'BAN') { + return props.showBanUserDialog(props.user, props.id)} />; } return ( {}} /> ); - }; export default ActionButton; -const lang = new I18n(translations); diff --git a/client/coral-admin/src/components/BanUserButton.css b/client/coral-admin/src/components/BanUserButton.css new file mode 100644 index 000000000..79b805c30 --- /dev/null +++ b/client/coral-admin/src/components/BanUserButton.css @@ -0,0 +1,10 @@ +.banButton { + width: 114px; + letter-spacing: 1px; + + i { + vertical-align: middle; + margin-right: 10px; + font-size: 14px; + } +} diff --git a/client/coral-admin/src/components/BanUserButton.js b/client/coral-admin/src/components/BanUserButton.js new file mode 100644 index 000000000..191164ca5 --- /dev/null +++ b/client/coral-admin/src/components/BanUserButton.js @@ -0,0 +1,26 @@ +import React, {PropTypes} from 'react'; +import {Button, Icon} from 'coral-ui'; +import styles from './BanUserButton.css'; + +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-admin/src/translations.json'; +const lang = new I18n(translations); + +const BanUserButton = ({user, ...props}) => ( +
+ +
+); + +BanUserButton.propTypes = { + onClick: PropTypes.func.isRequired +}; + +export default BanUserButton; diff --git a/client/coral-admin/src/components/BanUserDialog.js b/client/coral-admin/src/components/BanUserDialog.js index 0ad149fbe..b23d8f9d1 100644 --- a/client/coral-admin/src/components/BanUserDialog.js +++ b/client/coral-admin/src/components/BanUserDialog.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import {Dialog} from 'coral-ui'; import styles from './BanUserDialog.css'; @@ -8,34 +8,28 @@ import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); -const BanUserDialog = ({open, handleClose, onClickBanUser, user = {}}) => ( +const BanUserDialog = ({open, handleClose, handleBanUser, user}) => ( handleClose()} - onCancel={() => handleClose()} + onClose={handleClose} + onCancel={handleClose} title={lang.t('bandialog.ban_user')}> ×
-

- {lang.t('bandialog.ban_user')} -

+

{lang.t('bandialog.ban_user')}

-

- {lang.t('bandialog.are_you_sure', user.userName)} -

- - {lang.t('bandialog.note')} - +

{lang.t('bandialog.are_you_sure', user.name)}

+ {lang.t('bandialog.note')}
- -
@@ -43,4 +37,10 @@ const BanUserDialog = ({open, handleClose, onClickBanUser, 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/components/User.js b/client/coral-admin/src/components/User.js index 54de0375e..5743b141e 100644 --- a/client/coral-admin/src/components/User.js +++ b/client/coral-admin/src/components/User.js @@ -25,9 +25,8 @@ const User = props => { {props.modActions.map( (action, i) => + ); @@ -89,10 +99,13 @@ const mapDispatchToProps = dispatch => ({ onClose: () => dispatch(toggleModal(false)), singleView: () => dispatch(singleView()), updateAssets: assets => dispatch(updateAssets(assets)), - fetchSettings: () => dispatch(fetchSettings()) + fetchSettings: () => dispatch(fetchSettings()), + showBanUserDialog: (user, commentId) => dispatch(showBanUserDialog(user, commentId)), + hideBanUserDialog: () => dispatch(hideBanUserDialog(false)), }); export default compose( connect(mapStateToProps, mapDispatchToProps), - modQueueQuery + modQueueQuery, + banUser )(ModerationContainer); diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainerOld.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainerOld.js deleted file mode 100644 index 50e45124d..000000000 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainerOld.js +++ /dev/null @@ -1,132 +0,0 @@ -import React from 'react'; -import key from 'keymaster'; -import {connect} from 'react-redux'; -import {compose} from 'react-apollo'; - -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 {setActiveTab, toggleModal, singleView} from 'actions/moderation'; - -import ModerationQueue from './ModerationQueue'; - -class ModerationContainer extends React.Component { - - componentWillMount() { - const {toggleModal, singleView} = this.props; - - this.props.fetchModerationQueueComments(); - this.props.fetchSettings(); - - key('s', () => singleView()); - key('shift+/', () => toggleModal(true)); - key('esc', () => toggleModal(false)); - } - - componentWillUnmount() { - key.unbind('s'); - key.unbind('shift+/'); - key.unbind('esc'); - } - - onTabClick = (activeTab) => { - const {setActiveTab} = this.props; - setActiveTab(activeTab); - - if (activeTab === 'premod') { - this.props.fetchPremodQueue(); - } else if (activeTab === 'rejected') { - this.props.fetchRejectedQueue(); - } else if (activeTab === 'flagged') { - this.props.fetchFlaggedQueue(); - } else { - this.props.fetchModerationQueueComments(); - } - } - - onClose = () => { - const {toggleModal} = this.props; - toggleModal(false); - } - - render () { - const {comments, actions, settings, moderation} = this.props; - - // Remove all this filters - 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 && - comments.byId[id].status !== 'REJECTED' && - comments.byId[id].status !== 'ACCEPTED' - ); - const userActionIds = actions.ids.filter(id => actions.byId[id].item_type === 'USERS'); - - // show the Pre-Mod tab if premod is enabled globally OR there are pre-mod comments in the db. - let enablePremodTab = (settings.settings && settings.settings.moderation === 'PRE') || premodIds.length; - - return ( - - ); - } -} - -ModerationContainer.contextTypes = { - router: React.PropTypes.func.isRequired -}; - -const mapStateToProps = state => ({ - moderation: state.moderation.toJS(), - comments: state.comments.toJS(), - settings: state.settings.toJS(), - users: state.users.toJS(), - actions: state.actions.toJS() -}); - -const mapDispatchToProps = dispatch => ({ - setActiveTab: tab => dispatch(setActiveTab(tab)), - toggleModal: open => dispatch(toggleModal(open)), - 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)) -}); - -export default compose( - connect(mapStateToProps, mapDispatchToProps), - modQueueQuery -)(ModerationContainer); diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.css b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.css deleted file mode 100644 index 84ee8b923..000000000 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.css +++ /dev/null @@ -1,53 +0,0 @@ -@custom-media --big-viewport (min-width: 780px); - -.listContainer { - max-width: 860px; - margin: 0 auto; -} - -.tabBar { - background: #262626; - 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; - } -} diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js index 47d3d6745..41f0f80bd 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js @@ -1,24 +1,20 @@ import React, {PropTypes} from 'react'; import Comment from './components/Comment'; - -const actionsMap = { - premod: ['reject', 'approve', 'ban'] -}; +import {actionsMap} from './helpers/moderationQueueActionsMap'; const ModerationQueue = props => { - console.log(props); return (
{links ? Contains Link : null} -
- - - -
+
+ {props.actions.map((action, i) => + props.showBanUserDialog(props.user, props.id)} + /> + )} +
{props.user.banned === 'banned' ? @@ -42,9 +45,9 @@ const Comment = props => {
-
- {props.asset.title} Moderate Article -
+
+ {props.asset.title} Moderate Article +

@@ -53,9 +56,11 @@ const Comment = props => {

+ {/* */} {/* View context*/} {/* */} + ); }; @@ -65,9 +70,6 @@ const linkStyles = { padding: '1px 2px' }; -const linkify = new Linkify(); -const lang = new I18n(translations); - Comment.propTypes = { user: PropTypes.object.isRequired, asset: PropTypes.object.isRequired diff --git a/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js index 803f62ecd..51605c443 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js @@ -1,7 +1,7 @@ import React, {PropTypes} from 'react'; -import styles from '../ModerationQueue.css'; +import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../../../translations.json'; +import translations from 'coral-admin/src/translations.json'; const lang = new I18n(translations); diff --git a/client/coral-admin/src/containers/ModerationQueue/components/styles.css b/client/coral-admin/src/containers/ModerationQueue/components/styles.css index f87efec24..3290b6e1f 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/styles.css +++ b/client/coral-admin/src/containers/ModerationQueue/components/styles.css @@ -1,3 +1,57 @@ +@custom-media --big-viewport (min-width: 780px); + +.listContainer { + max-width: 860px; + margin: 0 auto; +} + +.tabBar { + background: #262626; + 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; @@ -238,18 +292,6 @@ margin-top: 5px; } -.banButton { - width: 114px; - letter-spacing: 1px; - - i { - vertical-align: middle; - margin-right: 10px; - font-size: 14px; - } -} - - .Comment { .moderateArticle { padding: 10px 0px; @@ -270,3 +312,5 @@ } } } + + diff --git a/client/coral-admin/src/containers/ModerationQueue/helpers/moderationQueueActionsMap.js b/client/coral-admin/src/containers/ModerationQueue/helpers/moderationQueueActionsMap.js new file mode 100644 index 000000000..0da93e898 --- /dev/null +++ b/client/coral-admin/src/containers/ModerationQueue/helpers/moderationQueueActionsMap.js @@ -0,0 +1,13 @@ +export const actionsMap = { + PREMOD: ['REJECT', 'APPROVE', 'BAN'], + FLAGGED: ['REJECT', 'APPROVE'], + REJECTED: ['APPROVE'] +}; + +export const menuActionsMap = { + 'REJECT': {status: 'REJECTED', icon: 'close', key: 'r'}, + 'APPROVE': {status: 'ACCEPTED', icon: 'done', key: 't'}, + 'FLAGGED': {status: 'FLAGGED', icon: 'flag', filter: 'Untouched'}, + 'BAN': {status: 'BANNED', icon: 'not interested'}, + '': {icon: 'done'} +}; diff --git a/client/coral-admin/src/graphql/fragments/commentView.graphql b/client/coral-admin/src/graphql/fragments/commentView.graphql index ced2f89fc..c31e67fb1 100644 --- a/client/coral-admin/src/graphql/fragments/commentView.graphql +++ b/client/coral-admin/src/graphql/fragments/commentView.graphql @@ -12,12 +12,4 @@ fragment commentView on Comment { id title } - actions { - type: action_type - count - current: current_user { - id - created_at - } - } } diff --git a/client/coral-admin/src/graphql/mutations/index.js b/client/coral-admin/src/graphql/mutations/index.js index 3c6b8923c..372f87e56 100644 --- a/client/coral-admin/src/graphql/mutations/index.js +++ b/client/coral-admin/src/graphql/mutations/index.js @@ -1,2 +1,16 @@ // acceptComment // rejectComment +import {graphql} from 'react-apollo'; +import SET_USER_STATUS from './setUserStatus.graphql'; + +export const banUser = graphql(SET_USER_STATUS, { + props: ({mutate}) => ({ + banUser: ({userId}) => { + return mutate({ + variables: { + userId, + status: 'BANNED' + } + }); + }}), +}); diff --git a/client/coral-admin/src/graphql/mutations/setUserStatus.graphql b/client/coral-admin/src/graphql/mutations/setUserStatus.graphql new file mode 100644 index 000000000..0ebaf54fd --- /dev/null +++ b/client/coral-admin/src/graphql/mutations/setUserStatus.graphql @@ -0,0 +1,3 @@ +mutation setUserStatus($userId: ID!, $status: USER_STATUS!) { + setUserStatus(id: $userId, status: $status) +} diff --git a/client/coral-admin/src/reducers/moderation.js b/client/coral-admin/src/reducers/moderation.js index 3f04abfc6..3131f6096 100644 --- a/client/coral-admin/src/reducers/moderation.js +++ b/client/coral-admin/src/reducers/moderation.js @@ -4,11 +4,24 @@ import * as actions from '../constants/moderation'; const initialState = Map({ activeTab: 'all', singleView: false, - modalOpen: false + modalOpen: false, + user: Map({}), + commentId: null, + banDialog: false }); export default function moderation (state = initialState, action) { switch (action.type) { + case actions.HIDE_BANUSER_DIALOG: + return state + .set('banDialog', false); + case actions.SHOW_BANUSER_DIALOG: + return state + .merge({ + user: Map(action.user), + commentId: action.commentId, + banDialog: true + }); case actions.SET_ACTIVE_TAB: return state .set('activeTab', action.activeTab); diff --git a/client/coral-docs/src/index.js b/client/coral-docs/src/index.js new file mode 100644 index 000000000..5d8c49d9d --- /dev/null +++ b/client/coral-docs/src/index.js @@ -0,0 +1,8 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import {GraphQLDocs} from 'graphql-docs'; + +import fetcher from './services/fetcher'; + +// Render the application into the DOM +ReactDOM.render(, document.querySelector('#root')); diff --git a/client/coral-docs/src/services/fetcher.js b/client/coral-docs/src/services/fetcher.js new file mode 100644 index 000000000..e4d6f091d --- /dev/null +++ b/client/coral-docs/src/services/fetcher.js @@ -0,0 +1,10 @@ +export default function fetcher(query) { + return fetch(`${window.location.host}/api/v1/graph/ql`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({query}), + }).then((res) => res.json()); +} diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index c0c0d57d1..3bf787a9c 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -10,6 +10,8 @@ import React, {PropTypes} from 'react'; import PermalinkButton from 'coral-plugin-permalinks/PermalinkButton'; import AuthorName from 'coral-plugin-author-name/AuthorName'; + +import TagLabel from 'coral-plugin-tag-label/TagLabel'; import Content from 'coral-plugin-commentcontent/CommentContent'; import PubDate from 'coral-plugin-pubdate/PubDate'; import {ReplyBox, ReplyButton} from 'coral-plugin-replies'; @@ -18,7 +20,9 @@ import LikeButton from 'coral-plugin-likes/LikeButton'; import styles from './Comment.css'; -const getAction = (type, comment) => comment.actions.filter((a) => a.type === type)[0]; +const getActionSummary = (type, comment) => comment.action_summaries + .filter((a) => a.__typename === type)[0]; +const isStaff = (tags) => !tags.every((t) => t.name !== 'STAFF') ; class Comment extends React.Component { @@ -35,7 +39,8 @@ class Comment extends React.Component { setActiveReplyBox: PropTypes.func.isRequired, refetch: PropTypes.func.isRequired, showSignInDialog: PropTypes.func.isRequired, - postAction: PropTypes.func.isRequired, + postFlag: PropTypes.func.isRequired, + postLike: PropTypes.func.isRequired, deleteAction: PropTypes.func.isRequired, parentId: PropTypes.string, addNotification: PropTypes.func.isRequired, @@ -51,15 +56,19 @@ class Comment extends React.Component { }), comment: PropTypes.shape({ depth: PropTypes.number, - actions: PropTypes.array.isRequired, + action_summaries: PropTypes.array.isRequired, body: PropTypes.string.isRequired, id: PropTypes.string.isRequired, + tags: PropTypes.arrayOf( + PropTypes.shape({ + name: PropTypes.string + }) + ), replies: PropTypes.arrayOf( PropTypes.shape({ body: PropTypes.string.isRequired, id: PropTypes.string.isRequired - }) - ), + })), user: PropTypes.shape({ id: PropTypes.string.isRequired, name: PropTypes.string.isRequired @@ -78,14 +87,15 @@ class Comment extends React.Component { refetch, addNotification, showSignInDialog, - postAction, + postLike, + postFlag, setActiveReplyBox, activeReplyBox, deleteAction } = this.props; - const like = getAction('LIKE', comment); - const flag = getAction('FLAG', comment); + const like = getActionSummary('LikeActionSummary', comment); + const flag = getActionSummary('FlagActionSummary', comment); return (
+ { isStaff(comment.tags) + ? + : null }
@@ -117,7 +130,7 @@ class Comment extends React.Component { flag={flag} id={comment.id} author_id={comment.user.id} - postAction={postAction} + postFlag={postFlag} deleteAction={deleteAction} showSignInDialog={showSignInDialog} currentUser={currentUser} /> @@ -150,7 +163,8 @@ class Comment extends React.Component { depth={depth + 1} asset={asset} currentUser={currentUser} - postAction={postAction} + postLike={postLike} + postFlag={postFlag} deleteAction={deleteAction} showSignInDialog={showSignInDialog} reactKey={reply.id} @@ -158,7 +172,6 @@ class Comment extends React.Component { comment={reply} />; }) } -
); } diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index 2def22ce8..236e677e8 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -10,7 +10,7 @@ const {addNotification, clearNotification} = notificationActions; const {fetchAssetSuccess} = assetActions; import {queryStream} from 'coral-framework/graphql/queries'; -import {postComment, postAction, deleteAction} from 'coral-framework/graphql/mutations'; +import {postComment, postFlag, postLike, deleteAction} from 'coral-framework/graphql/mutations'; import {editName} from 'coral-framework/actions/user'; import {Notification, notificationActions, authActions, assetActions, pym} from 'coral-framework'; @@ -92,7 +92,7 @@ class Embed extends Component { minHeight: document.body.scrollHeight + 200 } : {}; - if (loading) { + if (loading || !asset) { return ; } @@ -148,7 +148,8 @@ class Embed extends Component { postItem={this.props.postItem} asset={asset} currentUser={user} - postAction={this.props.postAction} + postLike={this.props.postLike} + postFlag={this.props.postFlag} deleteAction={this.props.deleteAction} showSignInDialog={this.props.showSignInDialog} comments={asset.comments} /> @@ -211,7 +212,8 @@ const mapDispatchToProps = dispatch => ({ export default compose( connect(mapStateToProps, mapDispatchToProps), postComment, - postAction, + postFlag, + postLike, deleteAction, queryStream )(Embed); diff --git a/client/coral-embed-stream/src/Stream.js b/client/coral-embed-stream/src/Stream.js index 65743e6c7..53b54d4ba 100644 --- a/client/coral-embed-stream/src/Stream.js +++ b/client/coral-embed-stream/src/Stream.js @@ -37,7 +37,8 @@ class Stream extends React.Component { asset, postItem, addNotification, - postAction, + postFlag, + postLike, deleteAction, showSignInDialog, refetch @@ -56,7 +57,8 @@ class Stream extends React.Component { postItem={postItem} asset={asset} currentUser={currentUser} - postAction={postAction} + postLike={postLike} + postFlag={postFlag} deleteAction={deleteAction} showSignInDialog={showSignInDialog} key={comment.id} diff --git a/client/coral-framework/graphql/fragments/actionSummaryView.graphql b/client/coral-framework/graphql/fragments/actionSummaryView.graphql new file mode 100644 index 000000000..4ac232bf6 --- /dev/null +++ b/client/coral-framework/graphql/fragments/actionSummaryView.graphql @@ -0,0 +1,8 @@ +fragment actionSummaryView on ActionSummary { + __typename + count + current_user { + id + created_at + } +} diff --git a/client/coral-framework/graphql/fragments/commentView.graphql b/client/coral-framework/graphql/fragments/commentView.graphql index 29f9b3bfe..123ce9a09 100644 --- a/client/coral-framework/graphql/fragments/commentView.graphql +++ b/client/coral-framework/graphql/fragments/commentView.graphql @@ -1,18 +1,18 @@ +#import "../fragments/actionSummaryView.graphql" + fragment commentView on Comment { id body created_at status + tags { + name + } user { id name: displayName } - actions { - type: action_type - count - current: current_user { - id - created_at - } + action_summaries { + ...actionSummaryView } } diff --git a/client/coral-framework/graphql/mutations/deleteAction.graphql b/client/coral-framework/graphql/mutations/deleteAction.graphql index bfce8cf6a..f8adf371c 100644 --- a/client/coral-framework/graphql/mutations/deleteAction.graphql +++ b/client/coral-framework/graphql/mutations/deleteAction.graphql @@ -1,3 +1,7 @@ mutation deleteAction ($id: ID!) { - deleteAction(id:$id) + deleteAction(id:$id) { + errors { + translation_key + } + } } diff --git a/client/coral-framework/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js index b97e5ff22..40ca0a7a3 100644 --- a/client/coral-framework/graphql/mutations/index.js +++ b/client/coral-framework/graphql/mutations/index.js @@ -1,6 +1,7 @@ import {graphql} from 'react-apollo'; import POST_COMMENT from './postComment.graphql'; -import POST_ACTION from './postAction.graphql'; +import POST_FLAG from './postFlag.graphql'; +import POST_LIKE from './postLike.graphql'; import DELETE_ACTION from './deleteAction.graphql'; import commentView from '../fragments/commentView.graphql'; @@ -21,12 +22,23 @@ export const postComment = graphql(POST_COMMENT, { }}), }); -export const postAction = graphql(POST_ACTION, { +export const postLike = graphql(POST_LIKE, { props: ({mutate}) => ({ - postAction: (action) => { + postLike: (like) => { return mutate({ variables: { - action + like + } + }); + }}), +}); + +export const postFlag = graphql(POST_FLAG, { + props: ({mutate}) => ({ + postFlag: (flag) => { + return mutate({ + variables: { + flag } }); }}), diff --git a/client/coral-framework/graphql/mutations/postAction.graphql b/client/coral-framework/graphql/mutations/postAction.graphql deleted file mode 100644 index fff737fa8..000000000 --- a/client/coral-framework/graphql/mutations/postAction.graphql +++ /dev/null @@ -1,5 +0,0 @@ -mutation CreateAction ($action: CreateActionInput!) { - createAction(action:$action) { - id - } -} diff --git a/client/coral-framework/graphql/mutations/postComment.graphql b/client/coral-framework/graphql/mutations/postComment.graphql index 499871766..6ce46eaa8 100644 --- a/client/coral-framework/graphql/mutations/postComment.graphql +++ b/client/coral-framework/graphql/mutations/postComment.graphql @@ -2,6 +2,11 @@ mutation CreateComment ($asset_id: ID!, $parent_id: ID, $body: String!) { createComment(asset_id:$asset_id, parent_id:$parent_id, body:$body) { - ...commentView + comment { + ...commentView + } + errors { + translation_key + } } } diff --git a/client/coral-framework/graphql/mutations/postFlag.graphql b/client/coral-framework/graphql/mutations/postFlag.graphql new file mode 100644 index 000000000..cabc2feef --- /dev/null +++ b/client/coral-framework/graphql/mutations/postFlag.graphql @@ -0,0 +1,10 @@ +mutation CreateFlag($flag: CreateFlagInput!) { + createFlag(flag:$flag) { + flag { + id + } + errors { + translation_key + } + } +} diff --git a/client/coral-framework/graphql/mutations/postLike.graphql b/client/coral-framework/graphql/mutations/postLike.graphql new file mode 100644 index 000000000..350904352 --- /dev/null +++ b/client/coral-framework/graphql/mutations/postLike.graphql @@ -0,0 +1,10 @@ +mutation CreateLike ($like: CreateLikeInput!) { + createLike(like:$like) { + like { + id + } + errors { + translation_key + } + } +} diff --git a/client/coral-framework/graphql/queries/index.js b/client/coral-framework/graphql/queries/index.js index 7ce065baa..ffd7dfdc9 100644 --- a/client/coral-framework/graphql/queries/index.js +++ b/client/coral-framework/graphql/queries/index.js @@ -13,7 +13,7 @@ function getQueryVariable(variable) { } // If no query is included, return a default string for development - return 'http://dev.default.stream'; + return 'http://localhost/default/stream'; } export const queryStream = graphql(STREAM_QUERY, { diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index 41c8f75fb..344ade150 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -8,9 +8,6 @@ const name = 'coral-plugin-commentbox'; class CommentBox extends Component { static propTypes = { - - // updateItem: PropTypes.func, - // comments: PropTypes.array, commentPostedHandler: PropTypes.func, postItem: PropTypes.func.isRequired, cancelButtonClicked: PropTypes.func, @@ -29,10 +26,6 @@ class CommentBox extends Component { postComment = () => { const { - - // child_id, - // updateItem, - // appendItemArray, commentPostedHandler, postItem, assetId, @@ -48,28 +41,13 @@ class CommentBox extends Component { parent_id: parentId }; - // let related; - // let parent_type; - // if (parent_id) { - // comment.parent_id = parent_id; - // related = 'children'; - // parent_type = 'comments'; - // } else { - // related = 'comments'; - // parent_type = 'assets'; - // } - // if (child_id || parent_id) { - // updateItem(child_id || parent_id, 'showReply', false, 'comments'); - // } - if (this.props.charCount && this.state.body.length > this.props.charCount) { return; } postItem(comment, 'comments') .then(({data}) => { - const postedComment = data.createComment; + const postedComment = data.createComment.comment; - // const commentId = postedComment.id; if (postedComment.status === 'REJECTED') { addNotification('error', lang.t('comment-post-banned-word')); } else if (postedComment.status === 'PREMOD') { diff --git a/client/coral-plugin-flags/FlagButton.js b/client/coral-plugin-flags/FlagButton.js index ec62f5396..e94dfc5fc 100644 --- a/client/coral-plugin-flags/FlagButton.js +++ b/client/coral-plugin-flags/FlagButton.js @@ -12,7 +12,7 @@ class FlagButton extends Component { showMenu: false, itemType: '', reason: '', - note: '', + message: '', step: 0, posted: false, localPost: null, @@ -23,7 +23,7 @@ class FlagButton extends Component { onReportClick = () => { const {currentUser, flag, deleteAction} = this.props; const {localPost, localDelete} = this.state; - const flagged = (flag && flag.current && !localDelete) || localPost; + const flagged = (flag && flag.current_user && !localDelete) || localPost; if (!currentUser) { const offset = document.getElementById(`c_${this.props.id}`).getBoundingClientRect().top - 75; this.props.showSignInDialog(offset); @@ -31,15 +31,15 @@ class FlagButton extends Component { } if (flagged) { this.setState((prev) => prev.localPost ? {...prev, localPost: null, step: 0} : {...prev, localDelete: true}); - deleteAction(localPost || flag.current.id); + deleteAction(localPost || flag.current_user.id); } else { this.setState({showMenu: !this.state.showMenu}); } } onPopupContinue = () => { - const {postAction, id, author_id} = this.props; - const {itemType, reason, step, posted} = this.state; + const {postFlag, id, author_id} = this.props; + const {itemType, reason, step, posted, message} = this.state; // Proceed to the next step or close the menu if we've reached the end if (step + 1 >= this.props.getPopupMenu.length) { @@ -67,13 +67,14 @@ class FlagButton extends Component { if (itemType === 'COMMENTS') { this.setState({localPost: 'temp'}); } - postAction({ + postFlag({ item_id, item_type: itemType, - action_type: 'FLAG' + reason, + message }).then(({data}) => { if (itemType === 'COMMENTS') { - this.setState({localPost: data.createAction.id}); + this.setState({localPost: data.createFlag.flag.id}); } }); } @@ -99,7 +100,7 @@ class FlagButton extends Component { } onNoteTextChange = (e) => { - this.setState({note: e.target.value}); + this.setState({message: e.target.value}); } handleClickOutside () { @@ -109,7 +110,7 @@ class FlagButton extends Component { render () { const {flag, getPopupMenu} = this.props; const {localPost, localDelete} = this.state; - const flagged = (flag && flag.current && !localDelete) || localPost; + const flagged = (flag && flag.current_user && !localDelete) || localPost; const popupMenu = getPopupMenu[this.state.step](this.state.itemType); return
@@ -150,15 +151,15 @@ class FlagButton extends Component { } { this.state.reason &&
-