Merge branch 'master' into subscribe-mod-actions

This commit is contained in:
Chi Vinh Le
2017-06-19 21:17:33 +07:00
34 changed files with 273 additions and 67 deletions
+1
View File
@@ -11,4 +11,5 @@ plugins/*
!plugins/coral-plugin-mod
!plugins/coral-plugin-love
!plugins/coral-plugin-viewing-options
!plugins/coral-plugin-comment-content
node_modules
+1
View File
@@ -24,5 +24,6 @@ plugins/*
!plugins/coral-plugin-mod
!plugins/coral-plugin-love
!plugins/coral-plugin-viewing-options
!plugins/coral-plugin-comment-content
**/node_modules/*
+7 -6
View File
@@ -8,6 +8,7 @@ const program = require('./commander');
const inquirer = require('inquirer');
const UsersService = require('../services/users');
const UserModel = require('../models/user');
const USER_ROLES = require('../models/enum/user_roles');
const mongoose = require('../services/mongoose');
const util = require('./util');
const Table = require('cli-table');
@@ -36,7 +37,7 @@ function getUserCreateAnswers(options) {
roles: []
};
if (options.role && UserModel.USER_ROLES.indexOf(options.role) > -1) {
if (options.role && USER_ROLES.indexOf(options.role) > -1) {
user.roles = [options.role];
}
@@ -89,7 +90,7 @@ function getUserCreateAnswers(options) {
name: 'roles',
message: 'User Role',
type: 'checkbox',
choices: UserModel.USER_ROLES
choices: USER_ROLES
}
]);
}
@@ -291,8 +292,8 @@ function mergeUsers(dstUserID, srcUserID) {
*/
function addRole(userID, role) {
if (UserModel.USER_ROLES.indexOf(role) === -1) {
console.error(`Role '${role}' is not supported. Supported roles are ${UserModel.USER_ROLES.join(', ')}.`);
if (USER_ROLES.indexOf(role) === -1) {
console.error(`Role '${role}' is not supported. Supported roles are ${USER_ROLES.join(', ')}.`);
util.shutdown(1);
return;
}
@@ -316,8 +317,8 @@ function addRole(userID, role) {
*/
function removeRole(userID, role) {
if (UserModel.USER_ROLES.indexOf(role) === -1) {
console.error(`Role '${role}' is not supported. Supported roles are ${UserModel.USER_ROLES.join(', ')}.`);
if (USER_ROLES.indexOf(role) === -1) {
console.error(`Role '${role}' is not supported. Supported roles are ${USER_ROLES.join(', ')}.`);
util.shutdown(1);
return;
}
@@ -3,13 +3,13 @@ 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';
import FlagComment from 'coral-plugin-flags/FlagComment';
import {can} from 'coral-framework/services/perms';
import {TransitionGroup} from 'react-transition-group';
import cn from 'classnames';
import styles from './Comment.css';
import {
BestButton,
@@ -18,14 +18,14 @@ import {
commentIsBest,
BestIndicator
} from 'coral-plugin-best/BestButton';
import Slot from 'coral-framework/components/Slot';
import LoadMore from './LoadMore';
import {getEditableUntilDate} from './util';
import {TopRightMenu} from './TopRightMenu';
import CommentContent from './CommentContent';
import Slot from 'coral-framework/components/Slot';
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
import {EditableCommentContent} from './EditableCommentContent';
import {getActionSummary, iPerformedThisAction} from 'coral-framework/utils';
import {getEditableUntilDate} from './util';
import styles from './Comment.css';
const isStaff = (tags) => !tags.every((t) => t.tag.name !== 'STAFF');
const hasTag = (tags, lookupTag) => !!tags.filter((t) => t.tag.name === lookupTag).length;
@@ -466,8 +466,7 @@ export default class Comment extends React.Component {
stopEditing={this.stopEditing}
/>
: <div>
<Content body={comment.body} />
<Slot fill="commentContent" />
<Slot fill="commentContent" comment={comment} defaultComponent={CommentContent} />
</div>
}
@@ -0,0 +1,19 @@
import React from 'react';
const CommentContent = ({comment}) => {
const textbreaks = comment.body.split('\n');
return <div className={`${name}-text`}>
{
textbreaks.map((line, i) => {
return (
<span key={i} className={`${name}-line`}>
{line}
<br className={`${name}-linebreak`}/>
</span>
);
})
}
</div>;
};
export default CommentContent;
+6
View File
@@ -54,6 +54,12 @@ function configurePymParent(pymParent, opts) {
pymParent.sendMessage('config', JSON.stringify(config));
}
pymParent.onMessage('coral-auth-changed', function(message) {
if (opts.onAuthChanged) {
opts.onAuthChanged(message ? JSON.parse(message) : null);
}
});
// Sends config to the child
pymParent.onMessage('getConfig', function() {
sendConfig(opts || {});
+3
View File
@@ -3,6 +3,7 @@ import bowser from 'bowser';
import * as actions from '../constants/auth';
import * as Storage from '../helpers/storage';
import coralApi, {base} from '../helpers/request';
import pym from '../services/PymConnection';
import {resetWebsocket} from 'coral-framework/services/client';
import t from 'coral-framework/services/i18n';
@@ -284,6 +285,7 @@ export const logout = () => (dispatch) => {
resetWebsocket();
dispatch({type: actions.LOGOUT});
pym.sendMessage('coral-auth-changed');
});
};
@@ -315,6 +317,7 @@ export const checkLogin = () => (dispatch) => {
resetWebsocket();
dispatch(checkLoginSuccess(result.user));
pym.sendMessage('coral-auth-changed', JSON.stringify(result.user));
// Display create username dialog if necessary.
if (result.user.canEditName && result.user.status !== 'BANNED') {
+7 -2
View File
@@ -4,10 +4,15 @@ import styles from './Slot.css';
import {connect} from 'react-redux';
import {getSlotElements} from 'coral-framework/helpers/plugins';
function Slot ({fill, inline = false, className, plugin_config: config, ...rest}) {
function Slot ({fill, inline = false, className, plugin_config: config, defaultComponent: DefaultComponent, ...rest}) {
let children = getSlotElements(fill, {...rest, config});
if (children.length === 0 && DefaultComponent) {
children = <DefaultComponent {...rest} />;
}
return (
<div className={cn({[styles.inline]: inline, [styles.debug]: config.debug}, className)}>
{getSlotElements(fill, {...rest, config})}
{children}
</div>
);
}
@@ -1,17 +0,0 @@
import React from 'react';
const name = 'coral-plugin-commentcontent';
const Content = ({body, styles}) => {
const textbreaks = body.split('\n');
return <div
className={`${name}-text`}
style={styles && styles.text}>
{
textbreaks.map((line, i) => <span key={i} className={`${name}-line`}>
{line} <br className={`${name}-linebreak`}/>
</span>)
}
</div>;
};
export default Content;
@@ -1,11 +0,0 @@
import React from 'react';
import {shallow} from 'enzyme';
import {expect} from 'chai';
import CommentContent from '../CommentContent';
describe('CommentContent', () => {
it('should render content', () => {
const render = shallow(<CommentContent content="test"/>);
expect(render.contains('test')).to.be.truthy;
});
});
+6 -3
View File
@@ -1,8 +1,9 @@
import React, {PropTypes} from 'react';
import {Icon} from '../coral-ui';
import styles from './Comment.css';
import Slot from 'coral-framework/components/Slot';
import PubDate from '../coral-plugin-pubdate/PubDate';
import Content from '../coral-plugin-commentcontent/CommentContent';
import CommentContent from '../coral-embed-stream/src/components/CommentContent';
import t from 'coral-framework/services/i18n';
@@ -10,9 +11,11 @@ const Comment = (props) => {
return (
<div className={styles.myComment}>
<div>
<Content
<Slot
fill="commentContent"
defaultComponent={CommentContent}
className={`${styles.commentBody} myCommentBody`}
body={props.comment.body}
comment={props.comment}
/>
<p className="myCommentAsset">
<a
+3 -3
View File
@@ -94,13 +94,13 @@ en:
edit_comment_timeframe_text_pre: "Commenters will have"
edit_comment_timeframe_text_post: "seconds to edit their comments."
embed_comment_stream: "Embed Stream"
enable_premod_links_text: "Moderators must approve any comment containing a link before its published."
enable_premod_links_text: "Moderators must approve any comment containing a link before it is published."
enable_pre_moderation: "Enable pre-moderation"
enable_pre_moderation_text: "Moderators must approve any comment before it is published."
enable_premod_links: "Pre-Moderate Comments Containing Links"
enable_premod: "Enable Premoderation"
enable_premod_description: "Moderators must approve any comment before its published."
enable_premod_links_description: "Moderators must approve any comment containing a link before its published."
enable_premod_description: "Moderators must approve any comment before it is published."
enable_premod_links_description: "Moderators must approve any comment containing a link before it is published."
enable_questionbox: "Ask Readers a Question"
enable_questionbox_description: "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc."
hours: Hours
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "talk",
"version": "1.9.1",
"version": "2.0.1",
"description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net",
"main": "app.js",
"scripts": {
@@ -1,2 +1 @@
export {Slot} from 'coral-framework/components';
export {Icon} from 'coral-ui';
@@ -0,0 +1 @@
export * from 'coral-ui';
+2 -1
View File
@@ -11,6 +11,7 @@
"coral-plugin-like",
"coral-plugin-auth",
"coral-plugin-offtopic",
"coral-plugin-viewing-options"
"coral-plugin-viewing-options",
"coral-plugin-comment-content"
]
}
@@ -1,8 +1,7 @@
import React from 'react';
import styles from './styles.css';
import {Dialog, Alert, TextField} from 'coral-ui';
import {Dialog, Alert, TextField, Button} from 'plugin-api/beta/client/components/ui';
import {FakeComment} from './FakeComment';
import Button from 'coral-ui/components/Button';
import t from 'coral-framework/services/i18n';
const CreateUsernameDialog = ({
@@ -33,7 +32,7 @@ const CreateUsernameDialog = ({
className={styles.fakeComment}
username={formData.username}
created_at={Date.now()}
body={t('createdisplay.fake_comment_body')}
comment={{body:t('createdisplay.fake_comment_body')}}
/>
<p className={styles.ifyoudont}>
{t('createdisplay.if_you_dont_change_your_name')}
@@ -1,17 +1,17 @@
import React from 'react';
import t from 'coral-framework/services/i18n';
import {ReplyButton} from 'coral-plugin-replies';
import PubDate from 'coral-plugin-pubdate/PubDate';
import Slot from 'coral-framework/components/Slot';
import AuthorName from 'coral-plugin-author-name/AuthorName';
import Content from 'coral-plugin-commentcontent/CommentContent';
import styles from 'coral-embed-stream/src/components/Comment.css';
import t from 'coral-framework/services/i18n';
export const FakeComment = ({username, created_at, body}) => (
export const FakeComment = ({username, created_at, comment}) => (
<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} />
<Slot comment={comment} />
<div className="commentActionsLeft comment__action-container">
<div className={`${'coral-plugin-likes'}-container`}>
<button className={'coral-plugin-likes-button'}>
@@ -1,6 +1,6 @@
import React from 'react';
import styles from './styles.css';
import Button from 'coral-ui/components/Button';
import {Button} from 'plugin-api/beta/client/components/ui';
import t from 'coral-framework/services/i18n';
class ForgotContent extends React.Component {
@@ -1,5 +1,5 @@
import React from 'react';
import {Dialog} from 'coral-ui';
import {Dialog} from 'plugin-api/beta/client/components/ui';
import styles from './styles.css';
import SignInContent from './SignInContent';
@@ -1,5 +1,5 @@
import React from 'react';
import {Button} from 'coral-ui';
import {Button} from 'plugin-api/beta/client/components/ui';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {showSignInDialog} from 'coral-framework/actions/auth';
@@ -1,5 +1,5 @@
import React, {PropTypes} from 'react';
import {Button, TextField, Spinner, Success, Alert} from 'coral-ui';
import {Button, TextField, Spinner, Success, Alert} from 'plugin-api/beta/client/components/ui';
import styles from './styles.css';
import t from 'coral-framework/services/i18n';
@@ -1,6 +1,6 @@
import styles from './styles.css';
import React from 'react';
import {Button, TextField, Spinner, Success, Alert} from 'coral-ui';
import {Button, TextField, Spinner, Success, Alert} from 'plugin-api/beta/client/components/ui';
import t from 'coral-framework/services/i18n';
class SignUpContent extends React.Component {
@@ -0,0 +1,14 @@
{
"presets": [
"es2015"
],
"plugins": [
"add-module-exports",
"transform-class-properties",
"transform-decorators-legacy",
"transform-object-assign",
"transform-object-rest-spread",
"transform-async-to-generator",
"transform-react-jsx"
]
}
@@ -0,0 +1,23 @@
{
"env": {
"browser": true,
"es6": true,
"mocha": true
},
"parserOptions": {
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
}
},
"parser": "babel-eslint",
"plugins": [
"react"
],
"rules": {
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"no-console": ["warn", { "allow": ["warn", "error"] }]
}
}
@@ -0,0 +1,24 @@
import React from 'react';
import Linkify from 'react-linkify';
const name = 'coral-plugin-comment-content';
const CommentContent = ({comment}) => {
const textbreaks = comment.body.split('\n');
return <div className={`${name}-text`}>
{
textbreaks.map((line, i) => {
return (
<span key={i} className={`${name}-line`}>
<Linkify properties={{target: '_blank'}}>
{line}
</Linkify>
<br className={`${name}-linebreak`}/>
</span>
);
})
}
</div>;
};
export default CommentContent;
@@ -0,0 +1,7 @@
import CommentContent from './components/CommentContent';
export default {
slots: {
commentContent: [CommentContent]
}
};
@@ -0,0 +1 @@
module.exports = {};
@@ -0,0 +1,14 @@
{
"name": "coral-plugin-comment-content",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"react-linkify": "^0.2.1"
}
}
@@ -0,0 +1,112 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
asap@~2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
dependencies:
iconv-lite "~0.4.13"
fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
loose-envify "^1.0.0"
object-assign "^4.1.0"
promise "^7.1.1"
setimmediate "^1.0.5"
ua-parser-js "^0.7.9"
iconv-lite@~0.4.13:
version "0.4.18"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
isomorphic-fetch@^2.1.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
linkify-it@^1.2.0:
version "1.2.4"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-1.2.4.tgz#0773526c317c8fd13bd534ee1d180ff88abf881a"
dependencies:
uc.micro "^1.0.1"
loose-envify@^1.0.0, loose-envify@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
dependencies:
js-tokens "^3.0.0"
node-fetch@^1.0.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5"
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
promise@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf"
dependencies:
asap "~2.0.3"
prop-types@^15.5.8:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
react-linkify@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/react-linkify/-/react-linkify-0.2.1.tgz#b28d3f9544539a622fec8d42b4800eb9d23bf981"
dependencies:
linkify-it "^1.2.0"
prop-types "^15.5.8"
tlds "^1.57.0"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
tlds@^1.57.0:
version "1.189.0"
resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.189.0.tgz#b8cb46ea76dc2f4a01d45b8d907bf19a66e9f729"
ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
uc.micro@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
whatwg-fetch@>=0.10.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
@@ -2,7 +2,7 @@ import React from 'react';
import styles from './styles.css';
import {withReaction} from 'plugin-api/beta/client/hocs';
import {t, can} from 'plugin-api/beta/client/services';
import {Icon} from 'plugin-api/beta/client/components';
import {Icon} from 'plugin-api/beta/client/components/ui';
import cn from 'classnames';
const plugin = 'coral-plugin-like';
@@ -2,7 +2,7 @@ import React from 'react';
import styles from './styles.css';
import {withReaction} from 'plugin-api/beta/client/hocs';
import {t, can} from 'plugin-api/beta/client/services';
import {Icon} from 'plugin-api/beta/client/components';
import {Icon} from 'plugin-api/beta/client/components/ui';
import cn from 'classnames';
const plugin = 'coral-plugin-love';
@@ -1,6 +1,6 @@
import React from 'react';
import Box from './Box';
import {Button} from 'coral-ui';
import {Button} from 'plugin-api/beta/client/components/ui';
import styles from './styles.css';
export default class Footer extends React.Component {
@@ -1,7 +1,8 @@
import React from 'react';
import cn from 'classnames';
import styles from './ViewingOptions.css';
import {Slot, Icon} from 'plugin-api/beta/client/components';
import {Slot} from 'plugin-api/beta/client/components';
import {Icon} from 'plugin-api/beta/client/components/ui';
const ViewingOptions = (props) => {
const toggleOpen = () => {