From b73620bcb0de6ef33f10b8491e486fe9be6cfe73 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 20 Apr 2018 10:00:52 +0200 Subject: [PATCH 01/23] WIP --- .gitignore | 1 + .../plugin/talk-plugin-global-switchoff.md | 25 ++++++++ .../client/.eslintrc.json | 23 ++++++++ .../client/components/GlobalSwitchoff.js | 59 +++++++++++++++++++ .../client/components/styles.css | 0 .../client/index.js | 9 +++ .../client/translations.yml | 8 +++ plugins/talk-plugin-global-switchoff/index.js | 11 ++++ .../server/index.js | 1 + .../server/resolvers.js | 10 ++++ .../server/typeDefs.graphql | 10 ++++ 11 files changed, 157 insertions(+) create mode 100644 docs/source/plugin/talk-plugin-global-switchoff.md create mode 100644 plugins/talk-plugin-global-switchoff/client/.eslintrc.json create mode 100644 plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js create mode 100644 plugins/talk-plugin-global-switchoff/client/components/styles.css create mode 100644 plugins/talk-plugin-global-switchoff/client/index.js create mode 100644 plugins/talk-plugin-global-switchoff/client/translations.yml create mode 100644 plugins/talk-plugin-global-switchoff/index.js create mode 100644 plugins/talk-plugin-global-switchoff/server/index.js create mode 100644 plugins/talk-plugin-global-switchoff/server/resolvers.js create mode 100644 plugins/talk-plugin-global-switchoff/server/typeDefs.graphql diff --git a/.gitignore b/.gitignore index 24022b9d7..ce5146929 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ plugins/* !plugins/talk-plugin-facebook-auth !plugins/talk-plugin-featured-comments !plugins/talk-plugin-flag-details +!plugins/talk-plugin-global-switchoff !plugins/talk-plugin-google-auth !plugins/talk-plugin-ignore-user !plugins/talk-plugin-like diff --git a/docs/source/plugin/talk-plugin-global-switchoff.md b/docs/source/plugin/talk-plugin-global-switchoff.md new file mode 100644 index 000000000..317fb4b3b --- /dev/null +++ b/docs/source/plugin/talk-plugin-global-switchoff.md @@ -0,0 +1,25 @@ +--- +title: talk-plugin-global-switchoff +permalink: /plugin/talk-plugin-global-switchoff/ +layout: plugin +plugin: + name: talk-plugin-global-switchoff + provides: + - Client + - Server +--- + +Add a switch to the settings page that disables commenting globally. + +## Installation + +TBD + +Add `"talk-plugin-global-switchoff"` to the `plugins.json` in your Talk installation. +This plugin provides a server and a client side implementation. + +## Server implementation + +### How does this work? + +TODO diff --git a/plugins/talk-plugin-global-switchoff/client/.eslintrc.json b/plugins/talk-plugin-global-switchoff/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js new file mode 100644 index 000000000..a5150ed10 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { gql } from 'react-apollo'; +import ConfigureCard from 'coral-framework/components/ConfigureCard'; +import MarkdownEditor from 'coral-framework/components/MarkdownEditor'; +import t from 'coral-framework/services/i18n'; +import { withFragments } from 'plugin-api/beta/client/hocs'; +import cn from 'classnames'; +import styles from './styles.css'; + +const plugin = 'talk-plugin-global-switchoff'; + +class GlobalSwitchoff extends React.Component { + updateGlobalSwitchoffEnable = () => { + const updater = { + globalSwitchoffEnable: { + $set: !this.props.settings.globalSwitchoffEnable, + }, + }; + this.props.updatePending({ updater }); + }; + + updateGlobalSwitchoffMessage = () => {}; + + render() { + const { settings } = this.props; + return ( + +

{t(plugin + '.setting_desc')}

+
+ +
+
+ ); + } +} + +// export default GlobalSwitchoff; + +export default withFragments({ + settings: gql` + fragment TalkPlugin_GlobalSwitchoff_settings on Settings { + globalSwitchoffEnable + globalSwitchoffMessage + } + `, +})(GlobalSwitchoff); diff --git a/plugins/talk-plugin-global-switchoff/client/components/styles.css b/plugins/talk-plugin-global-switchoff/client/components/styles.css new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/talk-plugin-global-switchoff/client/index.js b/plugins/talk-plugin-global-switchoff/client/index.js new file mode 100644 index 000000000..de8b516e7 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/index.js @@ -0,0 +1,9 @@ +import GlobalSwitchoff from './components/GlobalSwitchoff'; +import translations from './translations.yml'; + +export default { + translations, + slots: { + adminStreamSettings: [GlobalSwitchoff], + }, +}; diff --git a/plugins/talk-plugin-global-switchoff/client/translations.yml b/plugins/talk-plugin-global-switchoff/client/translations.yml new file mode 100644 index 000000000..c135337f4 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/translations.yml @@ -0,0 +1,8 @@ +en: + talk-plugin-global-switchoff: + setting_title: 'Deactivate commenting globally' + setting_desc: 'Write a message that will be displayed while commenting is deactivated.' +de: + talk-plugin-global-switchoff: + setting_title: 'Kommentieren global deaktivieren' + setting_desc: 'Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist.' diff --git a/plugins/talk-plugin-global-switchoff/index.js b/plugins/talk-plugin-global-switchoff/index.js new file mode 100644 index 000000000..dfd1f0d04 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/index.js @@ -0,0 +1,11 @@ +const { readFileSync } = require('fs'); +const path = require('path'); +const resolvers = require('./server/resolvers'); + +module.exports = { + typeDefs: readFileSync( + path.join(__dirname, 'server/typeDefs.graphql'), + 'utf8' + ), + resolvers, +}; diff --git a/plugins/talk-plugin-global-switchoff/server/index.js b/plugins/talk-plugin-global-switchoff/server/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/server/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/plugins/talk-plugin-global-switchoff/server/resolvers.js b/plugins/talk-plugin-global-switchoff/server/resolvers.js new file mode 100644 index 000000000..4e249ff3a --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/server/resolvers.js @@ -0,0 +1,10 @@ +const { get } = require('lodash'); + +module.exports = { + Settings: { + globalSwitchoffEnable: settings => + get(settings, 'globalSwitchoffEnable', false), + globalSwitchoffMessage: settings => + get(settings, 'globalSwitchoffMessage', ''), + }, +}; diff --git a/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql b/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql new file mode 100644 index 000000000..efb4b80f6 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql @@ -0,0 +1,10 @@ + +type Settings { + globalSwitchoffEnable: Boolean + globalSwitchoffMessage: String +} + +input UpdateSettingsInput { + globalSwitchoffEnable: Boolean + globalSwitchoffMessage: String +} From bbd3050b95d24228a6bf50898b126b99a7a49e11 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 23 Apr 2018 12:04:53 +0200 Subject: [PATCH 02/23] Small refactoring --- .../client/components/GlobalSwitchoff.js | 13 +------------ .../client/containers/GlobalSwitchoff.js | 12 ++++++++++++ .../talk-plugin-global-switchoff/client/index.js | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) create mode 100644 plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js diff --git a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js index a5150ed10..d676e7531 100644 --- a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js +++ b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js @@ -1,9 +1,7 @@ import React from 'react'; -import { gql } from 'react-apollo'; import ConfigureCard from 'coral-framework/components/ConfigureCard'; import MarkdownEditor from 'coral-framework/components/MarkdownEditor'; import t from 'coral-framework/services/i18n'; -import { withFragments } from 'plugin-api/beta/client/hocs'; import cn from 'classnames'; import styles from './styles.css'; @@ -47,13 +45,4 @@ class GlobalSwitchoff extends React.Component { } } -// export default GlobalSwitchoff; - -export default withFragments({ - settings: gql` - fragment TalkPlugin_GlobalSwitchoff_settings on Settings { - globalSwitchoffEnable - globalSwitchoffMessage - } - `, -})(GlobalSwitchoff); +export default GlobalSwitchoff; diff --git a/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js new file mode 100644 index 000000000..b935bcb5a --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js @@ -0,0 +1,12 @@ +import { gql } from 'react-apollo'; +import GlobalSwitchoff from '../components/GlobalSwitchoff'; +import { withFragments } from 'plugin-api/beta/client/hocs'; + +export default withFragments({ + settings: gql` + fragment TalkPlugin_GlobalSwitchoff_settings on Settings { + globalSwitchoffEnable + globalSwitchoffMessage + } + `, +})(GlobalSwitchoff); diff --git a/plugins/talk-plugin-global-switchoff/client/index.js b/plugins/talk-plugin-global-switchoff/client/index.js index de8b516e7..c9994ce5e 100644 --- a/plugins/talk-plugin-global-switchoff/client/index.js +++ b/plugins/talk-plugin-global-switchoff/client/index.js @@ -1,4 +1,4 @@ -import GlobalSwitchoff from './components/GlobalSwitchoff'; +import GlobalSwitchoff from './containers/GlobalSwitchoff'; import translations from './translations.yml'; export default { From 499030028c152969430e76039e297d01899f2eb5 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 23 Apr 2018 15:35:02 +0200 Subject: [PATCH 03/23] Add hooks to RootMutation to save our setting in the database. --- .../{client => }/.eslintrc.json | 0 plugins/talk-plugin-global-switchoff/index.js | 2 ++ .../talk-plugin-global-switchoff/server/hooks.js | 13 +++++++++++++ 3 files changed, 15 insertions(+) rename plugins/talk-plugin-global-switchoff/{client => }/.eslintrc.json (100%) create mode 100644 plugins/talk-plugin-global-switchoff/server/hooks.js diff --git a/plugins/talk-plugin-global-switchoff/client/.eslintrc.json b/plugins/talk-plugin-global-switchoff/.eslintrc.json similarity index 100% rename from plugins/talk-plugin-global-switchoff/client/.eslintrc.json rename to plugins/talk-plugin-global-switchoff/.eslintrc.json diff --git a/plugins/talk-plugin-global-switchoff/index.js b/plugins/talk-plugin-global-switchoff/index.js index dfd1f0d04..a318f8a11 100644 --- a/plugins/talk-plugin-global-switchoff/index.js +++ b/plugins/talk-plugin-global-switchoff/index.js @@ -1,5 +1,6 @@ const { readFileSync } = require('fs'); const path = require('path'); +const hooks = require('./server/hooks'); const resolvers = require('./server/resolvers'); module.exports = { @@ -7,5 +8,6 @@ module.exports = { path.join(__dirname, 'server/typeDefs.graphql'), 'utf8' ), + hooks, resolvers, }; diff --git a/plugins/talk-plugin-global-switchoff/server/hooks.js b/plugins/talk-plugin-global-switchoff/server/hooks.js new file mode 100644 index 000000000..be0498fb6 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/server/hooks.js @@ -0,0 +1,13 @@ +module.exports = { + RootMutation: { + updateSettings: { + async pre(_, { input }) { + input.metadata = { + ...input.metadata, + globalSwitchoffEnable: input.globalSwitchoffEnable, + }; + delete input.globalSwitchoffEnable; + }, + }, + }, +}; From fab15daacd008c2d3275e26040683b66b2a76be8 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Mon, 23 Apr 2018 17:06:46 +0200 Subject: [PATCH 04/23] Fix: use the correct keys to get the settings --- plugins/talk-plugin-global-switchoff/server/resolvers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-global-switchoff/server/resolvers.js b/plugins/talk-plugin-global-switchoff/server/resolvers.js index 4e249ff3a..f28e765fc 100644 --- a/plugins/talk-plugin-global-switchoff/server/resolvers.js +++ b/plugins/talk-plugin-global-switchoff/server/resolvers.js @@ -3,8 +3,8 @@ const { get } = require('lodash'); module.exports = { Settings: { globalSwitchoffEnable: settings => - get(settings, 'globalSwitchoffEnable', false), + get(settings, 'metadata.globalSwitchoffEnable', false), globalSwitchoffMessage: settings => - get(settings, 'globalSwitchoffMessage', ''), + get(settings, 'metadata.globalSwitchoffMessage', ''), }, }; From 48fc3ab5db24e2a05d6faf06ef09edbdbb3baf48 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Thu, 26 Apr 2018 13:12:27 +0200 Subject: [PATCH 05/23] Move "global switchoff" code from plugin to core --- .gitignore | 1 - .../Configure/components/StreamSettings.js | 33 +++++++++++++ .../Configure/containers/StreamSettings.js | 2 + .../src/tabs/stream/components/Stream.js | 11 ++++- .../src/tabs/stream/containers/Stream.js | 2 + errors.js | 19 ++++++++ graph/typeDefs.graphql | 14 ++++++ locales/de.yml | 3 ++ locales/en.yml | 3 ++ models/schema/setting.js | 8 ++++ .../.eslintrc.json | 23 --------- .../client/components/GlobalSwitchoff.js | 48 ------------------- .../client/components/styles.css | 0 .../client/containers/GlobalSwitchoff.js | 12 ----- .../client/index.js | 9 ---- .../client/translations.yml | 8 ---- plugins/talk-plugin-global-switchoff/index.js | 13 ----- .../server/hooks.js | 13 ----- .../server/index.js | 1 - .../server/resolvers.js | 10 ---- .../server/typeDefs.graphql | 10 ---- services/moderation/index.js | 2 + .../moderation/phases/commentingDisabled.js | 9 ++++ services/moderation/phases/index.js | 1 + 24 files changed, 105 insertions(+), 150 deletions(-) delete mode 100644 plugins/talk-plugin-global-switchoff/.eslintrc.json delete mode 100644 plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js delete mode 100644 plugins/talk-plugin-global-switchoff/client/components/styles.css delete mode 100644 plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js delete mode 100644 plugins/talk-plugin-global-switchoff/client/index.js delete mode 100644 plugins/talk-plugin-global-switchoff/client/translations.yml delete mode 100644 plugins/talk-plugin-global-switchoff/index.js delete mode 100644 plugins/talk-plugin-global-switchoff/server/hooks.js delete mode 100644 plugins/talk-plugin-global-switchoff/server/index.js delete mode 100644 plugins/talk-plugin-global-switchoff/server/resolvers.js delete mode 100644 plugins/talk-plugin-global-switchoff/server/typeDefs.graphql create mode 100644 services/moderation/phases/commentingDisabled.js diff --git a/.gitignore b/.gitignore index ce5146929..24022b9d7 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,6 @@ plugins/* !plugins/talk-plugin-facebook-auth !plugins/talk-plugin-featured-comments !plugins/talk-plugin-flag-details -!plugins/talk-plugin-global-switchoff !plugins/talk-plugin-google-auth !plugins/talk-plugin-ignore-user !plugins/talk-plugin-like diff --git a/client/coral-admin/src/routes/Configure/components/StreamSettings.js b/client/coral-admin/src/routes/Configure/components/StreamSettings.js index e6424848f..ce69da129 100644 --- a/client/coral-admin/src/routes/Configure/components/StreamSettings.js +++ b/client/coral-admin/src/routes/Configure/components/StreamSettings.js @@ -82,6 +82,20 @@ class StreamSettings extends React.Component { this.props.updatePending({ updater }); }; + updateGlobalSwitchoffEnable = () => { + const updater = { + globalSwitchoffEnable: { + $set: !this.props.settings.globalSwitchoffEnable, + }, + }; + this.props.updatePending({ updater }); + }; + + updateGlobalSwitchoffMessage = value => { + const updater = { globalSwitchoffMessage: { $set: value } }; + this.props.updatePending({ updater }); + }; + updateAutoClose = () => { const updater = { autoCloseStream: { $set: !this.props.settings.autoCloseStream }, @@ -192,6 +206,25 @@ class StreamSettings extends React.Component {   {t('configure.edit_comment_timeframe_text_post')} + +

{t('configure.global_switchoff_desc')}

+
+ +
+
) : ( -

{asset.settings.closedMessage}

+
+ {asset.isClosed ? ( +

{asset.settings.closedMessage}

+ ) : ( + + )} +
)} diff --git a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js index f1a973f03..99878a9b9 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -434,6 +434,8 @@ const fragments = { questionBoxIcon closedTimeout closedMessage + globalSwitchoffEnable + globalSwitchoffMessage charCountEnable charCount requireEmailConfirmation diff --git a/errors.js b/errors.js index da1287dd3..39cb6b8ff 100644 --- a/errors.js +++ b/errors.js @@ -161,6 +161,24 @@ class ErrAssetCommentingClosed extends TalkError { } } +// ErrCommentingDisabled is returned when a comment or action is attempted while +// commenting has been disabled site-wide. +class ErrCommentingDisabled extends TalkError { + constructor(message = null) { + super( + 'asset commenting is closed', + { + status: 400, + translation_key: 'COMMENTING_DISABLED', + }, + { + // Include the closedMessage in the metadata piece of the error. + message, + } + ); + } +} + /** * ErrAuthentication is returned when there is an error authenticating and the * message is provided. @@ -387,6 +405,7 @@ module.exports = { ErrAuthentication, ErrCannotIgnoreStaff, ErrCommentTooShort, + ErrCommentingDisabled, ErrContainsProfanity, ErrEditWindowHasEnded, ErrEmailAlreadyVerified, diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 03c97ce58..dda86291f 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -837,6 +837,13 @@ type Settings { # closed. closedMessage: String + # globalSwitchoffEnable will disable commenting site-wide. + globalSwitchoffEnable: Boolean + + # globalSwitchoffMessage will be shown above the comment stream while + # commenting is disabled site-wide. + globalSwitchoffMessage: String + # editCommentWindowLength is the length of time (in milliseconds) after a # comment is posted that it can still be edited by the author. editCommentWindowLength: Int @@ -1300,6 +1307,13 @@ input UpdateSettingsInput { # closed. closedMessage: String + # globalSwitchoffEnable will disable commenting site-wide. + globalSwitchoffEnable: Boolean + + # globalSwitchoffMessage will be shown above the comment stream while + # commenting is disabled site-wide. + globalSwitchoffMessage: String + # charCountEnable is true when the character count restriction is enabled. charCountEnable: Boolean diff --git a/locales/de.yml b/locales/de.yml index d2b247fbc..00cbb007c 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -136,6 +136,8 @@ de: enable_premod_links_description: "Moderatoren müssen jeden Kommentar, der einen Link enthält, freigeben, bevor er veröffentlicht wird." enable_questionbox: "Stellen Sie den Lesern eine Frage" enable_questionbox_description: "Diese Frage erscheint am Anfang des Kommentarbereichs. Regen Sie eine Diskussion an." + global_switchoff_title: "Kommentieren global deaktivieren" + global_switchoff_desc: "Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist." hours: Stunden include_comment_stream: "Einleitung zum Kommentarbereich" include_comment_stream_desc: "Verfassen Sie eine Einleitung, die über jedem Kommentarbereich erscheint. Nützlich z.B. für Community-Richtlinien." @@ -223,6 +225,7 @@ de: LOGIN_MAXIMUM_EXCEEDED: "Sie haben zu häufig erfolglos versucht, sich anzumelden. Bitte warten Sie." PASSWORD_REQUIRED: "Passwort ist erforderlich" COMMENTING_CLOSED: "Kommentarbereich ist bereits geschlossen" + COMMENTING_DISABLED: "Die Kommentarfunktion ist derzeit abgeschaltet" NOT_FOUND: "Ressource nicht gefunden" ALREADY_EXISTS: "Ressource existiert bereits" INVALID_ASSET_URL: "Asset-URL ist ungültig" diff --git a/locales/en.yml b/locales/en.yml index e293fb40b..eae0e43c9 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -140,6 +140,8 @@ en: enable_premod_links_description: "Moderators must approve any comment containing a link before it is published." enable_questionbox: "Ask Readers a Question" enable_questionbox_description: "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc." + global_switchoff_title: "Deactivate commenting site-wide" + global_switchoff_desc: "Write a message that will be displayed while commenting is deactivated." hours: Hours include_comment_stream: "Include Comment Stream Description for Readers" include_comment_stream_desc: "Write a message to be added to the top of your comment stream. Pose a topic include community guidelines etc." @@ -247,6 +249,7 @@ en: LOGIN_MAXIMUM_EXCEEDED: "You have made too many unsuccessful password attempts. Please wait." PASSWORD_REQUIRED: "Must input a password" COMMENTING_CLOSED: "Commenting is already closed" + COMMENTING_DISABLED: "Commenting is currently disabled on this site" NOT_FOUND: "Resource not found" ALREADY_EXISTS: "Resource already exists" INVALID_ASSET_URL: "Assert URL is invalid" diff --git a/models/schema/setting.js b/models/schema/setting.js index eb9dc76d1..a896c797e 100644 --- a/models/schema/setting.js +++ b/models/schema/setting.js @@ -66,6 +66,14 @@ const Setting = new Schema( type: String, default: 'Expired', }, + globalSwitchoffEnable: { + type: Boolean, + default: false, + }, + globalSwitchoffMessage: { + type: String, + default: '', + }, wordlist: { banned: { type: Array, diff --git a/plugins/talk-plugin-global-switchoff/.eslintrc.json b/plugins/talk-plugin-global-switchoff/.eslintrc.json deleted file mode 100644 index 9fe56bd14..000000000 --- a/plugins/talk-plugin-global-switchoff/.eslintrc.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "mocha": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - } - }, - "parser": "babel-eslint", - "plugins": [ - "react" - ], - "rules": { - "react/jsx-uses-react": "error", - "react/jsx-uses-vars": "error", - "no-console": ["warn", { "allow": ["warn", "error"] }] - } -} diff --git a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js deleted file mode 100644 index d676e7531..000000000 --- a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import ConfigureCard from 'coral-framework/components/ConfigureCard'; -import MarkdownEditor from 'coral-framework/components/MarkdownEditor'; -import t from 'coral-framework/services/i18n'; -import cn from 'classnames'; -import styles from './styles.css'; - -const plugin = 'talk-plugin-global-switchoff'; - -class GlobalSwitchoff extends React.Component { - updateGlobalSwitchoffEnable = () => { - const updater = { - globalSwitchoffEnable: { - $set: !this.props.settings.globalSwitchoffEnable, - }, - }; - this.props.updatePending({ updater }); - }; - - updateGlobalSwitchoffMessage = () => {}; - - render() { - const { settings } = this.props; - return ( - -

{t(plugin + '.setting_desc')}

-
- -
-
- ); - } -} - -export default GlobalSwitchoff; diff --git a/plugins/talk-plugin-global-switchoff/client/components/styles.css b/plugins/talk-plugin-global-switchoff/client/components/styles.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js deleted file mode 100644 index b935bcb5a..000000000 --- a/plugins/talk-plugin-global-switchoff/client/containers/GlobalSwitchoff.js +++ /dev/null @@ -1,12 +0,0 @@ -import { gql } from 'react-apollo'; -import GlobalSwitchoff from '../components/GlobalSwitchoff'; -import { withFragments } from 'plugin-api/beta/client/hocs'; - -export default withFragments({ - settings: gql` - fragment TalkPlugin_GlobalSwitchoff_settings on Settings { - globalSwitchoffEnable - globalSwitchoffMessage - } - `, -})(GlobalSwitchoff); diff --git a/plugins/talk-plugin-global-switchoff/client/index.js b/plugins/talk-plugin-global-switchoff/client/index.js deleted file mode 100644 index c9994ce5e..000000000 --- a/plugins/talk-plugin-global-switchoff/client/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import GlobalSwitchoff from './containers/GlobalSwitchoff'; -import translations from './translations.yml'; - -export default { - translations, - slots: { - adminStreamSettings: [GlobalSwitchoff], - }, -}; diff --git a/plugins/talk-plugin-global-switchoff/client/translations.yml b/plugins/talk-plugin-global-switchoff/client/translations.yml deleted file mode 100644 index c135337f4..000000000 --- a/plugins/talk-plugin-global-switchoff/client/translations.yml +++ /dev/null @@ -1,8 +0,0 @@ -en: - talk-plugin-global-switchoff: - setting_title: 'Deactivate commenting globally' - setting_desc: 'Write a message that will be displayed while commenting is deactivated.' -de: - talk-plugin-global-switchoff: - setting_title: 'Kommentieren global deaktivieren' - setting_desc: 'Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist.' diff --git a/plugins/talk-plugin-global-switchoff/index.js b/plugins/talk-plugin-global-switchoff/index.js deleted file mode 100644 index a318f8a11..000000000 --- a/plugins/talk-plugin-global-switchoff/index.js +++ /dev/null @@ -1,13 +0,0 @@ -const { readFileSync } = require('fs'); -const path = require('path'); -const hooks = require('./server/hooks'); -const resolvers = require('./server/resolvers'); - -module.exports = { - typeDefs: readFileSync( - path.join(__dirname, 'server/typeDefs.graphql'), - 'utf8' - ), - hooks, - resolvers, -}; diff --git a/plugins/talk-plugin-global-switchoff/server/hooks.js b/plugins/talk-plugin-global-switchoff/server/hooks.js deleted file mode 100644 index be0498fb6..000000000 --- a/plugins/talk-plugin-global-switchoff/server/hooks.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - RootMutation: { - updateSettings: { - async pre(_, { input }) { - input.metadata = { - ...input.metadata, - globalSwitchoffEnable: input.globalSwitchoffEnable, - }; - delete input.globalSwitchoffEnable; - }, - }, - }, -}; diff --git a/plugins/talk-plugin-global-switchoff/server/index.js b/plugins/talk-plugin-global-switchoff/server/index.js deleted file mode 100644 index f053ebf79..000000000 --- a/plugins/talk-plugin-global-switchoff/server/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; diff --git a/plugins/talk-plugin-global-switchoff/server/resolvers.js b/plugins/talk-plugin-global-switchoff/server/resolvers.js deleted file mode 100644 index f28e765fc..000000000 --- a/plugins/talk-plugin-global-switchoff/server/resolvers.js +++ /dev/null @@ -1,10 +0,0 @@ -const { get } = require('lodash'); - -module.exports = { - Settings: { - globalSwitchoffEnable: settings => - get(settings, 'metadata.globalSwitchoffEnable', false), - globalSwitchoffMessage: settings => - get(settings, 'metadata.globalSwitchoffMessage', ''), - }, -}; diff --git a/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql b/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql deleted file mode 100644 index efb4b80f6..000000000 --- a/plugins/talk-plugin-global-switchoff/server/typeDefs.graphql +++ /dev/null @@ -1,10 +0,0 @@ - -type Settings { - globalSwitchoffEnable: Boolean - globalSwitchoffMessage: String -} - -input UpdateSettingsInput { - globalSwitchoffEnable: Boolean - globalSwitchoffMessage: String -} diff --git a/services/moderation/index.js b/services/moderation/index.js index 27346e620..cc3a74a73 100644 --- a/services/moderation/index.js +++ b/services/moderation/index.js @@ -6,6 +6,7 @@ const { wordlist, commentLength, assetClosed, + commentingDisabled, karma, staff, links, @@ -36,6 +37,7 @@ const applyStatus = status => () => ({ status }); const phases = [ commentLength, assetClosed, + commentingDisabled, wordlist, staff, links, diff --git a/services/moderation/phases/commentingDisabled.js b/services/moderation/phases/commentingDisabled.js new file mode 100644 index 000000000..8c62d5d98 --- /dev/null +++ b/services/moderation/phases/commentingDisabled.js @@ -0,0 +1,9 @@ +const { ErrCommentingDisabled } = require('../../../errors'); + +// This phase checks to see if commenting is site-wide disabled. +module.exports = (ctx, comment, { asset }) => { + // Check to see if the asset has closed commenting... + if (asset.settings.globalSwitchoffEnable) { + throw new ErrCommentingDisabled(asset.settings.globalSwitchoffMessage); + } +}; diff --git a/services/moderation/phases/index.js b/services/moderation/phases/index.js index a1c2e7bf5..425c57197 100644 --- a/services/moderation/phases/index.js +++ b/services/moderation/phases/index.js @@ -1,6 +1,7 @@ module.exports.wordlist = require('./wordlist'); module.exports.commentLength = require('./commentLength'); module.exports.assetClosed = require('./assetClosed'); +module.exports.commentingDisabled = require('./commentingDisabled'); module.exports.karma = require('./karma'); module.exports.staff = require('./staff'); module.exports.links = require('./links'); From f28a3f2f4e99012171b969d9ad3cfe5ec90fdfef Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Thu, 26 Apr 2018 13:49:38 +0200 Subject: [PATCH 06/23] Add test case: err if trying to comment while it's disabled --- test/server/graph/mutations/createComment.js | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/server/graph/mutations/createComment.js b/test/server/graph/mutations/createComment.js index fbbbf4d38..373045efc 100644 --- a/test/server/graph/mutations/createComment.js +++ b/test/server/graph/mutations/createComment.js @@ -179,6 +179,54 @@ describe('graph.mutations.createComment', () => { }); }); + describe('assets while commenting is disabled', () => { + [ + { + disabled: false, + error: null, + }, + { + disabled: true, + error: 'COMMENTING_DISABLED', + }, + ].forEach(({ disabled, error }) => { + describe(`commentingDisabled=${disabled}`, () => { + beforeEach(() => + AssetModel.create({ + id: '123', + settings: { globalSwitchoffEnable: disabled }, + }) + ); + + it( + error ? 'does not create the comment' : 'creates the comment', + () => { + const context = new Context({ user: new UserModel({}) }); + + return graphql(schema, query, {}, context).then( + ({ data, errors }) => { + expect(errors).to.be.undefined; + if (error) { + expect(data.createComment).to.have.property('comment').null; + expect(data.createComment).to.have.property('errors').not + .null; + expect(data.createComment.errors[0]).to.have.property( + 'translation_key', + error + ); + } else { + expect(data.createComment).to.have.property('comment').not + .null; + expect(data.createComment).to.have.property('errors').null; + } + } + ); + } + ); + }); + }); + }); + describe('comments made with different asset moderation settings', () => { [ { moderation: 'PRE', status: 'PREMOD' }, From d7313570019385e2922ddfdbfcac74ad9cf54447 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 11 May 2018 12:20:26 +0200 Subject: [PATCH 07/23] Remove plugin docs for global-switchoff. Not a plugin anymore. --- .../plugin/talk-plugin-global-switchoff.md | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 docs/source/plugin/talk-plugin-global-switchoff.md diff --git a/docs/source/plugin/talk-plugin-global-switchoff.md b/docs/source/plugin/talk-plugin-global-switchoff.md deleted file mode 100644 index 317fb4b3b..000000000 --- a/docs/source/plugin/talk-plugin-global-switchoff.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: talk-plugin-global-switchoff -permalink: /plugin/talk-plugin-global-switchoff/ -layout: plugin -plugin: - name: talk-plugin-global-switchoff - provides: - - Client - - Server ---- - -Add a switch to the settings page that disables commenting globally. - -## Installation - -TBD - -Add `"talk-plugin-global-switchoff"` to the `plugins.json` in your Talk installation. -This plugin provides a server and a client side implementation. - -## Server implementation - -### How does this work? - -TODO From bae20c38ec9fcc27d3d90144d06081ceea9049d9 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 11 May 2018 12:21:13 +0200 Subject: [PATCH 08/23] Rename globalSwitchoff to disableCommenting. --- .../Configure/components/StreamSettings.js | 26 +++++++++---------- .../Configure/containers/StreamSettings.js | 4 +-- .../src/tabs/stream/components/Stream.js | 4 +-- .../src/tabs/stream/containers/Stream.js | 4 +-- graph/typeDefs.graphql | 16 ++++++------ locales/de.yml | 4 +-- locales/en.yml | 4 +-- models/schema/setting.js | 4 +-- .../moderation/phases/commentingDisabled.js | 4 +-- test/server/graph/mutations/createComment.js | 2 +- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/StreamSettings.js b/client/coral-admin/src/routes/Configure/components/StreamSettings.js index ce69da129..1f661fd72 100644 --- a/client/coral-admin/src/routes/Configure/components/StreamSettings.js +++ b/client/coral-admin/src/routes/Configure/components/StreamSettings.js @@ -82,17 +82,17 @@ class StreamSettings extends React.Component { this.props.updatePending({ updater }); }; - updateGlobalSwitchoffEnable = () => { + updateDisableCommenting = () => { const updater = { - globalSwitchoffEnable: { - $set: !this.props.settings.globalSwitchoffEnable, + disableCommenting: { + $set: !this.props.settings.disableCommenting, }, }; this.props.updatePending({ updater }); }; - updateGlobalSwitchoffMessage = value => { - const updater = { globalSwitchoffMessage: { $set: value } }; + updateDisableCommentingMessage = value => { + const updater = { disableCommentingMessage: { $set: value } }; this.props.updatePending({ updater }); }; @@ -207,21 +207,21 @@ class StreamSettings extends React.Component { {t('configure.edit_comment_timeframe_text_post')}
-

{t('configure.global_switchoff_desc')}

+

{t('configure.disable_commenting_desc')}

diff --git a/client/coral-admin/src/routes/Configure/containers/StreamSettings.js b/client/coral-admin/src/routes/Configure/containers/StreamSettings.js index 6eaff0d9a..faffb1aec 100644 --- a/client/coral-admin/src/routes/Configure/containers/StreamSettings.js +++ b/client/coral-admin/src/routes/Configure/containers/StreamSettings.js @@ -39,8 +39,8 @@ export default compose( autoCloseStream closedTimeout closedMessage - globalSwitchoffEnable - globalSwitchoffMessage + disableCommenting + disableCommentingMessage ${getSlotFragmentSpreads(slots, 'settings')} } `, diff --git a/client/coral-embed-stream/src/tabs/stream/components/Stream.js b/client/coral-embed-stream/src/tabs/stream/components/Stream.js index fbe49a069..2b7396720 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Stream.js @@ -216,7 +216,7 @@ class Stream extends React.Component { currentUser, } = this.props; const { keepCommentBox } = this.state; - const open = !(asset.isClosed || asset.settings.globalSwitchoffEnable); + const open = !(asset.isClosed || asset.settings.disableCommenting); const banned = get(currentUser, 'status.banned.status'); const suspensionUntil = get(currentUser, 'status.suspension.until'); @@ -298,7 +298,7 @@ class Stream extends React.Component { {asset.isClosed ? (

{asset.settings.closedMessage}

) : ( - + )} )} diff --git a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js index 99878a9b9..d6ca27558 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -434,8 +434,8 @@ const fragments = { questionBoxIcon closedTimeout closedMessage - globalSwitchoffEnable - globalSwitchoffMessage + disableCommenting + disableCommentingMessage charCountEnable charCount requireEmailConfirmation diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index dda86291f..07947af6e 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -837,12 +837,12 @@ type Settings { # closed. closedMessage: String - # globalSwitchoffEnable will disable commenting site-wide. - globalSwitchoffEnable: Boolean + # disableCommenting will disable commenting site-wide. + disableCommenting: Boolean - # globalSwitchoffMessage will be shown above the comment stream while + # disableCommentingMessage will be shown above the comment stream while # commenting is disabled site-wide. - globalSwitchoffMessage: String + disableCommentingMessage: String # editCommentWindowLength is the length of time (in milliseconds) after a # comment is posted that it can still be edited by the author. @@ -1307,12 +1307,12 @@ input UpdateSettingsInput { # closed. closedMessage: String - # globalSwitchoffEnable will disable commenting site-wide. - globalSwitchoffEnable: Boolean + # disableCommenting will disable commenting site-wide. + disableCommenting: Boolean - # globalSwitchoffMessage will be shown above the comment stream while + # disableCommentingMessage will be shown above the comment stream while # commenting is disabled site-wide. - globalSwitchoffMessage: String + disableCommentingMessage: String # charCountEnable is true when the character count restriction is enabled. charCountEnable: Boolean diff --git a/locales/de.yml b/locales/de.yml index 00cbb007c..15404856c 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -121,6 +121,8 @@ de: custom_css_url_desc: "URL eines CSS-Stylesheets zum Überschreiben des Standard-Designs" days: Tage description: "Als Administrator können Sie die Einstellungen für den Kommentarbereich dieses Artikels anpassen:" + disable_commenting_title: "Kommentieren global deaktivieren" + disable_commenting_desc: "Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist." domain_list_text: "Geben Sie Domains an, für die diese Talk-Instanz freigegeben werden soll, z.B. für lokale Test- oder Produktionsumgebungen (Bsp.: localhost:3000 staging.domain.com domain.com)." domain_list_title: "Zugelassene Domains" edit_comment_timeframe_heading: "Zeitlimit zur Bearbeitung von Kommentaren" @@ -136,8 +138,6 @@ de: enable_premod_links_description: "Moderatoren müssen jeden Kommentar, der einen Link enthält, freigeben, bevor er veröffentlicht wird." enable_questionbox: "Stellen Sie den Lesern eine Frage" enable_questionbox_description: "Diese Frage erscheint am Anfang des Kommentarbereichs. Regen Sie eine Diskussion an." - global_switchoff_title: "Kommentieren global deaktivieren" - global_switchoff_desc: "Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist." hours: Stunden include_comment_stream: "Einleitung zum Kommentarbereich" include_comment_stream_desc: "Verfassen Sie eine Einleitung, die über jedem Kommentarbereich erscheint. Nützlich z.B. für Community-Richtlinien." diff --git a/locales/en.yml b/locales/en.yml index eae0e43c9..283ec4301 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -124,6 +124,8 @@ en: custom_css_url_desc: "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external." days: Days description: "Change the comment settings on this story." + disable_commenting_title: "Deactivate commenting site-wide" + disable_commenting_desc: "Write a message that will be displayed while commenting is deactivated." domain_list_text: "Enter the domains you would like to permit for Talk e.g. your local staging and production environments (ex. localhost:3000 staging.domain.com domain.com)." domain_list_title: "Permitted Domains" edit_info: "Edit Info" @@ -140,8 +142,6 @@ en: enable_premod_links_description: "Moderators must approve any comment containing a link before it is published." enable_questionbox: "Ask Readers a Question" enable_questionbox_description: "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc." - global_switchoff_title: "Deactivate commenting site-wide" - global_switchoff_desc: "Write a message that will be displayed while commenting is deactivated." hours: Hours include_comment_stream: "Include Comment Stream Description for Readers" include_comment_stream_desc: "Write a message to be added to the top of your comment stream. Pose a topic include community guidelines etc." diff --git a/models/schema/setting.js b/models/schema/setting.js index a896c797e..d75bed29e 100644 --- a/models/schema/setting.js +++ b/models/schema/setting.js @@ -66,11 +66,11 @@ const Setting = new Schema( type: String, default: 'Expired', }, - globalSwitchoffEnable: { + disableCommenting: { type: Boolean, default: false, }, - globalSwitchoffMessage: { + disableCommentingMessage: { type: String, default: '', }, diff --git a/services/moderation/phases/commentingDisabled.js b/services/moderation/phases/commentingDisabled.js index 8c62d5d98..060da473c 100644 --- a/services/moderation/phases/commentingDisabled.js +++ b/services/moderation/phases/commentingDisabled.js @@ -3,7 +3,7 @@ const { ErrCommentingDisabled } = require('../../../errors'); // This phase checks to see if commenting is site-wide disabled. module.exports = (ctx, comment, { asset }) => { // Check to see if the asset has closed commenting... - if (asset.settings.globalSwitchoffEnable) { - throw new ErrCommentingDisabled(asset.settings.globalSwitchoffMessage); + if (asset.settings.disableCommenting) { + throw new ErrCommentingDisabled(asset.settings.disableCommentingMessage); } }; diff --git a/test/server/graph/mutations/createComment.js b/test/server/graph/mutations/createComment.js index 373045efc..662404bf2 100644 --- a/test/server/graph/mutations/createComment.js +++ b/test/server/graph/mutations/createComment.js @@ -194,7 +194,7 @@ describe('graph.mutations.createComment', () => { beforeEach(() => AssetModel.create({ id: '123', - settings: { globalSwitchoffEnable: disabled }, + settings: { disableCommenting: disabled }, }) ); From 1236e7a5048385f1c9dc7e8ddd42713fb53fc9ed Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 11 May 2018 12:52:44 +0200 Subject: [PATCH 09/23] Disable/hide the reply buttons when commenting is disabled. --- .../coral-embed-stream/src/tabs/stream/components/Stream.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Stream.js b/client/coral-embed-stream/src/tabs/stream/components/Stream.js index 2b7396720..a07f8ff8b 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Stream.js @@ -182,7 +182,9 @@ class Stream extends React.Component { setActiveReplyBox={setActiveReplyBox} activeReplyBox={activeReplyBox} notify={notify} - disableReply={asset.isClosed} + disableReply={ + asset.isClosed || asset.settings.disableCommenting + } postComment={postComment} currentUser={currentUser} postFlag={postFlag} From 1f7c4e58a1ebd6c3abd9579498a7c0c3746ac087 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 14 May 2018 13:31:24 -0300 Subject: [PATCH 10/23] sepatate state --- .../components/ChangeEmailContentDialog.js | 92 +++++++++++++++++-- .../client/components/Profile.js | 7 +- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index f29dd8d86..b0fdeb14d 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -4,10 +4,77 @@ import styles from './ChangeEmailContentDialog.css'; import InputField from './InputField'; import { Button } from 'plugin-api/beta/client/components/ui'; import { t } from 'plugin-api/beta/client/services'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; + +const initialState = { + showError: false, + formData: {}, + errors: {}, +}; class ChangeEmailContentDialog extends React.Component { - state = { - showError: false, + state = initialState; + + clearForm = () => { + this.setState(initialState); + }; + + addError = err => { + this.setState(({ errors }) => ({ + errors: { ...errors, ...err }, + })); + }; + + removeError = errKey => { + this.setState(state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }); + }; + + fieldValidation = (value, type, name) => { + if (!value.length) { + this.addError({ + [name]: t('talk-plugin-local-auth.change_password.required_field'), + }); + } else if (!validate[type](value)) { + this.addError({ [name]: errorMsj[type] }); + } else { + this.removeError(name); + } + }; + + onChange = e => { + const { name, value, type, dataset } = e.target; + const validationType = dataset.validationType || type; + + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + this.fieldValidation(value, validationType, name); + } + ); + }; + + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + isSaveEnabled = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + return !formHasErrors; + }; + + getError = errorKey => { + return this.state.errors[errorKey]; }; showError = () => { @@ -16,24 +83,31 @@ class ChangeEmailContentDialog extends React.Component { }); }; + cancel = () => { + this.clearForm(); + this.disableEditing(); + }; + confirmChanges = async e => { e.preventDefault(); + const { confirmPassword = '' } = this.state.formData; + if (this.formHasError()) { this.showError(); return; } - await this.props.save(); + await this.props.save(confirmPassword); this.props.next(); }; - formHasError = () => this.props.hasError('confirmPassword'); + formHasError = () => this.hasError('confirmPassword'); render() { return (
- + ×

@@ -59,17 +133,17 @@ class ChangeEmailContentDialog extends React.Component { label={t('talk-plugin-local-auth.change_email.enter_password')} name="confirmPassword" type="password" - onChange={this.props.onChange} + onChange={this.onChange} defaultValue="" - hasError={this.props.hasError('confirmPassword')} - errorMsg={this.props.getError('confirmPassword')} + hasError={this.hasError('confirmPassword')} + errorMsg={this.getError('confirmPassword')} showError={this.state.showError} columnDisplay />
diff --git a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js index e47a162ef..c22843c8f 100644 --- a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js +++ b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js @@ -204,7 +204,7 @@ class ModerationQueue extends React.Component { } componentDidUpdate(prev) { - const { commentCount, selectedCommentId } = this.props; + const { selectedCommentId, hasNextPage } = this.props; const switchedToMultiMode = prev.singleView && !this.props.singleView; const switchedMode = prev.singleView !== this.props.singleView; @@ -212,7 +212,6 @@ class ModerationQueue extends React.Component { prev.selectedCommentId !== selectedCommentId && selectedCommentId; const moderatedLastComment = prev.comments.length > 0 && this.getCommentCountWithoutDagling() === 0; - const hasMoreComment = commentCount > 0; if (switchedToMultiMode) { // Reflow virtual list. @@ -223,7 +222,7 @@ class ModerationQueue extends React.Component { this.scrollToSelectedComment(); } - if (moderatedLastComment && hasMoreComment) { + if (moderatedLastComment && hasNextPage) { this.props.loadMore(); } } @@ -240,10 +239,7 @@ class ModerationQueue extends React.Component { const index = view.findIndex( ({ id }) => id === this.props.selectedCommentId ); - if ( - index === view.length - 1 && - this.getCommentCountWithoutDagling() !== this.props.commentCount - ) { + if (index === view.length - 1 && this.props.hasNextPage) { await this.props.loadMore(); this.selectDown(); return; @@ -467,7 +463,6 @@ ModerationQueue.propTypes = { acceptComment: PropTypes.func.isRequired, commentBelongToQueue: PropTypes.func.isRequired, cleanUpQueue: PropTypes.func.isRequired, - commentCount: PropTypes.number.isRequired, loadMore: PropTypes.func.isRequired, singleView: PropTypes.bool, isLoadingMore: PropTypes.bool, diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index c908404cb..eae2f875f 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -314,11 +314,11 @@ class ModerationContainer extends Component { const currentQueueConfig = Object.assign({}, this.props.queueConfig); - if (premodEnabled && root.newCount === 0) { + if (premodEnabled && root.new.nodes.length === 0) { delete currentQueueConfig.new; } - if (!premodEnabled && root.premodCount === 0) { + if (!premodEnabled && root.premod.nodes.length === 0) { delete currentQueueConfig.premod; } @@ -456,7 +456,11 @@ const withModQueueQuery = withQuery( } ` )} - ${Object.keys(queueConfig).map( + ${ + '' + /* + TODO: eventually we'll reintroduce counting.. + Object.keys(queueConfig).map( queue => ` ${queue}Count: commentCount(query: { excludeDeleted: true, @@ -478,7 +482,8 @@ const withModQueueQuery = withQuery( asset_id: $asset_id, }) ` - )} + )*/ + } asset(id: $asset_id) @skip(if: $allAssets) { id title From 12e848aace2fd03e79006c67f86ca6e07bc4919d Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 19:27:18 +0200 Subject: [PATCH 12/23] Exclude deleted when loading more --- .../coral-admin/src/routes/Moderation/containers/Moderation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index eae2f875f..e3f35081c 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -402,7 +402,7 @@ const COMMENT_RESET_SUBSCRIPTION = gql` const LOAD_MORE_QUERY = gql` query CoralAdmin_Moderation_LoadMore($limit: Int = 10, $cursor: Cursor, $sortOrder: SORT_ORDER, $asset_id: ID, $tags:[String!], $statuses:[COMMENT_STATUS!], $action_type: ACTION_TYPE) { - comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sortOrder: $sortOrder, action_type: $action_type, tags: $tags}) { + comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sortOrder: $sortOrder, action_type: $action_type, tags: $tags, excludeDeleted: true}) { nodes { ...${getDefinitionName(Comment.fragments.comment)} } From ab7e5bc858b0bec3865bff1688aec972a3cb8016 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 20:05:18 +0200 Subject: [PATCH 13/23] No indicator on new queue --- .../coral-admin/src/routes/Moderation/components/Moderation.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/components/Moderation.js b/client/coral-admin/src/routes/Moderation/components/Moderation.js index 0c5ae4c7c..7ea7856ca 100644 --- a/client/coral-admin/src/routes/Moderation/components/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/components/Moderation.js @@ -140,8 +140,7 @@ class Moderation extends Component { name: queueConfig[queue].name, icon: queueConfig[queue].icon, indicator: - ['new', 'premod', 'reported'].includes(queue) && - root[queue].nodes.length > 0, + ['premod', 'reported'].includes(queue) && root[queue].nodes.length > 0, // TODO: Eventually we'll reintroduce counting // count: root[`${props.queue}Count`] })); From 5a190839d1490123afa5e059c68f5cf748482909 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 20:44:30 +0200 Subject: [PATCH 14/23] Show username already exists error --- client/coral-framework/hocs/withSetUsername.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/coral-framework/hocs/withSetUsername.js b/client/coral-framework/hocs/withSetUsername.js index 05323efa1..3a8f65a22 100644 --- a/client/coral-framework/hocs/withSetUsername.js +++ b/client/coral-framework/hocs/withSetUsername.js @@ -59,6 +59,7 @@ const withSetUsername = hoistStatics(WrappedComponent => { } const changeSet = { success: false, loading: false, error }; this.setState(changeSet); + throw error; } }; From beef4e8b3b91a495715d3363b9832e4606d61cce Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 21:28:48 +0200 Subject: [PATCH 15/23] Remove ModerationIndicator from container --- client/coral-admin/src/containers/Header.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/coral-admin/src/containers/Header.js b/client/coral-admin/src/containers/Header.js index d3be66764..c1abac35b 100644 --- a/client/coral-admin/src/containers/Header.js +++ b/client/coral-admin/src/containers/Header.js @@ -2,16 +2,13 @@ import { gql } from 'react-apollo'; import withQuery from 'coral-framework/hocs/withQuery'; import Header from '../components/Header'; import CommunityIndicator from '../routes/Community/containers/Indicator'; -import ModerationIndicator from '../routes/Moderation/containers/Indicator'; import { getDefinitionName } from 'coral-framework/utils'; export default withQuery( gql` query TalkAdmin_Header($nullID: ID) { - ...${getDefinitionName(ModerationIndicator.fragments.root)} ...${getDefinitionName(CommunityIndicator.fragments.root)} } - ${ModerationIndicator.fragments.root} ${CommunityIndicator.fragments.root} `, { From b5adea4b2a0ebc0e16cf08888b6222f5108713ef Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 21:30:09 +0200 Subject: [PATCH 16/23] Remove unused variable --- client/coral-admin/src/containers/Header.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/coral-admin/src/containers/Header.js b/client/coral-admin/src/containers/Header.js index c1abac35b..49aff5aa8 100644 --- a/client/coral-admin/src/containers/Header.js +++ b/client/coral-admin/src/containers/Header.js @@ -2,6 +2,8 @@ import { gql } from 'react-apollo'; import withQuery from 'coral-framework/hocs/withQuery'; import Header from '../components/Header'; import CommunityIndicator from '../routes/Community/containers/Indicator'; +// TODO: eventually we will readd modqueue counts +// import ModerationIndicator from '../routes/Moderation/containers/Indicator'; import { getDefinitionName } from 'coral-framework/utils'; export default withQuery( @@ -13,7 +15,7 @@ export default withQuery( `, { options: { - variables: { nullID: null }, + // variables: { nullID: null }, }, } )(Header); From 08d523a4d61cdc3335f83b6754d958475c9ac741 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 14 May 2018 21:38:30 +0200 Subject: [PATCH 17/23] Remove unused variable 2 --- client/coral-admin/src/containers/Header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/containers/Header.js b/client/coral-admin/src/containers/Header.js index 49aff5aa8..4b8760cc7 100644 --- a/client/coral-admin/src/containers/Header.js +++ b/client/coral-admin/src/containers/Header.js @@ -8,7 +8,7 @@ import { getDefinitionName } from 'coral-framework/utils'; export default withQuery( gql` - query TalkAdmin_Header($nullID: ID) { + query TalkAdmin_Header { ...${getDefinitionName(CommunityIndicator.fragments.root)} } ${CommunityIndicator.fragments.root} From 8d44525c16adcf173da456c173c84698daf0031d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 14 May 2018 14:37:27 -0600 Subject: [PATCH 18/23] Added support for new indexes --- graph/loaders/settings.js | 12 ++ graph/resolvers/comment.js | 4 +- models/schema/action.js | 19 +-- models/schema/comment.js | 159 +++++++------------- models/schema/setting.js | 2 + models/schema/user.js | 47 +++--- plugin-api/beta/server/getReactionConfig.js | 18 ++- services/settings.js | 10 +- 8 files changed, 118 insertions(+), 153 deletions(-) diff --git a/graph/loaders/settings.js b/graph/loaders/settings.js index 8b07d712b..7010d7533 100644 --- a/graph/loaders/settings.js +++ b/graph/loaders/settings.js @@ -55,6 +55,18 @@ class SettingsLoader { // assembled Settings object. return zipObject(fields, values); } + + /** + * get, like select, will retrieve the settings, but get will only return a + * single setting. + * + * @param {String} field the field to get + */ + async get(field) { + const value = await this._loader.load(field); + + return value; + } } module.exports = () => ({ Settings: new SettingsLoader() }); diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index c40aa49e0..acd55cb1a 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -57,8 +57,8 @@ const Comment = { asset({ asset_id }, _, { loaders: { Assets } }) { return Assets.getByID.load(asset_id); }, - async editing(comment, _, { loaders: { Settings } }) { - const { editCommentWindowLength } = await Settings.select( + editing: async (comment, _, { loaders: { Settings } }) => { + const editCommentWindowLength = await Settings.get( 'editCommentWindowLength' ); diff --git a/models/schema/action.js b/models/schema/action.js index 1df7bd793..d2047faac 100644 --- a/models/schema/action.js +++ b/models/schema/action.js @@ -9,7 +9,8 @@ const Action = new Schema( id: { type: String, default: uuid.v4, - unique: true, + unique: 1, + index: 1, }, action_type: { type: String, @@ -19,7 +20,10 @@ const Action = new Schema( type: String, enum: ITEM_TYPES, }, - item_id: String, + item_id: { + type: String, + index: 1, + }, user_id: String, // The element that summaries will additionally group on in addtion to their action_type, item_type, and @@ -37,15 +41,4 @@ const Action = new Schema( } ); -// Create an index on the `item_id` field so that queries looking for -// actions based on the item id can resolve faster. -Action.index( - { - item_id: 1, - }, - { - background: true, - } -); - module.exports = Action; diff --git a/models/schema/comment.js b/models/schema/comment.js index a211884ff..7ae51ff41 100644 --- a/models/schema/comment.js +++ b/models/schema/comment.js @@ -55,12 +55,16 @@ const Comment = new Schema( type: String, default: uuid.v4, unique: true, + index: true, }, body: { type: String, }, body_history: [BodyHistoryItemSchema], - asset_id: String, + asset_id: { + type: String, + index: true, + }, author_id: String, status_history: [Status], status: { @@ -90,7 +94,6 @@ const Comment = new Schema( // deleted_at stores the date that the given comment was deleted. deleted_at: { type: Date, - default: null, }, // Additional metadata stored on the field. @@ -110,95 +113,67 @@ const Comment = new Schema( } ); -// Add the indexes for the id of the comment. Comment.index( { - id: 1, - }, - { - unique: true, - background: false, - } -); - -Comment.index( - { - status: 1, - created_at: 1, - }, - { - background: true, - } -); - -Comment.index( - { - status: 1, - created_at: 1, - asset_id: 1, - }, - { - background: true, - } -); - -// Create a sparse index to search across. -Comment.index( - { - created_at: 1, - 'action_counts.flag': 1, - status: 1, - }, - { - background: true, - sparse: true, - } -); - -// Create a sparse index to search across. -Comment.index( - { - 'action_counts.flag': 1, - status: 1, - }, - { - background: true, - sparse: true, - } -); - -// Add an index that is optimized for finding flagged comments. -Comment.index( - { - asset_id: 1, - created_at: 1, - 'action_counts.flag': 1, - }, - { - background: true, - } -); - -// Add an index for the reply sort. -Comment.index( - { - asset_id: 1, + deleted_at: 1, created_at: -1, - reply_count: -1, }, - { - background: true, - } + { partialFilterExpression: { deleted_at: null } } ); -// Add an index that is optimized for finding a user's comments. Comment.index( { - author_id: 1, + deleted_at: 1, + status: 1, + created_at: -1, + }, + { partialFilterExpression: { deleted_at: null } } +); + +Comment.index({ + asset_id: 1, + created_at: -1, +}); + +Comment.index({ + asset_id: 1, + created_at: 1, +}); + +Comment.index({ + author_id: 1, + created_at: -1, +}); + +Comment.index({ + asset_id: 1, + status: 1, +}); + +Comment.index({ + asset_id: 1, + parent_id: 1, + reply_count: -1, + created_at: -1, +}); + +Comment.index({ + asset_id: 1, + reply_count: -1, + created_at: -1, +}); + +Comment.index( + { + 'action_counts.flag': 1, + status: 1, created_at: -1, }, { - background: true, + partialFilterExpression: { + 'action_counts.flag': { $exists: true, $gt: 0 }, + deleted_at: null, + }, } ); @@ -210,34 +185,10 @@ Comment.index( status: 1, }, { - background: true, - } -); - -// Optimize for tag searches/counts. -Comment.index( - { - 'tags.tag.name': 1, - status: 1, - }, - { - background: true, sparse: true, } ); -// Add an index that is optimized for sorting based on the created_at timestamp -// but also good at locating comments that have a specific asset id. -Comment.index( - { - asset_id: 1, - created_at: 1, - }, - { - background: true, - } -); - Comment.virtual('edited').get(function() { return this.body_history.length > 1; }); diff --git a/models/schema/setting.js b/models/schema/setting.js index eb9dc76d1..4e6a2c6ab 100644 --- a/models/schema/setting.js +++ b/models/schema/setting.js @@ -12,6 +12,8 @@ const Setting = new Schema( id: { type: String, default: '1', + unique: 1, + index: true, }, moderation: { type: String, diff --git a/models/schema/user.js b/models/schema/user.js index ec9c018cc..a4ccfd185 100644 --- a/models/schema/user.js +++ b/models/schema/user.js @@ -58,6 +58,7 @@ const User = new Schema( default: uuid.v4, unique: true, required: true, + index: true, }, // This is sourced from the social provider or set manually during user setup @@ -107,6 +108,7 @@ const User = new Schema( status: { type: String, enum: USER_STATUS_USERNAME, + index: true, }, // History stores the history of username status changes. @@ -135,6 +137,7 @@ const User = new Schema( type: Boolean, required: true, default: false, + index: true, }, history: [ { @@ -226,41 +229,26 @@ User.index( } ); -User.index( - { - lowercaseUsername: 1, - 'profiles.id': 1, - created_at: -1, - }, - { - background: true, - } -); +User.index({ + lowercaseUsername: 1, + 'profiles.id': 1, + created_at: -1, +}); // This query is executed often, to count the number of flagged accounts with // usernames. -User.index( - { - 'action_counts.flag': 1, - 'status.username.status': 1, - }, - { - background: true, - } -); +User.index({ + 'action_counts.flag': 1, + 'status.username.status': 1, +}); // Sorting users by created at is the default people search. -User.index( - { - created_at: -1, - }, - { - background: true, - } -); +User.index({ + created_at: -1, +}); /** - * returns true if a commenter is staff + * returns true if a commenter is staff. */ User.method('isStaff', function() { return this.role !== 'COMMENTER'; @@ -330,6 +318,9 @@ User.virtual('hasVerifiedEmail').get(function() { }); }); +/** + * system returns true when the user is a system user. + */ User.virtual('system') .get(function() { return this._system; diff --git a/plugin-api/beta/server/getReactionConfig.js b/plugin-api/beta/server/getReactionConfig.js index 5aa3063b3..f1f25b261 100644 --- a/plugin-api/beta/server/getReactionConfig.js +++ b/plugin-api/beta/server/getReactionConfig.js @@ -11,10 +11,22 @@ function getReactionConfig(reaction) { if (CREATE_MONGO_INDEXES) { // Create the index on the comment model based on the reaction config. - Comment.collection.createIndex( + Comment.collection.ensureIndex( { - created_at: 1, - [`action_counts.${sc(reaction)}`]: 1, + asset_id: 1, + [`action_counts.${sc(reaction)}`]: -1, + created_at: -1, + }, + { + background: true, + } + ); + + Comment.collection.ensureIndex( + { + asset_id: 1, + [`action_counts.${sc(reaction)}`]: -1, + created_at: -1, }, { background: true, diff --git a/services/settings.js b/services/settings.js index def42187a..e009c707b 100644 --- a/services/settings.js +++ b/services/settings.js @@ -1,13 +1,17 @@ const Setting = require('../models/setting'); const { ErrSettingsNotInit } = require('../errors'); const { dotize } = require('./utils'); -const { isEmpty, zipObject, uniq } = require('lodash'); +const { isEmpty, zipObject } = require('lodash'); const DataLoader = require('dataloader'); const selector = { id: '1' }; -async function loadFn(fields = []) { - const model = await Setting.findOne(selector).select(uniq(fields)); +async function loadFn(/* fields = [] */) { + // Originally, we used the projection operation, turns out this isn't that + // fast. We should utilize the redis cache instead here. + // const model = await Setting.findOne(selector).select(uniq(fields)); + + const model = await Setting.findOne(selector); if (!model) { throw new ErrSettingsNotInit(); } From 50acf9ca5043c4e08739de2f32d3ff3aa930c869 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 15 May 2018 11:47:07 -0300 Subject: [PATCH 19/23] Removing --- .../client/components/ChangeEmailContentDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index b0fdeb14d..cd6738d02 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -85,7 +85,6 @@ class ChangeEmailContentDialog extends React.Component { cancel = () => { this.clearForm(); - this.disableEditing(); }; confirmChanges = async e => { From ef5e5ddbcf41a0a9d17739c95e4758bf2d8261d9 Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Tue, 15 May 2018 11:55:02 -0400 Subject: [PATCH 20/23] Set is_test to false Akismet is no longer in test mode. --- plugins/talk-plugin-akismet/server/hooks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-akismet/server/hooks.js b/plugins/talk-plugin-akismet/server/hooks.js index 80a233584..b06557783 100644 --- a/plugins/talk-plugin-akismet/server/hooks.js +++ b/plugins/talk-plugin-akismet/server/hooks.js @@ -71,7 +71,7 @@ module.exports = { permalink: asset.url, comment_type: 'comment', comment_content: input.body, - is_test: true, + is_test: false, }); debug(`comment analyzed as ${spam ? 'being' : 'not being'} spam`); From 40a431b374e883d44777a6c248077c117f914bf9 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 15 May 2018 13:31:29 -0300 Subject: [PATCH 21/23] Ready --- .../components/ChangeEmailContentDialog.js | 19 +++++++------------ .../client/components/Profile.js | 1 + 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index cd6738d02..f671c065b 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -9,7 +9,9 @@ import errorMsj from 'coral-framework/helpers/error'; const initialState = { showError: false, - formData: {}, + formData: { + confirmPassword: '', + }, errors: {}, }; @@ -68,11 +70,6 @@ class ChangeEmailContentDialog extends React.Component { return Object.keys(this.state.errors).indexOf(err) !== -1; }; - isSaveEnabled = () => { - const formHasErrors = !!Object.keys(this.state.errors).length; - return !formHasErrors; - }; - getError = errorKey => { return this.state.errors[errorKey]; }; @@ -85,6 +82,7 @@ class ChangeEmailContentDialog extends React.Component { cancel = () => { this.clearForm(); + this.props.closeDialog(); }; confirmChanges = async e => { @@ -133,7 +131,7 @@ class ChangeEmailContentDialog extends React.Component { name="confirmPassword" type="password" onChange={this.onChange} - defaultValue="" + value={this.state.formData.confirmPassword} hasError={this.hasError('confirmPassword')} errorMsg={this.getError('confirmPassword')} showError={this.state.showError} @@ -159,14 +157,11 @@ class ChangeEmailContentDialog extends React.Component { } ChangeEmailContentDialog.propTypes = { - save: PropTypes.func, next: PropTypes.func, - cancel: PropTypes.func, - onChange: PropTypes.func, + save: PropTypes.func, formData: PropTypes.object, email: PropTypes.string, - hasError: PropTypes.func, - getError: PropTypes.func, + closeDialog: PropTypes.func, }; export default ChangeEmailContentDialog; diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 7c4c8e493..8484fa2b8 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -205,6 +205,7 @@ class Profile extends React.Component { formData={this.state.formData} email={email} enable={formData.newEmail && email !== formData.newEmail} + closeDialog={this.closeDialog} /> From ee0790dbe8bd19a7ed1c6410717776cb207baafa Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 15 May 2018 11:25:58 -0600 Subject: [PATCH 22/23] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 01b671dde..97f4e373d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "talk", - "version": "4.4.0", + "version": "4.4.1", "description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net", "main": "app.js", "private": true, From 0b407d516b30efbb2937814aca879645c167394b Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 15 May 2018 15:51:14 -0600 Subject: [PATCH 23/23] copy updates --- .../client/components/Profile.js | 18 ++++++++++++++---- .../talk-plugin-local-auth/translations.yml | 6 ++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 8484fa2b8..caa09543b 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -223,11 +223,21 @@ class Profile extends React.Component { disabled={!usernameCanBeUpdated} columnDisplay > - - {t( - 'talk-plugin-local-auth.change_username.change_username_note' +
+ + {t( + 'talk-plugin-local-auth.change_username.change_username_note' + )} + + {!usernameCanBeUpdated && ( + + {' '} + {t( + 'talk-plugin-local-auth.change_username.is_not_eligible' + )} + )} - +