diff --git a/client/coral-framework/components/CloseCommentsInfo.js b/client/coral-configure/components/CloseCommentsInfo.js
similarity index 100%
rename from client/coral-framework/components/CloseCommentsInfo.js
rename to client/coral-configure/components/CloseCommentsInfo.js
diff --git a/client/coral-configure/components/ConfigureCommentStream.css b/client/coral-configure/components/ConfigureCommentStream.css
new file mode 100644
index 000000000..8526edc09
--- /dev/null
+++ b/client/coral-configure/components/ConfigureCommentStream.css
@@ -0,0 +1,37 @@
+.container {
+ position: relative;
+}
+
+.apply {
+ position: absolute;
+ top: 38%;
+ transform: translateX(-50%);
+ right: 0;
+}
+
+ul {
+ list-style: none;
+ padding: 0;
+}
+
+ul ul {
+ padding-left: 20px
+}
+
+.checkbox {
+ vertical-align: top;
+ margin: 12px 12px 12px 0;
+}
+
+h4 {
+ font-size: 14px;
+ margin-bottom: 5px;
+}
+
+p {
+ max-width: 380px;
+}
+
+.wrapper {
+ margin-bottom: 20px;
+}
diff --git a/client/coral-configure/components/ConfigureCommentStream.js b/client/coral-configure/components/ConfigureCommentStream.js
new file mode 100644
index 000000000..507c764d7
--- /dev/null
+++ b/client/coral-configure/components/ConfigureCommentStream.js
@@ -0,0 +1,53 @@
+import React from 'react';
+import {Button, Checkbox} from 'coral-ui';
+import styles from './ConfigureCommentStream.css';
+
+import I18n from 'coral-framework/modules/i18n/i18n';
+import translations from '../translations.json';
+const lang = new I18n(translations);
+
+export default ({handleChange, handleApply, changed, ...props}) => (
+
+
+
{lang.t('configureCommentStream.title')}
+
{lang.t('configureCommentStream.description')}
+
+
+
+
+);
diff --git a/client/coral-configure/containers/ConfigureStreamContainer.js b/client/coral-configure/containers/ConfigureStreamContainer.js
new file mode 100644
index 000000000..d4b71f4e5
--- /dev/null
+++ b/client/coral-configure/containers/ConfigureStreamContainer.js
@@ -0,0 +1,83 @@
+import React, {Component} from 'react';
+import {connect} from 'react-redux';
+
+import {updateOpenStatus, updateConfiguration} from '../../coral-framework/actions/config';
+
+import CloseCommentsInfo from '../components/CloseCommentsInfo';
+import ConfigureCommentStream from '../components/ConfigureCommentStream';
+
+class ConfigureStreamContainer extends Component {
+ constructor (props) {
+ super(props);
+
+ this.state = {
+ premod: props.config.moderation === 'pre',
+ premodLinks: false
+ };
+
+ this.toggleStatus = this.toggleStatus.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ this.handleApply = this.handleApply.bind(this);
+ }
+
+ handleApply () {
+ const {premod, changed} = this.state;
+ const newConfig = {
+ moderation: premod ? 'pre' : 'post'
+ };
+ if (changed) {
+ this.props.updateConfiguration(newConfig);
+ setTimeout(() => {
+ this.setState({
+ changed: false
+ });
+ }, 300);
+ }
+ }
+
+ handleChange (e) {
+ const {name, checked} = e.target;
+ this.setState({
+ [name]: checked,
+ changed: true
+ });
+ }
+
+ toggleStatus () {
+ this.props.updateStatus(this.props.config.status === 'open' ? 'closed' : 'open');
+ }
+
+ render () {
+ const {status} = this.props;
+ return (
+
+
+
+ {status === 'open' ? 'Close' : 'Open'} Comment Stream
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => ({
+ config: state.config.toJS()
+});
+
+const mapDispatchToProps = dispatch => ({
+ updateStatus: status => dispatch(updateOpenStatus(status)),
+ updateConfiguration: newConfig => dispatch(updateConfiguration(newConfig))
+});
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(ConfigureStreamContainer);
diff --git a/client/coral-configure/translations.json b/client/coral-configure/translations.json
new file mode 100644
index 000000000..e597c9c9a
--- /dev/null
+++ b/client/coral-configure/translations.json
@@ -0,0 +1,24 @@
+{
+ "en": {
+ "configureCommentStream": {
+ "apply": "Apply",
+ "title": "Configure Comment Stream",
+ "description": "As an admin you may customize the settings for the comment stream for this article",
+ "enablePremod": "Enable Premoderation",
+ "enablePremodDescription": "Moderators must approve any comment before its published.",
+ "enablePremodLinks": "Pre-Moderate Comments Containing Links",
+ "enablePremodLinksDescription": "Moderators must approve any comment containing a link before its published."
+ }
+ },
+ "es": {
+ "configureCommentStream": {
+ "apply": "Aplicar",
+ "title": "Configurar los comentarios",
+ "description": "Como Administrador puedes modificar las opciones de los comentarios en este artículo",
+ "enablePremod": "Activar Pre Moderación",
+ "enablePremodDescription": "Los Moderadores deben aprobar cualquier comentario antes de su publicación",
+ "enablePremodLinks": "Pre-Moderar Commentarios que contienen Links",
+ "enablePremodLinksDescription": "Los Moderadores deben probar cualquier comentario que contengan links antes de su publicación."
+ }
+ }
+}
diff --git a/client/coral-embed-stream/src/CommentStream.js b/client/coral-embed-stream/src/CommentStream.js
index fb8a1962f..bb59ffa8e 100644
--- a/client/coral-embed-stream/src/CommentStream.js
+++ b/client/coral-embed-stream/src/CommentStream.js
@@ -6,8 +6,7 @@ import {
itemActions,
Notification,
notificationActions,
- authActions,
- configActions
+ authActions
} from '../../coral-framework';
import CommentBox from '../../coral-plugin-commentbox/CommentBox';
@@ -27,12 +26,12 @@ import {TabBar, Tab, TabContent, Spinner} from '../../coral-ui';
import SettingsContainer from '../../coral-settings/containers/SettingsContainer';
import RestrictedContent from '../../coral-framework/components/RestrictedContent';
import SuspendedAccount from '../../coral-framework/components/SuspendedAccount';
-import CloseCommentsInfo from '../../coral-framework/components/CloseCommentsInfo';
+
+import ConfigureStreamContainer from '../../coral-configure/containers/ConfigureStreamContainer';
const {addItem, updateItem, postItem, getStream, postAction, deleteAction, appendItemArray} = itemActions;
const {addNotification, clearNotification} = notificationActions;
const {logout, showSignInDialog} = authActions;
-const {updateOpenStatus} = configActions;
class CommentStream extends Component {
@@ -44,7 +43,6 @@ class CommentStream extends Component {
};
this.changeTab = this.changeTab.bind(this);
- this.toggleStatus = this.toggleStatus.bind(this);
}
changeTab (tab) {
@@ -53,10 +51,6 @@ class CommentStream extends Component {
});
}
- toggleStatus () {
- this.props.updateStatus(this.props.config.status === 'open' ? 'closed' : 'open');
- }
-
static propTypes = {
items: PropTypes.object.isRequired,
addItem: PropTypes.func.isRequired,
@@ -272,9 +266,11 @@ class CommentStream extends Component {
/>
- {status === 'open' ? 'Close' : 'Open'} Comment Stream
-
+
({
deleteAction: (item, action, user, itemType) => dispatch(deleteAction(item, action, user, itemType)),
appendItemArray: (item, property, value, addToFront, itemType) => dispatch(appendItemArray(item, property, value, addToFront, itemType)),
handleSignInDialog: () => dispatch(authActions.showSignInDialog()),
- logout: () => dispatch(logout()),
- updateStatus: status => dispatch(updateOpenStatus(status))
+ logout: () => dispatch(logout())
});
export default connect(mapStateToProps, mapDispatchToProps)(CommentStream);
diff --git a/client/coral-framework/actions/config.js b/client/coral-framework/actions/config.js
index e004fa1eb..f85e609eb 100644
--- a/client/coral-framework/actions/config.js
+++ b/client/coral-framework/actions/config.js
@@ -1,19 +1,33 @@
import coralApi from '../helpers/response';
-/* Config Actions */
+import * as actions from '../constants/config';
+import {addNotification} from '../actions/notification';
-/**
- * Action name constants
- */
-
-export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
-export const OPEN_COMMENTS = 'OPEN_COMMENTS';
-export const CLOSE_COMMENTS = 'CLOSE_COMMENTS';
-export const ADD_ITEM = 'ADD_ITEM';
+import I18n from 'coral-framework/modules/i18n/i18n';
+import translations from './../translations';
+const lang = new I18n(translations);
export const updateOpenStatus = status => (dispatch, getState) => {
const assetId = getState().items.get('assets')
.keySeq()
.toArray()[0];
return coralApi(`/asset/${assetId}/status?status=${status}`, {method: 'PUT'})
- .then(() => dispatch({type: status === 'open' ? OPEN_COMMENTS : CLOSE_COMMENTS}));
+ .then(() => dispatch({type: status === 'open' ? actions.OPEN_COMMENTS : actions.CLOSE_COMMENTS}));
+};
+
+const updateConfigRequest = () => ({type: actions.UPDATE_CONFIG_REQUEST});
+const updateConfigSuccess = config => ({type: actions.UPDATE_CONFIG_SUCCESS, config});
+const updateConfigFailure = () => ({type: actions.UPDATE_CONFIG_FAILURE});
+
+export const updateConfiguration = newConfig => (dispatch, getState) => {
+ const assetId = getState().items.get('assets')
+ .keySeq()
+ .toArray()[0];
+
+ dispatch(updateConfigRequest());
+ coralApi(`/asset/${assetId}/settings`, {method: 'PUT', body: newConfig})
+ .then(() => {
+ dispatch(addNotification('success', lang.t('successUpdateSettings')));
+ dispatch(updateConfigSuccess(newConfig));
+ })
+ .catch(error => dispatch(updateConfigFailure(error)));
};
diff --git a/client/coral-framework/actions/items.js b/client/coral-framework/actions/items.js
index 2029714c7..cdaa7c1a6 100644
--- a/client/coral-framework/actions/items.js
+++ b/client/coral-framework/actions/items.js
@@ -1,14 +1,9 @@
import coralApi from '../helpers/response';
import {fromJS} from 'immutable';
-/* Item Actions */
-
-/**
- * Action name constants
- */
+import {UPDATE_CONFIG} from '../constants/config';
export const ADD_ITEM = 'ADD_ITEM';
export const UPDATE_ITEM = 'UPDATE_ITEM';
-export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
export const APPEND_ITEM_ARRAY = 'APPEND_ITEM_ARRAY';
/**
@@ -106,7 +101,7 @@ export function getStream (assetUrl) {
dispatch(addItem(action, 'actions'));
});
} else if (type === 'settings') {
- dispatch({type: UPDATE_SETTINGS, config: fromJS(json[type])});
+ dispatch({type: UPDATE_CONFIG, config: fromJS(json[type])});
} else {
json[type].forEach(item => {
dispatch(addItem(item, type));
diff --git a/client/coral-framework/constants/config.js b/client/coral-framework/constants/config.js
new file mode 100644
index 000000000..5dca44ba9
--- /dev/null
+++ b/client/coral-framework/constants/config.js
@@ -0,0 +1,9 @@
+export const UPDATE_CONFIG_REQUEST = 'UPDATE_CONFIG_REQUEST';
+export const UPDATE_CONFIG_SUCCESS = 'UPDATE_CONFIG_SUCCESS';
+export const UPDATE_CONFIG_FAILURE = 'UPDATE_CONFIG_FAILURE';
+
+export const UPDATE_CONFIG = 'UPDATE_CONFIG';
+
+export const OPEN_COMMENTS = 'OPEN_COMMENTS';
+export const CLOSE_COMMENTS = 'CLOSE_COMMENTS';
+export const ADD_ITEM = 'ADD_ITEM';
diff --git a/client/coral-framework/reducers/config.js b/client/coral-framework/reducers/config.js
index 7fbccaa49..8266fbfa1 100644
--- a/client/coral-framework/reducers/config.js
+++ b/client/coral-framework/reducers/config.js
@@ -1,31 +1,28 @@
-/* @flow */
-
import {Map} from 'immutable';
-import * as actions from '../actions/config';
+import * as actions from '../constants/config';
const initialState = Map({
features: Map({}),
status: 'open',
- closedMessage: ''
+ moderation: null
});
export default (state = initialState, action) => {
switch(action.type) {
- // Override config if worked
- case actions.UPDATE_SETTINGS:
- return action.config;
-
+ case actions.UPDATE_CONFIG:
+ return state
+ .merge(Map(action.config));
+ case actions.UPDATE_CONFIG_SUCCESS:
+ return state
+ .merge(Map(action.config));
case actions.OPEN_COMMENTS:
- return state.set('status', 'open');
-
+ return state
+ .set('status', 'open');
case actions.CLOSE_COMMENTS:
- return state.set('status', 'closed');
-
+ return state
+ .set('status', 'closed');
case actions.ADD_ITEM:
- return action.item_type === 'assets' ?
- state.set('status', action.item.status)
- : state;
-
+ return action.item_type === 'assets' ? state.set('status', action.item.status) : state;
default:
return state;
}
diff --git a/client/coral-framework/translations.json b/client/coral-framework/translations.json
index ab65ba565..06a39944a 100644
--- a/client/coral-framework/translations.json
+++ b/client/coral-framework/translations.json
@@ -1,5 +1,6 @@
{
"en": {
+ "successUpdateSettings": "The changes you have made have been applied to the comment stream on this article",
"successBioUpdate": "Your Bio has been updated",
"contentNotAvailable": "This content is not available",
"suspendedAccountMsg": "Your account is currently suspended. This means that you cannot Like, Flag, or write comments. Please contact moderator@fakeurl.com for more information",
@@ -13,6 +14,7 @@
}
},
"es": {
+ "successUpdateSettings": "La configuración de este articulo fue actualizada",
"successBioUpdate": "Tu bio fue actualizada",
"contentNotAvailable": "El contenido no se encuentra disponible",
"suspendedAccountMsg": "Tu cuenta se encuentra suspendida. Esto significa que no puedes dar Like, Marcar o escribir commentarios. Por favor, contacta moderator@fakeurl for more information",
diff --git a/client/coral-settings/index.js b/client/coral-settings/index.js
deleted file mode 100644
index e69de29bb..000000000
diff --git a/client/coral-ui/components/Button.css b/client/coral-ui/components/Button.css
index 3a3a4221e..e36f55886 100644
--- a/client/coral-ui/components/Button.css
+++ b/client/coral-ui/components/Button.css
@@ -77,6 +77,16 @@
background: #696969;
}
+.type--green {
+ color: white;
+ background: #00897B;
+}
+
+.type--green:hover {
+ color: white;
+ background: #00a291;
+}
+
.full {
width: 100%;
margin: 0;
diff --git a/client/coral-ui/components/Checkbox.css b/client/coral-ui/components/Checkbox.css
new file mode 100644
index 000000000..d20886689
--- /dev/null
+++ b/client/coral-ui/components/Checkbox.css
@@ -0,0 +1,70 @@
+.label {
+ position: relative;
+ display: inline-block;
+}
+
+.label input {
+ visibility: hidden;
+ position: absolute;
+ left: 7px;
+ bottom: 7px;
+ margin: 0;
+ padding: 0;
+ outline: none;
+ cursor: pointer;
+ opacity: 0;
+}
+
+.checkbox {
+ cursor: pointer;
+}
+
+.label input[type="checkbox"]:checked + .checkbox:before {
+ content: "\e834";
+}
+
+.label input[type="checkbox"] + .checkbox:before {
+ content: "\e835";
+ color: #717171;
+}
+
+.label.type--green input[type="checkbox"] + .checkbox:before {
+ color: #00a291;
+}
+
+.label input[type="checkbox"] + .checkbox:before {
+ position: absolute;
+ left: 4px;
+ top: 0px;
+ width: 18px;
+ height: 18px;
+ font-family: 'Material Icons';
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24px;
+ line-height: 1;
+ text-transform: none;
+ letter-spacing: normal;
+ word-wrap: normal;
+ white-space: nowrap;
+ direction: ltr;
+ vertical-align: -6px;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-feature-settings: 'liga';
+ font-feature-settings: 'liga';
+ -webkit-transition: all .2s ease;
+ transition: all .2s ease;
+ z-index: 1;
+}
+
+.checkboxInfo {
+ display: inline-block;
+ max-width: 360px;
+ margin-left: 50px;
+}
+
+.checkboxInfo h4 {
+ margin: 0 0 5px;
+}
diff --git a/client/coral-ui/components/Checkbox.js b/client/coral-ui/components/Checkbox.js
new file mode 100644
index 000000000..94626295f
--- /dev/null
+++ b/client/coral-ui/components/Checkbox.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import styles from './Checkbox.css';
+
+export default ({name, cStyle = 'base', onChange, label, className, info, checked = 'false'}) => (
+
+);
diff --git a/client/coral-ui/index.js b/client/coral-ui/index.js
index ffdb3bbd2..afcce7354 100644
--- a/client/coral-ui/index.js
+++ b/client/coral-ui/index.js
@@ -7,3 +7,4 @@ export {default as TabContent} from './components/TabContent';
export {default as Button} from './components/Button';
export {default as Spinner} from './components/Spinner';
export {default as Tooltip} from './components/Tooltip';
+export {default as Checkbox} from './components/Checkbox';
diff --git a/models/asset.js b/models/asset.js
index 77b8ebff3..3c68b7c13 100644
--- a/models/asset.js
+++ b/models/asset.js
@@ -132,10 +132,12 @@ AssetSchema.statics.findOrCreateByUrl = (url) => Asset.findOneAndUpdate({url}, {
* @param {[type]} settings [description]
* @return {[type]} [description]
*/
-AssetSchema.statics.overrideSettings = (id, settings) => Asset.update({id}, {
+AssetSchema.statics.overrideSettings = (id, settings) => Asset.findOneAndUpdate({id}, {
$set: {
settings
}
+}, {
+ new: true
});
/**
diff --git a/routes/api/asset/index.js b/routes/api/asset/index.js
index 05926bc15..2ddc3ea23 100644
--- a/routes/api/asset/index.js
+++ b/routes/api/asset/index.js
@@ -82,18 +82,11 @@ router.post('/:asset_id/scrape', (req, res, next) => {
});
router.put('/:asset_id/settings', (req, res, next) => {
-
// Override the settings for the asset.
Asset
.overrideSettings(req.params.asset_id, req.body)
- .then(() => {
-
- res.status(204).end();
- })
- .catch((err) => {
- next(err);
- });
-
+ .then(() => res.status(204).end())
+ .catch((err) => next(err));
});
router.put('/:asset_id/status', (req, res, next) => {