mirror of
https://github.com/wassname/talk.git
synced 2026-09-13 13:10:43 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb54009567 | ||
|
|
c126d217ad | ||
|
|
d0eca26d5b | ||
|
|
b742923897 | ||
|
|
1781b926d9 | ||
|
|
7b97a8fca2 | ||
|
|
6bff2de371 | ||
|
|
05283b08f7 | ||
|
|
838687a3ae | ||
|
|
7b0213299a |
@@ -14,7 +14,7 @@ Learn more about Talk, including a deep dive into features for commenters and mo
|
||||
|
||||
## Pre-Launch Guide
|
||||
|
||||
You’ve installed Talk on your server, and you’re preparing to launch it on your site. The real community work starts now, before you go live. You have a unique opportunity pre-launch to set your community up for success. Read our [Talk Community Guide](https://blog.coralproject.net/youve-installed-talk-now-what/).
|
||||
You’ve installed Talk on your server, and you’re preparing to launch it on your site. The real community work starts now, before you go live. You have a unique opportunity pre-launch to set your community up for success. Read our [Talk Community Guide](https://coralproject.net/blog/youve-installed-talk-now-what/).
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createPostMessage } from 'coral-framework/services/postMessage';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const staticConfig = getStaticConfiguration();
|
||||
const { STATIC_ORIGIN: origin } = staticConfig;
|
||||
const { BASE_ORIGIN: origin } = staticConfig;
|
||||
const postMessage = createPostMessage(origin);
|
||||
|
||||
// Get the auth element and parse it as JSON by decoding it.
|
||||
|
||||
@@ -38,5 +38,4 @@
|
||||
position: relative;
|
||||
margin-top: 28px;
|
||||
padding-bottom: 50px;
|
||||
min-height: 600px;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,11 @@ export const checkLogin = () => (
|
||||
|
||||
dispatch(checkLoginSuccess(result.user));
|
||||
pym.sendMessage('coral-auth-changed', JSON.stringify(result.user));
|
||||
client.resetWebsocket();
|
||||
|
||||
// We don't need to reset the websocket here because if the request
|
||||
// returned that there was a user (which is the case here), then the
|
||||
// original request has already succeeded, or a previous call to a token
|
||||
// set handler has already reset it.
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.status && error.status === 401 && localStorage) {
|
||||
@@ -49,7 +53,11 @@ const checkLoginSuccess = user => ({
|
||||
user,
|
||||
});
|
||||
|
||||
export const setAuthToken = token => (dispatch, _, { localStorage }) => {
|
||||
export const setAuthToken = token => (
|
||||
dispatch,
|
||||
_,
|
||||
{ localStorage, client }
|
||||
) => {
|
||||
localStorage.setItem('exp', jwtDecode(token).exp);
|
||||
localStorage.setItem('token', token);
|
||||
|
||||
@@ -57,6 +65,9 @@ export const setAuthToken = token => (dispatch, _, { localStorage }) => {
|
||||
// may not be able to persist the auth token any other way. Keep it in redux!
|
||||
dispatch({ type: actions.SET_AUTH_TOKEN, token });
|
||||
|
||||
// Now that we set a token, let's reset the subscriptions.
|
||||
client.resetWebsocket();
|
||||
|
||||
dispatch(checkLogin());
|
||||
};
|
||||
|
||||
@@ -79,6 +90,7 @@ export const handleSuccessfulLogin = (user, token) => (
|
||||
);
|
||||
}
|
||||
|
||||
// Now that we just set a token, set the token!
|
||||
client.resetWebsocket();
|
||||
|
||||
dispatch({
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ export async function createContext({
|
||||
});
|
||||
|
||||
const staticConfig = getStaticConfiguration();
|
||||
let { LIVE_URI: liveUri, STATIC_ORIGIN: origin } = staticConfig;
|
||||
let { LIVE_URI: liveUri, BASE_ORIGIN: origin } = staticConfig;
|
||||
if (liveUri == null) {
|
||||
// The protocol must match the origin protocol, secure/insecure.
|
||||
const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
|
||||
@@ -88,21 +88,23 @@ export function createClient(options = {}) {
|
||||
});
|
||||
|
||||
client.resetWebsocket = () => {
|
||||
// Close socket connection which will also unregister subscriptions on the server-side.
|
||||
wsClient.close();
|
||||
if (wsClient.client) {
|
||||
// Close socket connection which will also unregister subscriptions on the server-side.
|
||||
wsClient.close(true);
|
||||
|
||||
// Reconnect to the server.
|
||||
wsClient.connect();
|
||||
// Reconnect to the server.
|
||||
wsClient.connect();
|
||||
|
||||
// Reregister all subscriptions (uses non public api).
|
||||
// See: https://github.com/apollographql/subscriptions-transport-ws/issues/171
|
||||
Object.keys(wsClient.operations).forEach(id => {
|
||||
wsClient.sendMessage(
|
||||
id,
|
||||
MessageTypes.GQL_START,
|
||||
wsClient.operations[id].options
|
||||
);
|
||||
});
|
||||
// Re-register all subscriptions (uses non public api).
|
||||
// See: https://github.com/apollographql/subscriptions-transport-ws/issues/171
|
||||
Object.keys(wsClient.operations).forEach(id => {
|
||||
wsClient.sendMessage(
|
||||
id,
|
||||
MessageTypes.GQL_START,
|
||||
wsClient.operations[id].options
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return client;
|
||||
|
||||
@@ -22,13 +22,10 @@ to persist data. The following versions are supported:
|
||||
- MongoDB 3.2+
|
||||
- Redis 3.2.5+
|
||||
|
||||
An optional dependency for Talk is
|
||||
[Docker](https://www.docker.com/community-edition#/download).
|
||||
It is used during development to set up the database and can be
|
||||
used to [install via Docker](#installation-from-docker). We have tested Talk
|
||||
and this documentation with versions 17.06.2+.
|
||||
You can run Talk (and its dependencies) locally or from [Docker](https://www.docker.com/community-edition#/download) containers. Docker is used in the local example below for the database and cache, however it is possible to run Talk without Docker by configuring your own MongoDB and Redis instances. We have tested Talk
|
||||
and this documentation with Docker versions 17.06.2+.
|
||||
|
||||
Another optional dependency for Talk is
|
||||
An optional dependency for Talk is
|
||||
[Docker Compose](https://docs.docker.com/compose/install/). It
|
||||
can be used to setup your environment easily for testing. We have tested Talk
|
||||
and this documentation with versions 1.14.0+.
|
||||
@@ -38,8 +35,9 @@ and this documentation with versions 1.14.0+.
|
||||
### Installation from Docker
|
||||
|
||||
To use Talk without major customization you can run the application using our
|
||||
provided docker image. The following is a `docker-compose.yml` file that can
|
||||
be used to setup Talk:
|
||||
provided docker image.
|
||||
|
||||
Start by making a new directory and create a file called `docker-compose.yml` and copy the following:
|
||||
|
||||
```yml
|
||||
# For details on the syntax of docker-compose.yml files, check out:
|
||||
@@ -79,7 +77,7 @@ volumes:
|
||||
external: false
|
||||
```
|
||||
|
||||
This is the bare minimum needed to run the demo, for more configuration
|
||||
The environment variables listed above are the bare minimum needed to run the demo, for more configuration
|
||||
variables, check out the [Configuration](/talk/configuration/) section.
|
||||
|
||||
|
||||
@@ -104,8 +102,7 @@ Creating talk_1 ...
|
||||
Creating talk_1 ... done
|
||||
```
|
||||
|
||||
|
||||
And when you run `docker-compose ps`, you should see something like:
|
||||
Once everything has completed, run `docker-compose ps`, and you should see something like:
|
||||
|
||||
```
|
||||
Name Command State Ports
|
||||
@@ -116,8 +113,8 @@ talk_1 yarn start Up 0.0.0.0:3000->3000/tcp
|
||||
```
|
||||
|
||||
|
||||
Continue onto the [Running](#running) section for details on how to complete the
|
||||
installation and get started using Talk.
|
||||
You now have a Talk instance up and running! Continue on to the [Setup](#setup) section for details on how to complete the
|
||||
initial setup and get started using Talk.
|
||||
|
||||
### Installation from Source
|
||||
|
||||
@@ -178,32 +175,35 @@ You can now start the application by running:
|
||||
yarn watch:server
|
||||
```
|
||||
|
||||
Continue onto the [Running](#running) section for details on how to complete the
|
||||
Continue onto the [Setup](#setup) section for details on how to complete the
|
||||
installation and get started using Talk.
|
||||
|
||||
## Running
|
||||
## Setup
|
||||
### Create Admin Account
|
||||
|
||||
You can now navigate to
|
||||
With Talk running, you can now navigate to
|
||||
[http://127.0.0.1:3000/admin/install](http://127.0.0.1:3000/admin/install)
|
||||
and go through the admin installation. There you will be prompted to create your
|
||||
first admin account, and specify the domain whitelist for domains that are
|
||||
allowed to have the comment box on.
|
||||
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._
|
||||
|
||||
Once you've completed the installation, you can visit
|
||||
[http://127.0.0.1:3000/](http://127.0.0.1:3000/) where you can
|
||||
view our development area where we test out features in Talk where you can write
|
||||
comments and see them in the admin interface where you can do moderation and
|
||||
reconfigure the user experience.
|
||||
Once the setup wizard has been completed you can log into Talk ([http://127.0.0.1:3000/](http://127.0.0.1:3000/)) using the email address and password for the Admin user account that you just created.
|
||||
|
||||
## Demo
|
||||
From here you can test out features in Talk, see comments in the admin interface where you can do moderation, and configure the user experience.
|
||||
In the next step you'll create some user comments to moderate.
|
||||
|
||||
|
||||
### Demo Embedded Comments
|
||||
|
||||
If you've followed the documentation above, you'll now have a running copy of
|
||||
Talk. To demonstrate what your own self-hosted copy of Talk can do, below
|
||||
you'll find a demo that can be used to test the copy that is running now on your
|
||||
Talk. To demonstrate what your own self-hosted copy of Talk can do, we created the demo below
|
||||
that can be used to test the copy that is running now on your
|
||||
machine.
|
||||
|
||||
In order for the demo to work, you must add
|
||||
|
||||
@@ -144,9 +144,9 @@ Some queries you may notice seem to return `null` or an error of
|
||||
route that requires authorization. You can perform authorization a few ways in
|
||||
Talk:
|
||||
|
||||
1. As a [Bearer Token](#Bearer-Token)
|
||||
2. As a [Query Parameter](#Query-Parameter)
|
||||
3. As a [Cookie](#Cookie)
|
||||
1. As a [Bearer Token](#bearer-token)
|
||||
2. As a [Query Parameter](#query-parameter)
|
||||
3. As a [Cookie](#cookie)
|
||||
|
||||
Essentially, you need to get access to a JWT token that you can use to authorize
|
||||
your requests. Generating one is simple, you can use the CLI tools in Talk to do
|
||||
|
||||
@@ -18,11 +18,11 @@ 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).
|
||||
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).
|
||||
|
||||
We will then modify our embed so that we can [Target the Asset](#Target-the-Asset).
|
||||
We will then modify our embed so that we can [Target the Asset](#target-the-asset).
|
||||
|
||||
But first we should grab our basic plugin structure:
|
||||
|
||||
@@ -248,7 +248,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-a-New-Asset-Route)
|
||||
, 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.
|
||||
|
||||
@@ -343,6 +343,20 @@ class ErrCommentTooShort extends TalkError {
|
||||
}
|
||||
}
|
||||
|
||||
// ErrCommentTooLong is returned when the comment is too long.
|
||||
class ErrCommentTooLong extends TalkError {
|
||||
constructor(length, allowed) {
|
||||
super(
|
||||
'Comment was too long',
|
||||
{
|
||||
translation_key: 'COMMENT_TOO_LONG',
|
||||
status: 400,
|
||||
},
|
||||
{ length, allowed }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ErrAssetURLAlreadyExists is returned when a rename operation is requested
|
||||
// but an asset already exists with the new url.
|
||||
class ErrAssetURLAlreadyExists extends TalkError {
|
||||
@@ -413,13 +427,15 @@ module.exports = {
|
||||
ErrAssetURLAlreadyExists,
|
||||
ErrAuthentication,
|
||||
ErrCannotIgnoreStaff,
|
||||
ErrCommentTooShort,
|
||||
ErrCommentingDisabled,
|
||||
ErrCommentTooLong,
|
||||
ErrCommentTooShort,
|
||||
ErrContainsProfanity,
|
||||
ErrEditWindowHasEnded,
|
||||
ErrEmailAlreadyVerified,
|
||||
ErrEmailTaken,
|
||||
ErrEmailVerificationToken,
|
||||
ErrHTTPNotFound,
|
||||
ErrInstallLock,
|
||||
ErrInvalidAssetURL,
|
||||
ErrLoginAttemptMaximumExceeded,
|
||||
@@ -441,5 +457,4 @@ module.exports = {
|
||||
ErrSpecialChars,
|
||||
ErrUsernameTaken,
|
||||
ExtendableError,
|
||||
ErrHTTPNotFound,
|
||||
};
|
||||
|
||||
+1
-1
@@ -225,6 +225,7 @@ ar:
|
||||
CANNOT_IGNORE_STAFF: 'لا يمكن تجاهل الموظفين.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'التعليق الذي ترد عليه تمت إزالته أو غير موجود.'
|
||||
COMMENT_TOO_SHORT: 'يجب أن تكون التعليقات أكثر من حرف واحد، يرجى مراجعة تعليقك وإعادة المحاولة.'
|
||||
COMMENT_TOO_LONG: 'يتجاوز النص الحد الأقصى للطول المسموح'
|
||||
COMMENTING_CLOSED: 'تم إغلاق فاعلية التعليق'
|
||||
COMMENTING_DISABLED: 'التعليق معطّل حاليًا على هذا الموقع'
|
||||
confirm_password: 'كلمات المرور غير متطابقة. يرجى التحقق مرة أخرى'
|
||||
@@ -281,7 +282,6 @@ ar:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'كلمة محظورة'
|
||||
body_count: 'يتجاوز النص الحد الأقصى للطول المسموح'
|
||||
comment_noagree: أعارض
|
||||
comment_offensive: مسيء
|
||||
comment_other: آخر
|
||||
|
||||
+1
-1
@@ -197,6 +197,7 @@ da:
|
||||
CANNOT_IGNORE_STAFF: 'Kan ikke ignorere personale.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'Den kommentar, du svarer på er blevet fjernet eller eksisterer ikke.'
|
||||
COMMENT_TOO_SHORT: 'Din kommentar skal indeholde noget'
|
||||
COMMENT_TOO_LONG: 'Body overstiger max længde'
|
||||
COMMENTING_CLOSED: 'Kommentering er allerede lukket'
|
||||
confirm_password: 'Kodeordene matcher ikke. Tjek venligst igen.'
|
||||
EDIT_USERNAME_NOT_AUTHORIZED: 'Du har ikke tilladelse til at opdatere dit brugernavn.'
|
||||
@@ -238,7 +239,6 @@ da:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Forbudt ord'
|
||||
body_count: 'Body overstiger max længde'
|
||||
comment_noagree: Uenig
|
||||
comment_offensive: Offensiv
|
||||
comment_other: Andre
|
||||
|
||||
+1
-1
@@ -224,6 +224,7 @@ de:
|
||||
CANNOT_IGNORE_STAFF: 'Mitarbeiter können nicht ignoriert werden.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'Der Kommentar, auf den Sie antworten möchten, wurde entfernt oder existiert nicht.'
|
||||
COMMENT_TOO_SHORT: 'Kommentare sollten mehr als ein Zeichen enthalten, bitte überprüfen Sie Ihren Kommentar und probieren Sie es erneut.'
|
||||
COMMENT_TOO_LONG: 'Text überschreitet Zeichenlimit'
|
||||
COMMENTING_CLOSED: 'Kommentarbereich ist bereits geschlossen'
|
||||
COMMENTING_DISABLED: 'Die Kommentarfunktion ist derzeit abgeschaltet'
|
||||
confirm_password: 'Passwörter nicht identisch. Bitte erneut überprüfen'
|
||||
@@ -273,7 +274,6 @@ de:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Unzulässiges Wort'
|
||||
body_count: 'Text überschreitet Zeichenlimit'
|
||||
comment_noagree: 'Andere Meinung'
|
||||
comment_offensive: Unangemessen
|
||||
comment_other: Anderes
|
||||
|
||||
+1
-1
@@ -229,6 +229,7 @@ en:
|
||||
CANNOT_IGNORE_STAFF: 'Cannot ignore Staff members.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'The comment that you''re replying to has been removed or doesn''t exist.'
|
||||
COMMENT_TOO_SHORT: 'Comments should be more than one character, please revise your comment and try again.'
|
||||
COMMENT_TOO_LONG: 'Body exceeds max length'
|
||||
COMMENTING_CLOSED: 'Commenting is already closed'
|
||||
COMMENTING_DISABLED: 'Commenting is currently disabled on this site'
|
||||
confirm_password: 'Passwords don''t match. Please check again'
|
||||
@@ -286,7 +287,6 @@ en:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Banned Word'
|
||||
body_count: 'Body exceeds max length'
|
||||
comment_noagree: Disagree
|
||||
comment_offensive: Offensive
|
||||
comment_other: Other
|
||||
|
||||
+1
-1
@@ -215,6 +215,7 @@ es:
|
||||
CANNOT_IGNORE_STAFF: 'No puede ignorar a miembros del Staff.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'El comentario a la que estás contestando ha sido eliminado o no existe.'
|
||||
COMMENT_TOO_SHORT: 'Tu comentario debe tener algo escrito'
|
||||
COMMENT_TOO_LONG: 'El texto excede el límite permitido'
|
||||
COMMENTING_CLOSED: 'Los comentarios ya estan cerrados'
|
||||
confirm_password: 'Las contraseñas no coinciden. Inténtelo nuevamente'
|
||||
EDIT_USERNAME_NOT_AUTHORIZED: 'No tiene permiso para editar el nombre de usuario.'
|
||||
@@ -260,7 +261,6 @@ es:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Palabra prohibida'
|
||||
body_count: 'El texto exede el límite permitido'
|
||||
comment_noagree: 'No está de acuerdo'
|
||||
comment_offensive: 'Es ofensivo'
|
||||
comment_other: 'Otra razón'
|
||||
|
||||
+1
-1
@@ -197,6 +197,7 @@ fi_FI:
|
||||
CANNOT_IGNORE_STAFF: 'Työntekijöitä ei voi jättää huomioimatta'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'Kommenttia, johon yrität vastata, ei enää ole.'
|
||||
COMMENT_TOO_SHORT: 'Kommentin tulee olla vähintään kaksi merkkiä pitkä. Tarkista kirjoittamasi teksti.'
|
||||
COMMENT_TOO_LONG: Liian pitkä viesti'
|
||||
COMMENTING_CLOSED: 'Kommentointi on suljettu'
|
||||
confirm_password: 'Salasanat eivät täsmää. Tarkista, ole hyvä.'
|
||||
EDIT_USERNAME_NOT_AUTHORIZED: 'Sinulla ei ole oikeutta päivittää tai muokata käyttäjänimeä.'
|
||||
@@ -240,7 +241,6 @@ fi_FI:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Kielletty sana'
|
||||
body_count: 'Liian pitkä viesti'
|
||||
comment_noagree: 'Olen eri mieltä'
|
||||
comment_offensive: Loukkaava
|
||||
comment_other: Muu
|
||||
|
||||
+1
-1
@@ -191,6 +191,7 @@ fr:
|
||||
CANNOT_IGNORE_STAFF: 'Ne peut pas ignorer les membres de l''équipe.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'Le commentaire auquel vous répondez a été supprimé ou n’existe plus.'
|
||||
COMMENT_TOO_SHORT: 'Votre commentaire doit contenir quelque chose'
|
||||
COMMENT_TOO_LONG: 'Le texte dépasse la longueur maximale'
|
||||
COMMENTING_CLOSED: 'Les commentaires sont déjà fermés'
|
||||
confirm_password: 'Les mots de passe ne correspondent pas. Vérifiez à nouveau'
|
||||
EDIT_USERNAME_NOT_AUTHORIZED: 'Vous n''avez pas la permission de mettre à jour votre nom d''utilisateur.'
|
||||
@@ -235,7 +236,6 @@ fr:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Mot banni'
|
||||
body_count: 'Le texte dépasse la longueur maximale'
|
||||
comment_noagree: 'Pas d’accord'
|
||||
comment_offensive: Offensive
|
||||
comment_other: Autre
|
||||
|
||||
+1
-1
@@ -197,6 +197,7 @@ nl_NL:
|
||||
CANNOT_IGNORE_STAFF: 'Kan geen Staff-leden negeren.'
|
||||
COMMENT_PARENT_NOT_VISIBLE: 'De reactie waarop je probeert te reageren bestaat niet of is inmiddels verwijderd.'
|
||||
COMMENT_TOO_SHORT: 'Reacties moeten meer dan één teken hebben. Herzie je reactie en probeer opnieuw.'
|
||||
COMMENT_TOO_LONG: 'Tekst is te lang'
|
||||
COMMENTING_CLOSED: 'Reageren is al afgesloten.'
|
||||
confirm_password: 'Wachtwoorden komen niet overeen. Controleer opnieuw.'
|
||||
EDIT_USERNAME_NOT_AUTHORIZED: 'Je bent niet gemachtigd om je gebruikersnaam te wijzigen.'
|
||||
@@ -239,7 +240,6 @@ nl_NL:
|
||||
reasons:
|
||||
comment:
|
||||
banned_word: 'Geblokeerd woord'
|
||||
body_count: 'Tekst is te lang'
|
||||
comment_noagree: 'Niet eens'
|
||||
comment_offensive: Aanstootgevend
|
||||
comment_other: Anders
|
||||
|
||||
@@ -5,6 +5,7 @@ const { merge } = require('lodash');
|
||||
|
||||
const {
|
||||
BASE_URL,
|
||||
BASE_ORIGIN,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
@@ -29,6 +30,7 @@ const TALK_CLIENT_ENV = Object.keys(process.env)
|
||||
LIVE_URI: WEBSOCKET_LIVE_URI,
|
||||
STATIC_URL,
|
||||
STATIC_ORIGIN,
|
||||
BASE_ORIGIN,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "talk",
|
||||
"version": "4.6.3",
|
||||
"version": "4.6.5",
|
||||
"description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net",
|
||||
"main": "app.js",
|
||||
"private": true,
|
||||
@@ -201,7 +201,7 @@
|
||||
"smoothscroll-polyfill": "^0.3.5",
|
||||
"snake-case": "2.1.0",
|
||||
"style-loader": "^0.16.0",
|
||||
"subscriptions-transport-ws": "^0.8.3",
|
||||
"subscriptions-transport-ws": "^0.7.2",
|
||||
"supports-color": "^4",
|
||||
"timeago.js": "^2.0.3",
|
||||
"timekeeper": "^1.0.0",
|
||||
|
||||
@@ -75,7 +75,7 @@ es:
|
||||
Puede editar el comentario o enviarlo para la revisión del moderador.
|
||||
talk-plugin-toxic-comments:
|
||||
unlikely: "Improbable"
|
||||
highly_likely: "Altamente Improbable"
|
||||
highly_likely: "Altamente Probable"
|
||||
possibly: "Posiblemente"
|
||||
likely: "Probable"
|
||||
toxic_comment: "Comentario Tóxico"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"author": "The Coral Project Team <coral@mozillafoundation.org>",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"debug": "^4.0.1",
|
||||
"ms": "^2.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const { getScores, isToxic } = require('./perspective');
|
||||
const { ErrToxic } = require('./errors');
|
||||
const debug = require('debug')('talk:plugin:toxic-comments');
|
||||
|
||||
function handlePositiveToxic(input) {
|
||||
input.status = 'SYSTEM_WITHHELD';
|
||||
@@ -20,7 +21,7 @@ async function getScore(body) {
|
||||
scores = await getScores(body);
|
||||
} catch (err) {
|
||||
// Warn and let mutation pass.
|
||||
console.trace(err); // TODO: log/handle this differently?
|
||||
debug('Error sending to API: %o', err);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ const {
|
||||
API_TIMEOUT,
|
||||
DO_NOT_STORE,
|
||||
} = require('./config');
|
||||
const debug = require('debug')('talk:plugin:toxic-comments');
|
||||
|
||||
/**
|
||||
* Get scores from the perspective api
|
||||
@@ -13,6 +14,8 @@ const {
|
||||
* @return {object} object containing toxicity scores
|
||||
*/
|
||||
async function getScores(text) {
|
||||
debug('Sending to Perspective: %o', text);
|
||||
|
||||
const response = await fetch(
|
||||
`${API_ENDPOINT}/comments:analyze?key=${API_KEY}`,
|
||||
{
|
||||
@@ -25,7 +28,6 @@ async function getScores(text) {
|
||||
comment: {
|
||||
text,
|
||||
},
|
||||
|
||||
// TODO: support other languages.
|
||||
languages: ['en'],
|
||||
doNotStore: DO_NOT_STORE,
|
||||
@@ -36,7 +38,22 @@ async function getScores(text) {
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
// If we get an error, just say it's not a toxic comment.
|
||||
if (data.error) {
|
||||
debug('Recieved Error when submitting: %o', data.error);
|
||||
return {
|
||||
TOXICITY: {
|
||||
summaryScore: 0.0,
|
||||
},
|
||||
SEVERE_TOXICITY: {
|
||||
summaryScore: 0.0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
TOXICITY: {
|
||||
summaryScore: data.attributeScores.TOXICITY.summaryScore.value,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { ErrCommentTooShort } = require('../../../errors');
|
||||
const { ErrCommentTooShort, ErrCommentTooLong } = require('../../../errors');
|
||||
|
||||
// This phase checks to see if the comment is long enough.
|
||||
module.exports = (
|
||||
@@ -17,19 +17,6 @@ module.exports = (
|
||||
|
||||
// Reject if the comment is too long
|
||||
if (charCountEnable && comment.body.length > charCount) {
|
||||
// Add the flag related to Trust to the comment.
|
||||
return {
|
||||
status: 'REJECTED',
|
||||
actions: [
|
||||
{
|
||||
action_type: 'FLAG',
|
||||
user_id: null,
|
||||
group_id: 'BODY_COUNT',
|
||||
metadata: {
|
||||
count: comment.body.length,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
throw new ErrCommentTooLong(comment.body.length, charCount);
|
||||
}
|
||||
};
|
||||
|
||||
+11
-1
@@ -19,6 +19,7 @@ const ms = require('ms');
|
||||
const _ = require('lodash');
|
||||
const { attachStaticLocals } = require('../middleware/staticTemplate');
|
||||
const { encodeJSONForHTML } = require('./response');
|
||||
const { STATIC_URL, BASE_URL } = require('../url');
|
||||
|
||||
// Create a redis client to use for authentication.
|
||||
const { createClientFactory } = require('./redis');
|
||||
@@ -97,6 +98,15 @@ const HandleGenerateCredentials = (req, res, next) => (err, user) => {
|
||||
res.json({ user, token });
|
||||
};
|
||||
|
||||
/**
|
||||
* authPopupCallbackCSP is the header sent via Content-Security-Policy when
|
||||
* a social callback request is being made.
|
||||
*/
|
||||
const authPopupCallbackCSP = (() =>
|
||||
STATIC_URL && BASE_URL !== STATIC_URL
|
||||
? `default-src 'self' ${STATIC_URL.replace(/\/$/, '')};`
|
||||
: "default-src 'self';")();
|
||||
|
||||
/**
|
||||
* Returns the response to the login attempt via a popup callback with some JS.
|
||||
*/
|
||||
@@ -106,7 +116,7 @@ const HandleAuthPopupCallback = (req, res, next) => (err, user) => {
|
||||
res.header('Pragma', 'no-cache');
|
||||
|
||||
// Ensure the only scripts that can run here are those on the Talk domain.
|
||||
res.header('Content-Security-Policy', "default-src 'self';");
|
||||
res.header('Content-Security-Policy', authPopupCallbackCSP);
|
||||
|
||||
// Attach static locals to the response locals object.
|
||||
attachStaticLocals(res.locals);
|
||||
|
||||
@@ -11,6 +11,8 @@ 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;
|
||||
|
||||
const BASE_ORIGIN = new URL(BASE_URL).origin;
|
||||
|
||||
// The MOUNT_PATH is derived from the BASE_PATH, if it is provided and enabled.
|
||||
// This will mount all the application routes onto it.
|
||||
const MOUNT_PATH = ROOT_URL_MOUNT_PATH ? BASE_PATH : '/';
|
||||
@@ -22,6 +24,7 @@ const STATIC_ORIGIN = new URL(STATIC_URI).origin;
|
||||
|
||||
module.exports = {
|
||||
BASE_URL,
|
||||
BASE_ORIGIN,
|
||||
BASE_PATH,
|
||||
MOUNT_PATH,
|
||||
STATIC_URL,
|
||||
|
||||
Reference in New Issue
Block a user