@@ -45,5 +45,11 @@ export default ({handleLogout, restricted = false}) => (
);
+CoralDrawer.propTypes = {
+ handleLogout: PropTypes.func.isRequired,
+ restricted: PropTypes.bool // hide app elements from a logged out user
+};
+
const lang = new I18n(translations);
+export default CoralDrawer;
diff --git a/client/coral-admin/src/components/ui/Header.js b/client/coral-admin/src/components/ui/Header.js
index 556b33b6c..4a2314926 100644
--- a/client/coral-admin/src/components/ui/Header.js
+++ b/client/coral-admin/src/components/ui/Header.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {PropTypes} from 'react';
import {Navigation, Header, IconButton, MenuItem, Menu} from 'react-mdl';
import {Link, IndexLink} from 'react-router';
import styles from './Header.css';
@@ -6,7 +6,7 @@ import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import {Logo} from './Logo';
-export default ({handleLogout, restricted = false}) => (
+const CoralHeader = ({handleLogout, restricted = false}) => (
{
@@ -64,4 +64,11 @@ export default ({handleLogout, restricted = false}) => (
);
+CoralHeader.propTypes = {
+ handleLogout: PropTypes.func.isRequired,
+ restricted: PropTypes.bool // hide elemnts from a user that's logged out
+};
+
const lang = new I18n(translations);
+
+export default CoralHeader;
diff --git a/client/coral-admin/src/components/ui/Layout.js b/client/coral-admin/src/components/ui/Layout.js
index f28e8dd80..c8b5bf57a 100644
--- a/client/coral-admin/src/components/ui/Layout.js
+++ b/client/coral-admin/src/components/ui/Layout.js
@@ -1,15 +1,22 @@
-import React from 'react';
+import React, {PropTypes} from 'react';
import {Layout as LayoutMDL} from 'react-mdl';
import Header from './Header';
import Drawer from './Drawer';
import styles from './Layout.css';
-export const Layout = ({children, ...props}) => (
+const Layout = ({children, handleLogout = () => {}, restricted = false, ...props}) => (
-
-
-
+
+
+
{children}
);
+
+Layout.propTypes = {
+ handleLogout: PropTypes.func,
+ restricted: PropTypes.bool // hide elements from a user that's logged out
+};
+
+export default Layout;
diff --git a/client/coral-admin/src/constants/auth.js b/client/coral-admin/src/constants/auth.js
index f77deb670..3c47bfc45 100644
--- a/client/coral-admin/src/constants/auth.js
+++ b/client/coral-admin/src/constants/auth.js
@@ -7,3 +7,11 @@ export const CHECK_CSRF_TOKEN = 'CHECK_CSRF_TOKEN';
export const LOGOUT_REQUEST = 'LOGOUT_REQUEST';
export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS';
export const LOGOUT_FAILURE = 'LOGOUT_FAILURE';
+
+export const LOGIN_REQUEST = 'LOGIN_REQUEST';
+export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
+export const LOGIN_FAILURE = 'LOGIN_FAILURE';
+
+export const FETCH_FORGOT_PASSWORD_REQUEST = 'FETCH_FORGOT_PASSWORD_REQUEST';
+export const FETCH_FORGOT_PASSWORD_SUCCESS = 'FETCH_FORGOT_PASSWORD_SUCCESS';
+export const FETCH_FORGOT_PASSWORD_FAILURE = 'FETCH_FORGOT_PASSWORD_FAILURE';
diff --git a/client/coral-admin/src/containers/Configure/Configure.css b/client/coral-admin/src/containers/Configure/Configure.css
index 1f23af30b..058ff7a64 100644
--- a/client/coral-admin/src/containers/Configure/Configure.css
+++ b/client/coral-admin/src/containers/Configure/Configure.css
@@ -3,7 +3,7 @@
h3 {
color: black;
- font-size: 1.76em;
+ font-size: 1.26em;
font-weight: 500;
}
}
@@ -24,6 +24,10 @@
margin-bottom: 20px;
align-items: flex-start;
min-height: 100px;
+
+ h3 {
+ margin: 0;
+ }
}
.settingsError {
@@ -118,18 +122,19 @@
}
#bannedWordlist, #suspectWordlist {
- width: 100%;
- padding: 10px;
-
+ display: block;
input {
width: 100%;
}
}
-.wordlistHeader {
- font-weight: bold;
- font-size:18px;
- margin-bottom:3px;
+.customCSSInput {
+ width: 100%;
+ font-size: 14px;
+ padding: 14px;
+ letter-spacing: 0.03em;
+ color: #555;
+ box-sizing: border-box;
}
.enabledSetting {
@@ -150,7 +155,7 @@
margin-top: 38px;
}
-.commentSettingsSection {
+.settingsSection {
padding-bottom: 200px;
.action {
display: inline-block;
diff --git a/client/coral-admin/src/containers/Configure/Configure.js b/client/coral-admin/src/containers/Configure/Configure.js
index 1ec78dcd2..b94394c61 100644
--- a/client/coral-admin/src/containers/Configure/Configure.js
+++ b/client/coral-admin/src/containers/Configure/Configure.js
@@ -8,22 +8,20 @@ import {
updateDomainlist
} from '../../actions/settings';
-import {Button, List, Item} from 'coral-ui';
+import {Button, List, Item, Card, Spinner} from 'coral-ui';
import styles from './Configure.css';
import I18n from 'coral-framework/modules/i18n/i18n';
-import translations from '../../translations.json';
-import EmbedLink from './EmbedLink';
-import CommentSettings from './CommentSettings';
-import Wordlist from './Wordlist';
-import Domainlist from './Domainlist';
-import has from 'lodash/has';
+import translations from 'coral-admin/src/translations.json';
+import StreamSettings from './StreamSettings';
+import ModerationSettings from './ModerationSettings';
+import TechSettings from './TechSettings';
class Configure extends Component {
constructor (props) {
super(props);
this.state = {
- activeSection: 'comments',
+ activeSection: 'stream',
changed: false,
errors: {}
};
@@ -70,40 +68,48 @@ class Configure extends Component {
getSection (section) {
const pageTitle = this.getPageTitle(section);
+ let sectionComponent;
switch(section){
- case 'comments':
- return
;
- case 'embed':
- return has(this, 'props.settings.domains.whitelist')
- ?
-
-
-
- : ;
- case 'wordlist':
- return has(this, 'props.settings.wordlist')
- ?
- : loading wordlists
;
+ break;
+ case 'moderation':
+ sectionComponent = ;
+ break;
+ case 'tech':
+ sectionComponent = ;
}
+
+ if (this.props.settings.fetchingSettings) {
+ return Loading settings... ;
+ }
+
+ return (
+
+
{pageTitle}
+ {sectionComponent}
+
+ );
}
getPageTitle (section) {
switch(section) {
- case 'comments':
- return lang.t('configure.comment-settings');
- case 'embed':
- return lang.t('configure.embed-comment-stream');
+ case 'stream':
+ return lang.t('configure.stream-settings');
+ case 'moderation':
+ return lang.t('configure.moderation-settings');
+ case 'tech':
+ return lang.t('configure.tech-settings');
default:
return '';
}
@@ -120,14 +126,14 @@ class Configure extends Component {
- -
- {lang.t('configure.comment-settings')}
+
-
+ {lang.t('configure.stream-settings')}
- -
- {lang.t('configure.embed-comment-stream')}
+
-
+ {lang.t('configure.moderation-settings')}
- -
- {lang.t('configure.wordlist')}
+
-
+ {lang.t('configure.tech-settings')}
diff --git a/client/coral-admin/src/containers/Configure/Domainlist.js b/client/coral-admin/src/containers/Configure/Domainlist.js
index 6918c0471..c8c7cbd6c 100644
--- a/client/coral-admin/src/containers/Configure/Domainlist.js
+++ b/client/coral-admin/src/containers/Configure/Domainlist.js
@@ -9,19 +9,17 @@ const lang = new I18n(translations);
const Domainlist = ({domains, onChangeDomainlist}) => {
return (
-
+
{lang.t('configure.domain-list-title')}
-
- {lang.t('configure.domain-list-text')}
- data.split(',').map(d => d.trim())}
- onChange={tags => onChangeDomainlist('whitelist', tags)}
- />
-
-
+
{lang.t('configure.domain-list-text')}
+
data.split(',').map(d => d.trim())}
+ onChange={tags => onChangeDomainlist('whitelist', tags)}
+ />
+
);
};
diff --git a/client/coral-admin/src/containers/Configure/EmbedLink.js b/client/coral-admin/src/containers/Configure/EmbedLink.js
index 413f421d7..674bafa6e 100644
--- a/client/coral-admin/src/containers/Configure/EmbedLink.js
+++ b/client/coral-admin/src/containers/Configure/EmbedLink.js
@@ -44,19 +44,15 @@ class EmbedLink extends Component {
">
`.trim();
return (
-
-
{this.props.title}
-
-
- {lang.t('configure.copy-and-paste')}
-
-
-
+
+ Embed Comment Stream
+ {lang.t('configure.copy-and-paste')}
+
);
}
}
diff --git a/client/coral-admin/src/containers/Configure/ModerationSettings.js b/client/coral-admin/src/containers/Configure/ModerationSettings.js
new file mode 100644
index 000000000..23f0f39d8
--- /dev/null
+++ b/client/coral-admin/src/containers/Configure/ModerationSettings.js
@@ -0,0 +1,73 @@
+import React, {PropTypes} from 'react';
+import styles from './Configure.css';
+import {Card} from 'coral-ui';
+import {Checkbox} from 'react-mdl';
+import Wordlist from './Wordlist';
+import I18n from 'coral-framework/modules/i18n/i18n';
+import translations from '../../translations.json';
+const lang = new I18n(translations);
+
+const updateModeration = (updateSettings, mod) => () => {
+ const moderation = mod === 'PRE' ? 'POST' : 'PRE';
+ updateSettings({moderation});
+};
+
+const updateEmailConfirmation = (updateSettings, verify) => () => {
+ updateSettings({requireEmailConfirmation: !verify});
+};
+
+const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
+
+ // just putting this here for shorthand below
+ const on = styles.enabledSetting;
+ const off = styles.disabledSetting;
+
+ return (
+
+
+
+
+
+
+
{lang.t('configure.require-email-verification')}
+
+ {lang.t('configure.require-email-verification-text')}
+
+
+
+
+
+
+
+
+
{lang.t('configure.enable-pre-moderation')}
+
+ {lang.t('configure.enable-pre-moderation-text')}
+
+
+
+
+
+ );
+};
+
+ModerationSettings.propTypes = {
+ onChangeWordlist: PropTypes.func.isRequired,
+ settings: PropTypes.shape({
+ moderation: PropTypes.string.isRequired,
+ wordlist: PropTypes.shape({
+ banned: PropTypes.array.isRequired,
+ suspect: PropTypes.array.isRequired
+ })
+ }).isRequired,
+ updateSettings: PropTypes.func.isRequired
+};
+
+export default ModerationSettings;
diff --git a/client/coral-admin/src/containers/Configure/CommentSettings.js b/client/coral-admin/src/containers/Configure/StreamSettings.js
similarity index 70%
rename from client/coral-admin/src/containers/Configure/CommentSettings.js
rename to client/coral-admin/src/containers/Configure/StreamSettings.js
index 90057c5fe..568e0a075 100644
--- a/client/coral-admin/src/containers/Configure/CommentSettings.js
+++ b/client/coral-admin/src/containers/Configure/StreamSettings.js
@@ -4,7 +4,7 @@ import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import styles from './Configure.css';
import {Textfield, Checkbox} from 'react-mdl';
-import {Card, Icon, Spinner} from 'coral-ui';
+import {Card, Icon} from 'coral-ui';
const TIMESTAMPS = {
weeks: 60 * 60 * 24 * 7,
@@ -27,15 +27,6 @@ const updateCharCount = (updateSettings, settingsError) => (event) => {
updateSettings({charCount: charCount});
};
-const updateModeration = (updateSettings, mod) => () => {
- const moderation = mod === 'PRE' ? 'POST' : 'PRE';
- updateSettings({moderation});
-};
-
-const updateEmailConfirmation = (updateSettings, verify) => () => {
- updateSettings({requireEmailConfirmation: !verify});
-};
-
const updateInfoBoxEnable = (updateSettings, infoBox) => () => {
const infoBoxEnable = !infoBox;
updateSettings({infoBoxEnable});
@@ -51,11 +42,6 @@ const updateClosedMessage = (updateSettings) => (event) => {
updateSettings({closedMessage});
};
-const updateCustomCssUrl = (updateSettings) => (event) => {
- const customCssUrl = event.target.value;
- updateSettings({customCssUrl});
-};
-
// If we are changing the measure we need to recalculate using the old amount
// Same thing if we are just changing the amount
const updateClosedTimeout = (updateSettings, ts, isMeasure) => (event) => {
@@ -71,44 +57,14 @@ const updateClosedTimeout = (updateSettings, ts, isMeasure) => (event) => {
}
};
-const CommentSettings = ({fetchingSettings, title, updateSettings, settingsError, settings, errors}) => {
- if (fetchingSettings) {
- return Loading settings... ;
- }
+const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
// just putting this here for shorthand below
const on = styles.enabledSetting;
const off = styles.disabledSetting;
return (
-
-
{title}
-
-
-
-
-
-
{lang.t('configure.enable-pre-moderation')}
-
- {lang.t('configure.enable-pre-moderation-text')}
-
-
-
-
-
-
-
-
-
{lang.t('configure.require-email-verification')}
-
- {lang.t('configure.require-email-verification-text')}
-
-
-
+
-
-
- {lang.t('configure.custom-css-url')}
-
{lang.t('configure.custom-css-url-desc')}
-
-
-
-
);
};
-export default CommentSettings;
+export default StreamSettings;
// To see if we are talking about weeks, days or hours
// We talk the remainder of the division and see if it's 0
diff --git a/client/coral-admin/src/containers/Configure/TechSettings.js b/client/coral-admin/src/containers/Configure/TechSettings.js
new file mode 100644
index 000000000..c50a7d507
--- /dev/null
+++ b/client/coral-admin/src/containers/Configure/TechSettings.js
@@ -0,0 +1,44 @@
+import React, {PropTypes} from 'react';
+import {Card} from 'coral-ui';
+import Domainlist from './Domainlist';
+import EmbedLink from './EmbedLink';
+import styles from './Configure.css';
+import I18n from 'coral-framework/modules/i18n/i18n';
+import translations from '../../translations.json';
+const lang = new I18n(translations);
+
+const updateCustomCssUrl = (updateSettings) => (event) => {
+ const customCssUrl = event.target.value;
+ updateSettings({customCssUrl});
+};
+
+const TechSettings = ({settings, onChangeDomainlist, updateSettings}) => {
+ return (
+
+
+
+
+ {lang.t('configure.custom-css-url')}
+ {lang.t('configure.custom-css-url-desc')}
+
+
+
+
+ );
+};
+
+TechSettings.propTypes = {
+ settings: PropTypes.shape({
+ domains: PropTypes.shape({
+ whitelist: PropTypes.array.isRequired
+ })
+ }).isRequired,
+ updateSettings: PropTypes.func.isRequired
+};
+
+export default TechSettings;
diff --git a/client/coral-admin/src/containers/Configure/Wordlist.js b/client/coral-admin/src/containers/Configure/Wordlist.js
index 1a808acc6..aa79cb8ae 100644
--- a/client/coral-admin/src/containers/Configure/Wordlist.js
+++ b/client/coral-admin/src/containers/Configure/Wordlist.js
@@ -7,9 +7,8 @@ import {Card} from 'coral-ui';
const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
-
{lang.t('configure.banned-words-title')}
-
- {lang.t('configure.banned-word-header')}
+
+ {lang.t('configure.banned-words-title')}
{lang.t('configure.banned-word-text')}
(
onChange={tags => onChangeWordlist('banned', tags)}
/>
- {lang.t('configure.suspect-words-title')}
-
- {lang.t('configure.suspect-word-header')}
+
+ {lang.t('configure.suspect-words-title')}
{lang.t('configure.suspect-word-text')}
{
- if (!this.props.auth.isAdmin) {
- location.href = '/admin/login';
- }
- });
+ checkLogin();
}
render () {
- const {isAdmin, loggedIn, loadingUser} = this.props.auth;
+ const {
+ isAdmin,
+ loggedIn,
+ loadingUser,
+ loginError,
+ passwordRequestSuccess
+ } = this.props.auth;
+ const {handleLogout} = this.props;
if (loadingUser) { return ; }
- if (!isAdmin) { return ; }
- if (isAdmin && loggedIn) { return ; }
+ if (!isAdmin) {
+ return ;
+ }
+ if (isAdmin && loggedIn) { return ; }
return ;
}
}
@@ -29,6 +38,8 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({
checkLogin: () => dispatch(checkLogin()),
+ handleLogin: (username, password) => dispatch(handleLogin(username, password)),
+ requestPasswordReset: email => dispatch(requestPasswordReset(email)),
handleLogout: () => dispatch(logout())
});
diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js
index 095ef7aac..b52efdb85 100644
--- a/client/coral-admin/src/reducers/auth.js
+++ b/client/coral-admin/src/reducers/auth.js
@@ -4,7 +4,9 @@ import * as actions from '../constants/auth';
const initialState = Map({
loggedIn: false,
user: null,
- isAdmin: false
+ isAdmin: false,
+ loginError: null,
+ passwordRequestSuccess: null
});
export default function auth (state = initialState, action) {
@@ -25,6 +27,14 @@ export default function auth (state = initialState, action) {
.set('user', action.user);
case actions.LOGOUT_SUCCESS:
return initialState;
+ case actions.LOGIN_REQUEST:
+ return state.set('loginError', null);
+ case actions.LOGIN_FAILURE:
+ return state.set('loginError', action.message);
+ case actions.FETCH_FORGOT_PASSWORD_REQUEST:
+ return state.set('passwordRequestSuccess', null);
+ case actions.FETCH_FORGOT_PASSWORD_SUCCESS:
+ return state.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email.');
default :
return state;
}
diff --git a/client/coral-admin/src/reducers/settings.js b/client/coral-admin/src/reducers/settings.js
index f74eb659f..67907b327 100644
--- a/client/coral-admin/src/reducers/settings.js
+++ b/client/coral-admin/src/reducers/settings.js
@@ -33,7 +33,7 @@ export default function settings (state = initialState, action) {
.set('fetchSettingsError', null);
case actions.SETTINGS_RECEIVED:
return state.merge({
- fetchingSettings: null,
+ fetchingSettings: false,
fetchSettingsError: null,
...action.settings
});
@@ -43,7 +43,7 @@ export default function settings (state = initialState, action) {
.set('fetchSettingsError', action.error);
case actions.SETTINGS_UPDATED:
return state.merge({
- fetchingSettings: null,
+ fetchingSettings: false,
fetchSettingsError: null,
...action.settings
});
diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json
index 92e0cbbff..cebc499ca 100644
--- a/client/coral-admin/src/translations.json
+++ b/client/coral-admin/src/translations.json
@@ -1,5 +1,8 @@
{
"en": {
+ "errors": {
+ "NOT_AUTHORIZED": "Your username or password is not recognized by our system."
+ },
"community": {
"username_and_email": "Username and Email",
"account_creation_date": "Account Creation Date",
@@ -50,6 +53,9 @@
"copy": "Copy to Clipboard"
},
"configure": {
+ "stream-settings": "Stream Settings",
+ "moderation-settings": "Moderation Settings",
+ "tech-settings": "Tech Settings",
"custom-css-url": "Custom CSS URL",
"custom-css-url-desc": "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.",
"dashboard": "Dashboard",
@@ -62,8 +68,6 @@
"include-text": "Include your text here.",
"comment-settings": "Settings",
"embed-comment-stream": "Embed Stream",
- "banned-word-header": "Write the banned words list",
- "suspect-word-header": "Write the suspect words list",
"banned-word-text": "Comments which contain these words or phrases (not case-sensitive) will be automatically removed from the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list.",
"suspect-word-text": "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list.",
"wordlist": "Banned Words",
@@ -85,7 +89,7 @@
"comment-count-text-pre": "Comments will be limited to ",
"comment-count-text-post": " characters.",
"comment-count-error": "Please enter a valid number.",
- "domain-list-title": "Domain Whitelist",
+ "domain-list-title": "Permitted Domains",
"domain-list-text": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com)."
},
"bandialog": {
@@ -134,6 +138,9 @@
}
},
"es": {
+ "errors": {
+ "NOT_AUTHORIZED": "Acción no autorizada."
+ },
"community": {
"username_and_email": "Usuario y E-mail",
"account_creation_date": "Fecha de creación de la cuenta",
@@ -171,6 +178,9 @@
"username_flags": ""
},
"configure": {
+ "stream-settings": "Configuración de Comentarios",
+ "moderation-settings": "Configuración de Moderación",
+ "tech-settings": "Configuración Technical",
"custom-css-url": "URL CSS a medida",
"custom-css-url-desc": "URL de una hoja de estilo que va a sobrescribir los estilos por defecto de Embed Stream. Puede ser interna o externa.",
"dashboard": "Panel",
@@ -184,8 +194,6 @@
"comment-settings": "Configuración de Comentarios",
"embed-comment-stream": "Colocar Hilo de Comentarios",
"wordlist": "Palabras Suspendidas y Suspechosas",
- "banned-word-header": "Escribir las palabras no permitidas",
- "suspect-word-header": "Write the suspect words list",
"banned-word-text": "Comentarios que contengan estas palabras o frases, no separadas por comas y en mayusculas o minusuculas, serán automaticamente separadas de los comentarios publicados.",
"suspect-word-text": "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list.",
"banned-words-title": "Banned words list",
@@ -215,7 +223,7 @@
},
"bandialog": {
"ban_user": "Quieres suspender el Usuario?",
- "are_you_sure": "Estas segura que quieres suspender a {props.author.username}?",
+ "are_you_sure": "Estas segura que quieres suspender a {0}?",
"note": "Nota: Suspender este usuario también va a colocar este comentario en la cola de Rechazados.",
"cancel": "Cancelar",
"yes_ban_user": "Si, Suspendan el usuario"
diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js
index e800e5fa3..5fc1673a1 100644
--- a/client/coral-embed-stream/src/Embed.js
+++ b/client/coral-embed-stream/src/Embed.js
@@ -83,8 +83,8 @@ class Embed extends Component {
}
}
- setActiveReplyBox (reactKey) {
- if (!this.props.currentUser) {
+ setActiveReplyBox = (reactKey) => {
+ if (!this.props.auth.user) {
const offset = document.getElementById(`c_${reactKey}`).getBoundingClientRect().top - 75;
this.props.showSignInDialog(offset);
} else {
diff --git a/client/coral-embed/src/index.js b/client/coral-embed/src/index.js
index a75706c8e..d3715b44d 100644
--- a/client/coral-embed/src/index.js
+++ b/client/coral-embed/src/index.js
@@ -5,24 +5,30 @@ const Coral = {};
const Talk = Coral.Talk = {};
// build the URL to load in the pym iframe
-function buildStreamIframeUrl(talkBaseUrl, asset, comment) {
+function buildStreamIframeUrl(talkBaseUrl, asset_url, comment, asset_id) {
let iframeArray = [
talkBaseUrl,
(talkBaseUrl.match(/\/$/) ? '' : '/'), // make sure no double-'/' if opts.talk already ends with '/'
'embed/stream?asset_url=',
- encodeURIComponent(asset)
+ encodeURIComponent(asset_url)
];
if (comment) {
iframeArray.push('&comment_id=');
iframeArray.push(encodeURIComponent(comment));
}
+
+ if (asset_id) {
+ iframeArray.push('&asset_id=');
+ iframeArray.push(encodeURIComponent(asset_id));
+ }
+
return iframeArray.join('');
}
// Set up postMessage listeners/handlers on the pymParent
// e.g. to resize the iframe, and navigate the host page
-function configurePymParent(pymParent, assetUrl) {
+function configurePymParent(pymParent, asset_url) {
let notificationOffset = 200;
let ready = false;
@@ -52,7 +58,7 @@ function configurePymParent(pymParent, assetUrl) {
window.clearInterval(interval);
// @todo - It's weird to me that this is sent here in addition to the iframe URL. Could it just be in one place?
- pymParent.sendMessage('DOMContentLoaded', assetUrl);
+ pymParent.sendMessage('DOMContentLoaded', asset_url);
}
}, 100);
});
@@ -88,11 +94,11 @@ function configurePymParent(pymParent, assetUrl) {
* @param {Object} opts - Configuration options for talk
* @param {String} opts.talk - Talk base URL
* @param {String} [opts.title] - Title of Stream (rendered in iframe)
- * @param {String} [opts.asset] - parent Asset ID or URL. Comments in the
- * stream will replies to this asset
+ * @param {String} [opts.asset_url] - Asset URL
+ * @param {String} [opts.asset_id] - Asset ID
*/
Talk.render = function (el, opts) {
- if ( ! el) {
+ if (!el) {
throw new Error('Please provide Coral.Talk.render() the HTMLElement you want to render Talk in.');
}
if (typeof el !== 'object') {
@@ -101,7 +107,7 @@ Talk.render = function (el, opts) {
opts = opts || {};
// @todo infer this URL without explicit user input (if possible, may have to be added at build/render time of this script)
- if (! opts.talk) {
+ if (!opts.talk) {
throw new Error('Coral.Talk.render() expects opts.talk as the Talk Base URL');
}
@@ -110,16 +116,23 @@ Talk.render = function (el, opts) {
el.id = `_${Math.random()}`;
}
- let asset = opts.asset || window.location.href.split('#')[0];
+ let asset_url = opts.asset_url || window.location.href.split('#')[0];
let comment = window.location.hash.slice(1);
- let pymParent = new pym.Parent(el.id, buildStreamIframeUrl(opts.talk, asset, comment), {
+
+ let query = {
title: opts.title,
- asset_url: asset,
+ asset_url: asset_url,
id: `${el.id}_iframe`,
name: `${el.id}_iframe`
- });
+ };
- configurePymParent(pymParent, asset);
+ if (opts.asset_id && opts.asset_id.length > 0) {
+ query.asset_id = opts.asset_id;
+ }
+
+ let pymParent = new pym.Parent(el.id, buildStreamIframeUrl(opts.talk, asset_url, comment), query);
+
+ configurePymParent(pymParent, asset_url);
};
export default Coral;
diff --git a/client/coral-framework/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js
index f25bddbd6..a874f8f0c 100644
--- a/client/coral-framework/graphql/mutations/index.js
+++ b/client/coral-framework/graphql/mutations/index.js
@@ -42,7 +42,7 @@ export const postComment = graphql(POST_COMMENT, {
updateQueries: {
AssetQuery: (oldData, {mutationResult:{data:{createComment:{comment}}}}) => {
- if (oldData.asset.moderation === 'PRE') {
+ if (oldData.asset.settings.moderation === 'PRE') {
return oldData;
}
diff --git a/client/coral-framework/graphql/queries/index.js b/client/coral-framework/graphql/queries/index.js
index 26a72498d..fa9d0f866 100644
--- a/client/coral-framework/graphql/queries/index.js
+++ b/client/coral-framework/graphql/queries/index.js
@@ -14,8 +14,8 @@ function getQueryVariable(variable) {
}
}
- // If no query is included, return a default string for development
- return 'http://localhost/default/stream';
+ // If not found, return null.
+ return null;
}
export const getCounts = (data) => ({asset_id, limit, sort}) => {
@@ -85,12 +85,19 @@ export const loadMore = (data) => ({limit, cursor, parent_id, asset_id, sort}, n
};
export const queryStream = graphql(STREAM_QUERY, {
- options: () => ({
- variables: {
- asset_url: getQueryVariable('asset_url'),
- comment_id: getQueryVariable('comment_id')
- }
- }),
+ options: () => {
+ let comment_id = getQueryVariable('comment_id');
+ let has_comment = comment_id != null;
+
+ return {
+ variables: {
+ asset_id: getQueryVariable('asset_id'),
+ asset_url: getQueryVariable('asset_url'),
+ comment_id: has_comment ? comment_id : 'no-comment',
+ has_comment
+ }
+ };
+ },
props: ({data}) => ({
data,
loadMore: loadMore(data),
diff --git a/client/coral-framework/graphql/queries/myCommentHistory.graphql b/client/coral-framework/graphql/queries/myCommentHistory.graphql
index 6a4309dac..0b37b192a 100644
--- a/client/coral-framework/graphql/queries/myCommentHistory.graphql
+++ b/client/coral-framework/graphql/queries/myCommentHistory.graphql
@@ -3,6 +3,11 @@ query myCommentHistory {
comments {
id
body
+ asset {
+ id
+ title
+ url
+ }
created_at
}
}
diff --git a/client/coral-framework/graphql/queries/streamQuery.graphql b/client/coral-framework/graphql/queries/streamQuery.graphql
index 4f09f628e..e9f4c827c 100644
--- a/client/coral-framework/graphql/queries/streamQuery.graphql
+++ b/client/coral-framework/graphql/queries/streamQuery.graphql
@@ -1,7 +1,7 @@
#import "../fragments/commentView.graphql"
-query AssetQuery($asset_url: String!, $comment_id: ID!) {
- comment(id: $comment_id) {
+query AssetQuery($asset_id: ID, $asset_url: String!, $comment_id: ID!, $has_comment: Boolean!) {
+ comment(id: $comment_id) @include(if: $has_comment) {
...commentView
parent {
...commentView
@@ -10,7 +10,7 @@ query AssetQuery($asset_url: String!, $comment_id: ID!) {
}
}
}
- asset(url: $asset_url) {
+ asset(id: $asset_id, url: $asset_url) {
id
title
url
diff --git a/client/coral-plugin-history/Comment.js b/client/coral-plugin-history/Comment.js
index df61b9e7d..00dcc40c7 100644
--- a/client/coral-plugin-history/Comment.js
+++ b/client/coral-plugin-history/Comment.js
@@ -5,7 +5,7 @@ const Comment = props => {
return (
@@ -18,7 +18,8 @@ Comment.propTypes = {
body: PropTypes.string
}).isRequired,
asset: PropTypes.shape({
- url: PropTypes.string
+ url: PropTypes.string,
+ title: PropTypes.string
}).isRequired
};
diff --git a/client/coral-plugin-history/CommentHistory.js b/client/coral-plugin-history/CommentHistory.js
index 1940f2695..a53035fb3 100644
--- a/client/coral-plugin-history/CommentHistory.js
+++ b/client/coral-plugin-history/CommentHistory.js
@@ -11,7 +11,7 @@ const CommentHistory = props => {
key={i}
comment={comment}
link={props.link}
- asset={props.asset} />;
+ asset={comment.asset} />;
})}
@@ -19,8 +19,7 @@ const CommentHistory = props => {
};
CommentHistory.propTypes = {
- comments: PropTypes.array.isRequired,
- asset: PropTypes.object.isRequired
+ comments: PropTypes.array.isRequired
};
export default CommentHistory;
diff --git a/client/coral-settings/components/NotLoggedIn.js b/client/coral-settings/components/NotLoggedIn.js
index acd3ae7e6..c76553c50 100644
--- a/client/coral-settings/components/NotLoggedIn.js
+++ b/client/coral-settings/components/NotLoggedIn.js
@@ -5,9 +5,9 @@ import translations from '../translations';
import I18n from 'coral-framework/modules/i18n/i18n';
const lang = new I18n(translations);
-export default ({showSignInDialog}) => (
+export default ({showSignInDialog, requireEmailConfirmation}) => (
-
+
{
showSignInDialog();
diff --git a/client/coral-settings/containers/ProfileContainer.js b/client/coral-settings/containers/ProfileContainer.js
index 4a98ed8ff..9a8117e87 100644
--- a/client/coral-settings/containers/ProfileContainer.js
+++ b/client/coral-settings/containers/ProfileContainer.js
@@ -35,7 +35,7 @@ class ProfileContainer extends Component {
const {me} = this.props.data;
if (!loggedIn || !me) {
- return ;
+ return ;
}
if (data.loading) {
diff --git a/client/coral-sign-in/components/CreateUsernameDialog.js b/client/coral-sign-in/components/CreateUsernameDialog.js
index d0e348046..4a7a99b81 100644
--- a/client/coral-sign-in/components/CreateUsernameDialog.js
+++ b/client/coral-sign-in/components/CreateUsernameDialog.js
@@ -1,8 +1,7 @@
import React from 'react';
import TextField from 'coral-ui/components/TextField';
-import Alert from './Alert';
import Button from 'coral-ui/components/Button';
-import {Dialog} from 'coral-ui';
+import {Dialog, Alert} from 'coral-ui';
import FakeComment from './FakeComment';
import styles from './styles.css';
diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js
index 1f339979b..a0ed5b5b4 100644
--- a/client/coral-sign-in/components/SignInContent.js
+++ b/client/coral-sign-in/components/SignInContent.js
@@ -1,6 +1,5 @@
import React, {PropTypes} from 'react';
-import Alert from './Alert';
-import {Button, TextField, Spinner, Success} from 'coral-ui';
+import {Button, TextField, Spinner, Success, Alert} from 'coral-ui';
import styles from './styles.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations';
diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js
index 216349412..d127cc2c7 100644
--- a/client/coral-sign-in/components/SignUpContent.js
+++ b/client/coral-sign-in/components/SignUpContent.js
@@ -1,6 +1,5 @@
import React, {PropTypes} from 'react';
-import Alert from './Alert';
-import {Button, TextField, Spinner, Success} from 'coral-ui';
+import {Button, TextField, Spinner, Success, Alert} from 'coral-ui';
import styles from './styles.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations';
diff --git a/client/coral-sign-in/components/styles.css b/client/coral-sign-in/components/styles.css
index 31d4a4fed..d3cd47b87 100644
--- a/client/coral-sign-in/components/styles.css
+++ b/client/coral-sign-in/components/styles.css
@@ -65,23 +65,6 @@ input.error{
padding: 3px 0 16px;
}
-.alert {
- padding: 10px;
- margin-bottom: 20px;
- border-radius: 2px;
-}
-
-.alert--success {
- border: solid 1px #1ec00e;
- background: #cbf1b8;
- color: #006900;
-}
-
-.alert--error {
- background: #FFEBEE;
- color: #B71C1C;
-}
-
.userBox {
padding: 10px 0 20px;
letter-spacing: 0.1px;
diff --git a/client/coral-ui/components/Alert.css b/client/coral-ui/components/Alert.css
new file mode 100644
index 000000000..47b4787a1
--- /dev/null
+++ b/client/coral-ui/components/Alert.css
@@ -0,0 +1,16 @@
+.alert {
+ padding: 10px;
+ margin-bottom: 20px;
+ border-radius: 2px;
+}
+
+.alert--success {
+ border: solid 1px #1ec00e;
+ background: #cbf1b8;
+ color: #006900;
+}
+
+.alert--error {
+ background: #FFEBEE;
+ color: #B71C1C;
+}
diff --git a/client/coral-sign-in/components/Alert.js b/client/coral-ui/components/Alert.js
similarity index 87%
rename from client/coral-sign-in/components/Alert.js
rename to client/coral-ui/components/Alert.js
index 019c3456a..02f0524ff 100644
--- a/client/coral-sign-in/components/Alert.js
+++ b/client/coral-ui/components/Alert.js
@@ -1,5 +1,5 @@
import React from 'react';
-import styles from './styles.css';
+import styles from './Alert.css';
const Alert = ({cStyle = 'error', children, className, ...props}) => (
{
// TODO: this is kind of fragile, we should refactor this to resolve
// all these const's that we're using like 'COMMENTS', 'FLAG' to be
// defined in a checkable schema.
- return context.mutators.Action.create({
+ return ActionsService.insertUserAction({
item_id: comment.id,
item_type: 'COMMENTS',
action_type: 'FLAG',
+ user_id: null,
group_id: 'Matched suspect word filter',
metadata: {}
})
diff --git a/routes/admin/index.js b/routes/admin/index.js
index a3699143e..e2473bca9 100644
--- a/routes/admin/index.js
+++ b/routes/admin/index.js
@@ -15,10 +15,6 @@ router.get('/password-reset', (req, res) => {
res.render('password-reset', {redirectUri: process.env.TALK_ROOT_URL});
});
-router.get('/login', (req, res, next) => {
- res.render('admin/login');
-});
-
router.get('*', (req, res) => {
res.render('admin', {basePath: '/client/coral-admin'});
});
diff --git a/test/client/coral-plugin-history/CommentHistory.spec.js b/test/client/coral-plugin-history/CommentHistory.spec.js
index 945bf45a3..671a50137 100644
--- a/test/client/coral-plugin-history/CommentHistory.spec.js
+++ b/test/client/coral-plugin-history/CommentHistory.spec.js
@@ -20,6 +20,10 @@ describe('coral-plugin-history/CommentHistory', () => {
'closedAt':null
};
+ comments.forEach((comment) => {
+ comment.asset = asset;
+ });
+
beforeEach(() => {
render = shallow(
{}}/>);
});
diff --git a/views/admin/login.ejs b/views/admin/login.ejs
deleted file mode 100644
index e88dd86fd..000000000
--- a/views/admin/login.ejs
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
- Admin Login
-
-
-
-
-
-
-
-
-
-
-
diff --git a/webpack.config.js b/webpack.config.js
index cd00696d8..432bb6155 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -17,7 +17,7 @@ const buildEmbeds = [
];
module.exports = {
- devtool: 'cheap-source-map',
+ devtool: '#cheap-module-source-map',
entry: Object.assign({}, {
'embed': [
'babel-polyfill',
@@ -58,7 +58,8 @@ module.exports = {
exclude: /node_modules/,
test: /\.js$/,
query: {
- cacheDirectory: true
+ cacheDirectory: true,
+ sourceMap: true
}
},
{