From 2e013c33ac1e834bbae94bd470f64cbf18390f21 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 19 Apr 2018 17:19:14 -0600 Subject: [PATCH 01/38] GDPR Email Support - Email and password can be used to create a new local profile - Email can be changed with accounts that already have a local profile --- plugins/talk-plugin-auth/README.md | 1 + plugins/talk-plugin-auth/index.js | 12 +- plugins/talk-plugin-auth/server/errors.js | 25 +++ plugins/talk-plugin-auth/server/mutators.js | 158 ++++++++++++++++++ plugins/talk-plugin-auth/server/resolvers.js | 10 ++ .../talk-plugin-auth/server/translations.yml | 8 + .../talk-plugin-auth/server/typeDefs.graphql | 47 ++++++ plugins/talk-plugin-auth/server/typeDefs.js | 7 + 8 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 plugins/talk-plugin-auth/server/errors.js create mode 100644 plugins/talk-plugin-auth/server/mutators.js create mode 100644 plugins/talk-plugin-auth/server/resolvers.js create mode 100644 plugins/talk-plugin-auth/server/translations.yml create mode 100644 plugins/talk-plugin-auth/server/typeDefs.graphql create mode 100644 plugins/talk-plugin-auth/server/typeDefs.js diff --git a/plugins/talk-plugin-auth/README.md b/plugins/talk-plugin-auth/README.md index fd5218365..0a00db5ea 100644 --- a/plugins/talk-plugin-auth/README.md +++ b/plugins/talk-plugin-auth/README.md @@ -7,6 +7,7 @@ plugin: default: true provides: - Client + - Server --- This provides the base plugin that is the basis for all auth based plugins that diff --git a/plugins/talk-plugin-auth/index.js b/plugins/talk-plugin-auth/index.js index f053ebf79..7e4ee6a3c 100644 --- a/plugins/talk-plugin-auth/index.js +++ b/plugins/talk-plugin-auth/index.js @@ -1 +1,11 @@ -module.exports = {}; +const typeDefs = require('./server/typeDefs'); +const resolvers = require('./server/resolvers'); +const mutators = require('./server/mutators'); +const path = require('path'); + +module.exports = { + translations: path.join(__dirname, 'server', 'translations.yml'), + typeDefs, + mutators, + resolvers, +}; diff --git a/plugins/talk-plugin-auth/server/errors.js b/plugins/talk-plugin-auth/server/errors.js new file mode 100644 index 000000000..808ceb3a6 --- /dev/null +++ b/plugins/talk-plugin-auth/server/errors.js @@ -0,0 +1,25 @@ +const { TalkError } = require('errors'); + +// ErrNoLocalProfile is returned when there is no existing local profile +// attached to a user. +class ErrNoLocalProfile extends TalkError { + constructor() { + super('No local profile associated with account', { + translation_key: 'NO_LOCAL_PROFILE', + status: 400, + }); + } +} + +// ErrLocalProfile is returned when a profile is already attached to a user and +// the user is trying to attach a new profile to it. +class ErrLocalProfile extends TalkError { + constructor() { + super('Local profile already associated with account', { + translation_key: 'LOCAL_PROFILE', + status: 400, + }); + } +} + +module.exports = { ErrLocalProfile, ErrNoLocalProfile }; diff --git a/plugins/talk-plugin-auth/server/mutators.js b/plugins/talk-plugin-auth/server/mutators.js new file mode 100644 index 000000000..9fe0dd0db --- /dev/null +++ b/plugins/talk-plugin-auth/server/mutators.js @@ -0,0 +1,158 @@ +const { + ErrNotAuthorized, + ErrPasswordTooShort, + ErrNotFound, + ErrEmailTaken, +} = require('errors'); +const { ErrNoLocalProfile, ErrLocalProfile } = require('./errors'); +const { get } = require('lodash'); +const bcrypt = require('bcryptjs'); + +function hasLocalProfile(user) { + return Boolean( + get(user, 'profiles', []).find(({ provider }) => provider === 'local') + ); +} + +// updateUserEmailAddress will verify that the user has sent the correct +// password followed by executing the email change and notifying the emails +// about that change. +async function updateUserEmailAddress(ctx, email, confirmPassword) { + const { + user, + loaders: { Settings }, + connectors: { models: { User }, services: { Mailer, I18n, Users } }, + } = ctx; + + // Ensure that the user has a local profile associated with their account. + if (!hasLocalProfile(user)) { + throw new ErrNoLocalProfile(); + } + + // Ensure that the password provided matches what we have on file. + if (!await user.verifyPassword(confirmPassword)) { + throw new ErrNotAuthorized(); + } + + // Cleanup the email address. + email = email.toLowerCase().trim(); + + // Update the Users email address. + await User.update( + { + id: user.id, + profiles: { $elemMatch: { provider: 'local' } }, + }, + { + $set: { 'profiles.$.id': email }, + } + ); + + // Get some context for the email to be sent. + const { organizationContactEmail } = await Settings.load([ + 'organizationContactEmail', + ]); + + // Send off the email to the old email address that we have changed it. + await Mailer.send({ + email: user.firstEmail, + template: 'plain', + locals: { + body: I18n.t( + 'email.email_change_original.body', + user.email, + email, + organizationContactEmail + ), + }, + subject: I18n.t('email.email_change_original.subject'), + }); + + // Send off the email to the new email address that we need to verify the new + // address. + await Users.sendEmailConfirmation(user, email); +} + +// attachUserLocalAuth will attach a new local profile to an existing user. +async function attachUserLocalAuth(ctx, email, password) { + const { user, connectors: { models: { User }, services: { Users } } } = ctx; + + // Ensure that the current user doesn't already have a local account + // associated with them. + if (hasLocalProfile(user)) { + throw new ErrLocalProfile(); + } + + // Cleanup the email address. + email = email.toLowerCase().trim(); + + // Validate the password. + if (!password || password.length < 8) { + throw new ErrPasswordTooShort(); + } + + // Hash the new password. + const hashedPassword = await bcrypt.hash(password, 10); + + try { + // Associate the account with the user. + const updatedUser = await User.findOneAndUpdate( + { + id: user.id, + 'profiles.provider': { $ne: 'local' }, + }, + { + $push: { + profiles: { + provider: 'local', + id: email, + }, + }, + $set: { + password: hashedPassword, + }, + }, + { new: true } + ); + if (!updatedUser) { + const foundUser = await User.findOne({ id: user.id }); + if (foundUser === null) { + throw new ErrNotFound(); + } + + if (hasLocalProfile(foundUser)) { + throw new ErrLocalProfile(); + } + + throw new Error('local auth attachment failed due to unexpected reason'); + } + + // Send off the email to the new email address that we need to verify the + // new address. + await Users.sendEmailConfirmation(updatedUser, email); + } catch (err) { + if (err.code === 11000) { + throw new ErrEmailTaken(); + } + throw err; + } +} + +module.exports = ctx => { + const mutators = { + User: { + updateEmailAddress: () => Promise.reject(new ErrNotAuthorized()), + attachLocalAuth: () => Promise.reject(new ErrNotAuthorized()), + }, + }; + + if (ctx.user) { + mutators.User.updateEmailAddress = ({ email, confirmPassword }) => + updateUserEmailAddress(ctx, email, confirmPassword); + + mutators.User.attachLocalAuth = ({ email, password }) => + attachUserLocalAuth(ctx, email, password); + } + + return mutators; +}; diff --git a/plugins/talk-plugin-auth/server/resolvers.js b/plugins/talk-plugin-auth/server/resolvers.js new file mode 100644 index 000000000..23815de00 --- /dev/null +++ b/plugins/talk-plugin-auth/server/resolvers.js @@ -0,0 +1,10 @@ +module.exports = { + RootMutation: { + updateEmailAddress: async (root, { input }, { mutators: { User } }) => { + await User.updateEmailAddress(input); + }, + attachLocalAuth: async (root, { input }, { mutators: { User } }) => { + await User.attachLocalAuth(input); + }, + }, +}; diff --git a/plugins/talk-plugin-auth/server/translations.yml b/plugins/talk-plugin-auth/server/translations.yml new file mode 100644 index 000000000..d35b02525 --- /dev/null +++ b/plugins/talk-plugin-auth/server/translations.yml @@ -0,0 +1,8 @@ +en: + email: + email_change_original: + subject: Email change + body: Your email address has been changed from {0} to {1}. If you did not initiate this change, please contact {2}. + error: + NO_LOCAL_PROFILE: No existing email address is associated with this account. + LOCAL_PROFILE: An email address is already associated with this account. diff --git a/plugins/talk-plugin-auth/server/typeDefs.graphql b/plugins/talk-plugin-auth/server/typeDefs.graphql new file mode 100644 index 000000000..6202e8842 --- /dev/null +++ b/plugins/talk-plugin-auth/server/typeDefs.graphql @@ -0,0 +1,47 @@ +# UpdateEmailAddressInput provides input for changing a users email address +# associated with their account. +input UpdateEmailAddressInput { + + # email is the Users email address that they want to update to. + email: String! + + # confirmPassword is the Users current password. + confirmPassword: String! +} + +# UpdateEmailAddressResponse is returned when you try to update a users email +# address. +type UpdateEmailAddressResponse implements Response { + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + +# AttachLocalAuthInput provides the input for attaching a new local +# authentication profile. +input AttachLocalAuthInput { + + # email is the Users email address that they want to add. + email: String! + + # password is the Users password that they want to add. + password: String! +} + +# AttachLocalAuthResponse returns any errors for when the user attempts to +# attach a new local authentication profile. +type AttachLocalAuthResponse implements Response { + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + +type RootMutation { + + # updateEmailAddress changes the email address of the current logged in user. + updateEmailAddress(input: UpdateEmailAddressInput!): UpdateEmailAddressResponse + + # attachLocalAuth will attach a new local authentication profile to an + # account. + attachLocalAuth(input: AttachLocalAuthInput!): AttachLocalAuthResponse +} diff --git a/plugins/talk-plugin-auth/server/typeDefs.js b/plugins/talk-plugin-auth/server/typeDefs.js new file mode 100644 index 000000000..7ab1954e1 --- /dev/null +++ b/plugins/talk-plugin-auth/server/typeDefs.js @@ -0,0 +1,7 @@ +const fs = require('fs'); +const path = require('path'); + +module.exports = fs.readFileSync( + path.join(__dirname, 'typeDefs.graphql'), + 'utf8' +); From 7d644115d1fc79fe70886e04b1325918f40917ca Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 20 Apr 2018 13:11:35 -0600 Subject: [PATCH 02/38] cleanups --- plugins/talk-plugin-auth/server/mutators.js | 25 +++++++------------ .../talk-plugin-auth/server/translations.yml | 2 +- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/plugins/talk-plugin-auth/server/mutators.js b/plugins/talk-plugin-auth/server/mutators.js index 9fe0dd0db..fb866b92c 100644 --- a/plugins/talk-plugin-auth/server/mutators.js +++ b/plugins/talk-plugin-auth/server/mutators.js @@ -1,18 +1,12 @@ -const { - ErrNotAuthorized, - ErrPasswordTooShort, - ErrNotFound, - ErrEmailTaken, -} = require('errors'); +const { ErrNotAuthorized, ErrNotFound, ErrEmailTaken } = require('errors'); const { ErrNoLocalProfile, ErrLocalProfile } = require('./errors'); const { get } = require('lodash'); const bcrypt = require('bcryptjs'); -function hasLocalProfile(user) { - return Boolean( - get(user, 'profiles', []).find(({ provider }) => provider === 'local') - ); -} +// hasLocalProfile checks a user's profiles to see if they already have a local +// profile associated with their account. +const hasLocalProfile = user => + get(user, 'profiles', []).some(({ provider }) => provider === 'local'); // updateUserEmailAddress will verify that the user has sent the correct // password followed by executing the email change and notifying the emails @@ -60,7 +54,7 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) { locals: { body: I18n.t( 'email.email_change_original.body', - user.email, + user.firstEmail, email, organizationContactEmail ), @@ -87,9 +81,7 @@ async function attachUserLocalAuth(ctx, email, password) { email = email.toLowerCase().trim(); // Validate the password. - if (!password || password.length < 8) { - throw new ErrPasswordTooShort(); - } + await Users.isValidPassword(password); // Hash the new password. const hashedPassword = await bcrypt.hash(password, 10); @@ -116,10 +108,11 @@ async function attachUserLocalAuth(ctx, email, password) { ); if (!updatedUser) { const foundUser = await User.findOne({ id: user.id }); - if (foundUser === null) { + if (!foundUser) { throw new ErrNotFound(); } + // Check to see if this was the result of a race. if (hasLocalProfile(foundUser)) { throw new ErrLocalProfile(); } diff --git a/plugins/talk-plugin-auth/server/translations.yml b/plugins/talk-plugin-auth/server/translations.yml index d35b02525..7df3d7b88 100644 --- a/plugins/talk-plugin-auth/server/translations.yml +++ b/plugins/talk-plugin-auth/server/translations.yml @@ -2,7 +2,7 @@ en: email: email_change_original: subject: Email change - body: Your email address has been changed from {0} to {1}. If you did not initiate this change, please contact {2}. + body: Your email address has been changed from {0} to {1}. If you did not initiate this change, please contact {2}. # TODO: update translation error: NO_LOCAL_PROFILE: No existing email address is associated with this account. LOCAL_PROFILE: An email address is already associated with this account. From 10d27357f49fcb688a2de9d54c3db87dca23faea Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 20 Apr 2018 13:17:57 -0600 Subject: [PATCH 03/38] reorganized --- .gitignore | 5 +++-- plugins.default.json | 11 +++++----- plugins/talk-plugin-auth/README.md | 1 - plugins/talk-plugin-auth/index.js | 12 +---------- plugins/talk-plugin-local-auth/README.md | 20 +++++++++++++++++++ plugins/talk-plugin-local-auth/index.js | 11 ++++++++++ .../server/errors.js | 0 .../server/mutators.js | 0 .../server/resolvers.js | 0 .../server/translations.yml | 0 .../server/typeDefs.graphql | 0 .../server/typeDefs.js | 0 12 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/README.md create mode 100644 plugins/talk-plugin-local-auth/index.js rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/errors.js (100%) rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/mutators.js (100%) rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/resolvers.js (100%) rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/translations.yml (100%) rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/typeDefs.graphql (100%) rename plugins/{talk-plugin-auth => talk-plugin-local-auth}/server/typeDefs.js (100%) diff --git a/.gitignore b/.gitignore index e8cb92653..9373b1893 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ plugins/* !plugins/talk-plugin-google-auth !plugins/talk-plugin-ignore-user !plugins/talk-plugin-like +!plugins/talk-plugin-local-auth !plugins/talk-plugin-love !plugins/talk-plugin-member-since !plugins/talk-plugin-mod @@ -50,10 +51,11 @@ plugins/* !plugins/talk-plugin-notifications-digest-hourly !plugins/talk-plugin-offtopic !plugins/talk-plugin-permalink -!plugins/talk-plugin-profile-settings !plugins/talk-plugin-profile-data +!plugins/talk-plugin-profile-settings !plugins/talk-plugin-remember-sort !plugins/talk-plugin-respect +!plugins/talk-plugin-rich-text !plugins/talk-plugin-slack-notifications !plugins/talk-plugin-sort-most-downvoted !plugins/talk-plugin-sort-most-liked @@ -67,7 +69,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-upvote !plugins/talk-plugin-viewing-options -!plugins/talk-plugin-rich-text **/node_modules/* yarn-error.log diff --git a/plugins.default.json b/plugins.default.json index e1011aa87..0fbc6e658 100644 --- a/plugins.default.json +++ b/plugins.default.json @@ -1,9 +1,9 @@ { "server": [ - "talk-plugin-auth", "talk-plugin-featured-comments", - "talk-plugin-respect", - "talk-plugin-profile-data" + "talk-plugin-local-auth", + "talk-plugin-profile-data", + "talk-plugin-respect" ], "client": [ "talk-plugin-auth", @@ -11,15 +11,16 @@ "talk-plugin-featured-comments", "talk-plugin-flag-details", "talk-plugin-ignore-user", + "talk-plugin-local-auth", "talk-plugin-member-since", "talk-plugin-moderation-actions", "talk-plugin-permalink", + "talk-plugin-profile-data", "talk-plugin-respect", "talk-plugin-sort-most-replied", "talk-plugin-sort-most-respected", "talk-plugin-sort-newest", "talk-plugin-sort-oldest", - "talk-plugin-viewing-options", - "talk-plugin-profile-data" + "talk-plugin-viewing-options" ] } diff --git a/plugins/talk-plugin-auth/README.md b/plugins/talk-plugin-auth/README.md index 0a00db5ea..fd5218365 100644 --- a/plugins/talk-plugin-auth/README.md +++ b/plugins/talk-plugin-auth/README.md @@ -7,7 +7,6 @@ plugin: default: true provides: - Client - - Server --- This provides the base plugin that is the basis for all auth based plugins that diff --git a/plugins/talk-plugin-auth/index.js b/plugins/talk-plugin-auth/index.js index 7e4ee6a3c..f053ebf79 100644 --- a/plugins/talk-plugin-auth/index.js +++ b/plugins/talk-plugin-auth/index.js @@ -1,11 +1 @@ -const typeDefs = require('./server/typeDefs'); -const resolvers = require('./server/resolvers'); -const mutators = require('./server/mutators'); -const path = require('path'); - -module.exports = { - translations: path.join(__dirname, 'server', 'translations.yml'), - typeDefs, - mutators, - resolvers, -}; +module.exports = {}; diff --git a/plugins/talk-plugin-local-auth/README.md b/plugins/talk-plugin-local-auth/README.md new file mode 100644 index 000000000..ee5a6b880 --- /dev/null +++ b/plugins/talk-plugin-local-auth/README.md @@ -0,0 +1,20 @@ +--- +title: talk-plugin-local-auth +permalink: /plugin/talk-plugin-local-auth/ +layout: plugin +plugin: + name: talk-plugin-local-auth + default: true + provides: + - Client + - Server +--- + +This plugin will eventually contain all the local authentication code that is +responsible for creating, resetting, and managing accounts provided locally +through an email and password based login. + +## Features + +- *Email Change*: Allows users to change their existing email address on their account. +- *Local Account Association*: Allows users that have signed up with an external auth strategy (such as Google) the ability to associate a email address and password for login. **Note: Existing users with external authentication will be prompted to setup a local account when they sign in and when new users create an account.** diff --git a/plugins/talk-plugin-local-auth/index.js b/plugins/talk-plugin-local-auth/index.js new file mode 100644 index 000000000..7e4ee6a3c --- /dev/null +++ b/plugins/talk-plugin-local-auth/index.js @@ -0,0 +1,11 @@ +const typeDefs = require('./server/typeDefs'); +const resolvers = require('./server/resolvers'); +const mutators = require('./server/mutators'); +const path = require('path'); + +module.exports = { + translations: path.join(__dirname, 'server', 'translations.yml'), + typeDefs, + mutators, + resolvers, +}; diff --git a/plugins/talk-plugin-auth/server/errors.js b/plugins/talk-plugin-local-auth/server/errors.js similarity index 100% rename from plugins/talk-plugin-auth/server/errors.js rename to plugins/talk-plugin-local-auth/server/errors.js diff --git a/plugins/talk-plugin-auth/server/mutators.js b/plugins/talk-plugin-local-auth/server/mutators.js similarity index 100% rename from plugins/talk-plugin-auth/server/mutators.js rename to plugins/talk-plugin-local-auth/server/mutators.js diff --git a/plugins/talk-plugin-auth/server/resolvers.js b/plugins/talk-plugin-local-auth/server/resolvers.js similarity index 100% rename from plugins/talk-plugin-auth/server/resolvers.js rename to plugins/talk-plugin-local-auth/server/resolvers.js diff --git a/plugins/talk-plugin-auth/server/translations.yml b/plugins/talk-plugin-local-auth/server/translations.yml similarity index 100% rename from plugins/talk-plugin-auth/server/translations.yml rename to plugins/talk-plugin-local-auth/server/translations.yml diff --git a/plugins/talk-plugin-auth/server/typeDefs.graphql b/plugins/talk-plugin-local-auth/server/typeDefs.graphql similarity index 100% rename from plugins/talk-plugin-auth/server/typeDefs.graphql rename to plugins/talk-plugin-local-auth/server/typeDefs.graphql diff --git a/plugins/talk-plugin-auth/server/typeDefs.js b/plugins/talk-plugin-local-auth/server/typeDefs.js similarity index 100% rename from plugins/talk-plugin-auth/server/typeDefs.js rename to plugins/talk-plugin-local-auth/server/typeDefs.js From 8e21857a529bef586bcd3f2a1abb656a9bc740ec Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 20 Apr 2018 13:20:11 -0600 Subject: [PATCH 04/38] added new plugin to registry --- docs/source/_data/plugins.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/source/_data/plugins.yml b/docs/source/_data/plugins.yml index a5621b0d6..35d88cb14 100644 --- a/docs/source/_data/plugins.yml +++ b/docs/source/_data/plugins.yml @@ -3,7 +3,12 @@ tags: - moderation - name: talk-plugin-auth - description: Enables internal authentication from Coral. + description: Enables internal sign-in authentication. + tags: + - default + - auth +- name: talk-plugin-local-auth + description: Enables email and password based authentication. tags: - default - auth From 94710261622363b4d3bdaa2531a59d7490793f3e Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 20 Apr 2018 13:20:55 -0600 Subject: [PATCH 05/38] Referenced new plugin --- docs/source/plugin/talk-plugin-local-auth.md | 1 + 1 file changed, 1 insertion(+) create mode 120000 docs/source/plugin/talk-plugin-local-auth.md diff --git a/docs/source/plugin/talk-plugin-local-auth.md b/docs/source/plugin/talk-plugin-local-auth.md new file mode 120000 index 000000000..918f29118 --- /dev/null +++ b/docs/source/plugin/talk-plugin-local-auth.md @@ -0,0 +1 @@ +../../../plugins/talk-plugin-local-auth/README.md \ No newline at end of file From c27c60346e62482c1c303737c97c77d16dccd417 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 20 Apr 2018 13:27:03 -0600 Subject: [PATCH 06/38] fixed client building --- plugins/talk-plugin-local-auth/client/.eslintrc.json | 3 +++ plugins/talk-plugin-local-auth/client/index.js | 1 + 2 files changed, 4 insertions(+) create mode 100644 plugins/talk-plugin-local-auth/client/.eslintrc.json create mode 100644 plugins/talk-plugin-local-auth/client/index.js diff --git a/plugins/talk-plugin-local-auth/client/.eslintrc.json b/plugins/talk-plugin-local-auth/client/.eslintrc.json new file mode 100644 index 000000000..c8a6db18a --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk/client" +} diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js new file mode 100644 index 000000000..ff8b4c563 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -0,0 +1 @@ +export default {}; From e67d68267c6791d1f7d98f489ddb7612edfac202 Mon Sep 17 00:00:00 2001 From: okbel Date: Sun, 29 Apr 2018 22:00:42 -0300 Subject: [PATCH 07/38] Adding Change Email --- .../components/ChangeEmailDialog.css | 77 +++++++++++++++ .../components/ChangeEmailDialog.js | 98 +++++++++++++++++++ .../components/ChangeUsername.js | 96 ++++++++++++++---- .../talk-plugin-auth/client/translations.yml | 11 +++ 4 files changed, 264 insertions(+), 18 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css new file mode 100644 index 000000000..a57c3662b --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css @@ -0,0 +1,77 @@ +.dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 320px; + top: 10px; + font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif; + font-size: 14px; + border-radius: 4px; + padding: 12px 20px; +} + +.close { + font-size: 20px; + line-height: 14px; + top: 10px; + right: 10px; + position: absolute; + display: block; + font-weight: bold; + color: #363636; + cursor: pointer; + + &:hover { + color: #6b6b6b; + } +} + +.title { + font-size: 1.3em; + margin-bottom: 8px; +} + +.description { + font-size: 1em; + line-height: 20px; + margin: 0; +} + +.item { + display: block; + color: #4C4C4D; + font-size: 1em; + margin-bottom: 2px; +} + +.bottomActions { + text-align: right; +} + +.emailChange { + margin: 18px 0; +} + +.cancel { + border: 1px solid #787d80; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; + + &:hover { + background-color: #eaeaea; + } +} + +.confirmChanges { + background-color: #3498DB; + border-color: #3498DB; + color: white; + height: 30px; + font-size: 0.9em; + + &:hover { + background-color: #3ba3ec; + color: white; + } +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js new file mode 100644 index 000000000..844b900e7 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js @@ -0,0 +1,98 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import styles from './ChangeUsernameDialog.css'; +import InputField from './InputField'; +import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; +import { t } from 'plugin-api/beta/client/services'; + +class ChangeEmailDialog extends React.Component { + state = { + showError: false, + errors: { + passowrd: '', + }, + }; + + showError = () => { + this.setState({ + showError: true, + }); + }; + + confirmChanges = async () => { + if (this.formHasError()) { + this.showError(); + } else { + await this.props.saveChanges(); + this.props.closeDialog(); + } + }; + + render() { + return ( + + + × + +

