mirror of
https://github.com/wassname/talk.git
synced 2026-07-13 17:45:56 +08:00
Merge branch 'master' into assets-by-like
This commit is contained in:
@@ -1,18 +1,49 @@
|
||||
import React from 'react';
|
||||
import {Navigation, Drawer} from 'react-mdl';
|
||||
import {Link} from 'react-router';
|
||||
import styles from './Header.css';
|
||||
import {IndexLink, Link} from 'react-router';
|
||||
import styles from './Drawer.css';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../../translations.json';
|
||||
|
||||
export default () => (
|
||||
<Drawer>
|
||||
<Navigation>
|
||||
<Link className={styles.navLink} to="/admin">{lang.t('configure.moderate')}</Link>
|
||||
<Link className={styles.navLink} to="/admin/community">{lang.t('configure.community')}</Link>
|
||||
<Link className={styles.navLink} to="/admin/configure">{lang.t('configure.configure')}</Link>
|
||||
</Navigation>
|
||||
export default ({handleLogout, restricted = false}) => (
|
||||
<Drawer className={styles.header}>
|
||||
{ !restricted ?
|
||||
<div>
|
||||
<Navigation className={styles.nav}>
|
||||
<IndexLink
|
||||
className={styles.navLink}
|
||||
to="/admin/dashboard"
|
||||
activeClassName={styles.active}>
|
||||
{lang.t('configure.dashboard')}
|
||||
</IndexLink>
|
||||
<Link
|
||||
className={styles.navLink}
|
||||
to="/admin/moderate"
|
||||
activeClassName={styles.active}>
|
||||
{lang.t('configure.moderate')}
|
||||
</Link>
|
||||
<Link className={styles.navLink}
|
||||
to="/admin/streams"
|
||||
activeClassName={styles.active}>
|
||||
{lang.t('configure.streams')}
|
||||
</Link>
|
||||
<Link className={styles.navLink}
|
||||
to="/admin/community"
|
||||
activeClassName={styles.active}>
|
||||
{lang.t('configure.community')}
|
||||
</Link>
|
||||
<Link
|
||||
className={styles.navLink}
|
||||
to="/admin/configure"
|
||||
activeClassName={styles.active}>
|
||||
{lang.t('configure.configure')}
|
||||
</Link>
|
||||
<a onClick={handleLogout}>Sign Out</a>
|
||||
<span>{`v${process.env.VERSION}`}</span>
|
||||
</Navigation>
|
||||
</div> : null }
|
||||
</Drawer>
|
||||
);
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
@custom-media --table-viewport (max-width: 1024px);
|
||||
|
||||
@media (--table-viewport) {
|
||||
.logo {
|
||||
margin-left: 58px;
|
||||
h1 {
|
||||
background: #696969;
|
||||
}
|
||||
span {
|
||||
color: #fcfcfc;
|
||||
}
|
||||
}
|
||||
.nav {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
min-height: 58px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.header > div {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {Logo} from './Logo';
|
||||
|
||||
export default ({handleLogout, restricted = false}) => (
|
||||
<Header className={styles.header}>
|
||||
<Logo />
|
||||
<Logo className={styles.logo} />
|
||||
{
|
||||
!restricted ?
|
||||
<div>
|
||||
|
||||
@@ -6,8 +6,8 @@ import styles from './Layout.css';
|
||||
|
||||
export const Layout = ({children, ...props}) => (
|
||||
<LayoutMDL fixedDrawer>
|
||||
<Header {...props}/>
|
||||
<Drawer />
|
||||
<Header {...props} />
|
||||
<Drawer {...props} />
|
||||
<div className={styles.layout} >
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,8 @@ import React from 'react';
|
||||
import styles from './Logo.css';
|
||||
import {CoralLogo} from 'coral-ui';
|
||||
|
||||
export const Logo = () => (
|
||||
<div className={styles.logo}>
|
||||
export const Logo = ({className = ''}) => (
|
||||
<div className={`${styles.logo} ${className}`}>
|
||||
<h1>
|
||||
<CoralLogo className={styles.base} />
|
||||
<span>Talk</span>
|
||||
|
||||
@@ -43,7 +43,7 @@ class ModerationContainer extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
const {data, moderation, settings, assets, ...props} = this.props;
|
||||
const {data, moderation, settings, assets, modQueueResort, ...props} = this.props;
|
||||
const providedAssetId = this.props.params.id;
|
||||
const activeTab = this.props.route.path === ':id' ? 'premod' : this.props.route.path;
|
||||
|
||||
@@ -75,6 +75,7 @@ class ModerationContainer extends Component {
|
||||
premodCount={data.premodCount}
|
||||
rejectedCount={data.rejectedCount}
|
||||
flaggedCount={data.flaggedCount}
|
||||
modQueueResort={modQueueResort}
|
||||
/>
|
||||
<ModerationQueue
|
||||
currentAsset={asset}
|
||||
|
||||
@@ -1,42 +1,64 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import React, {PropTypes, Component} from 'react';
|
||||
import CommentCount from './CommentCount';
|
||||
import styles from './styles.css';
|
||||
import {SelectField, Option} from 'react-mdl-selectfield';
|
||||
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 ModerationMenu = ({asset, premodCount, rejectedCount, flaggedCount}) => {
|
||||
const premodPath = asset ? `/admin/moderate/premod/${asset.id}` : '/admin/moderate/premod';
|
||||
const rejectPath = asset ? `/admin/moderate/rejected/${asset.id}` : '/admin/moderate/rejected';
|
||||
const flagPath = asset ? `/admin/moderate/flagged/${asset.id}` : '/admin/moderate/flagged';
|
||||
return (
|
||||
<div className='mdl-tabs'>
|
||||
<div className={`mdl-tabs__tab-bar ${styles.tabBar}`}>
|
||||
<div>
|
||||
<Link to={premodPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.premod')} <CommentCount count={premodCount} />
|
||||
</Link>
|
||||
<Link to={rejectPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.rejected')} <CommentCount count={rejectedCount} />
|
||||
</Link>
|
||||
<Link to={flagPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.flagged')} <CommentCount count={flaggedCount} />
|
||||
</Link>
|
||||
class ModerationMenu extends Component {
|
||||
state = {
|
||||
sort: 'REVERSE_CHRONOLOGICAL',
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
premodCount: PropTypes.number.isRequired,
|
||||
rejectedCount: PropTypes.number.isRequired,
|
||||
flaggedCount: PropTypes.number.isRequired,
|
||||
asset: PropTypes.shape({
|
||||
id: PropTypes.string
|
||||
})
|
||||
}
|
||||
|
||||
selectSort = (sort) => {
|
||||
this.setState({sort});
|
||||
this.props.modQueueResort(sort);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {asset, premodCount, rejectedCount, flaggedCount} = this.props;
|
||||
const premodPath = asset ? `/admin/moderate/premod/${asset.id}` : '/admin/moderate/premod';
|
||||
const rejectPath = asset ? `/admin/moderate/rejected/${asset.id}` : '/admin/moderate/rejected';
|
||||
const flagPath = asset ? `/admin/moderate/flagged/${asset.id}` : '/admin/moderate/flagged';
|
||||
return (
|
||||
<div className='mdl-tabs'>
|
||||
<div className={`mdl-tabs__tab-bar ${styles.tabBar}`}>
|
||||
<div className={styles.tabBarPadding}/>
|
||||
<div>
|
||||
<Link to={premodPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.premod')} <CommentCount count={premodCount} />
|
||||
</Link>
|
||||
<Link to={rejectPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.rejected')} <CommentCount count={rejectedCount} />
|
||||
</Link>
|
||||
<Link to={flagPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
|
||||
{lang.t('modqueue.flagged')} <CommentCount count={flaggedCount} />
|
||||
</Link>
|
||||
</div>
|
||||
<SelectField
|
||||
className={styles.selectField}
|
||||
label='Sort'
|
||||
value={this.state.sort}
|
||||
onChange={sort => this.selectSort(sort)}>
|
||||
<Option value={'CHRONOLOGICAL'}>Newest First</Option>
|
||||
<Option value={'REVERSE_CHRONOLOGICAL'}>Oldest First</Option>
|
||||
</SelectField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ModerationMenu.propTypes = {
|
||||
premodCount: PropTypes.number.isRequired,
|
||||
rejectedCount: PropTypes.number.isRequired,
|
||||
flaggedCount: PropTypes.number.isRequired,
|
||||
asset: PropTypes.shape({
|
||||
id: PropTypes.string
|
||||
})
|
||||
};
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ModerationMenu;
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
.tabBar {
|
||||
background-color: rgba(44, 44, 44, 0.89);
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tabBarPadding {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
@@ -334,3 +340,41 @@ span {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.selectField {
|
||||
position: relative;
|
||||
width: 140px;
|
||||
height: 36px;
|
||||
top: 5px;
|
||||
margin-right: 10px;
|
||||
background: #FFF;
|
||||
padding: 10px 15px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12);
|
||||
|
||||
> div {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
i {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.7px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
label {
|
||||
top: -4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,24 @@ export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
|
||||
options: ({params: {id = null}}) => {
|
||||
return {
|
||||
variables: {
|
||||
asset_id: id
|
||||
asset_id: id,
|
||||
sort: 'REVERSE_CHRONOLOGICAL'
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
props: ({ownProps: {params: {id = null}}, data}) => ({
|
||||
data,
|
||||
modQueueResort: modQueueResort(id, data.fetchMore)
|
||||
})
|
||||
});
|
||||
|
||||
export const modQueueResort = (id, fetchMore) => (sort) => {
|
||||
return fetchMore({
|
||||
query: MOD_QUEUE_QUERY,
|
||||
variables: {
|
||||
asset_id: id,
|
||||
sort
|
||||
},
|
||||
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#import "../fragments/commentView.graphql"
|
||||
|
||||
query ModQueue ($asset_id: ID) {
|
||||
query ModQueue ($asset_id: ID, $sort: SORT_ORDER) {
|
||||
premod: comments(query: {
|
||||
statuses: [PREMOD],
|
||||
asset_id: $asset_id
|
||||
asset_id: $asset_id,
|
||||
sort: $sort
|
||||
}) {
|
||||
...commentView
|
||||
}
|
||||
flagged: comments(query: {
|
||||
action_type: FLAG,
|
||||
asset_id: $asset_id,
|
||||
statuses: [NONE, PREMOD]
|
||||
statuses: [NONE, PREMOD],
|
||||
sort: $sort
|
||||
}) {
|
||||
...commentView
|
||||
action_summaries {
|
||||
@@ -22,7 +24,8 @@ query ModQueue ($asset_id: ID) {
|
||||
}
|
||||
rejected: comments(query: {
|
||||
statuses: [REJECTED],
|
||||
asset_id: $asset_id
|
||||
asset_id: $asset_id,
|
||||
sort: $sort
|
||||
}) {
|
||||
...commentView
|
||||
}
|
||||
|
||||
@@ -7,6 +7,9 @@ import store from './services/store';
|
||||
|
||||
import App from './components/App';
|
||||
|
||||
import 'react-mdl/extra/material.css';
|
||||
import 'react-mdl/extra/material.js';
|
||||
|
||||
render(
|
||||
<ApolloProvider client={client} store={store}>
|
||||
<App />
|
||||
|
||||
@@ -38,7 +38,6 @@ class Comment extends React.Component {
|
||||
// id of currently opened ReplyBox. tracked in Stream.js
|
||||
activeReplyBox: PropTypes.string.isRequired,
|
||||
setActiveReplyBox: PropTypes.func.isRequired,
|
||||
refetch: PropTypes.func.isRequired,
|
||||
showSignInDialog: PropTypes.func.isRequired,
|
||||
postFlag: PropTypes.func.isRequired,
|
||||
postLike: PropTypes.func.isRequired,
|
||||
@@ -85,11 +84,11 @@ class Comment extends React.Component {
|
||||
asset,
|
||||
depth,
|
||||
postItem,
|
||||
refetch,
|
||||
addNotification,
|
||||
showSignInDialog,
|
||||
postLike,
|
||||
postFlag,
|
||||
postDontAgree,
|
||||
loadMore,
|
||||
setActiveReplyBox,
|
||||
activeReplyBox,
|
||||
@@ -98,6 +97,7 @@ class Comment extends React.Component {
|
||||
|
||||
const like = getActionSummary('LikeActionSummary', comment);
|
||||
const flag = getActionSummary('FlagActionSummary', comment);
|
||||
const dontagree = getActionSummary('DontAgreeActionSummary', comment);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -129,10 +129,11 @@ class Comment extends React.Component {
|
||||
<div className="commentActionsRight">
|
||||
<PermalinkButton articleURL={asset.url} commentId={comment.id} />
|
||||
<FlagComment
|
||||
flag={flag}
|
||||
flag={flag && flag.current_user ? flag : dontagree}
|
||||
id={comment.id}
|
||||
author_id={comment.user.id}
|
||||
postFlag={postFlag}
|
||||
postDontAgree={postDontAgree}
|
||||
deleteAction={deleteAction}
|
||||
showSignInDialog={showSignInDialog}
|
||||
currentUser={currentUser} />
|
||||
@@ -155,7 +156,6 @@ class Comment extends React.Component {
|
||||
comment.replies &&
|
||||
comment.replies.map(reply => {
|
||||
return <Comment
|
||||
refetch={refetch}
|
||||
setActiveReplyBox={setActiveReplyBox}
|
||||
activeReplyBox={activeReplyBox}
|
||||
addNotification={addNotification}
|
||||
|
||||
@@ -2,6 +2,9 @@ import React, {Component} from 'react';
|
||||
import {compose} from 'react-apollo';
|
||||
import {connect} from 'react-redux';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from 'coral-framework/translations';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
import {TabBar, Tab, TabContent, Spinner} from 'coral-ui';
|
||||
|
||||
@@ -10,7 +13,7 @@ const {addNotification, clearNotification} = notificationActions;
|
||||
const {fetchAssetSuccess} = assetActions;
|
||||
|
||||
import {queryStream} from 'coral-framework/graphql/queries';
|
||||
import {postComment, postFlag, postLike, deleteAction} from 'coral-framework/graphql/mutations';
|
||||
import {postComment, postFlag, postLike, postDontAgree, deleteAction} from 'coral-framework/graphql/mutations';
|
||||
import {editName} from 'coral-framework/actions/user';
|
||||
import {updateCountCache} from 'coral-framework/actions/asset';
|
||||
import {Notification, notificationActions, authActions, assetActions, pym} from 'coral-framework';
|
||||
@@ -25,7 +28,7 @@ import UserBox from 'coral-sign-in/components/UserBox';
|
||||
import SignInContainer from 'coral-sign-in/containers/SignInContainer';
|
||||
import SuspendedAccount from 'coral-framework/components/SuspendedAccount';
|
||||
import ChangeUsernameContainer from '../../coral-sign-in/containers/ChangeUsernameContainer';
|
||||
import SettingsContainer from 'coral-settings/containers/SettingsContainer';
|
||||
import ProfileContainer from 'coral-settings/containers/ProfileContainer';
|
||||
import RestrictedContent from 'coral-framework/components/RestrictedContent';
|
||||
import ConfigureStreamContainer from 'coral-configure/containers/ConfigureStreamContainer';
|
||||
import LoadMore from './LoadMore';
|
||||
@@ -110,7 +113,7 @@ class Embed extends Component {
|
||||
<div className="commentStream">
|
||||
<TabBar onChange={this.changeTab} activeTab={activeTab}>
|
||||
<Tab><Count count={asset.commentCount}/></Tab>
|
||||
<Tab>Settings</Tab>
|
||||
<Tab>{lang.t('profile')}</Tab>
|
||||
<Tab restricted={!isAdmin}>Configure Stream</Tab>
|
||||
</TabBar>
|
||||
{loggedIn && <UserBox user={user} logout={this.props.logout} changeTab={this.changeTab}/>}
|
||||
@@ -172,6 +175,7 @@ class Embed extends Component {
|
||||
currentUser={user}
|
||||
postLike={this.props.postLike}
|
||||
postFlag={this.props.postFlag}
|
||||
postDontAgree={this.props.postDontAgree}
|
||||
getCounts={this.props.getCounts}
|
||||
updateCountCache={this.props.updateCountCache}
|
||||
loadMore={this.props.loadMore}
|
||||
@@ -190,7 +194,7 @@ class Embed extends Component {
|
||||
loadMore={this.props.loadMore}/>
|
||||
</TabContent>
|
||||
<TabContent show={activeTab === 1}>
|
||||
<SettingsContainer
|
||||
<ProfileContainer
|
||||
loggedIn={loggedIn}
|
||||
userData={this.props.userData}
|
||||
showSignInDialog={this.props.showSignInDialog}
|
||||
@@ -245,6 +249,7 @@ export default compose(
|
||||
postComment,
|
||||
postFlag,
|
||||
postLike,
|
||||
postDontAgree,
|
||||
deleteAction,
|
||||
queryStream
|
||||
)(Embed);
|
||||
|
||||
@@ -19,12 +19,13 @@ const NewCount = (props) => {
|
||||
|
||||
return <div className='coral-new-comments'>
|
||||
{
|
||||
props.countCache && newComments > 0 &&
|
||||
props.countCache && newComments > 0 ?
|
||||
<button onClick={onLoadMoreClick(props)} className='coral-load-more'>
|
||||
{newComments === 1
|
||||
? lang.t('newCount', newComments, lang.t('comment'))
|
||||
: lang.t('newCount', newComments, lang.t('comments'))}
|
||||
</button>
|
||||
: null
|
||||
}
|
||||
</div>;
|
||||
};
|
||||
|
||||
@@ -60,6 +60,7 @@ class Stream extends React.Component {
|
||||
addNotification,
|
||||
postFlag,
|
||||
postLike,
|
||||
postDontAgree,
|
||||
loadMore,
|
||||
deleteAction,
|
||||
showSignInDialog,
|
||||
@@ -81,6 +82,7 @@ class Stream extends React.Component {
|
||||
currentUser={currentUser}
|
||||
postLike={postLike}
|
||||
postFlag={postFlag}
|
||||
postDontAgree={postDontAgree}
|
||||
loadMore={loadMore}
|
||||
deleteAction={deleteAction}
|
||||
showSignInDialog={showSignInDialog}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {graphql} from 'react-apollo';
|
||||
import POST_COMMENT from './postComment.graphql';
|
||||
import POST_FLAG from './postFlag.graphql';
|
||||
import POST_LIKE from './postLike.graphql';
|
||||
import POST_DONT_AGREE from './postDontAgree.graphql';
|
||||
import DELETE_ACTION from './deleteAction.graphql';
|
||||
|
||||
import commentView from '../fragments/commentView.graphql';
|
||||
@@ -100,6 +101,17 @@ export const postFlag = graphql(POST_FLAG, {
|
||||
}}),
|
||||
});
|
||||
|
||||
export const postDontAgree = graphql(POST_DONT_AGREE, {
|
||||
props: ({mutate}) => ({
|
||||
postDontAgree: (dontagree) => {
|
||||
return mutate({
|
||||
variables: {
|
||||
dontagree
|
||||
}
|
||||
});
|
||||
}}),
|
||||
});
|
||||
|
||||
export const deleteAction = graphql(DELETE_ACTION, {
|
||||
props: ({mutate}) => ({
|
||||
deleteAction: (id) => {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
mutation CreateDontAgree($dontagree: CreateDontAgreeInput!) {
|
||||
createDontAgree(dontagree:$dontagree) {
|
||||
dontagree {
|
||||
id
|
||||
}
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ const handleResp = res => {
|
||||
}
|
||||
|
||||
if (err.error && err.error.translation_key) {
|
||||
message = err.error.translation_key;
|
||||
error.translation_key = err.error.translation_key;
|
||||
}
|
||||
|
||||
error.message = message;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"en": {
|
||||
"profile": "Profile",
|
||||
"successUpdateSettings": "The changes you have made have been applied to the comment stream on this article",
|
||||
"successNameUpdate": "Your username has been updated",
|
||||
"contentNotAvailable": "This content is not available",
|
||||
@@ -36,6 +37,7 @@
|
||||
}
|
||||
},
|
||||
"es": {
|
||||
"profile": "Perfil",
|
||||
"successUpdateSettings": "La configuración de este articulo fue actualizada",
|
||||
"successBioUpdate": "Tu bio fue actualizada",
|
||||
"contentNotAvailable": "El contenido no se encuentra disponible",
|
||||
|
||||
@@ -58,8 +58,6 @@ class CommentBox extends Component {
|
||||
} else if (postedComment.status === 'PREMOD') {
|
||||
addNotification('success', lang.t('comment-post-notif-premod'));
|
||||
!isReply && updateCountCache(assetId, countCache);
|
||||
} else {
|
||||
addNotification('success', 'Your comment has been posted.');
|
||||
}
|
||||
|
||||
if (commentPostedHandler) {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
import React from 'react';
|
||||
import FlagButton from './FlagButton';
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
|
||||
const FlagBio = (props) => <FlagButton {...props} getPopupMenu={getPopupMenu} />;
|
||||
|
||||
const getPopupMenu = [
|
||||
() => {
|
||||
return {
|
||||
header: lang.t('step-2-header'),
|
||||
itemType: 'USERS',
|
||||
field: 'bio',
|
||||
options: [
|
||||
{val: 'This bio is offensive', text: lang.t('bio-offensive')},
|
||||
{val: 'I don\'t like this bio', text: lang.t('no-like-bio')},
|
||||
{val: 'This looks like an ad/marketing', text: lang.t('marketing')},
|
||||
{val: 'other', text: lang.t('other')}
|
||||
],
|
||||
button: lang.t('continue'),
|
||||
sets: 'reason'
|
||||
};
|
||||
},
|
||||
() => {
|
||||
return {
|
||||
header: lang.t('step-3-header'),
|
||||
text: lang.t('thank-you'),
|
||||
button: lang.t('done'),
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
export default FlagBio;
|
||||
|
||||
const lang = new I18n(translations);
|
||||
@@ -38,7 +38,7 @@ class FlagButton extends Component {
|
||||
}
|
||||
|
||||
onPopupContinue = () => {
|
||||
const {postFlag, id, author_id} = this.props;
|
||||
const {postFlag, postDontAgree, 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
|
||||
@@ -52,7 +52,6 @@ class FlagButton extends Component {
|
||||
if (itemType && reason && !posted) {
|
||||
this.setState({posted: true});
|
||||
|
||||
// Set the text from the "other" field if it exists.
|
||||
let item_id;
|
||||
switch(itemType) {
|
||||
case 'COMMENTS':
|
||||
@@ -63,20 +62,31 @@ class FlagButton extends Component {
|
||||
break;
|
||||
}
|
||||
|
||||
// Note: Action metadata has been temporarily removed.
|
||||
if (itemType === 'COMMENTS') {
|
||||
this.setState({localPost: 'temp'});
|
||||
}
|
||||
postFlag({
|
||||
|
||||
let action = {
|
||||
item_id,
|
||||
item_type: itemType,
|
||||
reason,
|
||||
reason: null,
|
||||
message
|
||||
}).then(({data}) => {
|
||||
if (itemType === 'COMMENTS') {
|
||||
this.setState({localPost: data.createFlag.flag.id});
|
||||
}
|
||||
});
|
||||
};
|
||||
if (reason === 'I don\'t agree with this comment') {
|
||||
postDontAgree(action)
|
||||
.then(({data}) => {
|
||||
if (itemType === 'COMMENTS') {
|
||||
this.setState({localPost: data.createDontAgree.dontagree.id});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
postFlag({...action, reason})
|
||||
.then(({data}) => {
|
||||
if (itemType === 'COMMENTS') {
|
||||
this.setState({localPost: data.createFlag.flag.id});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ const getPopupMenu = [
|
||||
(itemType) => {
|
||||
const options = itemType === 'COMMENTS' ?
|
||||
[
|
||||
{val: 'I don\'t agree with this comment', text: lang.t('no-agree-comment')},
|
||||
{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')}
|
||||
]
|
||||
: [
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
import styles from './ProfileHeader.css';
|
||||
|
||||
const ProfileHeader = ({username}) => (
|
||||
<div className={styles.header}>
|
||||
<h1>{username}</h1>
|
||||
</div>
|
||||
);
|
||||
|
||||
ProfileHeader.propTypes = {username: PropTypes.string.isRequired};
|
||||
|
||||
export default ProfileHeader;
|
||||
@@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import styles from './SettingsHeader.css';
|
||||
|
||||
export default ({userData}) => (
|
||||
<div className={styles.header}>
|
||||
<h1>{userData.username}</h1>
|
||||
|
||||
{
|
||||
|
||||
// Hiding display of users ID unless there's a use case for it.
|
||||
// <h2>{userData.profiles.map(profile => profile.id)}</h2>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
+4
-4
@@ -8,13 +8,13 @@ import {myCommentHistory} from 'coral-framework/graphql/queries';
|
||||
import {link} from 'coral-framework/services/PymConnection';
|
||||
import NotLoggedIn from '../components/NotLoggedIn';
|
||||
import {Spinner} from 'coral-ui';
|
||||
import SettingsHeader from '../components/SettingsHeader';
|
||||
import ProfileHeader from '../components/ProfileHeader';
|
||||
import CommentHistory from 'coral-plugin-history/CommentHistory';
|
||||
|
||||
import translations from '../translations';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
class SettingsContainer extends Component {
|
||||
class ProfileContainer extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -44,7 +44,7 @@ class SettingsContainer extends Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SettingsHeader {...this.props} />
|
||||
<ProfileHeader username={this.props.userData.username} />
|
||||
{
|
||||
|
||||
// Hiding bio until moderation can get figured out
|
||||
@@ -88,4 +88,4 @@ const mapDispatchToProps = () => ({
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
myCommentHistory
|
||||
)(SettingsContainer);
|
||||
)(ProfileContainer);
|
||||
@@ -1,20 +1,22 @@
|
||||
{
|
||||
"en":{
|
||||
"profile": "Profile",
|
||||
"userNoComment": "You've never left a comment. Join the conversation!",
|
||||
"allComments": "All Comments",
|
||||
"profileSettings": "Profile Settings",
|
||||
"myCommentHistory": "My comment History",
|
||||
"signIn": "Sign in",
|
||||
"toAccess": " to access Settings",
|
||||
"fromSettingsPage": "From the Settings Page you can see your comment history."
|
||||
"toAccess": " to access Profile",
|
||||
"fromSettingsPage": "From the Profile Page you can see your comment history."
|
||||
},
|
||||
"es":{
|
||||
"profile": "Perfil",
|
||||
"userNoComment": "No has dejado áun ningún comentario. ¡Unete a la conversación!",
|
||||
"allComments": "Todos los comentarios",
|
||||
"profileSettings": "Configuración del perfil",
|
||||
"myCommentHistory": "Mi historial de comentarios",
|
||||
"signIn": "Entrar",
|
||||
"toAccess": "para acceder a la configuración",
|
||||
"toAccess": "para acceder a al perfil",
|
||||
"fromSettingsPage": "Desde la peagina de configuración puede ver su historia de comentarios."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,18 @@ import TextField from 'coral-ui/components/TextField';
|
||||
import Alert from './Alert';
|
||||
import Button from 'coral-ui/components/Button';
|
||||
import {Dialog} from 'coral-ui';
|
||||
import FakeComment from './FakeComment';
|
||||
|
||||
import styles from './styles.css';
|
||||
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../translations';
|
||||
const lang = new I18n(translations);
|
||||
|
||||
const CreateUsernameDialog = ({open, handleClose, offset, formData, handleSubmitUsername, handleChange, ...props}) => (
|
||||
const CreateUsernameDialog = ({open, handleClose, offset, formData, handleSubmitUsername, handleChange, ...props}) => {
|
||||
return (
|
||||
<Dialog
|
||||
className={styles.dialog}
|
||||
className={styles.dialogusername}
|
||||
id="createUsernameDialog"
|
||||
open={open}
|
||||
style={{
|
||||
@@ -25,24 +29,32 @@ const CreateUsernameDialog = ({open, handleClose, offset, formData, handleSubmit
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="username">{lang.t('createdisplay.yourusername')}</label>
|
||||
<p className={styles.yourusername}>{lang.t('createdisplay.yourusername')}</p>
|
||||
<FakeComment
|
||||
className={styles.fakeComment}
|
||||
username={formData.username}
|
||||
created_at={Date.now()}
|
||||
body={lang.t('createdisplay.fakecommentbody')}
|
||||
/>
|
||||
<p className={styles.ifyoudont}>{lang.t('createdisplay.ifyoudontchangeyourname')}</p>
|
||||
{ props.auth.error && <Alert>{props.auth.error}</Alert> }
|
||||
<form id="saveUsername" onSubmit={handleSubmitUsername}>
|
||||
<TextField
|
||||
id="username"
|
||||
type="string"
|
||||
label={lang.t('createdisplay.username')}
|
||||
value={formData.username}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{ props.errors.username && <span className={styles.hint}> {lang.t('createdisplay.specialCharacters')} </span> }
|
||||
<div className={styles.action}>
|
||||
{ props.errors.username && <span className={styles.hint}> {lang.t('createdisplay.specialCharacters')} </span> }
|
||||
<div className={styles.saveusername}>
|
||||
<TextField
|
||||
id="username"
|
||||
type="string"
|
||||
label={lang.t('createdisplay.username')}
|
||||
value={formData.username}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Button id="save" type="submit" className={styles.saveButton}>{lang.t('createdisplay.save')}</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateUsernameDialog;
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import styles from 'coral-embed-stream/src/Comment.css';
|
||||
|
||||
import AuthorName from 'coral-plugin-author-name/AuthorName';
|
||||
import Content from 'coral-plugin-commentcontent/CommentContent';
|
||||
import PubDate from 'coral-plugin-pubdate/PubDate';
|
||||
import {ReplyButton} from 'coral-plugin-replies';
|
||||
|
||||
import I18n from 'coral-framework/modules/i18n/i18n';
|
||||
import translations from '../translations';
|
||||
|
||||
const lang = new I18n(translations);
|
||||
|
||||
class FakeComment extends React.Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
const {username, created_at, body} = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`comment ${styles.Comment}`}
|
||||
style={{marginLeft: 0 * 30}}>
|
||||
<hr aria-hidden={true} />
|
||||
<AuthorName
|
||||
author={{'name': username}}/>
|
||||
<PubDate created_at={created_at} />
|
||||
<Content body={body} />
|
||||
<div className="commentActionsLeft">
|
||||
<div className={`${'coral-plugin-likes'}-container`}>
|
||||
<button className={`${'coral-plugin-likes'}-button`}>
|
||||
<span className={`${'coral-plugin-likes'}-button-text`}>{lang.t('like')}</span>
|
||||
<i className={`${'coral-plugin-likes'}-icon material-icons`}
|
||||
aria-hidden={true}>thumb_up</i>
|
||||
</button>
|
||||
</div>
|
||||
<ReplyButton
|
||||
onClick={() => {}}
|
||||
parentCommentId={'commentID'}
|
||||
currentUserId={{}}
|
||||
banned={false}
|
||||
/>
|
||||
</div>
|
||||
<div className="commentActionsRight">
|
||||
<div className="coral-plugin-permalinks-container">
|
||||
<button className="coral-plugin-permalinks-button">
|
||||
<i className="coral-plugin-permalinks-icon material-icons" aria-hidden={true}>link</i>
|
||||
{lang.t('permalink.permalink')}
|
||||
</button>
|
||||
</div>
|
||||
<div className={`${'coral-plugin-flags'}-container`}>
|
||||
<button className={`${'coral-plugin-flags'}-button`}>
|
||||
<span className={`${'coral-plugin-flags'}-button-text`}>{lang.t('report')}</span>
|
||||
<i className={`${'coral-plugin-flags'}-icon material-icons`}
|
||||
aria-hidden={true}>flag</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FakeComment;
|
||||
@@ -118,7 +118,7 @@ input.error{
|
||||
}
|
||||
|
||||
.action {
|
||||
margin-top: 15px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.passwordRequestSuccess {
|
||||
@@ -141,6 +141,40 @@ input.error{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.confirmSubmit {
|
||||
/* Change username Dialog*/
|
||||
|
||||
.dialogusername {
|
||||
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: 400px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.yourusername {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.example {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ifyoudont {
|
||||
display: block;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.saveusername {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.savebutton {
|
||||
display: inline;
|
||||
background-color: rgb(105,105,105);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fakeComment {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class ChangeUsernameContainer extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.initialState.formData.username = props.user.username;
|
||||
this.state = this.initialState;
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleSubmitUsername = this.handleSubmitUsername.bind(this);
|
||||
@@ -103,7 +104,7 @@ class ChangeUsernameContainer extends Component {
|
||||
return (
|
||||
<div>
|
||||
<CreateUsernameDialog
|
||||
open={auth.showCreateUsernameDialog && auth.fromSignUp}
|
||||
open={auth.showCreateUsernameDialog && auth.user.canEditName}
|
||||
offset={offset}
|
||||
handleClose={this.handleClose}
|
||||
loggedIn={loggedIn}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
facebookSignIn: 'Sign in with Facebook',
|
||||
facebookSignUp: 'Sign up with Facebook',
|
||||
logout: 'Logout',
|
||||
signIn: 'Sign In',
|
||||
signIn: 'Sign in to join the conversation',
|
||||
or: 'Or',
|
||||
email: 'E-mail Address',
|
||||
password: 'Password',
|
||||
@@ -30,15 +30,24 @@ export default {
|
||||
checkTheForm: 'Invalid Form. Please, check the fields'
|
||||
},
|
||||
'createdisplay': {
|
||||
writeyourusername: 'Write your username',
|
||||
yourusername: 'Your username is publicly visible on all comments you post. A username is needed before you can post your first comment.',
|
||||
writeyourusername: 'Edit your username',
|
||||
yourusername: 'Your username appears on every comment you post.',
|
||||
ifyoudontchangeyourname: 'If you don\'t change your username at this step, your Facebook display name will appear alongside of all your comments.',
|
||||
username: 'Username',
|
||||
continue: 'Continue with the same Facebook username',
|
||||
save: 'Save',
|
||||
fakecommentdate: '1 minute ago',
|
||||
fakecommentbody: 'This is an example comment. Readers can share their thoughts and opinions with newsrooms in the comments section.',
|
||||
requiredField: 'Required field',
|
||||
errorCreate: 'Error when changing username',
|
||||
checkTheForm: 'Invalid Form. Please, check the fields',
|
||||
specialCharacters: 'Usernames can contain letters, numbers and _ only'
|
||||
}
|
||||
},
|
||||
'permalink': {
|
||||
permalink: 'Link'
|
||||
},
|
||||
'report': 'Report',
|
||||
'like': 'Like',
|
||||
},
|
||||
es: {
|
||||
'signIn': {
|
||||
@@ -51,7 +60,7 @@ export default {
|
||||
facebookSignIn: 'Entrar con Facebook',
|
||||
facebookSignUp: 'Regístrate con Facebook',
|
||||
logout: 'Salir',
|
||||
signIn: 'Entrar',
|
||||
signIn: 'Entrar para Unirte a la Conversación',
|
||||
or: 'o',
|
||||
email: 'E-mail',
|
||||
password: 'Contraseña',
|
||||
@@ -71,14 +80,23 @@ export default {
|
||||
checkTheForm: 'Formulario Inválido. Por favor, completa los campos'
|
||||
},
|
||||
'createdisplay': {
|
||||
writeyourusername: 'Escribe tu nombre',
|
||||
yourusername: 'Tu nombre es visible publicamente en todos los comentarios que publiques. Es necesario tener un nombre de usuario antes de poder publicar tu primer comentario.',
|
||||
username: 'Nombre a mostrar',
|
||||
writeyourusername: 'Edita tu nombre',
|
||||
yourusername: 'Tu nombre aparece en cada comentario que publiques.',
|
||||
ifyoudontchangeyourname: 'Si no modificas tu nombre de usuario en este paso, tu nombre de Facebook aparecera al lado de cada comentario que publiques.',
|
||||
username: 'Nombre',
|
||||
continue: 'Continuar con nombre de Facebook',
|
||||
save: 'Guardar',
|
||||
fakecommentdate: 'hace un minuto',
|
||||
fakecommentbody: 'Este es un comentario de ejemplo. Las lectoras pueden compartir sus ideas y opiniones con los periodistas en la sección de comentarios.',
|
||||
requiredField: 'Campo necesario',
|
||||
errorCreate: 'Hubo un error al cambiar el nombre de usuario',
|
||||
checkTheForm: 'Formulario Invalido. Por favor, verifica los campos',
|
||||
specialCharacters: 'Sólo pueden contener letras, números y _'
|
||||
},
|
||||
'permalink': {
|
||||
permalink: 'Enlace'
|
||||
},
|
||||
'report': 'Informe',
|
||||
'like': 'Me gusta',
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
const Action = {
|
||||
__resolveType({action_type}) {
|
||||
switch (action_type) {
|
||||
case 'DONTAGREE':
|
||||
return 'DontAgreeAction';
|
||||
case 'FLAG':
|
||||
return 'FlagAction';
|
||||
case 'LIKE':
|
||||
|
||||
@@ -5,6 +5,8 @@ const ActionSummary = {
|
||||
return 'FlagActionSummary';
|
||||
case 'LIKE':
|
||||
return 'LikeActionSummary';
|
||||
case 'DONTAGREE':
|
||||
return 'DontAgreeActionSummary';
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
const DontAgreeAction = {
|
||||
|
||||
// Stored in the metadata, extract and return.
|
||||
reason({metadata: {reason}}) {
|
||||
return reason;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DontAgreeAction;
|
||||
@@ -0,0 +1,7 @@
|
||||
const DontAgreeActionSummary = {
|
||||
reason({group_id}) {
|
||||
return group_id;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DontAgreeActionSummary;
|
||||
@@ -6,6 +6,8 @@ const Comment = require('./comment');
|
||||
const Date = require('./date');
|
||||
const FlagActionSummary = require('./flag_action_summary');
|
||||
const FlagAction = require('./flag_action');
|
||||
const DontAgreeAction = require('./dont_agree_action');
|
||||
const DontAgreeActionSummary = require('./dont_agree_action_summary');
|
||||
const GenericUserError = require('./generic_user_error');
|
||||
const LikeAction = require('./like_action');
|
||||
const RootMutation = require('./root_mutation');
|
||||
@@ -24,6 +26,8 @@ module.exports = {
|
||||
Date,
|
||||
FlagActionSummary,
|
||||
FlagAction,
|
||||
DontAgreeAction,
|
||||
DontAgreeActionSummary,
|
||||
GenericUserError,
|
||||
LikeAction,
|
||||
RootMutation,
|
||||
|
||||
@@ -13,7 +13,6 @@ const wrapResponse = (key) => (promise) => {
|
||||
}
|
||||
return res;
|
||||
}).catch((err) => {
|
||||
|
||||
if (err instanceof errors.APIError) {
|
||||
return {
|
||||
errors: [err]
|
||||
@@ -38,6 +37,9 @@ const RootMutation = {
|
||||
createFlag(_, {flag: {item_id, item_type, reason, message}}, {mutators: {Action}}) {
|
||||
return wrapResponse('flag')(Action.create({item_id, item_type, action_type: 'FLAG', group_id: reason, metadata: {message}}));
|
||||
},
|
||||
createDontAgree(_, {dontagree: {item_id, item_type, reason, message}}, {mutators: {Action}}) {
|
||||
return wrapResponse('dontagree')(Action.create({item_id, item_type, action_type: 'DONTAGREE', group_id: reason, metadata: {message}}));
|
||||
},
|
||||
deleteAction(_, {id}, {mutators: {Action}}) {
|
||||
return wrapResponse(null)(Action.delete({id}));
|
||||
},
|
||||
|
||||
+79
-10
@@ -91,6 +91,9 @@ enum ACTION_TYPE {
|
||||
|
||||
# Represents a FlagAction.
|
||||
FLAG
|
||||
|
||||
# Represents a don't agree action
|
||||
DONTAGREE
|
||||
}
|
||||
|
||||
# CommentsQuery allows the ability to query comments by a specific methods.
|
||||
@@ -187,7 +190,7 @@ type Comment {
|
||||
## Actions
|
||||
################################################################################
|
||||
|
||||
# An action rendered against a parent enity item.
|
||||
# An action rendered against a parent entity item.
|
||||
interface Action {
|
||||
|
||||
# The ID of the action.
|
||||
@@ -290,6 +293,28 @@ type FlagAction implements Action {
|
||||
created_at: Date
|
||||
}
|
||||
|
||||
# A DONTAGREE action that contains do not agree metadata.
|
||||
type DontAgreeAction implements Action {
|
||||
|
||||
# The ID of the DontAgree Action.
|
||||
id: ID!
|
||||
|
||||
# The reason for which the DontAgree Action was created.
|
||||
reason: String
|
||||
|
||||
# An optional message sent with the flagging action by the user.
|
||||
message: String
|
||||
|
||||
# The user who created the action.
|
||||
user: User
|
||||
|
||||
# The time when the DontAgree Action was updated.
|
||||
updated_at: Date
|
||||
|
||||
# The time when the DontAgree Action was created.
|
||||
created_at: Date
|
||||
}
|
||||
|
||||
# Summary for Flag Action with a a unique reason.
|
||||
type FlagActionSummary implements ActionSummary {
|
||||
|
||||
@@ -303,6 +328,19 @@ type FlagActionSummary implements ActionSummary {
|
||||
current_user: FlagAction
|
||||
}
|
||||
|
||||
# Summary for Don't Agree Action with a a unique reason.
|
||||
type DontAgreeActionSummary implements ActionSummary {
|
||||
|
||||
# The total count of flags with this reason.
|
||||
count: Int!
|
||||
|
||||
# The reason for which the Flag Action was created.
|
||||
reason: String
|
||||
|
||||
# The don't agree action by the current user against the parent entity with this reason.
|
||||
current_user: DontAgreeAction
|
||||
}
|
||||
|
||||
################################################################################
|
||||
## Settings
|
||||
################################################################################
|
||||
@@ -472,18 +510,18 @@ type RootQuery {
|
||||
# Response defines what can be expected from any response to a mutation action.
|
||||
interface Response {
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
# CreateCommentResponse is returned with the comment that was created and any
|
||||
# errors that may have occured in the attempt to create it.
|
||||
# errors that may have occurred in the attempt to create it.
|
||||
type CreateCommentResponse implements Response {
|
||||
|
||||
# The comment that was created.
|
||||
comment: Comment
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
@@ -514,7 +552,7 @@ type CreateLikeResponse implements Response {
|
||||
# The like that was created.
|
||||
like: LikeAction
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
@@ -538,18 +576,46 @@ input CreateFlagInput {
|
||||
# was created.
|
||||
type CreateFlagResponse implements Response {
|
||||
|
||||
# The like that was created.
|
||||
# The flag that was created.
|
||||
flag: FlagAction
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
|
||||
# CreateDontAgreeResponse is the response returned with possibly some errors
|
||||
# relating to the creating the don't agree action attempt and possibly the don't agree that
|
||||
# was created.
|
||||
type CreateDontAgreeResponse implements Response {
|
||||
|
||||
# The don't agree that was created.
|
||||
dontagree: DontAgreeAction
|
||||
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
input CreateDontAgreeInput {
|
||||
|
||||
# The item's id for which we are to create a don't agree.
|
||||
item_id: ID!
|
||||
|
||||
# The type of the item for which we are to create the don't agree.
|
||||
item_type: ACTION_ITEM_TYPE!
|
||||
|
||||
# The reason for not agreeing with the item.
|
||||
reason: String
|
||||
|
||||
# An optional message sent with the don't agree action by the user.
|
||||
message: String
|
||||
}
|
||||
|
||||
# DeleteActionResponse is the response returned with possibly some errors
|
||||
# relating to the delete action attempt.
|
||||
type DeleteActionResponse implements Response {
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
@@ -557,7 +623,7 @@ type DeleteActionResponse implements Response {
|
||||
# relating to the delete action attempt.
|
||||
type SetUserStatusResponse implements Response {
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
@@ -565,7 +631,7 @@ type SetUserStatusResponse implements Response {
|
||||
# relating to the delete action attempt.
|
||||
type SetCommentStatusResponse implements Response {
|
||||
|
||||
# An array of errors relating to the mutation that occured.
|
||||
# An array of errors relating to the mutation that occurred.
|
||||
errors: [UserError]
|
||||
}
|
||||
|
||||
@@ -581,6 +647,9 @@ type RootMutation {
|
||||
# Creates a flag on an entity.
|
||||
createFlag(flag: CreateFlagInput!): CreateFlagResponse
|
||||
|
||||
# Creates a don't agree action on an entity.
|
||||
createDontAgree(dontagree: CreateDontAgreeInput!): CreateDontAgreeResponse
|
||||
|
||||
# Delete an action based on the action id.
|
||||
deleteAction(id: ID!): DeleteActionResponse
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ const express = require('express');
|
||||
const passport = require('../../../services/passport');
|
||||
const authorization = require('../../../middleware/authorization');
|
||||
const errors = require('../../../errors');
|
||||
const UsersService = require('../../../services/users');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -61,6 +60,7 @@ const HandleAuthCallback = (req, res, next) => (err, user) => {
|
||||
/**
|
||||
* Returns the response to the login attempt via a popup callback with some JS.
|
||||
*/
|
||||
|
||||
const HandleAuthPopupCallback = (req, res, next) => (err, user) => {
|
||||
if (err) {
|
||||
return res.render('auth-callback', {err: JSON.stringify(err), data: null});
|
||||
@@ -70,20 +70,15 @@ const HandleAuthPopupCallback = (req, res, next) => (err, user) => {
|
||||
return res.render('auth-callback', {err: JSON.stringify(errors.ErrNotAuthorized), data: null});
|
||||
}
|
||||
|
||||
// Authorize the user to edit their username.
|
||||
UsersService.toggleNameEdit(user.id, true)
|
||||
.then(() => {
|
||||
|
||||
// Perform the login of the user!
|
||||
req.logIn(user, (err) => {
|
||||
if (err) {
|
||||
return res.render('auth-callback', {err: JSON.stringify(err), data: null});
|
||||
}
|
||||
// Perform the login of the user!
|
||||
req.logIn(user, (err) => {
|
||||
if (err) {
|
||||
return res.render('auth-callback', {err: JSON.stringify(err), data: null});
|
||||
}
|
||||
|
||||
// We logged in the user! Let's send back the user data.
|
||||
res.render('auth-callback', {err: null, data: JSON.stringify(user)});
|
||||
});
|
||||
});
|
||||
// We logged in the user! Let's send back the user data.
|
||||
res.render('auth-callback', {err: null, data: JSON.stringify(user)});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
+4
-1
@@ -124,6 +124,8 @@ module.exports = class UsersService {
|
||||
return user;
|
||||
}
|
||||
|
||||
// User does not exist and need to be created.
|
||||
|
||||
let username = UsersService.castUsername(displayName);
|
||||
|
||||
// The user was not found, lets create them!
|
||||
@@ -131,7 +133,8 @@ module.exports = class UsersService {
|
||||
username,
|
||||
lowercaseUsername: username.toLowerCase(),
|
||||
roles: [],
|
||||
profiles: [{id, provider}]
|
||||
profiles: [{id, provider}],
|
||||
canEditName: true
|
||||
});
|
||||
|
||||
return user.save();
|
||||
|
||||
Reference in New Issue
Block a user