mirror of
https://github.com/wassname/talk.git
synced 2026-09-13 13:10:43 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1098c068f2 | ||
|
|
f0c95d0044 | ||
|
|
d31969592c | ||
|
|
794487b1a9 | ||
|
|
9f059e0c4a | ||
|
|
7d369f2d35 | ||
|
|
5fb5240f89 | ||
|
|
976931135c | ||
|
|
1e3d47eb87 | ||
|
|
2d804d783b | ||
|
|
3404578ecc | ||
|
|
48c5355a5b | ||
|
|
e3a300c643 | ||
|
|
a6653152e4 |
@@ -14,6 +14,11 @@ class TechSettings extends React.Component {
|
||||
this.props.updatePending({ updater });
|
||||
};
|
||||
|
||||
updateCustomAdminCssUrl = event => {
|
||||
const updater = { customAdminCssUrl: { $set: event.target.value } };
|
||||
this.props.updatePending({ updater });
|
||||
};
|
||||
|
||||
updateDomainlist = (listName, list) => {
|
||||
this.props.updatePending({
|
||||
updater: {
|
||||
@@ -50,6 +55,14 @@ class TechSettings extends React.Component {
|
||||
onChange={this.updateCustomCssUrl}
|
||||
/>
|
||||
</ConfigureCard>
|
||||
<ConfigureCard title={t('configure.custom_admin_css_url')}>
|
||||
<p>{t('configure.custom_admin_css_url_desc')}</p>
|
||||
<input
|
||||
className={styles.customCSSInput}
|
||||
value={settings.customAdminCssUrl}
|
||||
onChange={this.updateCustomAdminCssUrl}
|
||||
/>
|
||||
</ConfigureCard>
|
||||
<Slot fill="adminTechSettings" passthrough={slotPassthrough} />
|
||||
</ConfigurePage>
|
||||
);
|
||||
|
||||
@@ -32,6 +32,7 @@ export default compose(
|
||||
settings: gql`
|
||||
fragment TalkAdmin_TechSettings_settings on Settings {
|
||||
customCssUrl
|
||||
customAdminCssUrl
|
||||
domains {
|
||||
whitelist
|
||||
}
|
||||
|
||||
@@ -43,6 +43,32 @@ const CONFIG = {
|
||||
process.env.TALK_WHITELISTED_LANGUAGES &&
|
||||
process.env.TALK_WHITELISTED_LANGUAGES.split(',').map(l => l.trim()),
|
||||
|
||||
// USERNAME_CAST_REGEXP defiles the regex expression that will be used to
|
||||
// strip characters from a username during a username cast operation.
|
||||
USERNAME_CAST_REGEXP: new RegExp(
|
||||
process.env.USERNAME_CAST_REGEXP || '[^a-zA-Z_]',
|
||||
'g'
|
||||
),
|
||||
|
||||
// USERNAME_REPLACEMENT_CAST_REGEXP defiles the regex expression that will be
|
||||
// used to replace characters with the replacement character during a username
|
||||
// cast operation. First duplicates will be replaced, then
|
||||
USERNAME_REPLACEMENT_CAST_REGEXP: new RegExp(
|
||||
process.env.USERNAME_REPLACEMENT_CAST_REGEXP || ' +',
|
||||
'g'
|
||||
),
|
||||
|
||||
// USERNAME_REPLACEMENT_CHARACTER is the character used to replace other
|
||||
// characters matching the USERNAME_REPLACEMENT_CAST_REGEXP.
|
||||
USERNAME_REPLACEMENT_CHARACTER:
|
||||
process.env.USERNAME_REPLACEMENT_CHARACTER || '_',
|
||||
|
||||
// USERNAME_VALIDATION_REGEX defines the allowed characters for a username in
|
||||
// Talk.
|
||||
USERNAME_VALIDATION_REGEX: new RegExp(
|
||||
process.env.USERNAME_VALIDATION_REGEX || '^[A-Za-z0-9_]+$'
|
||||
),
|
||||
|
||||
// When TRUE, it ensures that database indexes created in core will not add
|
||||
// indexes.
|
||||
CREATE_MONGO_INDEXES: process.env.DISABLE_CREATE_MONGO_INDEXES !== 'TRUE',
|
||||
|
||||
+1
-3
@@ -76,9 +76,7 @@ sidebar:
|
||||
- title: GitHub
|
||||
url: https://github.com/coralproject/
|
||||
- title: Docker
|
||||
url: https://hub.docker.com/r/coralproject/
|
||||
- title: Roadmap
|
||||
url: https://www.pivotaltracker.com/n/projects/1863625
|
||||
url: https://hub.docker.com/r/coralproject/talk/
|
||||
side:
|
||||
- title: Installation
|
||||
children:
|
||||
|
||||
@@ -5,9 +5,18 @@ permalink: /
|
||||
|
||||
Online comments are broken. Our open-source Talk tool rethinks how moderation,
|
||||
comment display, and conversation function, creating the opportunity for safer,
|
||||
smarter discussions around your work. Read more about our product features and
|
||||
goals [here](https://coralproject.net/talk). The
|
||||
documentation available here is pertaining to the technical details for
|
||||
smarter discussions around your work.
|
||||
|
||||
More than 60 newsrooms use Talk to run their on-site communities, including the Washington Post, the Wall Street Journal, and IGN.
|
||||
|
||||
[Read more about our product features and
|
||||
goals here](https://coralproject.net/talk).
|
||||
|
||||
<div class="callout">
|
||||
We offer hosting and support packages for Talk. [Contact us for more information.](https://coralproject.net/pricing/)
|
||||
</div>
|
||||
|
||||
The documentation available here is pertaining to the technical details for
|
||||
installing, configuring, and deploying Talk.
|
||||
|
||||
Talk is a [Node](https://nodejs.org/) application with
|
||||
@@ -46,7 +55,7 @@ Start by making a new directory and create a file called `docker-compose.yml` an
|
||||
version: '2'
|
||||
services:
|
||||
talk:
|
||||
image: coralproject/talk:4.5
|
||||
image: coralproject/talk:4
|
||||
restart: always
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
@@ -43,7 +43,7 @@ be used to setup Talk:
|
||||
version: '2'
|
||||
services:
|
||||
talk:
|
||||
image: coralproject/talk:4.5
|
||||
image: coralproject/talk:4
|
||||
restart: always
|
||||
ports:
|
||||
- "3000:3000"
|
||||
@@ -121,7 +121,7 @@ base installation with additional custom plugins. Images can be created with the
|
||||
most basic of `Dockerfile`'s:
|
||||
|
||||
```docker
|
||||
FROM coralproject/talk:4.5-onbuild
|
||||
FROM coralproject/talk:4-onbuild
|
||||
```
|
||||
|
||||
And running the following to build the docker image:
|
||||
@@ -153,7 +153,7 @@ your containerized infrastructure. The versioning of our Docker tags as well
|
||||
lets you do something like:
|
||||
|
||||
```docker
|
||||
FROM coralproject/talk:4.5-onbuild
|
||||
FROM coralproject/talk:4-onbuild
|
||||
```
|
||||
|
||||
Which would pin your image to `4.5.x release's.
|
||||
Which would pin your image to `4.x.x release's.
|
||||
|
||||
@@ -111,7 +111,7 @@ If you deploy using Docker, you can extend from the `*-onbuild` image, an
|
||||
example `Dockerfile` for your project could be:
|
||||
|
||||
```Dockerfile
|
||||
FROM coralproject/talk:4.5-onbuild
|
||||
FROM coralproject/talk:4-onbuild
|
||||
```
|
||||
|
||||
Establish a private repository for your instance that includes the following:
|
||||
|
||||
+19
@@ -465,3 +465,22 @@ a.brand {
|
||||
background: rgb(0, 102, 176);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.callout {
|
||||
background-color: $coral_button_background;
|
||||
color: white;
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
@extend .coral-link;
|
||||
color: #FFF;
|
||||
border-color: #FFF;
|
||||
|
||||
&:hover {
|
||||
color: #FFF;
|
||||
border-color: darken(#FFF, 5%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,13 +64,13 @@ const wrapCheck = (
|
||||
|
||||
/**
|
||||
* checkPermissions checks that the current user has all the required
|
||||
* permissions.
|
||||
* permissions. It will return true if that's the case.
|
||||
*
|
||||
* @param {Object} ctx graph context
|
||||
* @param {Array<String>} permissions permissions that the user must have
|
||||
*/
|
||||
const checkPermissions = (ctx, permissions) =>
|
||||
!ctx.user || !ctx.user.can(...permissions);
|
||||
ctx.user && ctx.user.can(...permissions);
|
||||
|
||||
/**
|
||||
* wrapCheckPermissions will wrap a specific field with a permission check.
|
||||
@@ -89,7 +89,7 @@ const wrapCheckPermissions = (
|
||||
wrapCheck(
|
||||
typeResolver,
|
||||
field,
|
||||
(obj, args, ctx) => !checkPermissions(ctx, permissions),
|
||||
(obj, args, ctx) => checkPermissions(ctx, permissions),
|
||||
skipFieldResolver
|
||||
);
|
||||
|
||||
|
||||
@@ -879,6 +879,9 @@ type Settings {
|
||||
# customCssUrl is the URL of the custom CSS used to display on the frontend.
|
||||
customCssUrl: String
|
||||
|
||||
# customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
|
||||
customAdminCssUrl: String
|
||||
|
||||
# closedTimeout is the amount of seconds from the created_at timestamp that a
|
||||
# given asset will be considered closed.
|
||||
closedTimeout: Int
|
||||
@@ -1353,6 +1356,9 @@ input UpdateSettingsInput {
|
||||
# customCssUrl is the URL of the custom CSS used to display on the frontend.
|
||||
customCssUrl: String
|
||||
|
||||
# customAdminCssUrl is the URL of the custom CSS used to display on the admin panel.
|
||||
customAdminCssUrl: String
|
||||
|
||||
# closedTimeout is the amount of seconds from the created_at timestamp that a
|
||||
# given asset will be considered closed.
|
||||
closedTimeout: Int
|
||||
|
||||
@@ -124,6 +124,8 @@ en:
|
||||
copy_and_paste: 'Copy and paste code below into your CMS to embed your comment box in your articles'
|
||||
custom_css_url: 'Custom CSS URL'
|
||||
custom_css_url_desc: 'URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.'
|
||||
custom_admin_css_url: 'Custom Admin Panel CSS URL'
|
||||
custom_admin_css_url_desc: 'URL of a CSS stylesheet that will override default admin panel styles. Can be internal or external.'
|
||||
days: Days
|
||||
description: 'Change the comment settings on this story.'
|
||||
disable_commenting_desc: 'Write a message that will be displayed while commenting is deactivated.'
|
||||
|
||||
@@ -96,12 +96,18 @@ const createResolveFactory = (() => {
|
||||
|
||||
module.exports = async (req, res, next) => {
|
||||
try {
|
||||
// Attach the custom css url and organization name.
|
||||
const { customCssUrl, organizationName } = await SettingsService.select(
|
||||
// Attach the custom css urls and organization name.
|
||||
const {
|
||||
customCssUrl,
|
||||
customAdminCssUrl,
|
||||
organizationName,
|
||||
} = await SettingsService.select(
|
||||
'customCssUrl',
|
||||
'customAdminCssUrl',
|
||||
'organizationName'
|
||||
);
|
||||
res.locals.customCssUrl = customCssUrl;
|
||||
res.locals.customAdminCssUrl = customAdminCssUrl;
|
||||
res.locals.organizationName = organizationName;
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
|
||||
@@ -28,6 +28,10 @@ const Setting = new Schema(
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
customAdminCssUrl: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
infoBoxContent: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "talk",
|
||||
"version": "4.8.4",
|
||||
"version": "4.8.7",
|
||||
"description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net",
|
||||
"main": "app.js",
|
||||
"private": true,
|
||||
|
||||
@@ -29,7 +29,7 @@ Configuration:
|
||||
guide. This is only required while the `talk-plugin-facebook-auth` plugin is
|
||||
enabled.
|
||||
|
||||
_NOTE: FabceBook auth requires your site to use `https` (SSL) not `http`. If your site is not `https` you can not use this plugin!_
|
||||
_NOTE: Facebook auth requires your site to use `https` (SSL) not `http`. If your site is not `https` you can not use this plugin!_
|
||||
|
||||
## GDPR Compliance
|
||||
|
||||
|
||||
@@ -42,19 +42,10 @@
|
||||
text-align: left;
|
||||
letter-spacing: 0.1px;
|
||||
margin: 0;
|
||||
quotes: '\201c' '\201d';
|
||||
margin-bottom: 10px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.quote:before {
|
||||
content: open-quote;
|
||||
}
|
||||
|
||||
.quote:after {
|
||||
content: close-quote;
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class Editor extends React.Component {
|
||||
};
|
||||
|
||||
getHTML(props = this.props) {
|
||||
if (props.input.richTextBody) {
|
||||
if (props.input.richTextBody !== undefined) {
|
||||
return props.input.richTextBody;
|
||||
}
|
||||
return (
|
||||
|
||||
+14
-5
@@ -22,6 +22,10 @@ const {
|
||||
ROOT_URL,
|
||||
RECAPTCHA_WINDOW,
|
||||
RECAPTCHA_INCORRECT_TRIGGER,
|
||||
USERNAME_CAST_REGEXP,
|
||||
USERNAME_REPLACEMENT_CAST_REGEXP,
|
||||
USERNAME_REPLACEMENT_CHARACTER,
|
||||
USERNAME_VALIDATION_REGEX,
|
||||
} = require('../config');
|
||||
const { jwt: JWT_SECRET } = require('../secrets');
|
||||
const debug = require('debug')('talk:services:users');
|
||||
@@ -525,7 +529,10 @@ class Users {
|
||||
}
|
||||
|
||||
static castUsername(username) {
|
||||
return username.replace(/ /g, '_').replace(/[^a-zA-Z_]/g, '');
|
||||
return username
|
||||
.trim()
|
||||
.replace(USERNAME_REPLACEMENT_CAST_REGEXP, USERNAME_REPLACEMENT_CHARACTER)
|
||||
.replace(USERNAME_CAST_REGEXP, '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -554,7 +561,11 @@ class Users {
|
||||
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
||||
// Generate `GROUP_ATTEMPTS` guesses for the username.
|
||||
const usernameGuesses = Array.from(Array(GROUP_ATTEMPTS)).map(
|
||||
() => `${castedName}_${random(0, END_NUMBER_MAX)}`
|
||||
() =>
|
||||
`${castedName}${USERNAME_REPLACEMENT_CHARACTER}${random(
|
||||
0,
|
||||
END_NUMBER_MAX
|
||||
)}`
|
||||
);
|
||||
|
||||
// Map them all to lowercase.
|
||||
@@ -684,13 +695,11 @@ class Users {
|
||||
* @return {Promise}
|
||||
*/
|
||||
static async isValidUsername(username, checkAgainstWordlist = true) {
|
||||
const onlyLettersNumbersUnderscore = /^[A-Za-z0-9_]+$/;
|
||||
|
||||
if (!username) {
|
||||
throw new ErrMissingUsername();
|
||||
}
|
||||
|
||||
if (!onlyLettersNumbersUnderscore.test(username)) {
|
||||
if (!USERNAME_VALIDATION_REGEX.test(username)) {
|
||||
throw new ErrSpecialChars();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ describe('graph.queries.settings', () => {
|
||||
questionBoxIcon
|
||||
autoCloseStream
|
||||
customCssUrl
|
||||
customAdminCssUrl
|
||||
closedTimeout
|
||||
closedMessage
|
||||
charCountEnable
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
|
||||
<link href="https://code.getmdl.io/1.2.1/material.min.css" rel="stylesheet">
|
||||
<link href="{{ resolve('coral-admin/bundle.css') }}" rel="stylesheet">
|
||||
|
||||
{# Custom CSS is included after the CSS block so that its overrides will apply #}
|
||||
{% include "partials/custom-admin-css.njk" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{% if customAdminCssUrl %}
|
||||
<link nonce="{{ nonce }}" href="{{ customAdminCssUrl }}" rel="stylesheet">
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user