mirror of
https://github.com/wassname/talk.git
synced 2026-09-14 11:36:51 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1a3a5ca28 | ||
|
|
8ef44dc6f5 | ||
|
|
362f29f77e | ||
|
|
08d342ea2e |
@@ -11,6 +11,7 @@ ONBUILD ARG TALK_DEFAULT_LANG=en
|
||||
ONBUILD ARG TALK_WHITELISTED_LANGUAGES
|
||||
ONBUILD ARG TALK_PLUGINS_JSON
|
||||
ONBUILD ARG TALK_WEBPACK_SOURCE_MAP
|
||||
ONBUILD ARG TALK_DEFAULT_LAZY_RENDER
|
||||
|
||||
# Bundle app source
|
||||
ONBUILD COPY . /usr/src/app
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
/* global __webpack_public_path__ */ // eslint-disable-line no-unused-vars
|
||||
|
||||
import queryString from 'querystringify';
|
||||
import pym from 'pym.js';
|
||||
import EventEmitter from 'eventemitter2';
|
||||
import { buildUrl } from 'coral-framework/utils/url';
|
||||
import Snackbar from './Snackbar';
|
||||
import onIntersect from './onIntersect';
|
||||
import {
|
||||
createStorage,
|
||||
connectStorageToPym,
|
||||
@@ -10,13 +13,14 @@ import {
|
||||
|
||||
const NOTIFICATION_OFFSET = 200;
|
||||
|
||||
// Ensure there is a trailing slash.
|
||||
function ensureEndSlash(p) {
|
||||
return p.match(/\/$/) ? p : `${p}/`;
|
||||
}
|
||||
|
||||
// Build the URL to load in the pym iframe.
|
||||
function buildStreamIframeUrl(talkBaseUrl, query) {
|
||||
let url = [
|
||||
talkBaseUrl,
|
||||
talkBaseUrl.match(/\/$/) ? '' : '/', // make sure no double-'/' if opts.talk already ends with '/'
|
||||
'embed/stream?',
|
||||
].join('');
|
||||
let url = talkBaseUrl + 'embed/stream?';
|
||||
|
||||
url += queryString.stringify(query);
|
||||
|
||||
@@ -47,18 +51,76 @@ export default class Stream {
|
||||
events = null,
|
||||
snackBarStyles = null,
|
||||
onAuthChanged = null,
|
||||
talkStaticUrl = talkBaseUrl,
|
||||
...opts
|
||||
} = config;
|
||||
|
||||
this.onAuthChanged = onAuthChanged;
|
||||
this.el = el;
|
||||
this.talkBaseUrl = ensureEndSlash(talkBaseUrl);
|
||||
this.talkStaticUrl = ensureEndSlash(talkStaticUrl);
|
||||
this.opts = opts;
|
||||
|
||||
this.emitter = new EventEmitter({ wildcard: true });
|
||||
this.pym = new pym.Parent(el.id, buildStreamIframeUrl(talkBaseUrl, query), {
|
||||
title: opts.title,
|
||||
id: `${el.id}_iframe`,
|
||||
name: `${el.id}_iframe`,
|
||||
});
|
||||
this.snackBar = new Snackbar(snackBarStyles || {});
|
||||
this.emitter = new EventEmitter({ wildcard: true });
|
||||
|
||||
// Because we're loading chunks dynamically below, we need to point to the
|
||||
// static URL.
|
||||
//
|
||||
// The __webpack_public_path__ can be referenced:
|
||||
// https://webpack.js.org/configuration/output/#output-publicpath
|
||||
//
|
||||
__webpack_public_path__ = this.talkStaticUrl + 'static/';
|
||||
|
||||
// Attach to the events emitted by the pym parent.
|
||||
if (events) {
|
||||
events(this.emitter);
|
||||
}
|
||||
if (config.lazy || process.env.TALK_DEFAULT_LAZY_RENDER === 'TRUE') {
|
||||
const renderOnIntersect = () => onIntersect(this.el, () => this.render());
|
||||
if (!window.IntersectionObserver) {
|
||||
// Include a polyfill for the intersection observer.
|
||||
import('intersection-observer')
|
||||
.then(() => {
|
||||
// Polyfill applied.
|
||||
renderOnIntersect();
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
// Loading polyfill failed, just render it directly.
|
||||
this.render();
|
||||
});
|
||||
} else {
|
||||
// No need for polyfill.
|
||||
renderOnIntersect();
|
||||
}
|
||||
} else {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
||||
assertRendered() {
|
||||
if (!this.pym) {
|
||||
throw new Error('Stream Embed must be rendered first');
|
||||
}
|
||||
}
|
||||
|
||||
isRendered() {
|
||||
return !!this.pym;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.pym) {
|
||||
throw new Error('Stream Embed already rendered');
|
||||
}
|
||||
this.pym = new pym.Parent(
|
||||
this.el.id,
|
||||
buildStreamIframeUrl(this.talkBaseUrl, this.query),
|
||||
{
|
||||
title: this.opts.title,
|
||||
id: `${this.el.id}_iframe`,
|
||||
name: `${this.el.id}_iframe`,
|
||||
}
|
||||
);
|
||||
|
||||
// Workaround: IOS Safari ignores `width` but respects `min-width` value.
|
||||
this.pym.el.firstChild.style.width = '1px';
|
||||
@@ -73,19 +135,14 @@ export default class Stream {
|
||||
}
|
||||
});
|
||||
|
||||
// Attach to the events emitted by the pym parent.
|
||||
if (events) {
|
||||
events(this.emitter);
|
||||
}
|
||||
|
||||
this.pym.onMessage('getConfig', () => {
|
||||
this.pym.sendMessage('config', JSON.stringify(opts));
|
||||
this.pym.sendMessage('config', JSON.stringify(this.opts));
|
||||
});
|
||||
|
||||
// If the auth changes, and someone is listening for it, then re-emit it.
|
||||
if (onAuthChanged) {
|
||||
if (this.onAuthChanged) {
|
||||
this.pym.onMessage('coral-auth-changed', message => {
|
||||
onAuthChanged(message ? JSON.parse(message) : null);
|
||||
this.onAuthChanged(message ? JSON.parse(message) : null);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -163,22 +220,27 @@ export default class Stream {
|
||||
}
|
||||
|
||||
enablePluginsDebug() {
|
||||
this.assertRendered();
|
||||
this.pym.sendMessage('enablePluginsDebug');
|
||||
}
|
||||
|
||||
disablePluginsDebug() {
|
||||
this.assertRendered();
|
||||
this.pym.sendMessage('disablePluginsDebug');
|
||||
}
|
||||
|
||||
login(token) {
|
||||
this.assertRendered();
|
||||
this.pym.sendMessage('login', token);
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.assertRendered();
|
||||
this.pym.sendMessage('logout');
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.assertRendered();
|
||||
// Remove the event listeners.
|
||||
document.removeEventListener('click', this.handleClick.bind(this));
|
||||
this.emitter.removeAllListeners();
|
||||
@@ -191,6 +253,7 @@ export default class Stream {
|
||||
}
|
||||
|
||||
handleClick() {
|
||||
this.assertRendered();
|
||||
this.pym.sendMessage('click');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ export class Talk {
|
||||
* @param {String} [config.asset_url] - Asset URL
|
||||
* @param {String} [config.asset_id] - Asset ID
|
||||
* @param {String} [config.auth_token] - (optional) A jwt representing the session
|
||||
* @param {String} [config.lazy] - (optional) If set the stream will only render lazily.
|
||||
* @return {Object}
|
||||
*
|
||||
* Example:
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export default function onIntersect(el, callback) {
|
||||
if (!IntersectionObserver) {
|
||||
// tslint:disable-next-line:no-console
|
||||
console.warn('IntersectionObserver not available');
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
const options = {
|
||||
rootMargin: '100px',
|
||||
threshold: 1.0,
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
if (entries[0].isIntersecting) {
|
||||
observer.disconnect();
|
||||
callback();
|
||||
}
|
||||
}, options);
|
||||
observer.observe(el);
|
||||
}
|
||||
@@ -187,8 +187,10 @@ and walk through the initial setup steps.
|
||||
|
||||
* First, enter your **Organization Name** and **Organization Contact Email**. This will appear in emails when inviting new team members.
|
||||
* Next, create your Admin user. You can specify an **Email Address**, **Username**, and **Password**
|
||||
|
||||
* Finally, enter your list of **Permitted Domains**, read [here](/talk/configuring-talk/#permitted-domains) about whitelisting domains
|
||||
|
||||
|
||||
_During development, ensure you whitelist 127.0.0.1:3000 otherwise the
|
||||
[http://127.0.0.1:3000/](http://127.0.0.1:3000/) page will not
|
||||
load._
|
||||
@@ -220,6 +222,17 @@ Once you have added the domain of these docs, you can click the button below.
|
||||
<div class="mount"></div>
|
||||
</div>
|
||||
|
||||
### Developer Endpoints
|
||||
|
||||
With your local instance of Talk running in development mode (env variable `NODE_ENV=development`) you should now also be able to access the following developer routes:
|
||||
|
||||
* [http://127.0.0.1:3000/dev](http://127.0.0.1:3000/dev]) provides a sample comment stream
|
||||
|
||||
* [http://127.0.0.1:3000/dev/assets](http://127.0.0.1:3000/dev/assets]) provides a list of all stories in Talk and can generate new sample assets
|
||||
|
||||
### Conclusion
|
||||
At this point you've successfully installed, configured, and ran your very own
|
||||
instance of Talk! Continue through this documentation on this site to learn more
|
||||
on how to configure, develop with, and contribute to Talk!
|
||||
|
||||
|
||||
|
||||
@@ -70,5 +70,7 @@ You can now start the application by running:
|
||||
yarn watch:server
|
||||
```
|
||||
|
||||
If you are developing a custom plugin you can use `yarn watch:client` or `yarn watch` to run both client and server.
|
||||
|
||||
At this stage, you should refer to the [configuration](/talk/configuration/) for
|
||||
configuration variables that are specific to your installation.
|
||||
|
||||
@@ -23,11 +23,13 @@ permalink: /pre-launch-checklist/
|
||||
|
||||
- [ ] Do you need to migrate comments from a legacy system? We currently support Disqus, Livefyre, and Civil Comments.
|
||||
- Use the [Talk Import](https://github.com/coralproject/talk-importer) framework
|
||||
|
||||
|
||||
|
||||
- [ ] Do you want to provide single sign-on (SSO) by integrating with an external auth system?
|
||||
- See [Authenticating with Talk](/talk/integrating/authentication/)
|
||||
|
||||
- [ ] Do you want to integrate Talk with your CMS to automate embedding Talk Comment Stream into your site?
|
||||
- See [Asset Management](/talk/integrating/asset-management/)
|
||||
|
||||
- [ ] Do you want to use Social sign-on?
|
||||
- Facebook
|
||||
|
||||
@@ -5,13 +5,15 @@ permalink: /commenter-features/
|
||||
|
||||
## Signing up for Talk
|
||||
|
||||
There are 2 ways that newsrooms can support signup/login functionality with Talk:
|
||||
There are 3 ways that newsrooms can support signup/login functionality with Talk:
|
||||
|
||||
* Use Talk’s auth plugin out of the box (supports account registration with username and password, as well as features like forgot password)
|
||||
|
||||
* Use 3rd party authentication provider such as FaceBook or Google. We provide plugins that support logging in with either [Facebook](/talk/plugin/talk-plugin-facebook-auth/)
|
||||
or [Google](/talk/plugin/talk-plugin-google-auth/). (Note: you must provide your own Facebook App ID and Secret, which you can read more about here: [https://developers.facebook.com](https://developers.facebook.com))
|
||||
|
||||
* Create their own auth plugin to integrate with your own auth systems
|
||||
|
||||
We also provide a Facebook auth plugin that supports logging in with Facebook (you must provide your own Facebook App ID and Secret, which you can read more about here: [https://developers.facebook.com](https://developers.facebook.com))
|
||||
|
||||
## Comments and Replies
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ By default, Talk will use "Lazy Asset Creation" to dynamically generate Assets
|
||||
in Talk in order to make it easier for lighter installations. In order to have
|
||||
more strict control over this flow, we will create a plugin that will:
|
||||
|
||||
|
||||
1. Disable "Lazy Asset Creation" by [Overriding a Resolver](#overriding-a-resolver).
|
||||
2. Create Assets from our CMS by [Creating a New Asset Route](#creating-a-new-asset-route).
|
||||
3. Facilitate updates from our CMS to keep Talk in sync by [Creating an Asset Update Route](#creating-an-asset-update-route).
|
||||
@@ -248,7 +249,7 @@ module.exports = router => {
|
||||
};
|
||||
```
|
||||
|
||||
As you can see from the previous step of [Creating a New Asset Route](#creating-a-New-Asset-Route)
|
||||
As you can see from the previous step of [Creating a New Asset Route](#Creating%20a%20New%20Asset%20Route)
|
||||
, we have added the new `PUT` route to the router. This is a simple addition
|
||||
that allows your CMS to call into Talk when the asset has updated it's title,
|
||||
it's url (or really anything in the [AssetSchema](https://github.com/coralproject/talk/blob/master/models/asset.js)) to keep the Talk Admin and links up to date.
|
||||
|
||||
@@ -3,8 +3,10 @@ title: Authenticating with Talk
|
||||
permalink: /integrating/authentication/
|
||||
---
|
||||
|
||||
You can integrate Talk with any external authentication service that will enable
|
||||
seamless single sign-on for users within your organization. There are a few
|
||||
Out of the box Talk supports account registration with username and password, as well as features like forgot password.
|
||||
|
||||
You can also integrate Talk with any external authentication service that will enable
|
||||
seamless single sign-on (SSO) for users within your organization. There are a few
|
||||
methods of doing so:
|
||||
|
||||
1. Passport Middleware
|
||||
@@ -17,8 +19,12 @@ choice.
|
||||
|
||||
You would choose the **Passport Middleware** route when you are OK using an auth
|
||||
that is triggered from inside Talk that is not connected to an external auth
|
||||
state (you don't use the auth anywhere else now). A great example of this is our
|
||||
[talk-plugin-facebook-auth](/talk/plugin/talk-plugin-facebook-auth/) plugin.
|
||||
state (you don't use the auth anywhere else now).
|
||||
|
||||
Plugins are available for the following 3rd party authentication providers:
|
||||
|
||||
* [Facebook](/talk/plugin/talk-plugin-facebook-auth/)
|
||||
* [Google](/talk/plugin/talk-plugin-google-auth/)
|
||||
|
||||
## Custom Token Integration
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@ Then the application can be started as is.
|
||||
|
||||
### Docker
|
||||
|
||||
To deploy customized plugins to a production instance of Talk, we recommend using the Docker onbuild strategy outlined below.
|
||||
|
||||
If you deploy using Docker, you can extend from the `*-onbuild` image, an
|
||||
example `Dockerfile` for your project could be:
|
||||
|
||||
@@ -112,14 +114,22 @@ example `Dockerfile` for your project could be:
|
||||
FROM coralproject/talk:4.5-onbuild
|
||||
```
|
||||
|
||||
Where the directory for your instance would contain a `plugins.json` file
|
||||
describing the plugin requirements and a `plugins` directory containing any
|
||||
Establish a private repository for your instance that includes the following:
|
||||
|
||||
* a `plugins.json` file
|
||||
listing the plugin requirements
|
||||
* a `plugins` directory containing any
|
||||
other local plugins that should be included.
|
||||
* a Dockerfile as outlined above
|
||||
|
||||
Git submodules can also be used to point to plugin directories that might be outside your primary repository.
|
||||
|
||||
Onbuild triggers will execute when the image is building with your custom
|
||||
configuration and will ensure that the image is ready to use by building all
|
||||
assets inside the image as well.
|
||||
|
||||
Once built, you can deploy the docker image to your architecture by tagging the image and including it in your docker-compose.yml.
|
||||
|
||||
For more information on the onbuild image, refer to the
|
||||
[Installation from Docker](/talk/installation-from-docker/) documentation.
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "talk",
|
||||
"version": "4.6.7",
|
||||
"version": "4.6.8",
|
||||
"description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net",
|
||||
"main": "app.js",
|
||||
"private": true,
|
||||
@@ -130,6 +130,7 @@
|
||||
"imports-loader": "^0.7.1",
|
||||
"inquirer": "^3.2.2",
|
||||
"inquirer-autocomplete-prompt": "^0.12.1",
|
||||
"intersection-observer": "^0.5.1",
|
||||
"ioredis": "3.1.4",
|
||||
"ip": "^1.1.5",
|
||||
"jest": "^23.0.0",
|
||||
|
||||
@@ -159,6 +159,9 @@ const config = {
|
||||
'process.env': {
|
||||
VERSION: `"${require('./package.json').version}"`,
|
||||
NODE_ENV: `${JSON.stringify(process.env.NODE_ENV)}`,
|
||||
TALK_DEFAULT_LAZY_RENDER: `${JSON.stringify(
|
||||
process.env.TALK_DEFAULT_LAZY_RENDER
|
||||
)}`,
|
||||
},
|
||||
}),
|
||||
new webpack.EnvironmentPlugin({
|
||||
|
||||
@@ -6042,6 +6042,11 @@ interpret@^1.0.0, interpret@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614"
|
||||
integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=
|
||||
|
||||
intersection-observer@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.5.1.tgz#e340fc56ce74290fe2b2394d1ce88c4353ac6dfa"
|
||||
integrity sha512-Zd7Plneq82kiXFixs7bX62YnuZ0BMRci9br7io88LwDyF3V43cQMI+G5IiTlTNTt+LsDUppl19J/M2Fp9UkH6g==
|
||||
|
||||
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
|
||||
|
||||
Reference in New Issue
Block a user