From 26a660248ea1a17c9f4cf1b185c59939c16787bc Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 22 Feb 2018 14:22:58 -0700 Subject: [PATCH 01/10] replaced localStorage state events with postMessage --- client/coral-auth-callback/src/index.js | 35 +++++++--- .../coral-embed-stream/src/actions/login.js | 6 +- .../src/containers/Embed.js | 32 +++++++++ client/coral-framework/actions/auth.js | 15 +++- .../services/messages/constants.js | 11 +++ .../services/messages/index.js | 2 + .../services/messages/sendMessage.js | 13 ++++ .../services/messages/subscriptions.js | 70 +++++++++++++++++++ middleware/staticTemplate.js | 9 ++- .../client/actions.js | 6 +- .../talk-plugin-google-auth/client/actions.js | 6 +- url.js | 3 + views/auth-callback.ejs | 3 + views/partials/data.ejs | 3 + views/partials/head.ejs | 4 +- 15 files changed, 188 insertions(+), 30 deletions(-) create mode 100644 client/coral-framework/services/messages/constants.js create mode 100644 client/coral-framework/services/messages/index.js create mode 100644 client/coral-framework/services/messages/sendMessage.js create mode 100644 client/coral-framework/services/messages/subscriptions.js create mode 100644 views/partials/data.ejs diff --git a/client/coral-auth-callback/src/index.js b/client/coral-auth-callback/src/index.js index b7f3ed226..204a86470 100644 --- a/client/coral-auth-callback/src/index.js +++ b/client/coral-auth-callback/src/index.js @@ -1,14 +1,29 @@ +import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; +import sendMessage from 'coral-framework/services/messages/sendMessage'; + document.addEventListener('DOMContentLoaded', () => { - // Get the auth element and parse it as JSON by decoding it. - const auth = document.getElementById('auth'); - const doc = document.implementation.createHTMLDocument(''); - doc.body.innerHTML = auth.innerText; + try { + // Get the auth element and parse it as JSON by decoding it. + const auth = document.getElementById('auth'); + const doc = document.implementation.createHTMLDocument(''); + doc.body.innerHTML = auth.innerText; - // Set the item in localStorage. - localStorage.setItem('auth', doc.body.textContent); + // Auth state is contained within the node. + const { err, data } = JSON.parse(doc.body.textContent); + if (err) { + // TODO: send back the error message. + console.error(err); + } else { + // The data will contain a user and a token. + const { user, token } = data; - // Close the window. - setTimeout(() => { - window.close(); - }, 50); + // Send the state back. + sendMessage(HANDLE_SUCCESSFUL_LOGIN, { user, token }); + } + } finally { + // Always close the window. + setTimeout(() => { + window.close(); + }, 50); + } }); diff --git a/client/coral-embed-stream/src/actions/login.js b/client/coral-embed-stream/src/actions/login.js index c602bf7b6..fe1f76149 100644 --- a/client/coral-embed-stream/src/actions/login.js +++ b/client/coral-embed-stream/src/actions/login.js @@ -1,14 +1,10 @@ import * as actions from '../constants/login'; -import { checkLogin } from 'coral-framework/actions/auth'; export const showSignInDialog = () => ({ type: actions.SHOW_SIGNIN_DIALOG, }); -export const hideSignInDialog = () => dispatch => { - dispatch(checkLogin()); - dispatch({ type: actions.HIDE_SIGNIN_DIALOG }); -}; +export const hideSignInDialog = () => ({ type: actions.HIDE_SIGNIN_DIALOG }); export const focusSignInDialog = () => ({ type: actions.FOCUS_SIGNIN_DIALOG, diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index f8486fd14..acdbb184b 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -29,6 +29,17 @@ import t from 'coral-framework/services/i18n'; import PropTypes from 'prop-types'; import { setActiveTab } from '../actions/embed'; +// TODO: refactor out to a HOC +import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; +import { + handleSuccessfulLogin, + checkLogin, +} from 'coral-framework/actions/auth'; +import { + subscribeToMessages, + unsubscribeFromMessages, +} from 'coral-framework/services/messages'; + class EmbedContainer extends React.Component { static contextTypes = { pym: PropTypes.object, @@ -37,6 +48,8 @@ class EmbedContainer extends React.Component { subscriptions = []; subscribeToUpdates(props = this.props) { + subscribeToMessages(this.handleAuth); + if (props.currentUser) { const newSubscriptions = [ { @@ -86,8 +99,23 @@ class EmbedContainer extends React.Component { unsubscribe() { this.subscriptions.forEach(unsubscribe => unsubscribe()); this.subscriptions = []; + unsubscribeFromMessages(this.handleAuth); } + // TODO: refactor out to a HOC + handleAuth = ({ name, data }) => { + if (name !== HANDLE_SUCCESSFUL_LOGIN) { + return; + } + + // data will contain the user and token. + const { user, token } = data; + const { handleSuccessfulLogin, checkLogin } = this.props; + + handleSuccessfulLogin(user, token); + checkLogin(); + }; + resubscribe(props) { this.unsubscribe(); this.subscribeToUpdates(props); @@ -301,6 +329,8 @@ EmbedContainer.propTypes = { fetchAssetSuccess: PropTypes.func, showSignInDialog: PropTypes.bool, signInDialogFocus: PropTypes.bool, + handleSuccessfulLogin: PropTypes.func.isRequired, + checkLogin: PropTypes.func.isRequired, }; const mapStateToProps = state => ({ @@ -328,6 +358,8 @@ const mapDispatchToProps = dispatch => blurSignInDialog, hideSignInDialog, updateStatus, + handleSuccessfulLogin, + checkLogin, }, dispatch ); diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 0c4780548..6fe8ad508 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,5 +1,6 @@ import * as actions from '../constants/auth'; import jwtDecode from 'jwt-decode'; +import { sendMessage } from '../services/messages'; function cleanAuthData(localStorage) { localStorage.removeItem('token'); @@ -65,11 +66,23 @@ export const handleSuccessfulLogin = (user, token) => ( _, { client, localStorage } ) => { + const { exp } = jwtDecode(token); + if (localStorage) { - localStorage.setItem('exp', jwtDecode(token).exp); + localStorage.setItem('exp', exp); localStorage.setItem('token', token); } + // Send the message via the messages service to the window.opener if it + // exists. + if (window.opener) { + sendMessage( + actions.HANDLE_SUCCESSFUL_LOGIN, + { user, token }, + window.opener + ); + } + client.resetWebsocket(); dispatch({ diff --git a/client/coral-framework/services/messages/constants.js b/client/coral-framework/services/messages/constants.js new file mode 100644 index 000000000..7204194f7 --- /dev/null +++ b/client/coral-framework/services/messages/constants.js @@ -0,0 +1,11 @@ +import { getStaticConfiguration } from 'coral-framework/services/staticConfiguration'; + +// Load the static url from the static configuration, we'll use it to formulate +// the authorized domain to allow the message to be sent to. +const { STATIC_ORIGIN } = getStaticConfiguration(); + +// Export the origin that will be sent. +export { STATIC_ORIGIN as ORIGIN }; + +// Scope all the requests made via the messages service. +export const SCOPE = 'client'; diff --git a/client/coral-framework/services/messages/index.js b/client/coral-framework/services/messages/index.js new file mode 100644 index 000000000..311034624 --- /dev/null +++ b/client/coral-framework/services/messages/index.js @@ -0,0 +1,2 @@ +export { default as sendMessage } from './sendMessage'; +export { subscribeToMessages, unsubscribeFromMessages } from './subscriptions'; diff --git a/client/coral-framework/services/messages/sendMessage.js b/client/coral-framework/services/messages/sendMessage.js new file mode 100644 index 000000000..a0e7dd803 --- /dev/null +++ b/client/coral-framework/services/messages/sendMessage.js @@ -0,0 +1,13 @@ +import { SCOPE, ORIGIN } from './constants'; + +export default (name, data, target = window.opener) => { + if (!target) { + return; + } + + // Serialize the message to be sent via postMessage. + const msg = { name, data, scope: SCOPE }; + + // Send the message. + target.postMessage(msg, ORIGIN); +}; diff --git a/client/coral-framework/services/messages/subscriptions.js b/client/coral-framework/services/messages/subscriptions.js new file mode 100644 index 000000000..984a8377d --- /dev/null +++ b/client/coral-framework/services/messages/subscriptions.js @@ -0,0 +1,70 @@ +import { SCOPE, ORIGIN } from './constants'; + +import set from 'lodash/set'; +import has from 'lodash/has'; +import get from 'lodash/get'; +import remove from 'lodash/remove'; + +// withOriginCheck wraps a given handler for a messages event with a check to +// see if the origin matches. +const withOriginCheck = handler => { + return event => { + const origin = get(event, 'origin'); + if (origin !== ORIGIN) { + return; + } + + const scope = get(event, 'data.scope'); + if (scope !== SCOPE) { + return; + } + + // Pass the handler the event details. + handler(event); + }; +}; + +// withParseData will parse the data. +const withParseData = handler => { + return event => { + const data = get(event, 'data.data'); + const name = get(event, 'data.name'); + if (!data || !name) { + return; + } + + handler({ data, name, event }); + }; +}; + +// Store a reference to each listener added. +const listeners = {}; + +export const subscribeToMessages = (handler, target = window) => { + // If this handler is already attached to the target, detach it. + if (has(listeners, [target, handler])) { + unsubscribeFromMessages(handler, target); + } + + // Wrap the listener with a origin check. + const listener = withOriginCheck(withParseData(handler)); + + // Save a reference to the compiled listener. + set(listeners, [target, handler], listener); + + // Attach the listener to the target. + target.addEventListener('message', listener); +}; + +export const unsubscribeFromMessages = (handler, target = window) => { + if (!has(listeners, [target, handler])) { + return; + } + + const listener = get(listeners, [target, handler]); + + // Remove the listener from the target. + target.removeEventListener('message', listener); + + remove(listeners, [target, handler]); +}; diff --git a/middleware/staticTemplate.js b/middleware/staticTemplate.js index 6848e59e1..5a7c34b60 100644 --- a/middleware/staticTemplate.js +++ b/middleware/staticTemplate.js @@ -1,6 +1,12 @@ const SettingsService = require('../services/settings'); -const { BASE_URL, BASE_PATH, MOUNT_PATH, STATIC_URL } = require('../url'); +const { + BASE_URL, + BASE_PATH, + MOUNT_PATH, + STATIC_URL, + STATIC_ORIGIN, +} = require('../url'); const { RECAPTCHA_PUBLIC, WEBSOCKET_LIVE_URI } = require('../config'); @@ -15,6 +21,7 @@ const TEMPLATE_LOCALS = { TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC, LIVE_URI: WEBSOCKET_LIVE_URI, STATIC_URL, + STATIC_ORIGIN, }, }; diff --git a/plugins/talk-plugin-facebook-auth/client/actions.js b/plugins/talk-plugin-facebook-auth/client/actions.js index 5a9ebc66f..79f2d2a6a 100644 --- a/plugins/talk-plugin-facebook-auth/client/actions.js +++ b/plugins/talk-plugin-facebook-auth/client/actions.js @@ -1,7 +1,3 @@ export const loginWithFacebook = () => (dispatch, _, { rest }) => { - window.open( - `${rest.uri}/auth/facebook`, - 'Continue with Facebook', - 'menubar=0,resizable=0,width=500,height=500,top=200,left=500' - ); + window.location = `${rest.uri}/auth/facebook`; }; diff --git a/plugins/talk-plugin-google-auth/client/actions.js b/plugins/talk-plugin-google-auth/client/actions.js index 6519d9f2b..8b49bf39e 100644 --- a/plugins/talk-plugin-google-auth/client/actions.js +++ b/plugins/talk-plugin-google-auth/client/actions.js @@ -1,7 +1,3 @@ export const loginWithGoogle = () => (dispatch, _, { rest }) => { - window.open( - `${rest.uri}/auth/google`, - 'Continue with Google', - 'menubar=0,resizable=0,width=500,height=500,top=200,left=500' - ); + window.location = `${rest.uri}/auth/google`; }; diff --git a/url.js b/url.js index e855859de..294095d48 100644 --- a/url.js +++ b/url.js @@ -18,9 +18,12 @@ const MOUNT_PATH = ROOT_URL_MOUNT_PATH ? BASE_PATH : '/'; // The STATIC_URL is the url where static assets should be loaded from. const STATIC_URL = trailingSlash(STATIC_URI); +const STATIC_ORIGIN = new URL(STATIC_URI).origin; + module.exports = { BASE_URL, BASE_PATH, MOUNT_PATH, STATIC_URL, + STATIC_ORIGIN, }; diff --git a/views/auth-callback.ejs b/views/auth-callback.ejs index 25603bda4..424889065 100644 --- a/views/auth-callback.ejs +++ b/views/auth-callback.ejs @@ -1,5 +1,8 @@ + + <%- include partials/data %> + diff --git a/views/partials/data.ejs b/views/partials/data.ejs new file mode 100644 index 000000000..f0bbf5925 --- /dev/null +++ b/views/partials/data.ejs @@ -0,0 +1,3 @@ +<%_ if (data != null) { _%> + +<%_ } _%> \ No newline at end of file diff --git a/views/partials/head.ejs b/views/partials/head.ejs index bc8b949d3..555f5689e 100644 --- a/views/partials/head.ejs +++ b/views/partials/head.ejs @@ -18,7 +18,5 @@ <%_ if (locals.customCssUrl) { _%> <%_ } _%> -<%_ if (data != null) { _%> - -<%_ } _%> +<%- include data %> \ No newline at end of file From fd53de94a1fe4e5045a3ff588d0ab967229b5493 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 22 Feb 2018 14:24:54 -0700 Subject: [PATCH 02/10] linting --- .eslintignore | 5 ++- .../client/login/containers/Main.js | 43 ------------------- .../client/components/SignIn.js | 4 +- .../client/components/SignUp.js | 4 +- 4 files changed, 5 insertions(+), 51 deletions(-) diff --git a/.eslintignore b/.eslintignore index 5be504ff4..6dc63cb59 100644 --- a/.eslintignore +++ b/.eslintignore @@ -13,6 +13,7 @@ public !plugins/talk-plugin-facebook-auth !plugins/talk-plugin-featured-comments !plugins/talk-plugin-flag-details +!plugins/talk-plugin-google-auth !plugins/talk-plugin-ignore-user !plugins/talk-plugin-like !plugins/talk-plugin-love @@ -21,6 +22,7 @@ public !plugins/talk-plugin-moderation-actions !plugins/talk-plugin-offtopic !plugins/talk-plugin-permalink +!plugins/talk-plugin-profile-settings !plugins/talk-plugin-remember-sort !plugins/talk-plugin-respect !plugins/talk-plugin-sort-most-liked @@ -31,5 +33,4 @@ public !plugins/talk-plugin-sort-oldest !plugins/talk-plugin-subscriber !plugins/talk-plugin-toxic-comments -!plugins/talk-plugin-viewing-options -!plugins/talk-plugin-profile-settings +!plugins/talk-plugin-viewing-options \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/login/containers/Main.js b/plugins/talk-plugin-auth/client/login/containers/Main.js index 05778133a..235bd6cde 100644 --- a/plugins/talk-plugin-auth/client/login/containers/Main.js +++ b/plugins/talk-plugin-auth/client/login/containers/Main.js @@ -4,10 +4,6 @@ import Main from '../components/Main'; import { connect } from 'plugin-api/beta/client/hocs'; import { bindActionCreators } from 'redux'; import { setView } from '../actions'; -import { - setAuthToken, - handleSuccessfulLogin, -} from 'plugin-api/beta/client/actions/auth'; import * as views from '../enums/views'; class MainContainer extends React.Component { @@ -24,7 +20,6 @@ class MainContainer extends React.Component { componentDidMount() { this.resizeHeight(); - this.listenToStorageChanges(); } componentDidUpdate(prevProps) { @@ -33,40 +28,6 @@ class MainContainer extends React.Component { } } - componentWillUnmount() { - this.unlisten(); - } - - listenToStorageChanges() { - window.addEventListener('storage', this.handleAuth); - } - - unlisten() { - window.removeEventListener('storage', this.handleAuth); - } - - // External logins store auth data into `auth`, we use it to detect - // a successful sign in. - handleAuth = e => { - if (e.key === 'auth') { - const { err, data } = JSON.parse(e.newValue); - if (err) { - console.error(err); - } else if (data && data.token) { - if (data.user) { - this.props.handleSuccessfulLogin(data.user, data.token); - } else { - this.props.setAuthToken(data.token); - } - this.unlisten(); - localStorage.removeItem('auth'); - window.close(); - } else { - console.error('auth was set, but did not contain a token'); - } - } - }; - render() { return
; } @@ -75,8 +36,6 @@ class MainContainer extends React.Component { MainContainer.propTypes = { view: PropTypes.string.isRequired, setView: PropTypes.func.isRequired, - handleSuccessfulLogin: PropTypes.func.isRequired, - setAuthToken: PropTypes.func.isRequired, }; const mapStateToProps = ({ talkPluginAuth: state }) => ({ @@ -87,8 +46,6 @@ const mapDispatchToProps = dispatch => bindActionCreators( { setView, - handleSuccessfulLogin, - setAuthToken, }, dispatch ); diff --git a/plugins/talk-plugin-google-auth/client/components/SignIn.js b/plugins/talk-plugin-google-auth/client/components/SignIn.js index 527d41238..a361cfe70 100644 --- a/plugins/talk-plugin-google-auth/client/components/SignIn.js +++ b/plugins/talk-plugin-google-auth/client/components/SignIn.js @@ -3,7 +3,5 @@ import GoogleButton from '../containers/GoogleButton'; import { t } from 'plugin-api/beta/client/services'; export default () => { - return ( - {t('talk-plugin-google-auth.sign_in')} - ); + return {t('talk-plugin-google-auth.sign_in')}; }; diff --git a/plugins/talk-plugin-google-auth/client/components/SignUp.js b/plugins/talk-plugin-google-auth/client/components/SignUp.js index 704cc3963..3193b02fb 100644 --- a/plugins/talk-plugin-google-auth/client/components/SignUp.js +++ b/plugins/talk-plugin-google-auth/client/components/SignUp.js @@ -3,7 +3,5 @@ import GoogleButton from '../containers/GoogleButton'; import { t } from 'plugin-api/beta/client/services'; export default () => { - return ( - {t('talk-plugin-google-auth.sign_up')} - ); + return {t('talk-plugin-google-auth.sign_up')}; }; From 6a46703e98bb7a0c14bb0c12e824f8d6c13bc822 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 22 Feb 2018 15:08:59 -0700 Subject: [PATCH 03/10] added sessionStorage fallback --- client/coral-framework/services/storage.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/client/coral-framework/services/storage.js b/client/coral-framework/services/storage.js index de96fdf4c..66e2c96cd 100644 --- a/client/coral-framework/services/storage.js +++ b/client/coral-framework/services/storage.js @@ -1,9 +1,10 @@ import uuid from 'uuid/v4'; function getStorage(type) { - let storage = window[type], - x = '__storage_test__'; + let storage; try { + storage = window[type]; + const x = '__storage_test__'; storage.setItem(x, x); storage.removeItem(x); } catch (e) { @@ -11,6 +12,8 @@ function getStorage(type) { e instanceof DOMException && // everything except Firefox (e.code === 22 || + // SecurityError related to having 3rd party cookies disabled. + e.code === 18 || // Firefox e.code === 1014 || @@ -19,14 +22,18 @@ function getStorage(type) { // everything except Firefox e.name === 'QuotaExceededError' || // Firefox - e.name === 'NS_ERROR_DOM_QUOTA_REACHED') && - // acknowledge QuotaExceededError only if there's something already stored - storage.length !== 0; + e.name === 'NS_ERROR_DOM_QUOTA_REACHED'); if (!ignore) { - console.warning(e); // eslint-disable-line - return null; + console.warn(e); + } + + // When third party cookies are disabled, session storage is readable/ + // writable, but localStorage is not. Try to get the sessionStorage to use. + if (type !== 'sessionStorage') { + return getStorage('sessionStorage'); } } + return storage; } From 1b05f146fe2586f23003b1b4fa40f1a503d4b687 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 17:29:53 +0100 Subject: [PATCH 04/10] Remove redudant request for user object --- .../coral-embed-stream/src/containers/Embed.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index acdbb184b..812c18e22 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -33,7 +33,7 @@ import { setActiveTab } from '../actions/embed'; import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; import { handleSuccessfulLogin, - checkLogin, + setAuthToken, } from 'coral-framework/actions/auth'; import { subscribeToMessages, @@ -110,10 +110,15 @@ class EmbedContainer extends React.Component { // data will contain the user and token. const { user, token } = data; - const { handleSuccessfulLogin, checkLogin } = this.props; + const { handleSuccessfulLogin, setAuthToken } = this.props; - handleSuccessfulLogin(user, token); - checkLogin(); + if (user && token) { + handleSuccessfulLogin(user, token); + } else if (token) { + setAuthToken(token); + } else { + console.error('Invalid auth data supplied', data); + } }; resubscribe(props) { @@ -330,7 +335,7 @@ EmbedContainer.propTypes = { showSignInDialog: PropTypes.bool, signInDialogFocus: PropTypes.bool, handleSuccessfulLogin: PropTypes.func.isRequired, - checkLogin: PropTypes.func.isRequired, + setAuthToken: PropTypes.func.isRequired, }; const mapStateToProps = state => ({ @@ -359,7 +364,7 @@ const mapDispatchToProps = dispatch => hideSignInDialog, updateStatus, handleSuccessfulLogin, - checkLogin, + setAuthToken, }, dispatch ); From 17a0aebdf7af3e47682c9ebe8dc1762dc4a54176 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:10:01 +0100 Subject: [PATCH 05/10] Refactor postMessage service --- client/coral-auth-callback/src/index.js | 9 +- .../src/containers/Embed.js | 40 +-------- client/coral-framework/actions/auth.js | 5 +- .../components/TalkProvider.js | 2 + client/coral-framework/hocs/index.js | 1 + .../hocs/withPopupAuthHandler.js | 54 ++++++++++++ client/coral-framework/services/bootstrap.js | 6 +- .../services/messages/constants.js | 11 --- .../services/messages/index.js | 2 - .../services/messages/sendMessage.js | 13 --- .../services/messages/subscriptions.js | 70 --------------- .../coral-framework/services/postMessage.js | 86 +++++++++++++++++++ 12 files changed, 159 insertions(+), 140 deletions(-) create mode 100644 client/coral-framework/hocs/withPopupAuthHandler.js delete mode 100644 client/coral-framework/services/messages/constants.js delete mode 100644 client/coral-framework/services/messages/index.js delete mode 100644 client/coral-framework/services/messages/sendMessage.js delete mode 100644 client/coral-framework/services/messages/subscriptions.js create mode 100644 client/coral-framework/services/postMessage.js diff --git a/client/coral-auth-callback/src/index.js b/client/coral-auth-callback/src/index.js index 204a86470..41a83dcd2 100644 --- a/client/coral-auth-callback/src/index.js +++ b/client/coral-auth-callback/src/index.js @@ -1,8 +1,13 @@ import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; -import sendMessage from 'coral-framework/services/messages/sendMessage'; +import { getStaticConfiguration } from 'coral-framework/services/staticConfiguration'; +import { createPostMessage } from 'coral-framework/services/postMessage'; document.addEventListener('DOMContentLoaded', () => { try { + const staticConfig = getStaticConfiguration(); + const { STATIC_ORIGIN: origin } = staticConfig; + const postMessage = createPostMessage(origin); + // Get the auth element and parse it as JSON by decoding it. const auth = document.getElementById('auth'); const doc = document.implementation.createHTMLDocument(''); @@ -18,7 +23,7 @@ document.addEventListener('DOMContentLoaded', () => { const { user, token } = data; // Send the state back. - sendMessage(HANDLE_SUCCESSFUL_LOGIN, { user, token }); + postMessage.post(HANDLE_SUCCESSFUL_LOGIN, { user, token }); } } finally { // Always close the window. diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index 812c18e22..b9e0cd357 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -19,7 +19,7 @@ import { getDefinitionName, getSlotFragmentSpreads, } from 'coral-framework/utils'; -import { withQuery } from 'coral-framework/hocs'; +import { withQuery, withPopupAuthHandler } from 'coral-framework/hocs'; import Embed from '../components/Embed'; import Stream from '../tabs/stream/containers/Stream'; import AutomaticAssetClosure from './AutomaticAssetClosure'; @@ -29,17 +29,6 @@ import t from 'coral-framework/services/i18n'; import PropTypes from 'prop-types'; import { setActiveTab } from '../actions/embed'; -// TODO: refactor out to a HOC -import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; -import { - handleSuccessfulLogin, - setAuthToken, -} from 'coral-framework/actions/auth'; -import { - subscribeToMessages, - unsubscribeFromMessages, -} from 'coral-framework/services/messages'; - class EmbedContainer extends React.Component { static contextTypes = { pym: PropTypes.object, @@ -48,8 +37,6 @@ class EmbedContainer extends React.Component { subscriptions = []; subscribeToUpdates(props = this.props) { - subscribeToMessages(this.handleAuth); - if (props.currentUser) { const newSubscriptions = [ { @@ -99,28 +86,8 @@ class EmbedContainer extends React.Component { unsubscribe() { this.subscriptions.forEach(unsubscribe => unsubscribe()); this.subscriptions = []; - unsubscribeFromMessages(this.handleAuth); } - // TODO: refactor out to a HOC - handleAuth = ({ name, data }) => { - if (name !== HANDLE_SUCCESSFUL_LOGIN) { - return; - } - - // data will contain the user and token. - const { user, token } = data; - const { handleSuccessfulLogin, setAuthToken } = this.props; - - if (user && token) { - handleSuccessfulLogin(user, token); - } else if (token) { - setAuthToken(token); - } else { - console.error('Invalid auth data supplied', data); - } - }; - resubscribe(props) { this.unsubscribe(); this.subscribeToUpdates(props); @@ -334,8 +301,6 @@ EmbedContainer.propTypes = { fetchAssetSuccess: PropTypes.func, showSignInDialog: PropTypes.bool, signInDialogFocus: PropTypes.bool, - handleSuccessfulLogin: PropTypes.func.isRequired, - setAuthToken: PropTypes.func.isRequired, }; const mapStateToProps = state => ({ @@ -363,13 +328,12 @@ const mapDispatchToProps = dispatch => blurSignInDialog, hideSignInDialog, updateStatus, - handleSuccessfulLogin, - setAuthToken, }, dispatch ); export default compose( + withPopupAuthHandler, connect(mapStateToProps, mapDispatchToProps), branch(props => !props.checkedInitialLogin, renderComponent(Spinner)), withEmbedQuery diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 6fe8ad508..17b1c38f9 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,6 +1,5 @@ import * as actions from '../constants/auth'; import jwtDecode from 'jwt-decode'; -import { sendMessage } from '../services/messages'; function cleanAuthData(localStorage) { localStorage.removeItem('token'); @@ -64,7 +63,7 @@ export const setAuthToken = token => (dispatch, _, { localStorage }) => { export const handleSuccessfulLogin = (user, token) => ( dispatch, _, - { client, localStorage } + { client, localStorage, postMessage } ) => { const { exp } = jwtDecode(token); @@ -76,7 +75,7 @@ export const handleSuccessfulLogin = (user, token) => ( // Send the message via the messages service to the window.opener if it // exists. if (window.opener) { - sendMessage( + postMessage.post( actions.HANDLE_SUCCESSFUL_LOGIN, { user, token }, window.opener diff --git a/client/coral-framework/components/TalkProvider.js b/client/coral-framework/components/TalkProvider.js index 3164d8e9d..343d559ea 100644 --- a/client/coral-framework/components/TalkProvider.js +++ b/client/coral-framework/components/TalkProvider.js @@ -17,6 +17,7 @@ class TalkProvider extends React.Component { store: this.props.store, pymLocalStorage: this.props.pymLocalStorage, pymSessionStorage: this.props.pymSessionStorage, + postMessage: this.props.postMessage, }; } @@ -39,6 +40,7 @@ TalkProvider.childContextTypes = { pymSessionStorage: PropTypes.object, history: PropTypes.object, store: PropTypes.object, + postMessage: PropTypes.object, }; TalkProvider.propTypes = TalkProvider.childContextTypes; diff --git a/client/coral-framework/hocs/index.js b/client/coral-framework/hocs/index.js index eb481de99..5e2e3dd40 100644 --- a/client/coral-framework/hocs/index.js +++ b/client/coral-framework/hocs/index.js @@ -10,6 +10,7 @@ export { default as withSignIn } from './withSignIn'; export { default as withSignUp } from './withSignUp'; export { default as withForgotPassword } from './withForgotPassword'; export { default as withSetUsername } from './withSetUsername'; +export { default as withPopupAuthHandler } from './withPopupAuthHandler'; export { default as withResendEmailConfirmation, } from './withResendEmailConfirmation'; diff --git a/client/coral-framework/hocs/withPopupAuthHandler.js b/client/coral-framework/hocs/withPopupAuthHandler.js new file mode 100644 index 000000000..ab2530e66 --- /dev/null +++ b/client/coral-framework/hocs/withPopupAuthHandler.js @@ -0,0 +1,54 @@ +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; +import PropTypes from 'prop-types'; +import { HANDLE_SUCCESSFUL_LOGIN } from 'coral-framework/constants/auth'; +import { + handleSuccessfulLogin, + setAuthToken, +} from 'coral-framework/actions/auth'; + +/** + * WithPopupAuthHandler listens to successful logins over + * the `postMessage` service. + */ +export default hoistStatics(WrappedComponent => { + class WithPopupAuthHandler extends React.Component { + static contextTypes = { + store: PropTypes.object, + postMessage: PropTypes.object, + }; + + constructor(props, context) { + super(props, context); + context.postMessage.subscribe(this.handleAuth); + } + + componentWillUnmount() { + this.context.postMessage.unsubscribe(this.handleAuth); + } + + handleAuth = ({ name, data }) => { + if (name !== HANDLE_SUCCESSFUL_LOGIN) { + return; + } + + const { store } = this.context; + // data will contain the user and token. + const { user, token } = data; + + if (user && token) { + store.dispatch(handleSuccessfulLogin(user, token)); + } else if (token) { + store.dispatch(setAuthToken(token)); + } else { + console.error('Invalid auth data supplied', data); + } + }; + + render() { + return ; + } + } + + return WithPopupAuthHandler; +}); diff --git a/client/coral-framework/services/bootstrap.js b/client/coral-framework/services/bootstrap.js index a7dd6df98..691404369 100644 --- a/client/coral-framework/services/bootstrap.js +++ b/client/coral-framework/services/bootstrap.js @@ -14,6 +14,7 @@ import { createPluginsService } from './plugins'; import { createNotificationService } from './notification'; import { createGraphQLRegistry } from './graphqlRegistry'; import { createGraphQLService } from './graphql'; +import { createPostMessage } from './postMessage'; import globalFragments from 'coral-framework/graphql/fragments'; import { createStorage, @@ -118,7 +119,7 @@ export async function createContext({ }); const staticConfig = getStaticConfiguration(); - let { LIVE_URI: liveUri } = staticConfig; + let { LIVE_URI: liveUri, STATIC_ORIGIN: origin } = staticConfig; if (liveUri == null) { // The protocol must match the origin protocol, secure/insecure. const protocol = location.protocol === 'https:' ? 'wss' : 'ws'; @@ -128,6 +129,8 @@ export async function createContext({ liveUri = `${protocol}://${location.host}${BASE_PATH}api/v1/live`; } + const postMessage = createPostMessage(origin); + const client = createClient({ uri: `${BASE_PATH}api/v1/graph/ql`, liveUri, @@ -158,6 +161,7 @@ export async function createContext({ pymLocalStorage, pymSessionStorage, inIframe, + postMessage, }; // Load framework fragments. diff --git a/client/coral-framework/services/messages/constants.js b/client/coral-framework/services/messages/constants.js deleted file mode 100644 index 7204194f7..000000000 --- a/client/coral-framework/services/messages/constants.js +++ /dev/null @@ -1,11 +0,0 @@ -import { getStaticConfiguration } from 'coral-framework/services/staticConfiguration'; - -// Load the static url from the static configuration, we'll use it to formulate -// the authorized domain to allow the message to be sent to. -const { STATIC_ORIGIN } = getStaticConfiguration(); - -// Export the origin that will be sent. -export { STATIC_ORIGIN as ORIGIN }; - -// Scope all the requests made via the messages service. -export const SCOPE = 'client'; diff --git a/client/coral-framework/services/messages/index.js b/client/coral-framework/services/messages/index.js deleted file mode 100644 index 311034624..000000000 --- a/client/coral-framework/services/messages/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default as sendMessage } from './sendMessage'; -export { subscribeToMessages, unsubscribeFromMessages } from './subscriptions'; diff --git a/client/coral-framework/services/messages/sendMessage.js b/client/coral-framework/services/messages/sendMessage.js deleted file mode 100644 index a0e7dd803..000000000 --- a/client/coral-framework/services/messages/sendMessage.js +++ /dev/null @@ -1,13 +0,0 @@ -import { SCOPE, ORIGIN } from './constants'; - -export default (name, data, target = window.opener) => { - if (!target) { - return; - } - - // Serialize the message to be sent via postMessage. - const msg = { name, data, scope: SCOPE }; - - // Send the message. - target.postMessage(msg, ORIGIN); -}; diff --git a/client/coral-framework/services/messages/subscriptions.js b/client/coral-framework/services/messages/subscriptions.js deleted file mode 100644 index 984a8377d..000000000 --- a/client/coral-framework/services/messages/subscriptions.js +++ /dev/null @@ -1,70 +0,0 @@ -import { SCOPE, ORIGIN } from './constants'; - -import set from 'lodash/set'; -import has from 'lodash/has'; -import get from 'lodash/get'; -import remove from 'lodash/remove'; - -// withOriginCheck wraps a given handler for a messages event with a check to -// see if the origin matches. -const withOriginCheck = handler => { - return event => { - const origin = get(event, 'origin'); - if (origin !== ORIGIN) { - return; - } - - const scope = get(event, 'data.scope'); - if (scope !== SCOPE) { - return; - } - - // Pass the handler the event details. - handler(event); - }; -}; - -// withParseData will parse the data. -const withParseData = handler => { - return event => { - const data = get(event, 'data.data'); - const name = get(event, 'data.name'); - if (!data || !name) { - return; - } - - handler({ data, name, event }); - }; -}; - -// Store a reference to each listener added. -const listeners = {}; - -export const subscribeToMessages = (handler, target = window) => { - // If this handler is already attached to the target, detach it. - if (has(listeners, [target, handler])) { - unsubscribeFromMessages(handler, target); - } - - // Wrap the listener with a origin check. - const listener = withOriginCheck(withParseData(handler)); - - // Save a reference to the compiled listener. - set(listeners, [target, handler], listener); - - // Attach the listener to the target. - target.addEventListener('message', listener); -}; - -export const unsubscribeFromMessages = (handler, target = window) => { - if (!has(listeners, [target, handler])) { - return; - } - - const listener = get(listeners, [target, handler]); - - // Remove the listener from the target. - target.removeEventListener('message', listener); - - remove(listeners, [target, handler]); -}; diff --git a/client/coral-framework/services/postMessage.js b/client/coral-framework/services/postMessage.js new file mode 100644 index 000000000..bf4a11305 --- /dev/null +++ b/client/coral-framework/services/postMessage.js @@ -0,0 +1,86 @@ +import set from 'lodash/set'; +import has from 'lodash/has'; +import get from 'lodash/get'; +import remove from 'lodash/remove'; + +/** + * createPostMessage returns a service that deals with cross + * window communication using the postMessage API. + * @param {Object} options + * @return {Object} messenger service + */ +export function createPostMessage(origin, scope = 'client') { + // Store a reference to each listener added. + const listeners = {}; + + // withOriginCheck wraps a given handler for a messages event with a check to + // see if the origin matches. + const withOriginCheck = handler => { + return event => { + if (get(event, 'origin') !== origin) { + return; + } + + if (get(event, 'data.scope') !== scope) { + return; + } + + // Pass the handler the event details. + handler(event); + }; + }; + + // withParseData will parse the data. + const withParseData = handler => { + return event => { + const data = get(event, 'data.data'); + const name = get(event, 'data.name'); + if (!data || !name) { + return; + } + + handler({ data, name, event }); + }; + }; + + return { + post(name, data, target = window.opener) { + if (!target) { + return; + } + + // Serialize the message to be sent via postMessage. + const msg = { name, data, scope }; + + // Send the message. + target.postMessage(msg, origin); + }, + subscribe: (handler, target = window) => { + // If this handler is already attached to the target, detach it. + if (has(listeners, [target, handler])) { + this.unsubscribeFromMessages(handler, target); + } + + // Wrap the listener with a origin check. + const listener = withOriginCheck(withParseData(handler)); + + // Save a reference to the compiled listener. + set(listeners, [target, handler], listener); + + // Attach the listener to the target. + target.addEventListener('message', listener); + }, + unsubscribe: (handler, target = window) => { + if (!has(listeners, [target, handler])) { + return; + } + + const listener = get(listeners, [target, handler]); + + // Remove the listener from the target. + target.removeEventListener('message', listener); + + remove(listeners, [target, handler]); + }, + }; +} From c0293a4487ea5103de8f0970d6da0c8fac6f3984 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:32:29 +0100 Subject: [PATCH 06/10] Remove deprecated part <3 --- client/coral-embed-stream/src/containers/Embed.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index b9e0cd357..b06f7e035 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -2,7 +2,6 @@ import React from 'react'; import { compose, gql } from 'react-apollo'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import isEqual from 'lodash/isEqual'; import get from 'lodash/get'; import branch from 'recompose/branch'; import renderComponent from 'recompose/renderComponent'; @@ -107,12 +106,6 @@ class EmbedContainer extends React.Component { this.props.data.refetch(); this.resubscribe(nextProps); } - - const { fetchAssetSuccess } = this.props; - if (!isEqual(nextProps.root.asset, this.props.root.asset)) { - // TODO: remove asset data from redux store. - fetchAssetSuccess(nextProps.root.asset); - } } componentDidUpdate(prevProps) { From 81026af3ee4f4d677e394ea0072d9f2d7eaa9ce7 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:38:43 +0100 Subject: [PATCH 07/10] Bye bye old code --- .../coral-embed-stream/src/actions/asset.js | 75 ------------------- .../coral-embed-stream/src/actions/config.js | 6 -- .../coral-embed-stream/src/constants/asset.js | 10 --- .../src/constants/config.js | 1 - .../src/containers/Embed.js | 3 - .../coral-embed-stream/src/reducers/asset.js | 28 ------- .../coral-embed-stream/src/reducers/config.js | 15 ---- .../coral-embed-stream/src/reducers/index.js | 2 - 8 files changed, 140 deletions(-) delete mode 100644 client/coral-embed-stream/src/actions/asset.js delete mode 100644 client/coral-embed-stream/src/actions/config.js delete mode 100644 client/coral-embed-stream/src/constants/asset.js delete mode 100644 client/coral-embed-stream/src/constants/config.js delete mode 100644 client/coral-embed-stream/src/reducers/asset.js delete mode 100644 client/coral-embed-stream/src/reducers/config.js diff --git a/client/coral-embed-stream/src/actions/asset.js b/client/coral-embed-stream/src/actions/asset.js deleted file mode 100644 index 158e65594..000000000 --- a/client/coral-embed-stream/src/actions/asset.js +++ /dev/null @@ -1,75 +0,0 @@ -import * as actions from '../constants/asset'; -import { notify } from 'coral-framework/actions/notification'; - -import t from 'coral-framework/services/i18n'; - -export const fetchAssetRequest = () => ({ type: actions.FETCH_ASSET_REQUEST }); -export const fetchAssetSuccess = asset => ({ - type: actions.FETCH_ASSET_SUCCESS, - asset, -}); -export const fetchAssetFailure = error => ({ - type: actions.FETCH_ASSET_FAILURE, - error, -}); - -const updateAssetSettingsRequest = () => ({ - type: actions.UPDATE_ASSET_SETTINGS_REQUEST, -}); -const updateAssetSettingsSuccess = settings => ({ - type: actions.UPDATE_ASSET_SETTINGS_SUCCESS, - settings, -}); -const updateAssetSettingsFailure = error => ({ - type: actions.UPDATE_ASSET_SETTINGS_FAILURE, - error, -}); - -export const updateConfiguration = newConfig => ( - dispatch, - getState, - { rest } -) => { - const assetId = getState().asset.id; - dispatch(updateAssetSettingsRequest()); - rest(`/assets/${assetId}/settings`, { method: 'PUT', body: newConfig }) - .then(() => { - dispatch(notify('success', t('framework.success_update_settings'))); - dispatch(updateAssetSettingsSuccess(newConfig)); - }) - .catch(error => { - console.error(error); - dispatch(updateAssetSettingsFailure(error)); - }); -}; - -export const updateOpenStream = closedBody => ( - dispatch, - getState, - { rest } -) => { - const assetId = getState().asset.id; - dispatch(fetchAssetRequest()); - rest(`/assets/${assetId}/status`, { method: 'PUT', body: closedBody }) - .then(() => { - dispatch(notify('success', t('framework.success_update_settings'))); - dispatch(fetchAssetSuccess(closedBody)); - }) - .catch(error => { - console.error(error); - dispatch(fetchAssetFailure(error)); - }); -}; - -const openStream = () => ({ type: actions.OPEN_COMMENTS }); -const closeStream = () => ({ type: actions.CLOSE_COMMENTS }); - -export const updateOpenStatus = status => dispatch => { - if (status === 'open') { - dispatch(openStream()); - dispatch(updateOpenStream({ closedAt: null })); - } else { - dispatch(closeStream()); - dispatch(updateOpenStream({ closedAt: new Date().getTime() })); - } -}; diff --git a/client/coral-embed-stream/src/actions/config.js b/client/coral-embed-stream/src/actions/config.js deleted file mode 100644 index e30dc24cf..000000000 --- a/client/coral-embed-stream/src/actions/config.js +++ /dev/null @@ -1,6 +0,0 @@ -import { ADD_EXTERNAL_CONFIG } from '../constants/config'; - -export const addExternalConfig = config => ({ - type: ADD_EXTERNAL_CONFIG, - config, -}); diff --git a/client/coral-embed-stream/src/constants/asset.js b/client/coral-embed-stream/src/constants/asset.js deleted file mode 100644 index 40f746706..000000000 --- a/client/coral-embed-stream/src/constants/asset.js +++ /dev/null @@ -1,10 +0,0 @@ -export const FETCH_ASSET_REQUEST = 'FETCH_ASSET_REQUEST'; -export const FETCH_ASSET_FAILURE = 'FETCH_ASSET_FAILURE'; -export const FETCH_ASSET_SUCCESS = 'FETCH_ASSET_SUCCESS'; - -export const UPDATE_ASSET_SETTINGS_REQUEST = 'UPDATE_ASSET_SETTINGS_REQUEST'; -export const UPDATE_ASSET_SETTINGS_SUCCESS = 'UPDATE_ASSET_SETTINGS_SUCCESS'; -export const UPDATE_ASSET_SETTINGS_FAILURE = 'UPDATE_ASSET_SETTINGS_FAILURE'; - -export const OPEN_COMMENTS = 'OPEN_COMMENTS'; -export const CLOSE_COMMENTS = 'CLOSE_COMMENTS'; diff --git a/client/coral-embed-stream/src/constants/config.js b/client/coral-embed-stream/src/constants/config.js deleted file mode 100644 index 5821316c5..000000000 --- a/client/coral-embed-stream/src/constants/config.js +++ /dev/null @@ -1 +0,0 @@ -export const ADD_EXTERNAL_CONFIG = 'ADD_EXTERNAL_CONFIG'; diff --git a/client/coral-embed-stream/src/containers/Embed.js b/client/coral-embed-stream/src/containers/Embed.js index b06f7e035..d365af50d 100644 --- a/client/coral-embed-stream/src/containers/Embed.js +++ b/client/coral-embed-stream/src/containers/Embed.js @@ -13,7 +13,6 @@ import { hideSignInDialog, } from '../actions/login'; import { updateStatus } from 'coral-framework/actions/auth'; -import { fetchAssetSuccess } from '../actions/asset'; import { getDefinitionName, getSlotFragmentSpreads, @@ -291,7 +290,6 @@ EmbedContainer.propTypes = { activeTab: PropTypes.string, parentUrl: PropTypes.string, data: PropTypes.object, - fetchAssetSuccess: PropTypes.func, showSignInDialog: PropTypes.bool, signInDialogFocus: PropTypes.bool, }; @@ -315,7 +313,6 @@ const mapDispatchToProps = dispatch => bindActionCreators( { setActiveTab, - fetchAssetSuccess, notify, focusSignInDialog, blurSignInDialog, diff --git a/client/coral-embed-stream/src/reducers/asset.js b/client/coral-embed-stream/src/reducers/asset.js deleted file mode 100644 index b683eae30..000000000 --- a/client/coral-embed-stream/src/reducers/asset.js +++ /dev/null @@ -1,28 +0,0 @@ -import * as actions from '../constants/asset'; - -const initialState = { - closedAt: null, - settings: null, - title: null, - url: null, - features: {}, - status: 'open', - moderation: null, -}; - -export default function asset(state = initialState, action) { - switch (action.type) { - case actions.FETCH_ASSET_SUCCESS: - return { - ...state, - ...action.asset, - }; - case actions.UPDATE_ASSET_SETTINGS_SUCCESS: - return { - ...state, - settings: action.settings, - }; - default: - return state; - } -} diff --git a/client/coral-embed-stream/src/reducers/config.js b/client/coral-embed-stream/src/reducers/config.js deleted file mode 100644 index 09a89a743..000000000 --- a/client/coral-embed-stream/src/reducers/config.js +++ /dev/null @@ -1,15 +0,0 @@ -import { ADD_EXTERNAL_CONFIG } from '../constants/config'; - -const initialState = {}; - -export default function config(state = initialState, action) { - switch (action.type) { - case ADD_EXTERNAL_CONFIG: - return { - ...state, - ...action.config, - }; - default: - return state; - } -} diff --git a/client/coral-embed-stream/src/reducers/index.js b/client/coral-embed-stream/src/reducers/index.js index f8eed72d4..15056d414 100644 --- a/client/coral-embed-stream/src/reducers/index.js +++ b/client/coral-embed-stream/src/reducers/index.js @@ -1,5 +1,4 @@ import login from './login'; -import asset from './asset'; import embed from './embed'; import configure from './configure'; import stream from './stream'; @@ -7,7 +6,6 @@ import profile from './profile'; export default { login, - asset, embed, configure, stream, From 6d48c62679c6848abd42dd9b02b27fa33309946c Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:42:51 +0100 Subject: [PATCH 08/10] Fix closedAt wrong datatype --- client/coral-framework/graphql/mutations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index f34a2cc88..1b3b4c6fc 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -698,7 +698,7 @@ export const withCloseAsset = withMutation( const fragmentId = `Asset_${id}`; const data = { __typename: 'Asset', - closedAt: new Date(), + closedAt: new Date().toISOString(), isClosed: true, }; proxy.writeFragment({ fragment, id: fragmentId, data }); From 09eaba5a2ef11ab75a46ba4ac76775eb057887d8 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:51:02 +0100 Subject: [PATCH 09/10] fix jsdoc --- client/coral-framework/services/postMessage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/coral-framework/services/postMessage.js b/client/coral-framework/services/postMessage.js index bf4a11305..f3da0750c 100644 --- a/client/coral-framework/services/postMessage.js +++ b/client/coral-framework/services/postMessage.js @@ -6,7 +6,8 @@ import remove from 'lodash/remove'; /** * createPostMessage returns a service that deals with cross * window communication using the postMessage API. - * @param {Object} options + * @param {string} origin + * @param {string} scope * @return {Object} messenger service */ export function createPostMessage(origin, scope = 'client') { From 918ce04e83ccbfc26a879c4d448b61701072da6e Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 26 Feb 2018 22:51:46 +0100 Subject: [PATCH 10/10] fix jsdoc 2 --- client/coral-framework/services/postMessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-framework/services/postMessage.js b/client/coral-framework/services/postMessage.js index f3da0750c..ef9311e64 100644 --- a/client/coral-framework/services/postMessage.js +++ b/client/coral-framework/services/postMessage.js @@ -8,7 +8,7 @@ import remove from 'lodash/remove'; * window communication using the postMessage API. * @param {string} origin * @param {string} scope - * @return {Object} messenger service + * @return {Object} postMessage service */ export function createPostMessage(origin, scope = 'client') { // Store a reference to each listener added.