mirror of
https://github.com/wassname/talk.git
synced 2026-07-02 11:55:34 +08:00
Merge branch 'master' of github.com:coralproject/talk into instream-ban
This commit is contained in:
+7
-6
@@ -24,13 +24,14 @@
|
||||
"promise/no-promise-in-callback": "warn",
|
||||
"promise/no-callback-in-promise": "warn",
|
||||
|
||||
// TODO: Change all these to "error", or remove and use defaults.
|
||||
"react/display-name": "off",
|
||||
"react/jsx-no-duplicate-props": "warn",
|
||||
"react/jsx-no-target-blank": "warn",
|
||||
"react/no-find-dom-node": "warn",
|
||||
"react/no-unknown-property": "warn",
|
||||
"react/prop-types": "off",
|
||||
|
||||
// We'll keeping using this, as we'll switch over to Preact and we don't
|
||||
// need to worry about deprecation.
|
||||
"react/no-find-dom-node": "off",
|
||||
|
||||
// TODO: Use default after fixing the errors.
|
||||
"react/prop-types": "warn",
|
||||
|
||||
"array-callback-return": "warn",
|
||||
"arrow-parens": ["warn", "always"],
|
||||
|
||||
@@ -5,7 +5,12 @@ const path = require('path');
|
||||
const helmet = require('helmet');
|
||||
const compression = require('compression');
|
||||
const cookieParser = require('cookie-parser');
|
||||
const {BASE_URL, BASE_PATH, MOUNT_PATH} = require('./url');
|
||||
const {
|
||||
BASE_URL,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
} = require('./url');
|
||||
const routes = require('./routes');
|
||||
const debug = require('debug')('talk:app');
|
||||
|
||||
@@ -55,6 +60,7 @@ app.set('view engine', 'ejs');
|
||||
app.locals.BASE_URL = BASE_URL;
|
||||
app.locals.BASE_PATH = BASE_PATH;
|
||||
app.locals.MOUNT_PATH = MOUNT_PATH;
|
||||
app.locals.STATIC_URL = STATIC_URL;
|
||||
|
||||
debug(`mounting routes on the ${MOUNT_PATH} path`);
|
||||
|
||||
|
||||
@@ -28,7 +28,11 @@ const ActionButton = ({type = '', active, ...props}) => {
|
||||
};
|
||||
|
||||
ActionButton.propTypes = {
|
||||
active: PropTypes.bool
|
||||
active: PropTypes.bool,
|
||||
type: PropTypes.oneOf(['APPROVE', 'REJECT']),
|
||||
minimal: PropTypes.bool,
|
||||
acceptComment: PropTypes.func,
|
||||
rejectComment: PropTypes.func,
|
||||
};
|
||||
|
||||
export default ActionButton;
|
||||
|
||||
@@ -58,6 +58,7 @@ class ActionsMenu extends React.Component {
|
||||
|
||||
ActionsMenu.propTypes = {
|
||||
icon: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default ActionsMenu;
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import {MenuItem} from 'react-mdl';
|
||||
import PropTypes from 'prop-types';
|
||||
import styles from './ActionsMenu.css';
|
||||
|
||||
const ActionsMenuItem = (props) =>
|
||||
<MenuItem className={cn(styles.menuItem, props.className)} {...props} />;
|
||||
|
||||
ActionsMenuItem.propTypes = {
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default ActionsMenuItem;
|
||||
|
||||
@@ -105,7 +105,9 @@ AdminLogin.propTypes = {
|
||||
handleLogin: PropTypes.func.isRequired,
|
||||
passwordRequestSuccess: PropTypes.string,
|
||||
loginError: PropTypes.string,
|
||||
recaptchaPublic: PropTypes.string
|
||||
recaptchaPublic: PropTypes.string,
|
||||
requestPasswordReset: PropTypes.func,
|
||||
errorMessage: PropTypes.string,
|
||||
};
|
||||
|
||||
export default AdminLogin;
|
||||
|
||||
@@ -2,8 +2,9 @@ import React from 'react';
|
||||
import {murmur3} from 'murmurhash-js';
|
||||
import {CSSTransitionGroup} from 'react-transition-group';
|
||||
import styles from './CommentAnimatedEdit.css';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default ({children, body}) => {
|
||||
const CommentBodyHighlighter = ({children, body}) => {
|
||||
return (
|
||||
<CSSTransitionGroup
|
||||
component={'div'}
|
||||
@@ -23,3 +24,10 @@ export default ({children, body}) => {
|
||||
</CSSTransitionGroup>
|
||||
);
|
||||
};
|
||||
|
||||
CommentBodyHighlighter.propTypes = {
|
||||
children: PropTypes.node,
|
||||
body: PropTypes.string,
|
||||
};
|
||||
|
||||
export default CommentBodyHighlighter;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
.textareaContainer {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -183,7 +183,6 @@ export default class UserDetail extends React.Component {
|
||||
key={comment.id}
|
||||
user={user}
|
||||
comment={comment}
|
||||
selected={false}
|
||||
suspectWords={suspectWords}
|
||||
bannedWords={bannedWords}
|
||||
actions={actionsMap[status]}
|
||||
|
||||
@@ -73,12 +73,12 @@ const CoralHeader = ({
|
||||
<Menu target="menu-settings" align="right">
|
||||
<MenuItem onClick={() => showShortcuts(true)}>{t('configure.shortcuts')}</MenuItem>
|
||||
<MenuItem>
|
||||
<a href="https://github.com/coralproject/talk/releases" target="_blank">
|
||||
<a href="https://github.com/coralproject/talk/releases" target="_blank" rel="noopener noreferrer">
|
||||
View latest version
|
||||
</a>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<a href="https://coralproject.net/contribute.html#other-ideas-and-bug-reports" target="_blank">
|
||||
<a href="https://coralproject.net/contribute.html#other-ideas-and-bug-reports" target="_blank" rel="noopener noreferrer">
|
||||
Report a bug or give feedback
|
||||
</a>
|
||||
</MenuItem>
|
||||
|
||||
@@ -28,7 +28,8 @@ export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onComm
|
||||
{row.created_at}
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<SelectField label={'Select me'} value={row.status || ''}
|
||||
<SelectField
|
||||
value={row.status || ''}
|
||||
className={styles.selectField}
|
||||
label={t('community.status')}
|
||||
onChange={(status) => onCommenterStatusChange(row.id, status)}>
|
||||
@@ -37,7 +38,8 @@ export default ({headers, commenters, onHeaderClickHandler, onRoleChange, onComm
|
||||
</SelectField>
|
||||
</td>
|
||||
<td className="mdl-data-table__cell--non-numeric">
|
||||
<SelectField label={'Select me'} value={row.roles[0] || ''}
|
||||
<SelectField
|
||||
value={row.roles[0] || ''}
|
||||
className={styles.selectField}
|
||||
label={t('community.role')}
|
||||
onChange={(role) => onRoleChange(row.id, role)}>
|
||||
|
||||
@@ -150,7 +150,6 @@ class CommentBox extends React.Component {
|
||||
return <div>
|
||||
<CommentForm
|
||||
defaultValue={this.props.defaultValue}
|
||||
bodyInputId={isReply ? 'replyText' : 'commentText'}
|
||||
bodyLabel={isReply ? t('comment_box.reply') : t('comment.comment')}
|
||||
maxCharCount={maxCharCount}
|
||||
charCountEnable={this.props.charCountEnable}
|
||||
|
||||
@@ -117,6 +117,13 @@ const CONFIG = {
|
||||
// TALK_ROOT_URL and use it to mount the paths on.
|
||||
ROOT_URL_MOUNT_PATH: process.env.TALK_ROOT_URL_MOUNT_PATH === 'TRUE',
|
||||
|
||||
// DISABLE_STATIC_SERVER when TRUE will disable the routes used for static
|
||||
// asset serving.
|
||||
DISABLE_STATIC_SERVER: process.env.TALK_DISABLE_STATIC_SERVER === 'TRUE',
|
||||
|
||||
// STATIC_URI is the base uri where static files are hosted.
|
||||
STATIC_URI: process.env.TALK_STATIC_URI || process.env.TALK_ROOT_URL,
|
||||
|
||||
// The keepalive timeout (in ms) that should be used to send keep alive
|
||||
// messages through the websocket to keep the socket alive.
|
||||
KEEP_ALIVE: process.env.TALK_KEEP_ALIVE || '30s',
|
||||
|
||||
@@ -90,6 +90,12 @@ These are only used during the webpack build.
|
||||
managing the auth state manually, auth cannot be persisted, for further
|
||||
information refer to the [Persistence Documentation]({{ "/docs/running/persistence/" | absolute_url }})**
|
||||
(Default `${ssl ? 'ws' : 'wss'}://${location.host}${TALK_ROOT_URL_MOUNT_PATH}api/v1/live`)
|
||||
- `TALK_STATIC_URI` (_optional_) - Used to set the uri where the static assets
|
||||
should be served from. This is used when you want to upload the static assets
|
||||
through your build process to a service like Google Cloud Storage or Amazon S3
|
||||
and you would then specify the CDN/Storage url. (Default `process.env.TALK_ROOT_URL`)
|
||||
- `TALK_DISABLE_STATIC_SERVER` (_optional_) - When `TRUE`, it will not mount the
|
||||
static asset serving routes on the router. (Default `FALSE`)
|
||||
|
||||
### Word Filter
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
RECAPTCHA_PUBLIC,
|
||||
WEBSOCKET_LIVE_URI,
|
||||
} = require('../../config');
|
||||
const {data} = require('../static');
|
||||
|
||||
// Get /email-confirmation expects a signed JWT in the hash
|
||||
router.get('/confirm-email', (req, res) => {
|
||||
@@ -20,11 +17,6 @@ router.get('/password-reset', (req, res) => {
|
||||
});
|
||||
|
||||
router.get('*', (req, res) => {
|
||||
const data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
};
|
||||
|
||||
res.render('admin', {data});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const SettingsService = require('../../services/settings');
|
||||
const {
|
||||
RECAPTCHA_PUBLIC,
|
||||
WEBSOCKET_LIVE_URI,
|
||||
} = require('../../config');
|
||||
const {data} = require('../static');
|
||||
|
||||
router.use('/:embed', async (req, res, next) => {
|
||||
switch (req.params.embed) {
|
||||
case 'stream': {
|
||||
const {customCssUrl} = await SettingsService.retrieve();
|
||||
const data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
};
|
||||
|
||||
return res.render('embed/stream', {customCssUrl, data});
|
||||
}
|
||||
}
|
||||
|
||||
+19
-12
@@ -11,6 +11,7 @@ const errors = require('../errors');
|
||||
const {createGraphOptions} = require('../graph');
|
||||
const accepts = require('accepts');
|
||||
const apollo = require('graphql-server-express');
|
||||
const {DISABLE_STATIC_SERVER} = require('../config');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
@@ -39,20 +40,26 @@ if (process.env.NODE_ENV === 'production') {
|
||||
});
|
||||
}
|
||||
|
||||
router.use('/client', express.static(path.join(__dirname, '../dist')));
|
||||
router.use('/public', express.static(path.join(__dirname, '../public')));
|
||||
if (!DISABLE_STATIC_SERVER) {
|
||||
|
||||
/**
|
||||
* Serves a file based on a relative path.
|
||||
*/
|
||||
const serveFile = (filename) => (req, res) => res.sendFile(path.join(__dirname, filename));
|
||||
/**
|
||||
* Serve the directories under public/dist from this router.
|
||||
*/
|
||||
router.use('/client', express.static(path.join(__dirname, '../dist')));
|
||||
router.use('/public', express.static(path.join(__dirname, '../public')));
|
||||
|
||||
/**
|
||||
* Serves the embed javascript files.
|
||||
*/
|
||||
router.get('/embed.js', serveFile('../dist/embed.js'));
|
||||
router.get('/embed.js.gz', serveFile('../dist/embed.js.gz'));
|
||||
router.get('/embed.js.map', serveFile('../dist/embed.js.map'));
|
||||
/**
|
||||
* Serves a file based on a relative path.
|
||||
*/
|
||||
const serveFile = (filename) => (req, res) => res.sendFile(path.join(__dirname, filename));
|
||||
|
||||
/**
|
||||
* Serves the embed javascript files.
|
||||
*/
|
||||
router.get('/embed.js', serveFile('../dist/embed.js'));
|
||||
router.get('/embed.js.gz', serveFile('../dist/embed.js.gz'));
|
||||
router.get('/embed.js.map', serveFile('../dist/embed.js.map'));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// PASSPORT MIDDLEWARE
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
const {
|
||||
RECAPTCHA_PUBLIC,
|
||||
WEBSOCKET_LIVE_URI,
|
||||
} = require('../config');
|
||||
const {
|
||||
STATIC_URL,
|
||||
} = require('../url');
|
||||
|
||||
module.exports.data = {
|
||||
TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC,
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
STATIC_URL,
|
||||
};
|
||||
@@ -1,9 +1,15 @@
|
||||
const {ROOT_URL, ROOT_URL_MOUNT_PATH} = require('./config');
|
||||
const {
|
||||
ROOT_URL,
|
||||
ROOT_URL_MOUNT_PATH,
|
||||
STATIC_URI,
|
||||
} = require('./config');
|
||||
const {URL} = require('url');
|
||||
|
||||
const trailingSlash = (url) => url && url.length > 0 && url[url.length - 1] === '/' ? url : `${url}/`;
|
||||
|
||||
// Set the BASE_URL as the ROOT_URL, here we derive the root url by ensuring
|
||||
// that it ends in a `/`.
|
||||
const BASE_URL = ROOT_URL && ROOT_URL.length > 0 && ROOT_URL[ROOT_URL.length - 1] === '/' ? ROOT_URL : `${ROOT_URL}/`;
|
||||
const BASE_URL = trailingSlash(ROOT_URL);
|
||||
|
||||
// The BASE_PATH is simply the path component of the BASE_URL.
|
||||
const BASE_PATH = new URL(BASE_URL).pathname;
|
||||
@@ -12,8 +18,12 @@ const BASE_PATH = new URL(BASE_URL).pathname;
|
||||
// This will mount all the application routes onto it.
|
||||
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);
|
||||
|
||||
module.exports = {
|
||||
BASE_URL: BASE_URL,
|
||||
BASE_PATH: BASE_PATH,
|
||||
MOUNT_PATH: MOUNT_PATH,
|
||||
BASE_URL,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
};
|
||||
|
||||
+14
-14
@@ -4,19 +4,19 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
|
||||
<title>Talk - Coral Admin</title>
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="public/img/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="public/img/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="public/img/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="public/img/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="public/img/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="public/img/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="public/img/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="public/img/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="public/img/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="public/img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="public/img/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="public/img/favicon-16x16.png">
|
||||
<link rel="manifest" href="public/manifest.json">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="<%= STATIC_URL %>public/img/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="<%= STATIC_URL %>public/img/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="<%= STATIC_URL %>public/img/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="<%= STATIC_URL %>public/img/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="<%= STATIC_URL %>public/img/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="<%= STATIC_URL %>public/img/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="<%= STATIC_URL %>public/img/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="<%= STATIC_URL %>public/img/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="<%= STATIC_URL %>public/img/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="<%= STATIC_URL %>public/img/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="<%= STATIC_URL %>public/img/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="<%= STATIC_URL %>public/img/favicon-16x16.png">
|
||||
<link rel="manifest" href="<%= STATIC_URL %>public/manifest.json">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
||||
@@ -42,6 +42,6 @@
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src='https://www.google.com/recaptcha/api.js?render=explicit' async defer></script>
|
||||
<script src="<%= BASE_PATH %>client/coral-admin/bundle.js" charset="utf-8"></script>
|
||||
<script src="<%= STATIC_URL %>client/coral-admin/bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -28,6 +28,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script src="<%= BASE_PATH %>client/coral-docs/bundle.js" charset="utf-8"></script>
|
||||
<script src="<%= STATIC_URL %>client/coral-docs/bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
<p><%= body %></p>
|
||||
<p><a href="<%= BASE_PATH %>admin">Admin</a> - <a href="<%= BASE_PATH %>assets">All Assets</a></p>
|
||||
<div id='coralStreamEmbed'></div>
|
||||
<script src="<%= BASE_URL %>embed.js" async onload="
|
||||
<script src="<%= STATIC_URL %>embed.js" async onload="
|
||||
window.TalkEmbed = Coral.Talk.render(document.getElementById('coralStreamEmbed'), {
|
||||
talk: '<%= BASE_URL %>',
|
||||
asset_url: '<%= asset_url ? asset_url : '' %>',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<link rel="stylesheet" type="text/css" href="<%= BASE_URL %>client/embed/stream/default.css">
|
||||
<link rel="stylesheet" type="text/css" href="<%= STATIC_URL %>client/embed/stream/default.css">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<% if (locals.customCssUrl) { %>
|
||||
@@ -17,6 +17,6 @@
|
||||
<body>
|
||||
|
||||
<div id="talk-embed-stream-container"></div>
|
||||
<script src="<%= BASE_PATH %>client/embed/stream/bundle.js"></script>
|
||||
<script src="<%= STATIC_URL %>client/embed/stream/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user