diff --git a/app.js b/app.js
index 108ad2e11..0be7a1830 100644
--- a/app.js
+++ b/app.js
@@ -15,6 +15,7 @@ const apollo = require('graphql-server-express');
const accepts = require('accepts');
const compression = require('compression');
const cookieParser = require('cookie-parser');
+const {ROOT_URL} = require('./config');
const app = express();
@@ -74,6 +75,12 @@ app.use('/public', express.static(path.join(__dirname, 'public')));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
+// Set the BASE_URL as the ROOT_URL.
+app.locals.BASE_URL = ROOT_URL;
+if (app.locals.BASE_URL[app.locals.BASE_URL.length - 1] !== '/') {
+ app.locals.BASE_URL += '/';
+}
+
//==============================================================================
// PASSPORT MIDDLEWARE
//==============================================================================
diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js
index e89679036..f0e94f1ad 100644
--- a/client/coral-admin/src/AppRouter.js
+++ b/client/coral-admin/src/AppRouter.js
@@ -1,5 +1,6 @@
import React from 'react';
import {Router, Route, IndexRedirect, browserHistory, Redirect} from 'react-router';
+import {useBasename} from 'history';
import Configure from 'routes/Configure';
import Dashboard from 'routes/Dashboard';
@@ -59,6 +60,8 @@ const routes = (
);
-const AppRouter = () => ;
+const AppRouter = () => browserHistory)({
+ basename: '/talk/'
+})} routes={routes}/>;
export default AppRouter;
diff --git a/client/coral-admin/src/routes/Configure/components/EmbedLink.js b/client/coral-admin/src/routes/Configure/components/EmbedLink.js
index 1cd48cdc5..4506d2f06 100644
--- a/client/coral-admin/src/routes/Configure/components/EmbedLink.js
+++ b/client/coral-admin/src/routes/Configure/components/EmbedLink.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import t from 'coral-framework/services/i18n';
import styles from './Configure.css';
import {Button, Card} from 'coral-ui';
+import {BASE_URL} from 'coral-framework/constants/url';
class EmbedLink extends Component {
@@ -24,21 +25,14 @@ class EmbedLink extends Component {
}
render () {
- const location = window.location;
- const talkBaseUrl = [
- location.protocol,
- '//',
- location.hostname,
- location.port ? (`:${window.location.port}`) : ''
- ].join('');
- const coralJsUrl = [talkBaseUrl, '/embed.js'].join('');
+ const coralJsUrl = [BASE_URL, '/embed.js'].join('');
const nonce = String(Math.random()).slice(2);
const streamElementId = `coral_talk_${nonce}`;
const embedText = `
`.trim();
diff --git a/client/coral-framework/constants/url.js b/client/coral-framework/constants/url.js
new file mode 100644
index 000000000..92144bdec
--- /dev/null
+++ b/client/coral-framework/constants/url.js
@@ -0,0 +1,7 @@
+import url from 'url';
+
+const base = document.querySelector('base');
+const baseUrl = base && url.parse(base.href) || {};
+
+export const BASE_URL = base.href;
+export const BASE_PATH = baseUrl.pathname;
diff --git a/client/coral-framework/helpers/request.js b/client/coral-framework/helpers/request.js
index 57e3a6cde..782aa83f6 100644
--- a/client/coral-framework/helpers/request.js
+++ b/client/coral-framework/helpers/request.js
@@ -2,6 +2,7 @@ import bowser from 'bowser';
import * as Storage from './storage';
import merge from 'lodash/merge';
import {getStore} from 'coral-framework/services/store';
+import {BASE_PATH} from 'coral-framework/constants/url';
/**
* getAuthToken returns the active auth token or null
@@ -75,7 +76,7 @@ const handleResp = (res) => {
}
};
-export const base = '/api/v1';
+export const base = `${BASE_PATH}api/v1`;
export default (url, options) => {
return fetch(`${base}${url}`, buildOptions(options)).then(handleResp);
diff --git a/client/coral-framework/services/client.js b/client/coral-framework/services/client.js
index b266822fb..6f044f621 100644
--- a/client/coral-framework/services/client.js
+++ b/client/coral-framework/services/client.js
@@ -4,6 +4,7 @@ import {SubscriptionClient, addGraphQLSubscriptions} from 'subscriptions-transpo
import MessageTypes from 'subscriptions-transport-ws/dist/message-types';
import {getAuthToken} from '../helpers/request';
import introspectionQueryResultData from '../graphql/introspection.json';
+import {BASE_PATH} from 'coral-framework/constants/url';
let client, wsClient = null, wsClientToken = null;
@@ -33,7 +34,7 @@ export function getClient(options = {}) {
}
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
- wsClient = new SubscriptionClient(`${protocol}://${location.host}/api/v1/live`, {
+ wsClient = new SubscriptionClient(`${protocol}://${location.host}${BASE_PATH}api/v1/live`, {
reconnect: true,
lazy: true,
connectionParams: {
diff --git a/client/coral-framework/services/transport.js b/client/coral-framework/services/transport.js
index f11c20888..060bfc34b 100644
--- a/client/coral-framework/services/transport.js
+++ b/client/coral-framework/services/transport.js
@@ -1,12 +1,13 @@
import {createNetworkInterface} from 'apollo-client';
import {getAuthToken} from '../helpers/request';
+import {BASE_PATH} from 'coral-framework/constants/url';
//==============================================================================
// NETWORK INTERFACE
//==============================================================================
const networkInterface = createNetworkInterface({
- uri: '/api/v1/graph/ql',
+ uri: `${BASE_PATH}api/v1/graph/ql`,
opts: {
credentials: 'same-origin'
}
diff --git a/config.js b/config.js
index 83cb5089f..c6ea774a3 100644
--- a/config.js
+++ b/config.js
@@ -72,7 +72,7 @@ const CONFIG = {
PORT: process.env.TALK_PORT || '3000',
// The URL for this Talk Instance as viewable from the outside.
- ROOT_URL: process.env.TALK_ROOT_URL,
+ ROOT_URL: process.env.TALK_ROOT_URL || null,
// The keepalive timeout (in ms) that should be used to send keep alive
// messages through the websocket to keep the socket alive.
@@ -102,13 +102,22 @@ const CONFIG = {
// DISABLE_AUTOFLAG_SUSPECT_WORDS is true when the suspect words that are
// matched should not be flagged.
- DISABLE_AUTOFLAG_SUSPECT_WORDS: process.env.TALK_DISABLE_AUTOFLAG_SUSPECT_WORDS === 'TRUE'
+ DISABLE_AUTOFLAG_SUSPECT_WORDS: process.env.TALK_DISABLE_AUTOFLAG_SUSPECT_WORDS === 'TRUE',
+
+ // TRUST_THRESHOLDS defines the thresholds used for automoderation.
+ TRUST_THRESHOLDS: process.env.TRUST_THRESHOLDS || 'comment:-1,-1;flag:-1,-1'
};
//==============================================================================
// CONFIG VALIDATION
//==============================================================================
+if (process.env.NODE_ENV === 'test' && !CONFIG.ROOT_URL) {
+ CONFIG.ROOT_URL = 'http://localhost:3000';
+} else if (!CONFIG.ROOT_URL) {
+ throw new Error('TALK_ROOT_URL must be provided');
+}
+
//------------------------------------------------------------------------------
// JWT based configuration
//------------------------------------------------------------------------------
diff --git a/docs/_docs/02-01-configuration.md b/docs/_docs/02-01-configuration.md
index f8bb762fc..cb9a51d23 100644
--- a/docs/_docs/02-01-configuration.md
+++ b/docs/_docs/02-01-configuration.md
@@ -37,6 +37,15 @@ environment variables. Refer to the
[config.js](https://github.com/coralproject/talk/blob/master/config.js) file to
see how the configuration is parsed.
+### Webpack
+
+These are only used during the webpack build.
+
+- `TALK_THREADING_LEVEL` (_optional_) - specify the maximum depth of the comment
+ thread. (Default `3`)
+- `TALK_DEFAULT_STREAM_TAB` (_optional_) - specify the default stream tab in the
+ admin. (Default `all`)
+
### Database
- `TALK_MONGO_URL` (*required*) - the database connection string for the MongoDB database.
@@ -91,6 +100,29 @@ on the contents of those variables.**
- `TALK_RECAPTCHA_SECRET` (*required for reCAPTCHA support*) - server secret used for enabling reCAPTCHA powered logins. If not provided it will instead default to providing only a time based lockout.
- `TALK_RECAPTCHA_PUBLIC` (*required for reCAPTCHA support*) - client secret used for enabling reCAPTCHA powered logins. If not provided it will instead default to providing only a time based lockout.
+### Trust
+
+Trust can automoderate comments based on user history. By specifying this
+option, the beheviour can be changed to offer different results.
+
+- `TRUST_THRESHOLDS` (_optional_) - configure the reliability thresholds for
+ flagging and commenting. (Default `comment:-1,-1;flag:-1,-1`)
+
+The form of the environment variable:
+
+```
+:,;:,;...
+```
+
+The default could be read as:
+
+- When a commenter has one comment rejected, their next comment must be
+ premoderated once in order to post freely again. If they instead get rejected
+ again, then they must have two of their comments approved in order to get
+ added back to the queue.
+- At the moment of writing, beheviour is not attached to the flagging
+ reliability, but it is recorded.
+
### Plugins
- `TALK_PLUGINS_JSON` (_optional_) - used to specify the plugin config via the
diff --git a/docs/_sass/minimal-mistakes/_masthead.scss b/docs/_sass/minimal-mistakes/_masthead.scss
index 39ebd2c7d..2b24a2950 100755
--- a/docs/_sass/minimal-mistakes/_masthead.scss
+++ b/docs/_sass/minimal-mistakes/_masthead.scss
@@ -5,10 +5,10 @@
.masthead {
position: relative;
border-bottom: 1px solid $border-color;
- -webkit-animation: intro 0.3s both;
- animation: intro 0.3s both;
- -webkit-animation-delay: 0.15s;
- animation-delay: 0.15s;
+ // -webkit-animation: intro 0.3s both;
+ // animation: intro 0.3s both;
+ // -webkit-animation-delay: 0.15s;
+ // animation-delay: 0.15s;
z-index: 20;
&__inner-wrap {
diff --git a/docs/_sass/minimal-mistakes/_navigation.scss b/docs/_sass/minimal-mistakes/_navigation.scss
index 4c1748f97..c1b081891 100755
--- a/docs/_sass/minimal-mistakes/_navigation.scss
+++ b/docs/_sass/minimal-mistakes/_navigation.scss
@@ -14,10 +14,10 @@
padding-left: 2em;
padding-right: 2em;
font-family: $sans-serif;
- -webkit-animation: intro 0.3s both;
- animation: intro 0.3s both;
- -webkit-animation-delay: 0.30s;
- animation-delay: 0.30s;
+ // -webkit-animation: intro 0.3s both;
+ // animation: intro 0.3s both;
+ // -webkit-animation-delay: 0.30s;
+ // animation-delay: 0.30s;
@include breakpoint($large) {
padding-left: 1em;
diff --git a/docs/_sass/minimal-mistakes/_page.scss b/docs/_sass/minimal-mistakes/_page.scss
index 6b77b3262..bb185f02d 100755
--- a/docs/_sass/minimal-mistakes/_page.scss
+++ b/docs/_sass/minimal-mistakes/_page.scss
@@ -8,10 +8,10 @@
margin-top: 2em;
padding-left: 1em;
padding-right: 1em;
- -webkit-animation: intro 0.3s both;
- animation: intro 0.3s both;
- -webkit-animation-delay: 0.35s;
- animation-delay: 0.35s;
+ // -webkit-animation: intro 0.3s both;
+ // animation: intro 0.3s both;
+ // -webkit-animation-delay: 0.35s;
+ // animation-delay: 0.35s;
@include breakpoint($x-large) {
max-width: $x-large;
@@ -113,10 +113,10 @@
position: relative;
margin-bottom: 2em;
@include clearfix;
- -webkit-animation: intro 0.3s both;
- animation: intro 0.3s both;
- -webkit-animation-delay: 0.25s;
- animation-delay: 0.25s;
+ // -webkit-animation: intro 0.3s both;
+ // animation: intro 0.3s both;
+ // -webkit-animation-delay: 0.25s;
+ // animation-delay: 0.25s;
&--overlay {
position: relative;
@@ -126,10 +126,10 @@
background-size: cover;
background-repeat: no-repeat;
background-position: center;
- -webkit-animation: intro 0.3s both;
- animation: intro 0.3s both;
- -webkit-animation-delay: 0.25s;
- animation-delay: 0.25s;
+ // -webkit-animation: intro 0.3s both;
+ // animation: intro 0.3s both;
+ // -webkit-animation-delay: 0.25s;
+ // animation-delay: 0.25s;
a {
color: #fff;
diff --git a/docs/_sass/minimal-mistakes/_sidebar.scss b/docs/_sass/minimal-mistakes/_sidebar.scss
index 1470aa80f..2100e13e5 100755
--- a/docs/_sass/minimal-mistakes/_sidebar.scss
+++ b/docs/_sass/minimal-mistakes/_sidebar.scss
@@ -16,8 +16,8 @@
@include breakpoint($large) {
@include span(2 of 12);
opacity: 0.75;
- -webkit-transition: opacity 0.2s ease-in-out;
- transition: opacity 0.2s ease-in-out;
+ // -webkit-transition: opacity 0.2s ease-in-out;
+ // transition: opacity 0.2s ease-in-out;
&:hover {
opacity: 1;
diff --git a/docs/_sass/minimal-mistakes/_variables.scss b/docs/_sass/minimal-mistakes/_variables.scss
index 2b59066c2..a485b5579 100755
--- a/docs/_sass/minimal-mistakes/_variables.scss
+++ b/docs/_sass/minimal-mistakes/_variables.scss
@@ -91,7 +91,7 @@ $xing-color : #006567 !default;
/* links */
-$link-color : $info-color !default;
+$link-color : #f67150 !default;
$link-color-hover : mix(#000, $link-color, 25%) !default;
$link-color-visited : mix(#fff, $link-color, 25%) !default;
$masthead-link-color : $primary-color !default;
@@ -126,4 +126,4 @@ $border-radius : 4px !default;
$box-shadow : 0 1px 1px rgba(0, 0, 0, 0.125) !default;
$navicon-width : 1.5rem !default;
$navicon-height : 0.25rem !default;
-$global-transition : all 0.2s ease-in-out !default;
+$global-transition : none !default;
diff --git a/package.json b/package.json
index 54a136cee..476e7eda5 100644
--- a/package.json
+++ b/package.json
@@ -178,6 +178,7 @@
"graphql-docs": "^0.2.0",
"graphql-tag": "^1.2.3",
"hammerjs": "^2.0.8",
+ "history": "^3.0.0",
"ignore-styles": "^5.0.1",
"immutable": "^3.8.1",
"imports-loader": "^0.7.1",
diff --git a/plugins/talk-plugin-facebook-auth/server/passport.js b/plugins/talk-plugin-facebook-auth/server/passport.js
index ae69ec4bd..14849b7da 100644
--- a/plugins/talk-plugin-facebook-auth/server/passport.js
+++ b/plugins/talk-plugin-facebook-auth/server/passport.js
@@ -1,13 +1,20 @@
const FacebookStrategy = require('passport-facebook').Strategy;
const UsersService = require('services/users');
const {ValidateUserLogin} = require('services/passport');
+let {
+ ROOT_URL
+} = require('config');
+
+if (ROOT_URL[ROOT_URL.length - 1] !== '/') {
+ ROOT_URL += '/';
+}
module.exports = (passport) => {
if (process.env.TALK_FACEBOOK_APP_ID && process.env.TALK_FACEBOOK_APP_SECRET && process.env.TALK_ROOT_URL) {
passport.use(new FacebookStrategy({
clientID: process.env.TALK_FACEBOOK_APP_ID,
clientSecret: process.env.TALK_FACEBOOK_APP_SECRET,
- callbackURL: `${process.env.TALK_ROOT_URL}/api/v1/auth/facebook/callback`,
+ callbackURL: `${ROOT_URL}api/v1/auth/facebook/callback`,
passReqToCallback: true,
profileFields: ['id', 'displayName', 'picture.type(large)']
}, async (req, accessToken, refreshToken, profile, done) => {
diff --git a/routes/admin/index.js b/routes/admin/index.js
index 44ce83222..30bb69f5e 100644
--- a/routes/admin/index.js
+++ b/routes/admin/index.js
@@ -23,7 +23,7 @@ router.get('*', (req, res) => {
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC
};
- res.render('admin', {basePath: '/client/coral-admin', data});
+ res.render('admin', {data});
});
module.exports = router;
diff --git a/services/karma.js b/services/karma.js
index c76bcebb3..a2c087eaa 100644
--- a/services/karma.js
+++ b/services/karma.js
@@ -1,22 +1,25 @@
const debug = require('debug')('talk:services:karma');
const UserModel = require('../models/user');
+const {
+ TRUST_THRESHOLDS
+} = require('../config');
/**
* This will create an object with the property name of the action type as the
* key and an object as it's value. This will contain a RELIABLE, and UNRELIABLE
* property with the number of karma points associated with their particular
* state.
- *
+ *
* If only the RELIABLE variable is provided, then it will also be used as the
* UNRELIABLE variable.
- *
+ *
* The form of the environment variable is:
- *
+ *
* :,;:,;...
- *
+ *
* The default used is:
- *
- * comment:1,1;flag:-1,-1
+ *
+ * comment:-1,-1;flag:-1,-1
*/
const parseThresholds = (thresholds) => thresholds
.split(';')
@@ -50,16 +53,16 @@ const parseThresholds = (thresholds) => thresholds
return acc;
}, {
comment: {
- RELIABLE: -1,
- UNRELIABLE: -1
+ RELIABLE: 0,
+ UNRELIABLE: 0
},
flag: {
- RELIABLE: -1,
- UNRELIABLE: -1
+ RELIABLE: 0,
+ UNRELIABLE: 0
}
});
-const THRESHOLDS = parseThresholds(process.env.TRUST_THRESHOLDS || '');
+const THRESHOLDS = parseThresholds(TRUST_THRESHOLDS);
debug('using thresholds: ', THRESHOLDS);
diff --git a/views/admin.ejs b/views/admin.ejs
index 54c666395..0a7c1c218 100644
--- a/views/admin.ejs
+++ b/views/admin.ejs
@@ -4,19 +4,19 @@
Talk - Coral Admin
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -37,10 +37,11 @@
<% if (data != null) { %>
<% } %>
+
-
+