diff --git a/client/coral-admin/src/components/Comment.js b/client/coral-admin/src/components/Comment.js index 380a001c8..4a21b0846 100644 --- a/client/coral-admin/src/components/Comment.js +++ b/client/coral-admin/src/components/Comment.js @@ -14,18 +14,18 @@ const linkify = new Linkify(); // Render a single comment for the list export default props => { - const authorStatus = props.author.get('status'); const {comment, author} = props; - const links = linkify.getMatches(comment.get('body')); + let authorStatus = author.status; + const links = linkify.getMatches(comment.body); return (
  • person - {author.get('displayName') || lang.t('comment.anon')} - {timeago().format(comment.get('createdAt') || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))} - {comment.get('flagged') ?

    {lang.t('comment.flagged')}

    : null} + {author.displayName || lang.t('comment.anon')} + {timeago().format(comment.createdAt || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))} + {comment.flagged ?

    {lang.t('comment.flagged')}

    : null}
    {links ? @@ -42,7 +42,7 @@ export default props => {
    - {comment.get('body')} + {comment.body}
    @@ -52,9 +52,10 @@ export default props => { // Get the button of the action performed over a comment if any const getActionButton = (action, i, props) => { - const status = props.comment.get('status'); - const flagged = props.comment.get('flagged'); - const banned = (props.author.get('status') === 'banned'); + const {comment, author} = props; + const status = comment.status; + const flagged = comment.flagged; + const banned = (author.status === 'banned'); if (action === 'flag' && (status || flagged === true)) { return null; @@ -64,17 +65,19 @@ const getActionButton = (action, i, props) => { ); } return ( - props.onClickAction(props.actionsMap[action].status, props.comment.get('id'))} + onClick={() => props.onClickAction(props.actionsMap[action].status, comment.id)} /> ); }; diff --git a/client/coral-admin/src/components/CommentList.js b/client/coral-admin/src/components/CommentList.js index b4547335e..8c6655bb5 100644 --- a/client/coral-admin/src/components/CommentList.js +++ b/client/coral-admin/src/components/CommentList.js @@ -37,7 +37,7 @@ export default class CommentList extends React.Component { // If entering to singleview and no active, active is the first eleement componentWillReceiveProps (nextProps) { if (nextProps.singleView && !this.state.active) { - this.setState({active: nextProps.commentIds.get(0)}); + this.setState({active: nextProps.commentIds[0]}); } } @@ -81,12 +81,12 @@ export default class CommentList extends React.Component { const {commentIds} = this.props; const {active} = this.state; // check boundaries - if (active === null || !commentIds.size) { - this.setState({active: commentIds.get(0)}); - } else if (direction === 'up' && active !== commentIds.first()) { - this.setState({active: commentIds.get(commentIds.indexOf(active) - 1)}); - } else if (direction === 'down' && active !== commentIds.last()) { - this.setState({active: commentIds.get(commentIds.indexOf(active) + 1)}); + if (active === null || !commentIds.length) { + this.setState({active: commentIds[0]}); + } else if (direction === 'up' && active !== commentIds[0]) { + this.setState({active: commentIds[commentIds.indexOf(active) - 1]}); + } else if (direction === 'down' && active !== commentIds[commentIds.length - 1]) { + this.setState({active: commentIds[commentIds.indexOf(active) + 1]}); } // scroll to the position @@ -105,10 +105,10 @@ export default class CommentList extends React.Component { // activate the next comment if (id === this.state.active) { const {commentIds} = this.props; - if (commentIds.last() === this.state.active) { - this.setState({active: commentIds.get(commentIds.size - 2)}); + if (commentIds[commentIds.length - 1] === this.state.active) { + this.setState({active: commentIds[commentIds.length - 2]}); } else { - this.setState({active: commentIds.get(Math.min(commentIds.indexOf(this.state.active) + 1, commentIds.size - 1))}); + this.setState({active: commentIds[Math.min(commentIds.indexOf(this.state.active) + 1, commentIds.length - 1)]}); } } this.props.onClickAction(action, id, author_id); @@ -125,10 +125,10 @@ export default class CommentList extends React.Component { return (
      {commentIds.map((commentId, index) => { - const comment = comments.get(commentId); + const comment = comments[commentId]; + const author = users[comment.author_id]; return { if (el && commentId === active) { this._active = el; } }} + author={author} key={index} index={index} onClickAction={this.onClickAction} @@ -137,7 +137,7 @@ export default class CommentList extends React.Component { actionsMap={actions} isActive={commentId === active} hideActive={hideActive} />; - }).toArray()} + })}
    ); } diff --git a/client/coral-admin/src/containers/CommentStream/CommentStream.js b/client/coral-admin/src/containers/CommentStream/CommentStream.js index 113a7bc86..556e50463 100644 --- a/client/coral-admin/src/containers/CommentStream/CommentStream.js +++ b/client/coral-admin/src/containers/CommentStream/CommentStream.js @@ -46,9 +46,9 @@ class CommentStream extends React.Component { @@ -58,4 +58,9 @@ class CommentStream extends React.Component { } } -export default connect(({comments, users}) => ({comments, users}))(CommentStream); +const mapStateToProps = state => ({ + comments: state.comments.toJS(), + users: state.users.toJS() +}); + +export default connect(mapStateToProps)(CommentStream); diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js index 34b418a57..e0e3c636f 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js @@ -79,6 +79,10 @@ class ModerationQueue extends React.Component { const {comments, users} = this.props; const {activeTab, singleView, modalOpen} = this.state; + 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); + return (
    @@ -94,41 +98,26 @@ class ModerationQueue extends React.Component { - comments - .get('byId') - .get(id) - .get('status') === 'premod') - } - comments={comments.get('byId')} - users={users.get('byId')} + commentIds={premodIds} + comments={comments.byId} + users={users.byId} onClickAction={(action, commentId) => this.onCommentAction(action, commentId)} onClickShowBanDialog={(userId, userName, commentId) => this.showBanUserDialog(userId, userName, commentId)} actions={['reject', 'approve', 'ban']} loading={comments.loading} /> this.hideBanUserDialog()} onClickBanUser={(userId, commentId) => this.banUser(userId, commentId)} - user={comments.get('banUser')}/> + user={comments.banUser}/>
    - comments - .get('byId') - .get(id) - .get('status') === 'rejected') - } - comments={comments.get('byId')} - users={users.get('byId')} + commentIds={rejectedIds} + comments={comments.byId} + users={users.byId} onClickAction={(action, id) => this.onCommentAction(action, id)} actions={['approve']} loading={comments.loading} /> @@ -137,12 +126,9 @@ class ModerationQueue extends React.Component { { - const data = comments.get('byId').get(id); - return !data.get('status') && data.get('flagged') === true; - })} - comments={comments.get('byId')} - users={users.get('byId')} + commentIds={flaggedIds} + comments={comments.byId} + users={users.byId} onClickAction={(action, id) => this.onCommentAction(action, id)} actions={['reject', 'approve']} loading={comments.loading} /> @@ -155,6 +141,11 @@ class ModerationQueue extends React.Component { } } -export default connect(({comments, users}) => ({comments, users}))(ModerationQueue); +const mapStateToProps = state => ({ + comments: state.comments.toJS(), + users: state.users.toJS() +}); + +export default connect(mapStateToProps)(ModerationQueue); const lang = new I18n(translations); diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index e23326804..e462f7567 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -101,7 +101,7 @@ }, "configure": { "enable-pre-moderation": "Habilitar pre-moderación", - "enable-pre-moderation-text": "tracundeme!", + "enable-pre-moderation-text": "Los moderadores deben aprobar cada comentario antes de que sea publicado.", "include-comment-stream": "Incluir la Descripción a un Hilo de Comentario para los y las Lectoras.", "include-comment-stream-desc": "Escribir un mensaje que será agregado a la parte de arriba del tu hilo de comentarios. Por ejemplo, un tema, guias de comunidad, etc.", "include-text": "Incluir tu texto aqui.", diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 464ae0083..c5390607c 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -74,7 +74,7 @@ const signUpFailure = error => ({type: actions.FETCH_SIGNUP_FAILURE, error}); export const fetchSignUp = formData => dispatch => { dispatch(signUpRequest()); - coralApi('/user', {method: 'POST', body: formData}) + coralApi('/users', {method: 'POST', body: formData}) .then(({user}) => { dispatch(signUpSuccess(user)); setTimeout(() =>{ diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index d5df14e3d..086a0cf36 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -60,8 +60,7 @@ class CommentBox extends Component { postItem(comment, 'comments') .then((postedComment) => { const commentId = postedComment.id; - const status = postedComment.status; - if (status[0] && status[0].type === 'rejected') { + if (postedComment.status === 'rejected') { addNotification('error', lang.t('comment-post-banned-word')); } else if (premod === 'pre') { addNotification('success', lang.t('comment-post-notif-premod')); diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index 168b89fc3..3ca2f4877 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -97,7 +97,13 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { // Return `premod` if pre-moderation is enabled and an empty "new" status // in the event that it is not in pre-moderation mode. - .then(({moderation}) => moderation === 'pre' ? 'premod' : ''); + .then(({moderation, charCountEnable, charCount}) => { + // Reject if the comment is too long + if (charCountEnable && body.length > charCount) { + return 'rejected'; + } + return moderation === 'pre' ? 'premod' : ''; + }); } status.then((status) => Comment.publicCreate({ diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index b3e4e2675..fdd4e4bbe 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -197,6 +197,28 @@ describe('/api/v1/comments', () => { }); }); + it('should create a rejected comment if the body is above the character count', () => { + return Asset + .findOrCreateByUrl('https://coralproject.net/article1') + .then((asset) => { + return Asset + .overrideSettings(asset.id, {charCountEnable: true, charCount: 10}) + .then(() => asset); + }) + .then((asset) => { + return chai.request(app) + .post('/api/v1/comments') + .set(passport.inject({roles: []})) + .send({'body': 'This is way way way way way too long.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''}); + }) + .then((res) => { + expect(res).to.have.status(201); + expect(res.body).to.have.property('id'); + expect(res.body).to.have.property('asset_id'); + expect(res.body).to.have.property('status', 'rejected'); + }); + }); + it('shouldn\'t create a comment when the asset has expired commenting', () => { return Asset.create({ closedAt: new Date().setDate(0),