merge master

This commit is contained in:
riley
2016-11-16 11:58:01 -07:00
26 changed files with 316 additions and 173 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ import {Button, Icon} from 'react-mdl';
import timeago from 'timeago.js';
import styles from './CommentList.css';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../translations';
import translations from '../translations.json';
// Render a single comment for the list
export default props => (
+8 -4
View File
@@ -2,22 +2,26 @@ import React from 'react';
import {Layout, Navigation, Drawer, Header} from 'react-mdl';
import {Link} from 'react-router';
import styles from './Header.css';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../translations.json';
// App header. If we add a navbar it should be here
export default (props) => (
<Layout fixedDrawer>
<Header title='Talk'>
<Navigation>
<Link className={styles.navLink} to={'/admin/'}>Moderate</Link>
<Link className={styles.navLink} to={'/admin/configure'}>Configure</Link>
<Link className={styles.navLink} to={'/admin/'}>{lang.t('configure.moderate')}</Link>
<Link className={styles.navLink} to={'/admin/configure'}>{lang.t('Configure')}</Link>
</Navigation>
</Header>
<Drawer>
<Navigation>
<Link className={styles.navLink} to={'/admin/'}>Moderate</Link>
<Link className={styles.navLink} to={'/admin/configure'}>Configure</Link>
<Link className={styles.navLink} to={'/admin/'}>{lang.t('configure.moderate')}</Link>
<Link className={styles.navLink} to={'/admin/configure'}>{lang.t('configure.Configure')}</Link>
</Navigation>
</Drawer>
{props.children}
</Layout>
);
const lang = new I18n(translations);
@@ -1,5 +1,5 @@
import I18n from 'coral-framework/i18n/i18n';
import translations from '../translations';
import translations from '../translations.json';
import React from 'react';
import Modal from 'components/Modal';
import styles from './ModerationKeysModal.css';
@@ -2,13 +2,17 @@ import React from 'react';
import {Navigation, Drawer} from 'react-mdl';
import {Link} from 'react-router';
import styles from './Header.css';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../../translations.json';
export default () => (
<Drawer>
<Navigation>
<Link className={styles.navLink} to="/admin">Moderate</Link>
<Link className={styles.navLink} to="/admin/community">Community</Link>
<Link className={styles.navLink} to="/admin/configure">Configure</Link>
<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>
</Drawer>
);
const lang = new I18n(translations);
@@ -2,16 +2,20 @@ import React from 'react';
import {Navigation, Header} from 'react-mdl';
import {Link} from 'react-router';
import styles from './Header.css';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../../translations.json';
export default () => (
<Header title='Talk'>
<Navigation>
<Link className={styles.navLink} to="/admin">Moderate</Link>
<Link className={styles.navLink} to="/admin/community">Community</Link>
<Link className={styles.navLink} to="/admin/configure">Configure</Link>
<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>
<span>
{`v${process.env.VERSION}`}
</span>
</Navigation>
</Header>
);
const lang = new I18n(translations);
@@ -1,6 +1,6 @@
import React from 'react';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../../translations';
import translations from '../../translations.json';
import {Grid, Cell} from 'react-mdl';
import styles from './Community.css';
@@ -23,6 +23,21 @@
cursor: pointer;
}
.configSettingInfoBox {
border: 1px solid #ccc;
border-radius: 4px;
margin-bottom: 10px;
cursor: pointer;
width: auto;
height: auto;
text-align: left;
}
.configSettingInfoBox p {
font-size: 12px;
bottom: 0;
}
.configSettingEmbed {
border: 1px solid #ccc;
border-radius: 4px;
@@ -53,3 +68,7 @@
font-size: 14px;
letter-spacing: 0.03em;
}
.hidden {
display: none;
}
+41 -21
View File
@@ -7,14 +7,14 @@ import {
ListItem,
ListItemContent,
ListItemAction,
//Textfield,
Textfield,
Checkbox,
Button,
Icon
} from 'react-mdl';
import styles from './Configure.css';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../translations';
import translations from '../translations.json';
class Configure extends React.Component {
constructor (props) {
@@ -24,6 +24,8 @@ class Configure extends React.Component {
this.copyToClipBoard = this.copyToClipBoard.bind(this);
this.updateModeration = this.updateModeration.bind(this);
this.updateInfoBoxEnable = this.updateInfoBoxEnable.bind(this);
this.updateInfoBoxContent = this.updateInfoBoxContent.bind(this);
this.saveSettings = this.saveSettings.bind(this);
}
@@ -36,6 +38,16 @@ class Configure extends React.Component {
this.props.dispatch(updateSettings({moderation}));
}
updateInfoBoxEnable () {
const infoBoxEnable = !this.props.settings.infoBoxEnable;
this.props.dispatch(updateSettings({infoBoxEnable}));
}
updateInfoBoxContent (event) {
const infoBoxContent = event.target.value;
this.props.dispatch(updateSettings({infoBoxContent}));
}
saveSettings () {
this.props.dispatch(saveSettingsToServer());
}
@@ -48,22 +60,30 @@ class Configure extends React.Component {
onClick={this.updateModeration}
checked={this.props.settings.moderation === 'pre'} />
</ListItemAction>
Enable pre-moderation
{lang.t('configure.enable-pre-moderation')}
</ListItem>
{/*
<ListItem className={styles.configSetting}>
<ListItemAction><Checkbox /></ListItemAction>
Include Comment Stream Description for Readers
<ListItem threeLine className={styles.configSettingInfoBox}>
<ListItemAction>
<Checkbox
onClick={this.updateInfoBoxEnable}
checked={this.props.settings.infoBoxEnable} />
</ListItemAction>
<ListItemContent>
{lang.t('configure.include-comment-stream')}
<p>
{lang.t('configure.include-comment-stream-desc')}
</p>
</ListItemContent>
</ListItem>
<ListItem className={styles.configSetting}>
<ListItemAction><Checkbox /></ListItemAction>
Limit Comment Length
<Textfield
pattern='-?[0-9]*(\.[0-9]+)?'
error='Input is not a number!'
label='Maximum Characters' />
<ListItem className={`${styles.configSettingInfoBox} ${this.props.settings.infoBoxEnable ? null : styles.hidden}`} >
<ListItemContent>
<Textfield
onChange={this.updateInfoBoxContent}
value={this.props.settings.infoBoxContent}
label={lang.t('configure.include-text')}
rows={3}/>
</ListItemContent>
</ListItem>
*/}
</List>;
}
@@ -84,7 +104,7 @@ class Configure extends React.Component {
return <List>
<ListItem className={styles.configSettingEmbed}>
<p>Copy and paste code below into your CMS to embed your comment box in your articles</p>
<p>{lang.t('configure.copy-and-paste')}</p>
<textarea rows={5} type='text' className={styles.embedInput} value={embedText} readOnly={true}/>
<Button raised colored className={styles.copyButton} onClick={this.copyToClipBoard}>
{lang.t('embedlink.copy')}
@@ -100,8 +120,8 @@ class Configure extends React.Component {
render () {
let pageTitle = this.state.activeSection === 'comments'
? 'Comment Settings'
: 'Embed Comment Stream';
? lang.t('configure.comment-settings')
: lang.t('configure.embed-comment-stream');
if (this.props.fetchingSettings) {
pageTitle += ' - Loading...';
@@ -114,16 +134,16 @@ class Configure extends React.Component {
<ListItem className={styles.settingOption}>
<ListItemContent
onClick={this.changeSection.bind(this, 'comments')}
icon='settings'>Comment Settings</ListItemContent>
icon='settings'>{lang.t('configure.comment-settings')}</ListItemContent>
</ListItem>
<ListItem className={styles.settingOption}>
<ListItemContent
onClick={this.changeSection.bind(this, 'embed')}
icon='code'>Embed Comment Stream</ListItemContent>
icon='code'>{lang.t('configure.embed-comment-stream')}</ListItemContent>
</ListItem>
</List>
<Button raised colored onClick={this.saveSettings}>
<Icon name='save' /> Save Changes
<Icon name='save' /> {lang.t('configure.save-changes')}
</Button>
</div>
<div className={styles.mainContent}>
@@ -6,7 +6,7 @@ import {updateStatus} from 'actions/comments';
import styles from './ModerationQueue.css';
import key from 'keymaster';
import I18n from 'coral-framework/i18n/i18n';
import translations from '../translations';
import translations from '../translations.json';
/*
* Renders the moderation queue as a tabbed layout with 3 moderation
@@ -91,7 +91,7 @@ class ModerationQueue extends React.Component {
commentIds={
comments
.get('ids')
.filter(id =>
.filter(id =>
comments
.get('byId')
.get(id)
-55
View File
@@ -1,55 +0,0 @@
export default {
en: {
'community': {
username_and_email: 'Username and Email',
account_creation_date: 'Account Creation Date',
newsroom_role: 'Newsroom Role',
admin: 'Administrator',
moderator: 'Moderator',
role: 'Select role...'
},
'modqueue': {
'pending': 'pending',
'rejected': 'rejected',
'flagged': 'flagged',
'shortcuts': 'Shortcuts',
'close': 'Close',
'actions': 'Actions',
'navigation': 'Navigation',
'approve': 'Approve comment',
'reject': 'Reject comment',
'nextcomment': 'Go to the next comment',
'prevcomment': 'Go to the previous comment',
'singleview': 'Toggle single comment edit view',
'thismenu': 'Open this menu'
},
'comment': {
'flagged': 'flagged',
'anon': 'Anonymous'
},
'embedlink': {
'copy': 'Copy to Clipboard'
}
},
es: {
'community': {
username_and_email: 'Usuario y E-mail',
account_creation_date: 'Fecha de creación de la cuenta',
newsroom_role: 'Rol en la redacción',
admin: 'Administrador',
moderator: 'Moderador',
role: 'Select role...'
},
'modqueue': {
'pending': 'pendiente',
'rejected': 'rechazado',
'flagged': 'marcado',
'shortcuts': 'Atajos de teclado',
'close': 'Cerrar'
},
'comment': {
'flagged': 'marcado',
'anon': 'Anónimo'
}
}
};
+81
View File
@@ -0,0 +1,81 @@
{
"en": {
"community": {
"username_and_email": "Username and Email",
"account_creation_date": "Account Creation Date",
"newsroom_role": "Newsroom Role",
"admin": "Administrator",
"moderator": "Moderator",
"role": "Select role..."
},
"modqueue": {
"pending": "pending",
"rejected": "rejected",
"flagged": "flagged",
"shortcuts": "Shortcuts",
"close": "Close",
"actions": "Actions",
"navigation": "Navigation",
"approve": "Approve comment",
"reject": "Reject comment",
"nextcomment": "Go to the next comment",
"prevcomment": "Go to the previous comment",
"singleview": "Toggle single comment edit view",
"thismenu": "Open this menu"
},
"comment": {
"flagged": "flagged",
"anon": "Anonymous"
},
"embedlink": {
"copy": "Copy to Clipboard"
},
"configure": {
"enable-pre-moderation": "Enable pre-moderation",
"include-comment-stream": "Include Comment Stream Description for Readers.",
"include-comment-stream-desc": "Write a message to be added to the top of your comment stream. Pose a topic, include community guidelines, etc.",
"include-text": "Include your text here.",
"comment-settings": "Comment Settings",
"embed-comment-stream": "Embed Comment Stream",
"save-changes": "Save Changes",
"copy-and-paste": "Copy and paste code below into your CMS to embed your comment box in your articles",
"moderate": "Moderate",
"configure": "Configure",
"community": "Community"
}
},
"es": {
"community": {
"username_and_email": "Usuario y E-mail",
"account_creation_date": "Fecha de creación de la cuenta",
"newsroom_role": "Rol en la redacción",
"admin": "Administrador",
"moderator": "Moderador",
"role": "Select role..."
},
"modqueue": {
"pending": "pendiente",
"rejected": "rechazado",
"flagged": "marcado",
"shortcuts": "Atajos de teclado",
"close": "Cerrar"
},
"comment": {
"flagged": "marcado",
"anon": "Anónimo"
},
"configure": {
"enable-pre-moderation": "Habilitar pre-moderación",
"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.",
"comment-settings": "Configuración de Comentarios",
"embed-comment-stream": "Colocar Hilo de Comentarios",
"save-changes": "Guardar Cambios",
"copy-and-paste": "Copiar y pegar el código de más abajo en tu CMS para colocar la caja de comentarios en tus articulos",
"moderate": "Moderar",
"configure": "Configurar",
"community": "Comunidad"
}
}
}
+9 -17
View File
@@ -7,6 +7,7 @@ import {
} from '../../coral-framework';
import {connect} from 'react-redux';
import CommentBox from '../../coral-plugin-commentbox/CommentBox';
import InfoBox from '../../coral-plugin-infobox/InfoBox';
import Content from '../../coral-plugin-commentcontent/CommentContent';
import PubDate from '../../coral-plugin-pubdate/PubDate';
import Count from '../../coral-plugin-comment-count/CommentCount';
@@ -76,34 +77,25 @@ class CommentStream extends Component {
componentDidMount () {
// Set up messaging between embedded Iframe an parent component
// Using recommended Pym init code which violates .eslint standards
new Pym.Child({polling: 500});
this.props.getStream('assetTest');
const pym = new Pym.Child({polling: 100});
const path = /https?\:\/\/([^?]+)/.exec(pym.parentUrl)[1];
this.props.getStream(path);
}
render () {
if (Object.keys(this.props.items).length === 0) {
// Loading mock asset
this.props.postItem({
comments: [],
url: 'http://coralproject.net'
}, 'asset', 'assetTest');
// Loading mock user
this.props.postItem({name: 'Ban Ki-Moon'}, 'user', 'user_8989')
.then((id) => {
this.props.setLoggedInUser(id);
});
}
// TODO: Replace teststream id with id from params
const rootItemId = 'assetTest';
const rootItemId = this.props.items.assets && Object.keys(this.props.items.assets)[0];
const rootItem = this.props.items.assets && this.props.items.assets[rootItemId];
return <div>
{
rootItem
? <div>
<div id="commentBox">
<InfoBox
content={this.props.config.infoBoxContent}
enable={this.props.config.infoBoxEnable}/>
<Count
id={rootItemId}
items={this.props.items}/>
@@ -117,7 +109,7 @@ class CommentStream extends Component {
reply={false}/>
</div>
{
rootItem.comments.map((commentId) => {
rootItem.comments && rootItem.comments.map((commentId) => {
const comment = this.props.items.comments[commentId];
return <div className="comment" key={commentId}>
<hr aria-hidden={true}/>
@@ -49,6 +49,23 @@ hr {
font-weight: bold;
}
/* Info Box Styles */
.coral-plugin-infobox-info {
position: fixed;
top: 0;
border: 0;
background: rgb(105,105,105);
color: white;
border-radius: 2px;
font-weight: bold;
display: block;
}
.hidden {
visibility: hidden;
display: none;
}
/* Comment Box Styles */
.coral-plugin-commentbox-container {
display: flex;
@@ -94,9 +94,9 @@ export const appendItemArray = (id, property, value, add_to_front, item_type) =>
* @dispatches
* A set of items to the item store
*/
export function getStream (assetId) {
export function getStream (assetUrl) {
return (dispatch) => {
return fetch(`/api/v1/stream?asset_id=${assetId}`, getInit('GET'))
return fetch(`/api/v1/stream?asset_url=${encodeURIComponent(assetUrl)}`)
.then(responseHandler)
.then((json) => {
@@ -108,6 +108,8 @@ export function getStream (assetId) {
}
}
const assetId = json.assets[0].id;
/* Sort comments by date*/
json.comments.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
const rels = json.comments.reduce((h, item) => {
@@ -125,10 +127,7 @@ export function getStream (assetId) {
return h;
}, {rootComments: [], childComments: {}});
dispatch(addItem({
id: assetId,
comments: rels.rootComments,
}, 'assets'));
dispatch(updateItem(assetId, 'comments', rels.rootComments, 'assets'));
const childKeys = Object.keys(rels.childComments);
for (let i = 0; i < childKeys.length; i++ ) {
@@ -5,7 +5,7 @@ const name = 'coral-plugin-comment-count';
const CommentCount = ({items, id}) => {
let count = 0;
if (items.assets[id]) {
if (items.assets[id] && items.assets[id].comments) {
count += items.assets[id].comments.length;
}
const itemKeys = Object.keys(items.comments);
+10
View File
@@ -0,0 +1,10 @@
import React from 'react';
const packagename = 'coral-plugin-infobox';
const InfoBox = ({enable, content}) =>
<div
className={`${packagename}-info ${enable ? null : ', hidden'}` }>
{content}
</div>;
export default InfoBox;
@@ -0,0 +1,26 @@
import React from 'react';
import {shallow} from 'enzyme';
import {expect} from 'chai';
import InfoBox from '../InfoBox';
describe('InfoBox', () => {
let comment;
let render;
beforeEach(() => {
comment = {};
const postItem = (item) => {
comment.posted = item;
return Promise.resolve(4);
};
render = shallow(<InfoBox
postItem={postItem}
updateItem={(e) => comment.text = e.target.value}
item_id={'1'}
comments={['1', '2', '3']}/>);
});
it('should render the InfoBox appropriately', () => {
expect(render.contains('<div class="InfoBox"')).to.be.truthy;
expect(render.contains('<button class="postCommentButton"')).to.be.truthy;
});
});
+10 -1
View File
@@ -11,7 +11,8 @@ const Schema = mongoose.Schema;
const SettingSchema = new Schema({
id: {type: String, default: '1'},
moderation: {type: String, enum: ['pre', 'post'], default: 'pre'},
smtp_connection_string: {type: String, default: ''},
infoBoxEnable: {type: Boolean, default: false},
infoBoxContent: {type: String, default: ''}
}, {
timestamps: {
createdAt: 'created_at',
@@ -43,6 +44,14 @@ SettingSchema.statics.getModerationSetting = function () {
return this.findOne({id: '1'}).select('moderation');
};
/**
* Gets the info box settings and sends it back
* @return {Promise} content the content of the info Box
*/
SettingSchema.statics.getInfoBoxSetting = function () {
return this.findOne({id: '1'}).select('infoBoxEnable', 'infoBoxContent');
};
/**
* This will update the settings object with whatever you pass in
* @param {object} setting a hash of whatever settings you want to update
+6 -16
View File
@@ -5,25 +5,20 @@
"main": "app.js",
"scripts": {
"start": "./bin/www",
"build": "webpack --config webpack.config.js --bail",
"build-watch": "webpack --config webpack.config.dev.js --watch",
"build": "NODE_ENV=production webpack --config webpack.config.js --bail",
"build-watch": "NODE_ENV=development webpack --config webpack.config.dev.js --watch",
"lint": "eslint bin/* .",
"lint-fix": "eslint . --fix",
"pretest": "npm install",
"test": "mocha --compilers js:babel-core/register --recursive tests",
"test-watch": "mocha --compilers js:babel-core/register --recursive -w tests",
"embed-start": "npm run build && ./bin/www"
"embed-start": "NODE_ENV=development npm run build && ./bin/www"
},
"config": {
"pre-git": {
"commit-msg": [],
"pre-commit": [
"npm run lint",
"npm test"
],
"pre-push": [
"npm test"
],
"pre-commit": ["npm run lint", "npm test"],
"pre-push": ["npm test"],
"post-commit": [],
"post-merge": []
}
@@ -32,12 +27,7 @@
"type": "git",
"url": "git+https://github.com/coralproject/talk.git"
},
"keywords": [
"talk",
"coral",
"coralproject",
"ask"
],
"keywords": ["talk", "coral", "coralproject", "ask"],
"author": "",
"license": "Apache-2.0",
"bugs": {
+18 -8
View File
@@ -3,35 +3,45 @@ const express = require('express');
const Comment = require('../../../models/comment');
const User = require('../../../models/user');
const Action = require('../../../models/action');
const Asset = require('../../../models/asset');
const Setting = require('../../../models/setting');
const router = express.Router();
// Find all the comments by a specific asset_id.
// Find all the comments by a specific asset_url.
// . if pre: get the comments that are accepted.
// . if post: get the comments that are new and accepted.
router.get('/', (req, res, next) => {
const commentsPromise = Setting.getModerationSetting().then(({moderation}) => {
// Get the asset_id for this url (or create it if it doesn't exist)
Promise.all([
Asset.findOrCreateByUrl(decodeURIComponent(req.query.asset_url)),
Setting.getModerationSetting()
])
.then(([asset, {moderation}]) => {
// Get the sitewide moderation setting and return the appropriate comments
switch(moderation){
case 'pre':
return Comment.findAcceptedByAssetId(req.query.asset_id);
return Promise.all([Comment.findAcceptedByAssetId(asset.id), asset]);
case 'post':
return Comment.findAcceptedAndNewByAssetId(req.query.asset_id);
return Promise.all([Comment.findAcceptedAndNewByAssetId(asset.id), asset]);
default:
throw new Error('Moderation setting not found.');
}
});
})
// Get all the users and actions for those comments.
commentsPromise.then(comments => {
.then(([comments, asset]) => {
return Promise.all([
[asset],
comments,
User.findByIdArray(comments.map((comment) => comment.author_id)),
Action.getActionSummaries(comments.map((comment) => comment.id))
]);
}).then(([comments, users, actions]) => {
})
.then(([assets, comments, users, actions]) => {
res.json({
assets,
comments,
users,
actions
@@ -18,8 +18,11 @@ describe('itemActions', () => {
});
describe('getStream', () => {
const rootId = '1234';
const assetUrl = 'http://www.test.com';
const response = {
assets: [{
id: '1234', url: assetUrl
}],
comments: [
{body: 'stuff', id: '123'},
{body: 'morestuff', id: '456'}
@@ -42,17 +45,17 @@ describe('itemActions', () => {
it('should get an stream from an asset_id and send the appropriate dispatches', () => {
fetchMock.get('*', JSON.stringify(response));
return actions.getStream(rootId)(store.dispatch)
return actions.getStream(assetUrl)(store.dispatch)
.then((res) => {
expect(fetchMock.calls().matched[0][0]).to.equal('/api/v1/stream?asset_id=1234');
expect(fetchMock.calls().matched[0][0]).to.equal('/api/v1/stream?asset_url=http%3A%2F%2Fwww.test.com');
expect(res).to.deep.equal(response);
expect(store.getActions()[0]).to.deep.equal({
expect(store.getActions()[1]).to.deep.equal({
type: actions.ADD_ITEM,
item: response.comments[0],
item_type: 'comments',
id: '123'
});
expect(store.getActions()[1]).to.deep.equal({
expect(store.getActions()[2]).to.deep.equal({
type: actions.ADD_ITEM,
item: response.comments[1],
item_type: 'comments',
@@ -62,7 +65,7 @@ describe('itemActions', () => {
});
it('should handle an error', () => {
fetchMock.get('*', 404);
return actions.getStream(rootId)(store.dispatch)
return actions.getStream(assetUrl)(store.dispatch)
.catch((err) => {
expect(err).to.be.truthy;
});
+10 -2
View File
@@ -8,7 +8,7 @@ const expect = require('chai').expect;
describe('Setting: model', () => {
beforeEach(() => {
const defaults = {id: 1, moderation: 'pre'};
const defaults = {id: 1};
return Setting.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true});
});
@@ -18,13 +18,21 @@ describe('Setting: model', () => {
expect(settings).to.have.property('moderation').and.to.equal('pre');
});
});
it('should have two infoBox fields defined', () => {
return Setting.getSettings().then(settings => {
expect(settings).to.have.property('infoBoxEnable').and.to.equal(false);
expect(settings).to.have.property('infoBoxContent').and.to.equal('');
});
});
});
describe('#updateSettings()', () => {
it('should update the settings with a passed object', () => {
const mockSettings = {moderation: 'post'};
const mockSettings = {moderation: 'post', infoBoxEnable: true, infoBoxContent: 'yeah'};
return Setting.updateSettings(mockSettings).then(updatedSettings => {
expect(updatedSettings).to.have.property('moderation').and.to.equal('post');
expect(updatedSettings).to.have.property('infoBoxEnable', true);
expect(updatedSettings).to.have.property('infoBoxContent', 'yeah');
});
});
});
+19 -16
View File
@@ -11,6 +11,7 @@ chai.use(require('chai-http'));
const Action = require('../../../../models/action');
const User = require('../../../../models/user');
const Comment = require('../../../../models/comment');
const Asset = require('../../../../models/asset');
const Setting = require('../../../../models/setting');
@@ -21,14 +22,12 @@ describe('api/stream: routes', () => {
const comments = [{
id: 'abc',
body: 'comment 10',
asset_id: 'asset',
author_id: '',
parent_id: '',
status: 'accepted'
}, {
id: 'def',
body: 'comment 20',
asset_id: 'asset',
author_id: '',
parent_id: '',
status: ''
@@ -66,29 +65,33 @@ describe('api/stream: routes', () => {
beforeEach(() => {
return User
.createLocalUsers(users)
.then(users => {
return Promise.all([
User.createLocalUsers(users),
Asset.findOrCreateByUrl('http://test.com')
])
.then(([users, asset]) => {
comments[0].author_id = users[0].id;
comments[1].author_id = users[1].id;
return Promise.all([
Comment.create(comments),
Action.create(actions),
Setting.create(settings)
]);
comments[0].author_id = users[0].id;
comments[1].author_id = users[1].id;
});
comments[0].asset_id = asset.id;
comments[1].asset_id = asset.id;
return Promise.all([
Comment.create(comments),
Action.create(actions),
Setting.create(settings)
]);
});
});
it('should return a stream with comments, users and actions', () => {
it('should return a stream with comments, users and actions for an existing asset', () => {
return chai.request(app)
.get('/api/v1/stream')
.query({'asset_id': 'asset'})
.query({'asset_url': 'http://test.com'})
.then(res => {
expect(res).to.have.status(200);
expect(res.body.assets.length).to.equal(1);
expect(res.body.comments.length).to.equal(1);
expect(res.body.users.length).to.equal(1);
expect(res.body.actions.length).to.equal(1);
+7 -2
View File
@@ -17,7 +17,12 @@
</style>
</head>
<body>
<div id="coralStream"></div>
<script src="<%= basePath %>/bundle.js" charset="utf-8"></script>
<div id='coralStreamEmbed'></div>
<script type='text/javascript' src='https://pym.nprapps.org/pym.v1.min.js'></script>
<script>
var pymParent = new pym.Parent('coralStreamEmbed', '/embed/stream', {title: 'Talk Comments'});
pymParent.onMessage('height', function(height) {document.querySelector('#coralStreamEmbed iframe').height = height + 'px'})</script>
</div>
</body>
</body>
</html>
+1 -1
View File
@@ -85,7 +85,7 @@ module.exports = {
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': `"${'development'}"`,
'NODE_ENV': `"${process.env.NODE_ENV}"`,
'VERSION': `"${require('./package.json').version}"`
}
})
-6
View File
@@ -5,12 +5,6 @@ const devConfig = require('./webpack.config.dev');
devConfig.devtool = null;
devConfig.plugins = devConfig.plugins.concat([
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': `"${'production'}"`,
'VERSION': `"${require('./package.json').version}"`
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false