+ {t('talk-plugin-auth.change_email.confirm_email_change')} +

+
+

+ {t('talk-plugin-auth.change_email.description')} +

+
+ + {t('talk-plugin-auth.change_email.old_email')}: {this.props.email} + + + {t('talk-plugin-auth.change_email.new_email')}:{' '} + {this.props.formData.newEmail} + +
+
+ + +
+ + +
+
+
+ ); + } +} + +ChangeEmailDialog.propTypes = { + saveChanges: PropTypes.func, + closeDialog: PropTypes.func, + showDialog: PropTypes.bool, + onChange: PropTypes.func, + email: PropTypes.string, + formData: PropTypes.object, +}; + +export default ChangeEmailDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js index df8b3a641..d9f020491 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -4,14 +4,18 @@ import PropTypes from 'prop-types'; import styles from './ChangeUsername.css'; import { Button } from 'plugin-api/beta/client/components/ui'; import ChangeUsernameDialog from './ChangeUsernameDialog'; +import ChangeEmailDialog from './ChangeEmailDialog'; import { t } from 'plugin-api/beta/client/services'; import InputField from './InputField'; import { getErrorMessages } from 'coral-framework/utils'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; const initialState = { editing: false, showDialog: false, formData: {}, + errors: {}, }; class ChangeUsername extends React.Component { @@ -69,23 +73,72 @@ class ChangeUsername extends React.Component { this.disableEditing(); }; - onChange = e => { - const { name, value } = e.target; - - this.setState(state => ({ - formData: { - ...state.formData, - [name]: value, - }, + 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-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); + } + ); + }; + closeDialog = () => { this.setState({ showDialog: false, }); }; + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + isSaveEnabled = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + const validUsername = + this.state.formData.newUsername && + this.state.formData.newUsername !== this.props.username; + const validEmail = + this.state.formData.newEmail && + this.state.formData.newEmail !== this.props.emailAddress; + + return !formHasErrors && (validUsername || validEmail); + }; + render() { const { username, emailAddress } = this.props; const { editing } = this.state; @@ -105,6 +158,15 @@ class ChangeUsername extends React.Component { saveChanges={this.saveChanges} /> + + {editing ? (
@@ -114,8 +176,8 @@ class ChangeUsername extends React.Component { name="newUsername" onChange={this.onChange} defaultValue={username} - columnDisplay validationType="username" + columnDisplay > {t('talk-plugin-auth.change_username.change_username_note')} @@ -123,11 +185,12 @@ class ChangeUsername extends React.Component {
@@ -145,10 +208,7 @@ class ChangeUsername extends React.Component { className={cn(styles.button, styles.saveButton)} icon="save" onClick={this.onSave} - disabled={ - !this.state.formData.newUsername || - this.state.formData.newUsername === username - } + disabled={!this.isSaveEnabled()} > {t('talk-plugin-auth.change_username.save')} diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index 3cfb46a95..4ac5ae4e6 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -152,6 +152,17 @@ en: bottom_note: "Note: You will not be able to change your username again for 14 days" confirm_changes: "Confirm Changes" username_does_not_match: "Username does not match" + cant_be_equal: "Your new {0} must be different to your current one" + change_email: + confirm_email_change: "Confirm Email Address Change" + description: "You are attempting to change your email address. Your new email address will be used for your login and to receive account notifications." + old_email: "Old Email Address" + new_email: "New Email Address" + enter_password: "Enter Password" + incorrect_password: "Incorrect Password" + confirm_change: "Confirm Change" + cancel: "Cancel" + change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications" de: talk-plugin-auth: login: From 8df9a1e66e37b904fe90aa7ab04ae23b631c0a9f Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 30 Apr 2018 13:47:15 -0300 Subject: [PATCH 08/38] wip --- plugins/talk-plugin-auth/client/index.js | 4 +-- ...ialog.css => ChangeEmailContentDialog.css} | 0 ...lDialog.js => ChangeEmailContentDialog.js} | 22 ++++++------- ...og.css => ChangeUsernameContentDialog.css} | 11 ------- ...alog.js => ChangeUsernameContentDialog.js} | 18 +++++------ .../components/ConfirmChangesDialog.css | 10 ++++++ .../components/ConfirmChangesDialog.js | 22 +++++++++++++ .../{ChangeUsername.css => Profile.css} | 0 .../{ChangeUsername.js => Profile.js} | 31 +++++++++---------- .../{ChangeUsername.js => Profile.js} | 4 +-- 10 files changed, 67 insertions(+), 55 deletions(-) rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeEmailDialog.css => ChangeEmailContentDialog.css} (100%) rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeEmailDialog.js => ChangeEmailContentDialog.js} (83%) rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeUsernameDialog.css => ChangeUsernameContentDialog.css} (75%) rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeUsernameDialog.js => ChangeUsernameContentDialog.js} (86%) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeUsername.css => Profile.css} (100%) rename plugins/talk-plugin-auth/client/profile-settings/components/{ChangeUsername.js => Profile.js} (90%) rename plugins/talk-plugin-auth/client/profile-settings/containers/{ChangeUsername.js => Profile.js} (85%) diff --git a/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index 8fedb8033..6341dc7c9 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -5,7 +5,7 @@ import translations from './translations.yml'; import Login from './login/containers/Main'; import reducer from './login/reducer'; import ChangePassword from './profile-settings/containers/ChangePassword'; -import ChangeUsername from './profile-settings/containers/ChangeUsername'; +import Profile from './profile-settings/containers/Profile'; export default { reducer, @@ -13,7 +13,7 @@ export default { slots: { stream: [UserBox, SignInButton, SetUsernameDialog], login: [Login], - profileHeader: [ChangeUsername], + profileHeader: [Profile], profileSettings: [ChangePassword], }, }; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.css rename to plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js similarity index 83% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js rename to plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js index 844b900e7..1bb8f7410 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js @@ -1,12 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import cn from 'classnames'; -import styles from './ChangeUsernameDialog.css'; +import styles from './ChangeEmailContentDialog.css'; import InputField from './InputField'; -import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; +import { Button } from 'plugin-api/beta/client/components/ui'; import { t } from 'plugin-api/beta/client/services'; -class ChangeEmailDialog extends React.Component { +class ChangeEmailContentDialog extends React.Component { state = { showError: false, errors: { @@ -31,10 +30,7 @@ class ChangeEmailDialog extends React.Component { render() { return ( - +
× @@ -56,9 +52,9 @@ class ChangeEmailDialog extends React.Component {
-
+ ); } } -ChangeEmailDialog.propTypes = { +ChangeEmailContentDialog.propTypes = { saveChanges: PropTypes.func, closeDialog: PropTypes.func, showDialog: PropTypes.bool, @@ -95,4 +91,4 @@ ChangeEmailDialog.propTypes = { formData: PropTypes.object, }; -export default ChangeEmailDialog; +export default ChangeEmailContentDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.css similarity index 75% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css rename to plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.css index af681d596..2f3cdd14d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.css @@ -1,14 +1,3 @@ -.dialog { - border: none; - box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); - width: 320px; - top: 10px; - font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif; - font-size: 14px; - border-radius: 4px; - padding: 12px 20px; -} - .close { font-size: 20px; line-height: 14px; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.js similarity index 86% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js rename to plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.js index 3ebf6ff02..4cf75a8a7 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.js @@ -1,12 +1,11 @@ import React from 'react'; import PropTypes from 'prop-types'; -import cn from 'classnames'; -import styles from './ChangeUsernameDialog.css'; +import styles from './ChangeUsernameContentDialog.css'; import InputField from './InputField'; -import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; +import { Button } from 'plugin-api/beta/client/components/ui'; import { t } from 'plugin-api/beta/client/services'; -class ChangeUsernameDialog extends React.Component { +class ChangeUsernameContentDialog extends React.Component { state = { showError: false, }; @@ -31,10 +30,7 @@ class ChangeUsernameDialog extends React.Component { render() { return ( - +
× @@ -89,12 +85,12 @@ class ChangeUsernameDialog extends React.Component {
-
+ ); } } -ChangeUsernameDialog.propTypes = { +ChangeUsernameContentDialog.propTypes = { saveChanges: PropTypes.func, closeDialog: PropTypes.func, showDialog: PropTypes.bool, @@ -103,4 +99,4 @@ ChangeUsernameDialog.propTypes = { formData: PropTypes.object, }; -export default ChangeUsernameDialog; +export default ChangeUsernameContentDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css new file mode 100644 index 000000000..daa884404 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css @@ -0,0 +1,10 @@ +.dialog { + border: none; + box-shadow: 0 9px 46px 8px rgba(0, 0, 0, 0.14), 0 11px 15px -7px rgba(0, 0, 0, 0.12), 0 24px 38px 3px rgba(0, 0, 0, 0.2); + width: 320px; + top: 10px; + font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif; + font-size: 14px; + border-radius: 4px; + padding: 12px 20px; +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js new file mode 100644 index 000000000..4b6fa8221 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js @@ -0,0 +1,22 @@ +import React from 'react'; +import cn from 'classnames'; +import styles from './ConfirmChangesDialog.css'; +import { Dialog } from 'plugin-api/beta/client/components/ui'; +import ChangeUsernameContentDialog from './ChangeUsernameContentDialog'; +import ChangeEmailContentDialog from './ChangeEmailContentDialog'; + +class ConfirmChangesDialog extends React.Component { + render() { + return ( + + + + + ); + } +} + +export default ConfirmChangesDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css b/plugins/talk-plugin-auth/client/profile-settings/components/Profile.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css rename to plugins/talk-plugin-auth/client/profile-settings/components/Profile.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/components/Profile.js similarity index 90% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js rename to plugins/talk-plugin-auth/client/profile-settings/components/Profile.js index d9f020491..642917f00 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/Profile.js @@ -1,15 +1,14 @@ import React from 'react'; import cn from 'classnames'; import PropTypes from 'prop-types'; -import styles from './ChangeUsername.css'; +import styles from './Profile.css'; import { Button } from 'plugin-api/beta/client/components/ui'; -import ChangeUsernameDialog from './ChangeUsernameDialog'; -import ChangeEmailDialog from './ChangeEmailDialog'; import { t } from 'plugin-api/beta/client/services'; import InputField from './InputField'; import { getErrorMessages } from 'coral-framework/utils'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; +import ConfirmChangesDialog from './ConfirmChangesDialog'; const initialState = { editing: false, @@ -18,7 +17,7 @@ const initialState = { errors: {}, }; -class ChangeUsername extends React.Component { +class Profile extends React.Component { state = initialState; clearForm = () => { @@ -89,6 +88,7 @@ class ChangeUsername extends React.Component { }; fieldValidation = (value, type, name) => { + console.log(value, type, name); if (!value.length) { this.addError({ [name]: t('talk-plugin-auth.change_password.required_field'), @@ -136,6 +136,13 @@ class ChangeUsername extends React.Component { this.state.formData.newEmail && this.state.formData.newEmail !== this.props.emailAddress; + // const res = !formHasErrors && (!!validUsername || !!validEmail); + // console.log('formHasErrors:', formHasErrors); + // console.log('validUsername:', validUsername); + // console.log('validEmail:', validEmail); + // console.log('res:', res); + // console.log(this.state.errors); + return !formHasErrors && (validUsername || validEmail); }; @@ -149,20 +156,12 @@ class ChangeUsername extends React.Component { [styles.editing]: editing, })} > - - - @@ -232,11 +231,11 @@ class ChangeUsername extends React.Component { } } -ChangeUsername.propTypes = { +Profile.propTypes = { changeUsername: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, username: PropTypes.string, emailAddress: PropTypes.string, }; -export default ChangeUsername; +export default Profile; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/containers/Profile.js similarity index 85% rename from plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js rename to plugins/talk-plugin-auth/client/profile-settings/containers/Profile.js index 87e1e18b5..5495888b0 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/Profile.js @@ -1,12 +1,12 @@ import { compose } from 'react-apollo'; import { bindActionCreators } from 'redux'; import { connect } from 'plugin-api/beta/client/hocs'; -import ChangeUsername from '../components/ChangeUsername'; +import Profile from '../components/Profile'; import { notify } from 'coral-framework/actions/notification'; import { withChangeUsername } from 'plugin-api/beta/client/hocs'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); export default compose(connect(null, mapDispatchToProps), withChangeUsername)( - ChangeUsername + Profile ); From be86b70b24cdbb896d634d97f8c7625987a886dc Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 30 Apr 2018 16:01:35 -0300 Subject: [PATCH 09/38] WIP: Steps --- .../components/ChangeEmailContentDialog.js | 23 +++----- .../components/ChangeUsernameContentDialog.js | 10 ++-- .../components/ConfirmChangesDialog.js | 56 +++++++++++++++++-- .../profile-settings/components/Profile.js | 24 ++++---- 4 files changed, 74 insertions(+), 39 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js index 1bb8f7410..e0452601a 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js @@ -8,9 +8,7 @@ import { t } from 'plugin-api/beta/client/services'; class ChangeEmailContentDialog extends React.Component { state = { showError: false, - errors: { - passowrd: '', - }, + errors: {}, }; showError = () => { @@ -20,18 +18,13 @@ class ChangeEmailContentDialog extends React.Component { }; confirmChanges = async () => { - if (this.formHasError()) { - this.showError(); - } else { - await this.props.saveChanges(); - this.props.closeDialog(); - } + await this.props.saveChanges(); }; render() { return (
- + ×

@@ -43,7 +36,8 @@ class ChangeEmailContentDialog extends React.Component {

- {t('talk-plugin-auth.change_email.old_email')}: {this.props.email} + {t('talk-plugin-auth.change_email.old_email')}:{' '} + {this.props.emailAddress} {t('talk-plugin-auth.change_email.new_email')}:{' '} @@ -66,7 +60,7 @@ class ChangeEmailContentDialog extends React.Component { />
- - - {t('talk-plugin-auth.change_username.cancel')} - -
- ) : ( -
- -
- )} - - ); - } -} - -ChangeUsername.propTypes = { - root: PropTypes.object.isRequired, - changeUsername: PropTypes.func.isRequired, - notify: PropTypes.func.isRequired, - username: PropTypes.string, - emailAddress: PropTypes.string, -}; - -export default ChangeUsername; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js deleted file mode 100644 index 87e1e18b5..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js +++ /dev/null @@ -1,12 +0,0 @@ -import { compose } from 'react-apollo'; -import { bindActionCreators } from 'redux'; -import { connect } from 'plugin-api/beta/client/hocs'; -import ChangeUsername from '../components/ChangeUsername'; -import { notify } from 'coral-framework/actions/notification'; -import { withChangeUsername } from 'plugin-api/beta/client/hocs'; - -const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); - -export default compose(connect(null, mapDispatchToProps), withChangeUsername)( - ChangeUsername -); diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.css b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.css rename to plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeEmailContentDialog.js rename to plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css rename to plugins/talk-plugin-local-auth/client/components/ChangePassword.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js rename to plugins/talk-plugin-local-auth/client/components/ChangePassword.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.css b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.css rename to plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameContentDialog.js rename to plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css rename to plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js rename to plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css b/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.css rename to plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js b/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js rename to plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css b/plugins/talk-plugin-local-auth/client/components/ErrorMessage.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css rename to plugins/talk-plugin-local-auth/client/components/ErrorMessage.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js b/plugins/talk-plugin-local-auth/client/components/ErrorMessage.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js rename to plugins/talk-plugin-local-auth/client/components/ErrorMessage.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-local-auth/client/components/InputField.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/InputField.css rename to plugins/talk-plugin-local-auth/client/components/InputField.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-local-auth/client/components/InputField.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/InputField.js rename to plugins/talk-plugin-local-auth/client/components/InputField.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/Profile.css b/plugins/talk-plugin-local-auth/client/components/Profile.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/Profile.css rename to plugins/talk-plugin-local-auth/client/components/Profile.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/Profile.js rename to plugins/talk-plugin-local-auth/client/components/Profile.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js rename to plugins/talk-plugin-local-auth/client/containers/ChangePassword.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/containers/Profile.js rename to plugins/talk-plugin-local-auth/client/containers/Profile.js diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index ff8b4c563..01f3f7123 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -1 +1,9 @@ -export default {}; +import ChangePassword from './containers/ChangePassword'; +import Profile from './containers/Profile'; + +export default { + slots: { + profileHeader: [Profile], + profileSettings: [ChangePassword], + }, +}; From 8dcaf8ea4caf34dcad7eb065032f702dfa229f97 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:08:29 -0300 Subject: [PATCH 18/38] Moving the translations too --- .../components/ChangeEmailContentDialog.js | 18 +++--- .../client/components/ChangePassword.js | 30 +++++---- .../components/ChangeUsernameContentDialog.js | 18 +++--- .../client/components/ChangeUsernameDialog.js | 23 ++++--- .../client/components/ConfirmChangesDialog.js | 5 +- .../client/components/Profile.js | 26 +++++--- .../client/translations.yml | 62 +++++++++++++++++++ 7 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/client/translations.yml diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index e3796f80e..02d02680e 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -28,26 +28,26 @@ class ChangeEmailContentDialog extends React.Component { ×

- {t('talk-plugin-auth.change_email.confirm_email_change')} + {t('talk-plugin-local-auth.change_email.confirm_email_change')}

- {t('talk-plugin-auth.change_email.description')} + {t('talk-plugin-local-auth.change_email.description')}

- {t('talk-plugin-auth.change_email.old_email')}:{' '} + {t('talk-plugin-local-auth.change_email.old_email')}:{' '} {this.props.emailAddress} - {t('talk-plugin-auth.change_email.new_email')}:{' '} + {t('talk-plugin-local-auth.change_email.new_email')}:{' '} {this.props.formData.newEmail}
diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js index 90940728d..e5535b8ba 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js @@ -45,7 +45,9 @@ class ChangePassword extends React.Component { const cond = this.state.formData[field] === this.state.formData[field2]; if (!cond) { this.addError({ - [field2]: t('talk-plugin-auth.change_password.passwords_dont_match'), + [field2]: t( + 'talk-plugin-local-auth.change_password.passwords_dont_match' + ), }); } else { this.removeError(field2); @@ -56,7 +58,7 @@ class ChangePassword extends React.Component { fieldValidation = (value, type, name) => { if (!value.length) { this.addError({ - [name]: t('talk-plugin-auth.change_password.required_field'), + [name]: t('talk-plugin-local-auth.change_password.required_field'), }); } else if (!validate[type](value)) { this.addError({ [name]: errorMsj[type] }); @@ -113,7 +115,7 @@ class ChangePassword extends React.Component { }); this.props.notify( 'success', - t('talk-plugin-auth.change_password.changed_password_msg') + t('talk-plugin-local-auth.change_password.changed_password_msg') ); } catch (err) { this.props.notify('error', getErrorMessages(err)); @@ -139,15 +141,19 @@ class ChangePassword extends React.Component { return (

- {t('talk-plugin-auth.change_password.change_password')} + {t('talk-plugin-local-auth.change_password.change_password')}

{editing && ( - + - {t('talk-plugin-auth.change_password.forgot_password')} + {t('talk-plugin-local-auth.change_password.forgot_password')} @@ -197,16 +203,16 @@ class ChangePassword extends React.Component { onClick={this.onSave} disabled={this.isSubmitBlocked()} > - {t('talk-plugin-auth.change_password.save')} + {t('talk-plugin-local-auth.change_password.save')} - {t('talk-plugin-auth.change_password.cancel')} + {t('talk-plugin-local-auth.change_password.cancel')}
) : (
)} diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js index 408f3d836..894bdcbd6 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js @@ -25,7 +25,7 @@ class ChangeUsernameContentDialog extends React.Component { if (!this.props.canUsernameBeUpdated) { this.props.notify( 'error', - t('talk-plugin-auth.change_username.change_username_attempt') + t('talk-plugin-local-auth.change_username.change_username_attempt') ); return; } @@ -44,19 +44,19 @@ class ChangeUsernameContentDialog extends React.Component { ×

- {t('talk-plugin-auth.change_username.confirm_username_change')} + {t('talk-plugin-local-auth.change_username.confirm_username_change')}

- {t('talk-plugin-auth.change_username.description')} + {t('talk-plugin-local-auth.change_username.description')}

- {t('talk-plugin-auth.change_username.old_username')}:{' '} + {t('talk-plugin-local-auth.change_username.old_username')}:{' '} {this.props.username} - {t('talk-plugin-auth.change_username.new_username')}:{' '} + {t('talk-plugin-local-auth.change_username.new_username')}:{' '} {this.props.formData.newUsername}
@@ -70,7 +70,7 @@ class ChangeUsernameContentDialog extends React.Component { defaultValue="" hasError={this.formHasError() && this.state.showError} errorMsg={t( - 'talk-plugin-auth.change_username.username_does_not_match' + 'talk-plugin-local-auth.change_username.username_does_not_match' )} showError={this.state.showError} columnDisplay @@ -78,19 +78,19 @@ class ChangeUsernameContentDialog extends React.Component { validationType="username" > - {t('talk-plugin-auth.change_username.bottom_note')} + {t('talk-plugin-local-auth.change_username.bottom_note')}
diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js index 321b36926..097168b06 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js @@ -26,7 +26,7 @@ class ChangeUsernameDialog extends React.Component { if (!this.props.canUsernameBeUpdated) { this.props.notify( 'error', - t('talk-plugin-auth.change_username.change_username_attempt') + t('talk-plugin-local-auth.change_username.change_username_attempt') ); return; } @@ -42,25 +42,28 @@ class ChangeUsernameDialog extends React.Component { return ( ×

- {t('talk-plugin-auth.change_username.confirm_username_change')} + {t('talk-plugin-local-auth.change_username.confirm_username_change')}

- {t('talk-plugin-auth.change_username.description')} + {t('talk-plugin-local-auth.change_username.description')}

- {t('talk-plugin-auth.change_username.old_username')}:{' '} + {t('talk-plugin-local-auth.change_username.old_username')}:{' '} {this.props.username} - {t('talk-plugin-auth.change_username.new_username')}:{' '} + {t('talk-plugin-local-auth.change_username.new_username')}:{' '} {this.props.formData.newUsername}
@@ -74,7 +77,7 @@ class ChangeUsernameDialog extends React.Component { defaultValue="" hasError={this.formHasError() && this.state.showError} errorMsg={t( - 'talk-plugin-auth.change_username.username_does_not_match' + 'talk-plugin-local-auth.change_username.username_does_not_match' )} showError={this.state.showError} columnDisplay @@ -82,19 +85,19 @@ class ChangeUsernameDialog extends React.Component { validationType="username" > - {t('talk-plugin-auth.change_username.bottom_note')} + {t('talk-plugin-local-auth.change_username.bottom_note')}
diff --git a/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js b/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js index 0031bcb71..35995f654 100644 --- a/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ConfirmChangesDialog.js @@ -54,7 +54,10 @@ class ConfirmChangesDialog extends React.Component { return ( {this.renderSteps()} diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 3d8f10698..84474dbe3 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -72,7 +72,7 @@ class Profile extends React.Component { fieldValidation = (value, type, name) => { if (!value.length) { this.addError({ - [name]: t('talk-plugin-auth.change_password.required_field'), + [name]: t('talk-plugin-local-auth.change_password.required_field'), }); } else if (!validate[type](value)) { this.addError({ [name]: errorMsj[type] }); @@ -127,7 +127,7 @@ class Profile extends React.Component { await changeUsername(this.props.root.me.id, newUsername); this.props.notify( 'success', - t('talk-plugin-auth.change_username.changed_username_success_msg') + t('talk-plugin-local-auth.change_username.changed_username_success_msg') ); } catch (err) { this.props.notify('error', getErrorMessages(err)); @@ -144,7 +144,7 @@ class Profile extends React.Component { }); this.props.notify( 'success', - t('talk-plugin-auth.change_email.change_email_msg') + t('talk-plugin-local-auth.change_email.change_email_msg') ); } catch (err) { this.props.notify('error', getErrorMessages(err)); @@ -167,9 +167,13 @@ class Profile extends React.Component { return (
- {t('talk-plugin-auth.change_username.change_username_note')} + {t( + 'talk-plugin-local-auth.change_username.change_username_note' + )} - {t('talk-plugin-auth.change_username.save')} + {t('talk-plugin-local-auth.change_username.save')} - {t('talk-plugin-auth.change_username.cancel')} + {t('talk-plugin-local-auth.change_username.cancel')}
) : ( @@ -250,7 +256,7 @@ class Profile extends React.Component { icon="settings" onClick={this.enableEditing} > - {t('talk-plugin-auth.change_username.edit_profile')} + {t('talk-plugin-local-auth.change_username.edit_profile')} )} diff --git a/plugins/talk-plugin-local-auth/client/translations.yml b/plugins/talk-plugin-local-auth/client/translations.yml new file mode 100644 index 000000000..d3b323f54 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/translations.yml @@ -0,0 +1,62 @@ +en: + talk-plugin-local-auth: + change_password: + change_password: "Change Password" + passwords_dont_match: "Passwords don`t match" + required_field: "This field is required" + forgot_password: "Forgot your password?" + save: "Save" + cancel: "Cancel" + edit: "Edit" + changed_password_msg: "Changed Password - Your password has been successfully changed" + change_username: + change_username_note: "Usernames can be changed every 14 days" + save: "Save" + edit_profile: "Edit Profile" + cancel: "Cancel" + confirm_username_change: "Confirm Username Change" + description: "You are attempting to change your username. Your new username will appear on all of your past and future comments." + old_username: "Old Username" + new_username: "New Username" + bottom_note: "Note: You will not be able to change your username again for 14 days" + confirm_changes: "Confirm Changes" + username_does_not_match: "Username does not match" + cant_be_equal: "Your new {0} must be different to your current one" + change_username_attempt: "Username can't be updated. Usernames can be changed every 14 days" + change_email: + confirm_email_change: "Confirm Email Address Change" + description: "You are attempting to change your email address. Your new email address will be used for your login and to receive account notifications." + old_email: "Old Email Address" + new_email: "New Email Address" + enter_password: "Enter Password" + incorrect_password: "Incorrect Password" + confirm_change: "Confirm Change" + cancel: "Cancel" + change_email_msg: "Email Address Changed - Your email address has been successfully changed. This email address will now be used for signing in and email notifications." + changed_username_success_msg: "Username Changed - Your username has been successfully changed. You will not be able to change your user name for 14 days." + change_username_attempt: "Username can't be updated. Usernames can only be changed every 14 days." +es: + talk-plugin-local-auth: + change_password: + change_password: "Cambiar Contraseña" + passwords_dont_match: "Las contraseñas no coinciden" + required_field: "Este campo es requerido" + forgot_password: "Olvidaste tu contraseña?" + save: "Guardar" + cancel: "Cancelar" + edit: "Editar" + changed_password_msg: "Contraseña Actualizada - Tu contraseña ha sido exitosamente actualizada" + change_username: + change_username_note: "El usuario puede ser cambiado cada 14 días" + save: "Guardar" + edit_profile: "Editar Perfil" + cancel: "Cancelar" + confirm_username_change: "Confirmar Cambio de Usuario" + description: "Estás intentando cambiar tu usuario. Tu nuevo usuario aparecerá en todos tus pasados y futuros comentarios." + old_username: "Usuario viejo" + new_username: "Usuario nuevo" + bottom_note: "Nota: No podrás cambiar tu usuario por 14 días" + confirm_changes: "Confirmar Cambios" + username_does_not_match: "El usuario no coincide" + changed_username_success_msg: "Usuario Actualizado - Tu usuario ha sido exitosamente actualizado. No podrás cambiar el usuario por 14 días." + change_username_attempt: "El usuario no puede ser actualizado. Los usuarios pueden ser cambiados cada 14 días." \ No newline at end of file From 48a78735bd4d099a40fdb33a7dc531d9d9390014 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:11:11 -0300 Subject: [PATCH 19/38] Importing translations --- plugins/talk-plugin-local-auth/client/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index 01f3f7123..c669effaa 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -1,7 +1,9 @@ import ChangePassword from './containers/ChangePassword'; import Profile from './containers/Profile'; +import translations from './translations.yml'; export default { + translations, slots: { profileHeader: [Profile], profileSettings: [ChangePassword], From c8e5678c9c7eb4d67d64a8a958ddf3af62127bc8 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:18:40 -0300 Subject: [PATCH 20/38] Using fragments :) --- .../client/containers/Profile.js | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js index d47f4af38..bebf127fd 100644 --- a/plugins/talk-plugin-local-auth/client/containers/Profile.js +++ b/plugins/talk-plugin-local-auth/client/containers/Profile.js @@ -1,6 +1,6 @@ -import { compose } from 'react-apollo'; +import { compose, gql } from 'react-apollo'; import { bindActionCreators } from 'redux'; -import { connect } from 'plugin-api/beta/client/hocs'; +import { connect, withFragments } from 'plugin-api/beta/client/hocs'; import Profile from '../components/Profile'; import { notify } from 'coral-framework/actions/notification'; import { @@ -10,8 +10,30 @@ import { const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); +const withData = withFragments({ + root: gql` + fragment TalkPluginLocalAuth_Profile_root on RootQuery { + me { + id + state { + status { + username { + status + history { + status + created_at + } + } + } + } + } + } + `, +}); + export default compose( connect(null, mapDispatchToProps), withChangeUsername, - withUpdateEmailAddress + withUpdateEmailAddress, + withData )(Profile); From cb9b02c1801e73109da40454c33850646363c7f7 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Wed, 2 May 2018 14:20:19 -0400 Subject: [PATCH 21/38] remove profile-settings from gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9373b1893..24022b9d7 100644 --- a/.gitignore +++ b/.gitignore @@ -52,7 +52,6 @@ plugins/* !plugins/talk-plugin-offtopic !plugins/talk-plugin-permalink !plugins/talk-plugin-profile-data -!plugins/talk-plugin-profile-settings !plugins/talk-plugin-remember-sort !plugins/talk-plugin-respect !plugins/talk-plugin-rich-text From 0159918049790875f727d0541a5155ab00bf6cad Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 2 May 2018 13:03:59 -0600 Subject: [PATCH 22/38] docs updates --- docs/_config.yml | 4 +- docs/source/03-08-gdpr.md | 43 +++++++++++++++++++++ docs/source/_data/plugins.yml | 2 + docs/source/plugins/overview.md | 19 +++++++-- docs/source/plugins/plugins-directory.md | 3 +- docs/themes/coral/layout/plugins.swig | 9 +++-- docs/themes/coral/source/css/talk.scss | 14 +++++++ docs/themes/coral/source/js/plugins.js | 17 ++++++++ plugins/talk-plugin-auth/README.md | 6 +++ plugins/talk-plugin-facebook-auth/README.md | 8 +++- plugins/talk-plugin-google-auth/README.md | 6 +++ plugins/talk-plugin-local-auth/README.md | 6 +++ plugins/talk-plugin-profile-data/README.md | 11 +++++- 13 files changed, 136 insertions(+), 12 deletions(-) create mode 100644 docs/source/03-08-gdpr.md diff --git a/docs/_config.yml b/docs/_config.yml index 6c0da733b..ac90dbc96 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -41,7 +41,7 @@ relative_link: false future: true highlight: enable: false - + # Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) @@ -114,6 +114,8 @@ sidebar: url: /integrating/styling-css/ - title: Translations and i18n url: /integrating/translations-i18n/ + - title: GDPR Compliance + url: /integrating/gdpr/ - title: Product Guide children: - title: How Talk Works diff --git a/docs/source/03-08-gdpr.md b/docs/source/03-08-gdpr.md new file mode 100644 index 000000000..187920bbc --- /dev/null +++ b/docs/source/03-08-gdpr.md @@ -0,0 +1,43 @@ +--- +title: GDPR Compliance +permalink: /integrating/gdpr/ +--- + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +can enable the following plugins: + +- [talk-plugin-auth](/talk/plugin/talk-plugin-auth) - to facilitate username and password changes +- [talk-plugin-local-auth](/talk/plugin/talk-plugin-local-auth) - to facilitate email changes and email association +- [talk-plugin-profile-data](/talk/plugin/talk-plugin-profile-data) - to facilitate account download and deletion + +Even if you don't reside in a location where GDPR will apply, it is recommended +to enable these features anyways to provide your users with control over their +own data. + +## Custom Authentication Solutions + +As many of the newsrooms who have integrated Talk have followed our guides on +[Integrating Authentication](/talk/integrating/authentication/), we have also +provided tools for those newsrooms to integrate GDPR features into their +existing workflows. + +### Account Data + +Through the [talk-plugin-profile-data](/talk/plugin/talk-plugin-profile-data) +plugin we allow users to download and delete their account data easily. For +custom integrations, this isn't always possible, so we instead provide some +GraphQL mutations designed to allow you to integrate it into your existing user +interfaces or exports. + +- `downloadUser(id: ID!)` - lets you grab the direct link to download a users + account in a zip format. From there, you can integrate it into your existing + data export or simply proxy it to the user to allow them to download it + elsewhere in your UI. +- `delUser(id: ID!)` - lets you delete the specified user + +**Note: These mutations require an administrative token** + +If you would prefer to write your own user interfaces or integrate it into your +own, you can disable the client plugin for [talk-plugin-profile-data](/talk/plugin/talk-plugin-profile-data) +but keep the server side plugin active (See [Server and Client Plugins](/talk/plugins/#server-and-client-plugins) for more information). diff --git a/docs/source/_data/plugins.yml b/docs/source/_data/plugins.yml index 35d88cb14..0e09de210 100644 --- a/docs/source/_data/plugins.yml +++ b/docs/source/_data/plugins.yml @@ -7,11 +7,13 @@ tags: - default - auth + - gdpr - name: talk-plugin-local-auth description: Enables email and password based authentication. tags: - default - auth + - gdpr - name: talk-plugin-author-menu description: Enables the comment author name plugin area. tags: diff --git a/docs/source/plugins/overview.md b/docs/source/plugins/overview.md index 26230dc00..046f4db87 100644 --- a/docs/source/plugins/overview.md +++ b/docs/source/plugins/overview.md @@ -9,11 +9,16 @@ functionality. We provide methods to inject behavior into the server side and the client side application to affect different parts of the application life cycle. -## Recipes +## Server and Client Plugins -Recipes are plugin templates provided by the Coral Core team. Developers can use -these recipes to build their own plugins. You can find all the Talk recipes -here: [github.com/coralproject/talk-recipes](https://github.com/coralproject/talk-recipes/). +When you're adding a plugin to Talk, you can specify it in the `client` and/or +the `server` section. If you only want to enable the server side component of a +plugin, you simply only specify the plugin in the `server` section. If you only +want the client side plugin, the `client` section. + +Plugins listed in the [Plugins Directory](/talk/plugins-directory/) will +indicate if they have/support a client/server plugin, and should be activated +accordingly. ## Plugin Registration @@ -117,3 +122,9 @@ assets inside the image as well. For more information on the onbuild image, refer to the [Installation from Docker](/talk/installation-from-docker/) documentation. + +## Recipes + +Recipes are plugin templates provided by the Coral Core team. Developers can use +these recipes to build their own plugins. You can find all the Talk recipes +here: [github.com/coralproject/talk-recipes](https://github.com/coralproject/talk-recipes/). diff --git a/docs/source/plugins/plugins-directory.md b/docs/source/plugins/plugins-directory.md index ca9b26734..9161d0d68 100644 --- a/docs/source/plugins/plugins-directory.md +++ b/docs/source/plugins/plugins-directory.md @@ -3,8 +3,9 @@ title: Plugins Directory permalink: /plugins-directory/ layout: plugins data: plugins +class: plugins --- Talk provides a growing ecosystem of plugins that interact with our extensive Server and Client API's. Below you can search for a plugin to use with Talk and -discover what their requirements and configuration are. \ No newline at end of file +discover what their requirements and configuration are. diff --git a/docs/themes/coral/layout/plugins.swig b/docs/themes/coral/layout/plugins.swig index 959908105..adb60be30 100644 --- a/docs/themes/coral/layout/plugins.swig +++ b/docs/themes/coral/layout/plugins.swig @@ -4,9 +4,9 @@

{{ page.title }}


{% endif %} - + {{ page.content }} - +
@@ -15,6 +15,7 @@ Enter a few keywords about the plugin to filter the list
+
{% for plugin in _.sortBy(site.data[page.data], 'name') %}
@@ -25,7 +26,7 @@ {% if plugin.tags %}

{% for tag in plugin.tags %} - {{ tag }} + {{ tag }} {% endfor %}

{% endif %} @@ -35,4 +36,4 @@ {% endfor %} - \ No newline at end of file + diff --git a/docs/themes/coral/source/css/talk.scss b/docs/themes/coral/source/css/talk.scss index 391337876..afbd6f3af 100644 --- a/docs/themes/coral/source/css/talk.scss +++ b/docs/themes/coral/source/css/talk.scss @@ -448,3 +448,17 @@ a.brand { .plugin { display: none; } + +.badge-tag { + font-family: monospace; +} + +.badge-tag-default { + background: #28a745; + color: #fff; +} + +.badge-tag-gdpr { + background: rgb(0, 102, 176); + color: #fff; +} diff --git a/docs/themes/coral/source/js/plugins.js b/docs/themes/coral/source/js/plugins.js index 83f14d356..26f7707c3 100644 --- a/docs/themes/coral/source/js/plugins.js +++ b/docs/themes/coral/source/js/plugins.js @@ -1,6 +1,17 @@ /* global lunr */ /* eslint-env browser */ +// Sourced from https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +function getParameterByName(name, url) { + if (!url) url = window.location.href; + name = name.replace(/[\[\]]/g, '\\$&'); + var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, ' ')); +} + // Sourced from https://github.com/hexojs/site/blob/8e8ed4901769abbf76263125f82832df76ced58b/themes/navy/source/js/plugins.js. (function() { 'use strict'; @@ -60,6 +71,12 @@ updateCount(elements.length); } + var searchParam = getParameterByName('q'); + if (searchParam && searchParam.length > 0) { + $input.value = searchParam; + search(searchParam); + } + $input.addEventListener('input', function() { var value = this.value; diff --git a/plugins/talk-plugin-auth/README.md b/plugins/talk-plugin-auth/README.md index fd5218365..c09dc218b 100644 --- a/plugins/talk-plugin-auth/README.md +++ b/plugins/talk-plugin-auth/README.md @@ -14,3 +14,9 @@ utilize our internal authentication system. To sync Talk auth with your own auth systems, you can use this plugin as a template. + +## GDPR Compliance + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +should review our [GDPR Compliance](/talk/integrating/gdpr/) guidelines. diff --git a/plugins/talk-plugin-facebook-auth/README.md b/plugins/talk-plugin-facebook-auth/README.md index 19d003150..08780adda 100644 --- a/plugins/talk-plugin-facebook-auth/README.md +++ b/plugins/talk-plugin-facebook-auth/README.md @@ -27,4 +27,10 @@ Configuration: or by visiting the [Creating an App ID](https://developers.facebook.com/docs/apps/register) guide. This is only required while the `talk-plugin-facebook-auth` plugin is - enabled. \ No newline at end of file + enabled. + +## GDPR Compliance + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +should review our [GDPR Compliance](/talk/integrating/gdpr/) guidelines. diff --git a/plugins/talk-plugin-google-auth/README.md b/plugins/talk-plugin-google-auth/README.md index f68b56c32..15eb5cef7 100644 --- a/plugins/talk-plugin-google-auth/README.md +++ b/plugins/talk-plugin-google-auth/README.md @@ -27,3 +27,9 @@ Configuration: - `TALK_GOOGLE_CLIENT_SECRET` (**required**) - The Google OAuth2 client ID for your Google login web app. You can learn more about getting a Google Client ID at the [Google API Console](https://console.developers.google.com/apis/). + +## GDPR Compliance + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +should review our [GDPR Compliance](/talk/integrating/gdpr/) guidelines. diff --git a/plugins/talk-plugin-local-auth/README.md b/plugins/talk-plugin-local-auth/README.md index ee5a6b880..5fabe0d71 100644 --- a/plugins/talk-plugin-local-auth/README.md +++ b/plugins/talk-plugin-local-auth/README.md @@ -18,3 +18,9 @@ through an email and password based login. - *Email Change*: Allows users to change their existing email address on their account. - *Local Account Association*: Allows users that have signed up with an external auth strategy (such as Google) the ability to associate a email address and password for login. **Note: Existing users with external authentication will be prompted to setup a local account when they sign in and when new users create an account.** + +## GDPR Compliance + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +should review our [GDPR Compliance](/talk/integrating/gdpr/) guidelines. diff --git a/plugins/talk-plugin-profile-data/README.md b/plugins/talk-plugin-profile-data/README.md index 1d019a79b..c4fcbb456 100644 --- a/plugins/talk-plugin-profile-data/README.md +++ b/plugins/talk-plugin-profile-data/README.md @@ -21,4 +21,13 @@ that contains a download link. Only one link can be generated every 7 days, and the link will be valid for 24 hours. The downloaded zip file will contain all the users comments in a CSV format -including those that have been rejected, withheld, or still in premod. +including those that have been rejected, withheld, or still in pre-moderation. + +## GDPR Compliance + +In order to facilitate compliance with the +[EU General Data Protection Regulation (GDPR)](https://www.eugdpr.org/), you +should review our [GDPR Compliance](/talk/integrating/gdpr/) guidelines. This +plugin can work with its client plugin disabled and then directly integrated +with existing workflows for an organization of any size through use of the API +that this plugin provides. From c1492d10658d1dad16b2f2409006e5ad6a9966eb Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 2 May 2018 13:22:15 -0600 Subject: [PATCH 23/38] Added incorrect password error --- plugins/talk-plugin-local-auth/server/errors.js | 12 +++++++++++- plugins/talk-plugin-local-auth/server/mutators.js | 8 ++++++-- .../talk-plugin-local-auth/server/translations.yml | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/plugins/talk-plugin-local-auth/server/errors.js b/plugins/talk-plugin-local-auth/server/errors.js index 808ceb3a6..0f0653c19 100644 --- a/plugins/talk-plugin-local-auth/server/errors.js +++ b/plugins/talk-plugin-local-auth/server/errors.js @@ -22,4 +22,14 @@ class ErrLocalProfile extends TalkError { } } -module.exports = { ErrLocalProfile, ErrNoLocalProfile }; +// ErrIncorrectPassword is returned when the password passed was incorrect. +class ErrIncorrectPassword extends TalkError { + constructor() { + super('Password was incorrect', { + translation_key: 'INCORRECT_PASSWORD', + status: 400, + }); + } +} + +module.exports = { ErrLocalProfile, ErrNoLocalProfile, ErrIncorrectPassword }; diff --git a/plugins/talk-plugin-local-auth/server/mutators.js b/plugins/talk-plugin-local-auth/server/mutators.js index fb866b92c..cb34bed7a 100644 --- a/plugins/talk-plugin-local-auth/server/mutators.js +++ b/plugins/talk-plugin-local-auth/server/mutators.js @@ -1,5 +1,9 @@ const { ErrNotAuthorized, ErrNotFound, ErrEmailTaken } = require('errors'); -const { ErrNoLocalProfile, ErrLocalProfile } = require('./errors'); +const { + ErrNoLocalProfile, + ErrLocalProfile, + ErrIncorrectPassword, +} = require('./errors'); const { get } = require('lodash'); const bcrypt = require('bcryptjs'); @@ -25,7 +29,7 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) { // Ensure that the password provided matches what we have on file. if (!await user.verifyPassword(confirmPassword)) { - throw new ErrNotAuthorized(); + throw new ErrIncorrectPassword(); } // Cleanup the email address. diff --git a/plugins/talk-plugin-local-auth/server/translations.yml b/plugins/talk-plugin-local-auth/server/translations.yml index 7df3d7b88..d81de6c6d 100644 --- a/plugins/talk-plugin-local-auth/server/translations.yml +++ b/plugins/talk-plugin-local-auth/server/translations.yml @@ -6,3 +6,4 @@ en: error: NO_LOCAL_PROFILE: No existing email address is associated with this account. LOCAL_PROFILE: An email address is already associated with this account. + INCORRECT_PASSWORD: Provided password was incorrect. From c7db780582a3c2fc9af25ec0138ab5bbce5b58ab Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 16:46:20 -0300 Subject: [PATCH 24/38] Updating the cache with data from the fragment --- .../src/tabs/profile/containers/Profile.js | 2 +- client/coral-framework/graphql/mutations.js | 23 +++++++++++++++++++ .../components/ChangeEmailContentDialog.js | 4 ++-- .../client/components/Profile.js | 14 ++++------- .../client/containers/Profile.js | 2 ++ 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/profile/containers/Profile.js b/client/coral-embed-stream/src/tabs/profile/containers/Profile.js index 0272c1535..4a84f1810 100644 --- a/client/coral-embed-stream/src/tabs/profile/containers/Profile.js +++ b/client/coral-embed-stream/src/tabs/profile/containers/Profile.js @@ -46,7 +46,7 @@ ProfileContainer.propTypes = { currentUser: PropTypes.object, }; -const slots = ['profileSections']; +const slots = ['profileSections', 'profileSettings', 'profileHeader']; const withProfileQuery = withQuery( gql` diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 15596e9a7..29ec3fc96 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -336,6 +336,29 @@ export const withUpdateEmailAddress = withMutation( variables: { input, }, + update: proxy => { + const UpdateEmailAddressQuery = gql` + query Talk_UpdateEmailAddress { + me { + id + email + } + } + `; + + const prev = proxy.readQuery({ query: UpdateEmailAddressQuery }); + + const data = update(prev, { + me: { + email: { $set: input.email }, + }, + }); + + proxy.writeQuery({ + query: UpdateEmailAddressQuery, + data, + }); + }, }); }, }), diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index 02d02680e..4bc15757e 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -37,7 +37,7 @@ class ChangeEmailContentDialog extends React.Component {
{t('talk-plugin-local-auth.change_email.old_email')}:{' '} - {this.props.emailAddress} + {this.props.email} {t('talk-plugin-local-auth.change_email.new_email')}:{' '} @@ -86,7 +86,7 @@ ChangeEmailContentDialog.propTypes = { cancel: PropTypes.func, onChange: PropTypes.func, formData: PropTypes.object, - emailAddress: PropTypes.string, + email: PropTypes.string, }; 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 84474dbe3..949923e77 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -158,9 +158,7 @@ class Profile extends React.Component { render() { const { - username, - emailAddress, - root: { me: { state: { status } } }, + root: { me: { username, email, state: { status } } }, notify, } = this.props; const { editing, formData, showDialog } = this.state; @@ -193,8 +191,8 @@ class Profile extends React.Component { save={this.saveEmail} onChange={this.onChange} formData={this.state.formData} - emailAddress={emailAddress} - enable={formData.newEmail && emailAddress !== formData.newEmail} + email={email} + enable={formData.newEmail && email !== formData.newEmail} /> @@ -221,7 +219,7 @@ class Profile extends React.Component { id="newEmail" name="newEmail" onChange={this.onChange} - defaultValue={emailAddress} + defaultValue={email} validationType="email" columnDisplay /> @@ -230,9 +228,7 @@ class Profile extends React.Component { ) : (

{username}

- {emailAddress ? ( -

{emailAddress}

- ) : null} + {email ?

{email}

: null}
)} {editing ? ( diff --git a/plugins/talk-plugin-local-auth/client/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js index bebf127fd..239304535 100644 --- a/plugins/talk-plugin-local-auth/client/containers/Profile.js +++ b/plugins/talk-plugin-local-auth/client/containers/Profile.js @@ -15,6 +15,8 @@ const withData = withFragments({ fragment TalkPluginLocalAuth_Profile_root on RootQuery { me { id + email + username state { status { username { From bfb4b790d42b166a15c57f4a46021c5b3fa4ad75 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 16:49:56 -0300 Subject: [PATCH 25/38] Adding error --- locales/en.yml | 1 + locales/es.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/locales/en.yml b/locales/en.yml index 393d01e23..045d37c46 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -250,6 +250,7 @@ en: ALREADY_EXISTS: "Resource already exists" INVALID_ASSET_URL: "Assert URL is invalid" CANNOT_IGNORE_STAFF: "Cannot ignore Staff members." + INCORRECT_PASSWORD: "Incorrect Password" email: "Please enter a valid email." confirm_password: "Passwords don't match. Please check again" network_error: "Failed to connect to server. Check your internet connection and try again." diff --git a/locales/es.yml b/locales/es.yml index 628dd8faa..41e337df8 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -243,6 +243,7 @@ es: ALREADY_EXISTS: "Resource already exists" INVALID_ASSET_URL: "La URL del articulo no es valida" CANNOT_IGNORE_STAFF: "Cannot ignore Staff members." + INCORRECT_PASSWORD: "Contraseña Incorrecta" email: "No es un correo válido" confirm_password: "Las contraseñas no coinciden. Inténtelo nuevamente" network_error: "Error al conectar con el servidor. Compruebe su conexión a Internet y vuelva a intentarlo." From 8a9af896992c12ee9b955c08c05806bf84011f0e Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 15:12:23 -0300 Subject: [PATCH 26/38] withUpdateEmailAddress in the plugins hoc --- client/coral-framework/graphql/mutations.js | 44 ----------------- .../client/containers/Profile.js | 6 +-- .../client/hocs/index.js | 47 +++++++++++++++++++ 3 files changed, 49 insertions(+), 48 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/client/hocs/index.js diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 29ec3fc96..228911d4a 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -321,50 +321,6 @@ const SetUsernameFragment = gql` } `; -export const withUpdateEmailAddress = withMutation( - gql` - mutation UpdateEmailAddress($input: UpdateEmailAddressInput!) { - updateEmailAddress(input: $input) { - ...UpdateEmailAddressResponse - } - } - `, - { - props: ({ mutate }) => ({ - updateEmailAddress: input => { - return mutate({ - variables: { - input, - }, - update: proxy => { - const UpdateEmailAddressQuery = gql` - query Talk_UpdateEmailAddress { - me { - id - email - } - } - `; - - const prev = proxy.readQuery({ query: UpdateEmailAddressQuery }); - - const data = update(prev, { - me: { - email: { $set: input.email }, - }, - }); - - proxy.writeQuery({ - query: UpdateEmailAddressQuery, - data, - }); - }, - }); - }, - }), - } -); - export const withChangeUsername = withMutation( gql` mutation ChangeUsername($id: ID!, $username: String!) { diff --git a/plugins/talk-plugin-local-auth/client/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js index 239304535..8f442ea43 100644 --- a/plugins/talk-plugin-local-auth/client/containers/Profile.js +++ b/plugins/talk-plugin-local-auth/client/containers/Profile.js @@ -3,10 +3,8 @@ import { bindActionCreators } from 'redux'; import { connect, withFragments } from 'plugin-api/beta/client/hocs'; import Profile from '../components/Profile'; import { notify } from 'coral-framework/actions/notification'; -import { - withChangeUsername, - withUpdateEmailAddress, -} from 'plugin-api/beta/client/hocs'; +import { withChangeUsername } from 'plugin-api/beta/client/hocs'; +import { withUpdateEmailAddress } from './hocs'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); diff --git a/plugins/talk-plugin-local-auth/client/hocs/index.js b/plugins/talk-plugin-local-auth/client/hocs/index.js new file mode 100644 index 000000000..bcd439af2 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/hocs/index.js @@ -0,0 +1,47 @@ +import { gql } from 'react-apollo'; +import update from 'immutability-helper'; +import withMutation from 'coral-framework/hocs/withMutation'; + +export const withUpdateEmailAddress = withMutation( + gql` + mutation UpdateEmailAddress($input: UpdateEmailAddressInput!) { + updateEmailAddress(input: $input) { + ...UpdateEmailAddressResponse + } + } + `, + { + props: ({ mutate }) => ({ + updateEmailAddress: input => { + return mutate({ + variables: { + input, + }, + update: proxy => { + const UpdateEmailAddressQuery = gql` + query Talk_UpdateEmailAddress { + me { + id + email + } + } + `; + + const prev = proxy.readQuery({ query: UpdateEmailAddressQuery }); + + const data = update(prev, { + me: { + email: { $set: input.email }, + }, + }); + + proxy.writeQuery({ + query: UpdateEmailAddressQuery, + data, + }); + }, + }); + }, + }), + } +); From 687d0555c87996b7f6ff6f28639d0b37df8aecf1 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 15:18:09 -0300 Subject: [PATCH 27/38] moving mutations to /hocs folder --- .../client/containers/DownloadCommentHistory.js | 2 +- .../client/{mutations.js => hocs/index.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename plugins/talk-plugin-profile-data/client/{mutations.js => hocs/index.js} (100%) diff --git a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js index 96dbf6975..df9843d4a 100644 --- a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js +++ b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { compose, gql } from 'react-apollo'; import DownloadCommentHistory from '../components/DownloadCommentHistory'; import { withFragments } from 'plugin-api/beta/client/hocs'; -import { withRequestDownloadLink } from '../mutations'; +import { withRequestDownloadLink } from '../hocs'; class DownloadCommentHistoryContainer extends Component { static propTypes = { diff --git a/plugins/talk-plugin-profile-data/client/mutations.js b/plugins/talk-plugin-profile-data/client/hocs/index.js similarity index 100% rename from plugins/talk-plugin-profile-data/client/mutations.js rename to plugins/talk-plugin-profile-data/client/hocs/index.js From 788cf25fa50acb9fa7888260b228c6aae77ba858 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 15:20:07 -0300 Subject: [PATCH 28/38] moving mutations to /hocs folder --- plugins/talk-plugin-local-auth/client/containers/Profile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/client/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js index 8f442ea43..e1ed99ef6 100644 --- a/plugins/talk-plugin-local-auth/client/containers/Profile.js +++ b/plugins/talk-plugin-local-auth/client/containers/Profile.js @@ -4,7 +4,7 @@ import { connect, withFragments } from 'plugin-api/beta/client/hocs'; import Profile from '../components/Profile'; import { notify } from 'coral-framework/actions/notification'; import { withChangeUsername } from 'plugin-api/beta/client/hocs'; -import { withUpdateEmailAddress } from './hocs'; +import { withUpdateEmailAddress } from '../hocs'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); From 29a840fe067d774fcf1928017c5f80c0df5b433a Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 15:38:17 -0300 Subject: [PATCH 29/38] InputField conflict --- .../client/components/ChangePassword.css | 2 +- .../client/components/InputField.css | 6 +- .../client/components/InputField.js | 60 ++++++++++--------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css index 6c7f9ae41..af59ae65f 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css @@ -31,7 +31,7 @@ display: block; padding-top: 4px; text-align: right; - width: 280px; + width: 230px; } .detailLink { diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.css b/plugins/talk-plugin-local-auth/client/components/InputField.css index cd6015e47..d0dc51494 100644 --- a/plugins/talk-plugin-local-auth/client/components/InputField.css +++ b/plugins/talk-plugin-local-auth/client/components/InputField.css @@ -5,6 +5,7 @@ .detailItemContainer { display: flex; + flex-direction: column; } .columnDisplay { @@ -16,6 +17,10 @@ } .detailItemContent { + display: flex; +} + +.detailInput { border: solid 1px #787D80; border-radius: 2px; background-color: white; @@ -64,7 +69,6 @@ display: flex; align-items: center; padding-left: 6px; - padding-top: 16px; .warningIcon, .checkIcon { font-size: 17px; diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.js b/plugins/talk-plugin-local-auth/client/components/InputField.js index 34c314c20..944f5e7cf 100644 --- a/plugins/talk-plugin-local-auth/client/components/InputField.js +++ b/plugins/talk-plugin-local-auth/client/components/InputField.js @@ -30,41 +30,45 @@ const InputField = ({ return (
-
+
{label && ( )}
- {icon && } - -
-
- {!hasError && - showSuccess && - value && } - {hasError && showError && {errorMsg}} +
+ {icon && } + +
+
+ {!hasError && + showSuccess && + value && ( + + )} + {hasError && showError && {errorMsg}} +
{children} From 58b73a4d0a7d15734b9b88306c75150a421a8771 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 17:08:20 -0400 Subject: [PATCH 30/38] Add feature overview to GDPR docs --- docs/source/03-08-gdpr.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/source/03-08-gdpr.md b/docs/source/03-08-gdpr.md index 187920bbc..76fe23211 100644 --- a/docs/source/03-08-gdpr.md +++ b/docs/source/03-08-gdpr.md @@ -12,9 +12,19 @@ can enable the following plugins: - [talk-plugin-profile-data](/talk/plugin/talk-plugin-profile-data) - to facilitate account download and deletion Even if you don't reside in a location where GDPR will apply, it is recommended -to enable these features anyways to provide your users with control over their +to enable these features as a best practice to provide your users with control over their own data. +## GPDR Feature Overview + +Integrating our GDPR tools will give your users and organization the following benefits: + +- **Download my comment data**: Users can request a download of their comments. An email with a link is emailed to them to download a CSV with each comment they've made, what story it was made on, and the comment's ID and timestamp. +- **Delete my acccount**: Users can request deletion of their account. Deleted account requests are pending for 24 hours to allow the user to download their comments, or to change their mind and reactivate their account before the expiry. Account deletions remove all of their comments from the site, all their comments and actions from the database, and their account info from our system. +- **Add an email to an Oauth/external account**: Users are prompted to add an email to their non-Talk account (Facebook, Google, external, etc) so that they can take part in GDPR and other features requiring email communication. +** Change my username: Users can update their username. This is capped at once every 2 weeks. +** Change my email: Users can change their email. + ## Custom Authentication Solutions As many of the newsrooms who have integrated Talk have followed our guides on From bc3ceac61a405c25c5776b97c34a613641015eba Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 15:26:50 -0600 Subject: [PATCH 31/38] docs patch --- docs/source/03-08-gdpr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/03-08-gdpr.md b/docs/source/03-08-gdpr.md index 76fe23211..868897955 100644 --- a/docs/source/03-08-gdpr.md +++ b/docs/source/03-08-gdpr.md @@ -22,8 +22,8 @@ Integrating our GDPR tools will give your users and organization the following b - **Download my comment data**: Users can request a download of their comments. An email with a link is emailed to them to download a CSV with each comment they've made, what story it was made on, and the comment's ID and timestamp. - **Delete my acccount**: Users can request deletion of their account. Deleted account requests are pending for 24 hours to allow the user to download their comments, or to change their mind and reactivate their account before the expiry. Account deletions remove all of their comments from the site, all their comments and actions from the database, and their account info from our system. - **Add an email to an Oauth/external account**: Users are prompted to add an email to their non-Talk account (Facebook, Google, external, etc) so that they can take part in GDPR and other features requiring email communication. -** Change my username: Users can update their username. This is capped at once every 2 weeks. -** Change my email: Users can change their email. +- **Change my username**: Users can update their username. This is capped at once every 2 weeks. +- **Change my email**: Users can change their email. ## Custom Authentication Solutions From aee963ce39e788f9be6157ebe22dae42ab9c06db Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 17:34:41 -0400 Subject: [PATCH 32/38] Missed an s --- docs/source/03-08-gdpr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/03-08-gdpr.md b/docs/source/03-08-gdpr.md index 868897955..9b1050454 100644 --- a/docs/source/03-08-gdpr.md +++ b/docs/source/03-08-gdpr.md @@ -17,7 +17,7 @@ own data. ## GPDR Feature Overview -Integrating our GDPR tools will give your users and organization the following benefits: +Integrating our GDPR tools will give your users and organizations the following benefits: - **Download my comment data**: Users can request a download of their comments. An email with a link is emailed to them to download a CSV with each comment they've made, what story it was made on, and the comment's ID and timestamp. - **Delete my acccount**: Users can request deletion of their account. Deleted account requests are pending for 24 hours to allow the user to download their comments, or to change their mind and reactivate their account before the expiry. Account deletions remove all of their comments from the site, all their comments and actions from the database, and their account info from our system. From 35cefd55706c19ca15165c46e1768c9bc7e8aa97 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 17:42:47 -0400 Subject: [PATCH 33/38] Fix build fail --- .../client/containers/DownloadCommentHistory.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js index a610e834b..7a22ef37f 100644 --- a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js +++ b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { compose, gql } from 'react-apollo'; import DownloadCommentHistory from '../components/DownloadCommentHistory'; -import { withFragments } from 'plugin-api/beta/client/hocs'; import { withRequestDownloadLink } from '../hocs'; import { connect, withFragments } from 'plugin-api/beta/client/hocs'; import { withRequestDownloadLink } from '../hocs'; From b5958d5879153274faa7d48250432f4e7f524686 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 15:45:43 -0600 Subject: [PATCH 34/38] fixed merge error --- .../containers/DownloadCommentHistory.js | 1 - .../client/hocs/index.js | 92 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js index 7a22ef37f..1716de983 100644 --- a/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js +++ b/plugins/talk-plugin-profile-data/client/containers/DownloadCommentHistory.js @@ -5,7 +5,6 @@ import { compose, gql } from 'react-apollo'; import DownloadCommentHistory from '../components/DownloadCommentHistory'; import { withRequestDownloadLink } from '../hocs'; import { connect, withFragments } from 'plugin-api/beta/client/hocs'; -import { withRequestDownloadLink } from '../hocs'; import { notify } from 'coral-framework/actions/notification'; class DownloadCommentHistoryContainer extends Component { diff --git a/plugins/talk-plugin-profile-data/client/hocs/index.js b/plugins/talk-plugin-profile-data/client/hocs/index.js index a370c9ff0..c90ad21df 100644 --- a/plugins/talk-plugin-profile-data/client/hocs/index.js +++ b/plugins/talk-plugin-profile-data/client/hocs/index.js @@ -1,5 +1,7 @@ import { withMutation } from 'plugin-api/beta/client/hocs'; import { gql } from 'react-apollo'; +import moment from 'moment'; +import update from 'immutability-helper'; export const withRequestDownloadLink = withMutation( gql` @@ -17,3 +19,93 @@ export const withRequestDownloadLink = withMutation( }), } ); + +export const withRequestAccountDeletion = withMutation( + gql` + mutation RequestAccountDeletion { + requestAccountDeletion { + ...RequestAccountDeletionResponse + } + } + `, + { + props: ({ mutate }) => ({ + requestAccountDeletion: () => { + return mutate({ + variables: {}, + update: proxy => { + const RequestAccountDeletionQuery = gql` + query Talk_CancelAccountDeletion { + me { + id + scheduledDeletionDate + } + } + `; + + const prev = proxy.readQuery({ + query: RequestAccountDeletionQuery, + }); + + const scheduledDeletionDate = moment() + .add(24, 'hours') + .toDate(); + + const data = update(prev, { + me: { + scheduledDeletionDate: { $set: scheduledDeletionDate }, + }, + }); + + proxy.writeQuery({ + query: RequestAccountDeletionQuery, + data, + }); + }, + }); + }, + }), + } +); + +export const withCancelAccountDeletion = withMutation( + gql` + mutation RequestDownloadLink { + cancelAccountDeletion { + ...CancelAccountDeletionResponse + } + } + `, + { + props: ({ mutate }) => ({ + cancelAccountDeletion: () => { + return mutate({ + variables: {}, + update: proxy => { + const CancelAccountDeletionQuery = gql` + query Talk_CancelAccountDeletion { + me { + id + scheduledDeletionDate + } + } + `; + + const prev = proxy.readQuery({ query: CancelAccountDeletionQuery }); + + const data = update(prev, { + me: { + scheduledDeletionDate: { $set: null }, + }, + }); + + proxy.writeQuery({ + query: CancelAccountDeletionQuery, + data, + }); + }, + }); + }, + }), + } +); From ea71b779d2df69464235a18f0627611304c06054 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 15:51:50 -0600 Subject: [PATCH 35/38] password patches --- .../client/components/ChangePassword.css | 17 +++++++++++------ .../client/components/DeleteMyAccountDialog.js | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css index af59ae65f..0df8eb409 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css @@ -1,22 +1,27 @@ .container { position: relative; color: #202020; - padding: 10px; border-radius: 2px; border: solid 1px transparent; box-sizing: border-box; justify-content: space-between; - + &.editing { + padding: 10px; border-color: #979797; background-color: #EDEDED; + + .actions { + top: 10px; + right: 10px; + } } } .actions { position: absolute; - top: 10px; - right: 10px; + top: 0px; + right: 0px; display: flex; flex-direction: column; align-items: center; @@ -35,7 +40,7 @@ } .detailLink { - color: #00538A; + color: #00538A; text-decoration: none; font-size: 0.9em; &:hover { @@ -59,7 +64,7 @@ > i { font-size: 17px; } - + &:hover { background-color: #399ee2; color: white; diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js index 9264bb75c..584fbb1b8 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js @@ -97,7 +97,7 @@ DeleteMyAccountDialog.propTypes = { showDialog: PropTypes.bool.isRequired, closeDialog: PropTypes.func.isRequired, requestAccountDeletion: PropTypes.func.isRequired, - scheduledDeletionDate: PropTypes.any.isRequired, + scheduledDeletionDate: PropTypes.any, organizationContactEmail: PropTypes.string.isRequired, }; From fa66f07db6cbd8bf915a07e327186a387f4b8caa Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 15:58:52 -0600 Subject: [PATCH 36/38] standardized styles, fixed mutation bug --- .../client/components/DeleteMyAccount.css | 23 ------------- .../client/components/DeleteMyAccount.js | 34 +++---------------- .../client/graphql.js | 2 +- 3 files changed, 6 insertions(+), 53 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css index e524d990a..e69de29bb 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css @@ -1,23 +0,0 @@ -.button { - color: #787D80; - border-radius: 2px; - border: 1px solid #787d80; - background-color: transparent; - height: 30px; - font-size: 0.9em; - line-height: normal; - - &:hover { - background-color: #eaeaea; - } - - &.secondary { - background-color: #787D80; - color: white; - } - - > i { - font-size: 1.2em; - vertical-align: middle; - } -} \ No newline at end of file diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js index bbaca5b96..bbada134f 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js @@ -1,8 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import cn from 'classnames'; import moment from 'moment'; -import styles from './DeleteMyAccount.css'; import { Button } from 'plugin-api/beta/client/components/ui'; import DeleteMyAccountDialog from './DeleteMyAccountDialog'; import { getErrorMessages } from 'coral-framework/utils'; @@ -59,28 +57,13 @@ class DeleteMyAccount extends React.Component { scheduledDeletionDate={scheduledDeletionDate} organizationContactEmail={organizationContactEmail} /> -

+

{t('delete_request.delete_my_account')}

-

+

{t('delete_request.delete_my_account_description')}

-

+

{scheduledDeletionDate && t( 'delete_request.already_submitted_request_description', @@ -88,18 +71,11 @@ class DeleteMyAccount extends React.Component { )}

{scheduledDeletionDate ? ( - ) : ( - )} diff --git a/plugins/talk-plugin-profile-data/client/graphql.js b/plugins/talk-plugin-profile-data/client/graphql.js index e0c459f7e..9b3711bfc 100644 --- a/plugins/talk-plugin-profile-data/client/graphql.js +++ b/plugins/talk-plugin-profile-data/client/graphql.js @@ -10,7 +10,7 @@ export default { ), }, mutations: { - RequestDownloadLink: () => ({ + DownloadCommentHistory: () => ({ updateQueries: { CoralEmbedStream_Profile: previousData => update(previousData, { From 949925586f414cb54dc4aa0621174b4ce1f2c838 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 17:50:53 -0600 Subject: [PATCH 37/38] handle confirmed email better --- .../talk-plugin-local-auth/client/graphql.js | 34 +++++++++++++++++++ .../talk-plugin-local-auth/client/index.js | 2 ++ .../talk-plugin-local-auth/server/mutators.js | 1 + services/users.js | 5 ++- 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 plugins/talk-plugin-local-auth/client/graphql.js diff --git a/plugins/talk-plugin-local-auth/client/graphql.js b/plugins/talk-plugin-local-auth/client/graphql.js new file mode 100644 index 000000000..67fde246a --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/graphql.js @@ -0,0 +1,34 @@ +import update from 'immutability-helper'; +import get from 'lodash/get'; + +export default { + mutations: { + UpdateEmailAddress: () => ({ + updateQueries: { + CoralEmbedStream_Profile: previousData => { + // Find the local profile (if they have one). + const localIndex = get(previousData, 'me.profiles', []).indexOf( + ({ provider }) => provider === 'local' + ); + if (localIndex < 0) { + return previousData; + } + + // Mutate the confirmedAt, because we changed the email address, they + // can't possibly be confirmed now as well. + return update(previousData, { + me: { + profiles: { + [localIndex]: { + confirmedAt: { + $set: null, + }, + }, + }, + }, + }); + }, + }, + }), + }, +}; diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index c669effaa..d5f9f8636 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -1,6 +1,7 @@ import ChangePassword from './containers/ChangePassword'; import Profile from './containers/Profile'; import translations from './translations.yml'; +import graphql from './graphql'; export default { translations, @@ -8,4 +9,5 @@ export default { profileHeader: [Profile], profileSettings: [ChangePassword], }, + ...graphql, }; diff --git a/plugins/talk-plugin-local-auth/server/mutators.js b/plugins/talk-plugin-local-auth/server/mutators.js index cb34bed7a..6798584f5 100644 --- a/plugins/talk-plugin-local-auth/server/mutators.js +++ b/plugins/talk-plugin-local-auth/server/mutators.js @@ -43,6 +43,7 @@ async function updateUserEmailAddress(ctx, email, confirmPassword) { }, { $set: { 'profiles.$.id': email }, + $unset: { 'profiles.$.metadata.confirmed_at': 1 }, } ); diff --git a/services/users.js b/services/users.js index 1e84c8ff1..d5486b3f8 100644 --- a/services/users.js +++ b/services/users.js @@ -32,6 +32,7 @@ const i18n = require('./i18n'); const Wordlist = require('./wordlist'); const DomainList = require('./domain_list'); const Limit = require('./limit'); +const { get } = require('lodash'); const EMAIL_CONFIRM_JWT_SUBJECT = 'email_confirm'; const PASSWORD_RESET_JWT_SUBJECT = 'password_reset'; @@ -965,7 +966,9 @@ class Users { throw new ErrNotFound(); } - if (profile.metadata && profile.metadata.confirmed_at !== null) { + // Check to see if the profile has already been confirmed. + const confirmedAt = get(profile, 'metadata.confirmed_at', null); + if (confirmedAt && confirmedAt < Date.now()) { throw new ErrEmailAlreadyVerified(); } From 15df20e72056739c0a200db23cb81f87c751cda4 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 17:57:09 -0600 Subject: [PATCH 38/38] fix --- plugins/talk-plugin-local-auth/client/graphql.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/graphql.js b/plugins/talk-plugin-local-auth/client/graphql.js index 67fde246a..eddf58315 100644 --- a/plugins/talk-plugin-local-auth/client/graphql.js +++ b/plugins/talk-plugin-local-auth/client/graphql.js @@ -1,5 +1,6 @@ import update from 'immutability-helper'; import get from 'lodash/get'; +import findIndex from 'lodash/findIndex'; export default { mutations: { @@ -7,9 +8,9 @@ export default { updateQueries: { CoralEmbedStream_Profile: previousData => { // Find the local profile (if they have one). - const localIndex = get(previousData, 'me.profiles', []).indexOf( - ({ provider }) => provider === 'local' - ); + const localIndex = findIndex(get(previousData, 'me.profiles', []), { + provider: 'local', + }); if (localIndex < 0) { return previousData; }