From 2adec1bc344137ba2383b62820c70c30542658ec Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 18 Apr 2018 13:13:41 -0600 Subject: [PATCH 01/97] added deletion graph endpoints --- graph/mutators/user.js | 5 +- perms/constants/mutation.js | 2 +- perms/reducers/mutation.js | 1 + plugin-api/beta/server/getReactionConfig.js | 15 +--- plugins/talk-plugin-profile-data/package.json | 1 + .../server/connect.js | 88 ++++++++++++++++++- .../talk-plugin-profile-data/server/errors.js | 27 +++++- .../server/mutators.js | 64 ++++++++++++-- .../server/resolvers.js | 18 ++++ .../server/typeDefs.graphql | 38 ++++++++ 10 files changed, 235 insertions(+), 24 deletions(-) diff --git a/graph/mutators/user.js b/graph/mutators/user.js index 6c673111b..0343e1f2e 100644 --- a/graph/mutators/user.js +++ b/graph/mutators/user.js @@ -8,7 +8,7 @@ const { SET_USER_BAN_STATUS, SET_USER_SUSPENSION_STATUS, UPDATE_USER_ROLES, - DELETE_USER, + DELETE_OTHER_USER, } = require('../../perms/constants'); const setUserUsernameStatus = async (ctx, id, status) => { @@ -155,6 +155,7 @@ module.exports = ctx => { setUsername: () => Promise.reject(new ErrNotAuthorized()), stopIgnoringUser: () => Promise.reject(new ErrNotAuthorized()), del: () => Promise.reject(new ErrNotAuthorized()), + delSelf: () => Promise.reject(new ErrNotAuthorized()), }, }; @@ -191,7 +192,7 @@ module.exports = ctx => { setUserSuspensionStatus(ctx, id, until, message); } - if (ctx.user.can(DELETE_USER)) { + if (ctx.user.can(DELETE_OTHER_USER)) { mutators.User.del = id => delUser(ctx, id); } } diff --git a/perms/constants/mutation.js b/perms/constants/mutation.js index d2ebe73f1..dba126ceb 100644 --- a/perms/constants/mutation.js +++ b/perms/constants/mutation.js @@ -18,5 +18,5 @@ module.exports = { UPDATE_ASSET_SETTINGS: 'UPDATE_ASSET_SETTINGS', UPDATE_ASSET_STATUS: 'UPDATE_ASSET_STATUS', UPDATE_SETTINGS: 'UPDATE_SETTINGS', - DELETE_USER: 'DELETE_USER', + DELETE_OTHER_USER: 'DELETE_OTHER_USER', }; diff --git a/perms/reducers/mutation.js b/perms/reducers/mutation.js index 73ee7ef28..7e23b274b 100644 --- a/perms/reducers/mutation.js +++ b/perms/reducers/mutation.js @@ -36,6 +36,7 @@ module.exports = (user, perm) => { case types.UPDATE_USER_ROLES: case types.CREATE_TOKEN: case types.REVOKE_TOKEN: + case types.DELETE_OTHER_USER: return check(user, ['ADMIN']); default: diff --git a/plugin-api/beta/server/getReactionConfig.js b/plugin-api/beta/server/getReactionConfig.js index da075d76c..b6e0a5c1d 100644 --- a/plugin-api/beta/server/getReactionConfig.js +++ b/plugin-api/beta/server/getReactionConfig.js @@ -2,24 +2,11 @@ const { SEARCH_OTHER_USERS } = require('../../../perms/constants'); const { ErrNotFound, ErrAlreadyExists } = require('../../../errors'); const pluralize = require('pluralize'); const sc = require('snake-case'); -// const { CREATE_MONGO_INDEXES } = require('../../../config'); function getReactionConfig(reaction) { + // Ensure that the reaction is a lowercase string. reaction = reaction.toLowerCase(); - // if (CREATE_MONGO_INDEXES) { - // // Create the index on the comment model based on the reaction config. - // CommentModel.collection.createIndex( - // { - // created_at: 1, - // [`action_counts.${sc(reaction)}`]: 1, - // }, - // { - // background: true, - // } - // ); - // } - const reactionPlural = pluralize(reaction); const Reaction = reaction.charAt(0).toUpperCase() + reaction.slice(1); const REACTION = reaction.toUpperCase(); diff --git a/plugins/talk-plugin-profile-data/package.json b/plugins/talk-plugin-profile-data/package.json index ed5a29050..4329aba7e 100644 --- a/plugins/talk-plugin-profile-data/package.json +++ b/plugins/talk-plugin-profile-data/package.json @@ -7,6 +7,7 @@ "private": false, "dependencies": { "archiver": "^2.1.1", + "cron": "^1.3.0", "csv-stringify": "^3.0.0" } } diff --git a/plugins/talk-plugin-profile-data/server/connect.js b/plugins/talk-plugin-profile-data/server/connect.js index f09b2dc7b..eab76828f 100644 --- a/plugins/talk-plugin-profile-data/server/connect.js +++ b/plugins/talk-plugin-profile-data/server/connect.js @@ -1,7 +1,13 @@ const path = require('path'); +const moment = require('moment'); +const { CronJob } = require('cron'); module.exports = connectors => { - const { services: { Mailer } } = connectors; + const { + services: { Mailer }, + models: { User }, + graph: { Context }, + } = connectors; // Setup the mail templates. ['txt', 'html'].forEach(format => { @@ -11,4 +17,84 @@ module.exports = connectors => { format ); }); + + // Setup the cron job that will scan for accounts to delete every 30 minutes. + new CronJob({ + cronTime: '0,30 * * * *', + timeZone: 'America/New_York', + start: true, + runOnInit: true, + onTick: async () => { + // Create the context we'll use to perform user deletions. + const ctx = Context.forSystem(); + + // rescheduledDeletionDate is the date in the future that we'll set the + // user's account to be deleted on if this delete fails. + const rescheduledDeletionDate = moment() + .add(1, 'hours') + .toDate(); + + try { + // Keep running for each user we can pull. + while (true) { + // We'll find any user that has an account deletion date before now + // and update the user such that their deletion time is 1 hour from + // now. This will ensure that only one instance can pull the same + // user at a time, and if the delete fails, it will be retried an + // hour from now. If the deletion was successful, well, it can't be + // retried because the reference to the scheduledDeletionDate will + // get deleted along with the user. + const user = await User.findOneAndUpdate( + { + 'metadata.scheduledDeletionDate': { $lte: new Date() }, + }, + { + $set: { + 'metadata.scheduledDeletionDate': rescheduledDeletionDate, + }, + } + ); + if (!user) { + // There are no more users that meet the search criteria! We're + // done! + ctx.log.info('no more users are scheduled for deletion'); + break; + } + + ctx.log.info( + { + userID: user.id, + scheduledDeletionDate: user.metadata.scheduledDeletionDate, + }, + 'starting user delete' + ); + + // Delete the user using the existing graph call. + const { data, errors } = await ctx.graphql( + ` + mutation DeleteUser($user_id: ID!) { + delUser(id: $user_id) { + errors { + translation_key + } + } + } + `, + { user_id: user.id } + ); + if (errors) { + throw errors; + } + + if (data.errors) { + throw data.errors; + } + + ctx.log.info({ userID: user.id }, 'user was deleted successfully'); + } + } catch (err) { + ctx.log.error({ err }, 'could not handle user deletions'); + } + }, + }); }; diff --git a/plugins/talk-plugin-profile-data/server/errors.js b/plugins/talk-plugin-profile-data/server/errors.js index 6261ebe89..f205c1f6e 100644 --- a/plugins/talk-plugin-profile-data/server/errors.js +++ b/plugins/talk-plugin-profile-data/server/errors.js @@ -15,4 +15,29 @@ class ErrDownloadToken extends TalkError { } } -module.exports = { ErrDownloadToken }; +// ErrDeletionAlreadyScheduled is returned when a user requests that their +// account get deleted when their account is already scheduled for deletion. +class ErrDeletionAlreadyScheduled extends TalkError { + constructor() { + super('Deletion is already scheduled', { + translation_key: 'DELETION_ALREADY_SCHEDULED', + status: 400, + }); + } +} +// ErrDeletionNotScheduled is returned when a user requests that their +// account deletion to be canceled when it was not scheduled for deletion. +class ErrDeletionNotScheduled extends TalkError { + constructor() { + super('Deletion was not scheduled', { + translation_key: 'DELETION_NOT_SCHEDULED', + status: 400, + }); + } +} + +module.exports = { + ErrDownloadToken, + ErrDeletionAlreadyScheduled, + ErrDeletionNotScheduled, +}; diff --git a/plugins/talk-plugin-profile-data/server/mutators.js b/plugins/talk-plugin-profile-data/server/mutators.js index 5a897a2e1..dafc7dc42 100644 --- a/plugins/talk-plugin-profile-data/server/mutators.js +++ b/plugins/talk-plugin-profile-data/server/mutators.js @@ -1,6 +1,12 @@ +const { get } = require('lodash'); const moment = require('moment'); const uuid = require('uuid/v4'); const { DOWNLOAD_LINK_SUBJECT } = require('./constants'); +const { + ErrDeletionAlreadyScheduled, + ErrDeletionNotScheduled, +} = require('./errors'); +const { ErrNotAuthorized } = require('errors'); async function sendDownloadLink({ user, @@ -66,8 +72,56 @@ async function sendDownloadLink({ ); } -module.exports = ctx => ({ - User: { - requestDownloadLink: () => sendDownloadLink(ctx), - }, -}); +// requestDeletion will schedule the current user to have their account deleted +// by setting the `scheduledDeletionDate` on the user 12 hours from now. +async function requestDeletion({ user, connectors: { models: { User } } }) { + // Ensure the user doesn't already have a deletion scheduled. + if (get(user, 'metadata.scheduledDeletionDate')) { + throw new ErrDeletionAlreadyScheduled(); + } + + // Get the date in the future 12 hours from now. + const scheduledDeletionDate = moment() + .add(12, 'hours') + .toDate(); + + // Amend the scheduledDeletionDate on the user. + await User.update( + { id: user.id }, + { $set: { 'metadata.scheduledDeletionDate': scheduledDeletionDate } } + ); + + return scheduledDeletionDate; +} + +// cancelDeletion will unset the scheduled deletion date on the user account +// that is used to indicate that the user was scheduled for deletion. +async function cancelDeletion({ user, connectors: { models: { User } } }) { + // Ensure the user has a deletion scheduled. + if (!get(user, 'metadata.scheduledDeletionDate', null)) { + throw new ErrDeletionNotScheduled(); + } + + // Amend the scheduledDeletionDate on the user. + await User.update( + { id: user.id }, + { $unset: { 'metadata.scheduledDeletionDate': 1 } } + ); +} + +module.exports = ctx => + ctx.user + ? { + User: { + requestDownloadLink: () => sendDownloadLink(ctx), + requestDeletion: () => requestDeletion(ctx), + cancelDeletion: () => cancelDeletion(ctx), + }, + } + : { + User: { + requestDownloadLink: () => Promise.reject(new ErrNotAuthorized()), + requestDeletion: () => Promise.reject(new ErrNotAuthorized()), + cancelDeletion: () => Promise.reject(new ErrNotAuthorized()), + }, + }; diff --git a/plugins/talk-plugin-profile-data/server/resolvers.js b/plugins/talk-plugin-profile-data/server/resolvers.js index 691907f8c..a90c617e2 100644 --- a/plugins/talk-plugin-profile-data/server/resolvers.js +++ b/plugins/talk-plugin-profile-data/server/resolvers.js @@ -5,6 +5,12 @@ module.exports = { requestDownloadLink: async (_, args, { mutators: { User } }) => { await User.requestDownloadLink(); }, + requestAccountDeletion: async (_, args, { mutators: { User } }) => ({ + scheduledDeletionDate: await User.requestDeletion(), + }), + cancelAccountDeletion: async (_, args, { mutators: { User } }) => { + await User.cancelDeletion(); + }, }, User: { lastAccountDownload: (user, args, { user: currentUser }) => { @@ -16,5 +22,17 @@ module.exports = { return get(user, 'metadata.lastAccountDownload', null); }, + scheduledDeletionDate: (user, args, { user: currentUser }) => { + // If the current user is not the requesting user, and the user is not + // an admin or a moderator, return nothing. + if ( + user.id !== currentUser.id && + !['ADMIN', 'MODERATOR'].includes(user.role) + ) { + return null; + } + + return get(user, 'metadata.scheduledDeletionDate', null); + }, }, }; diff --git a/plugins/talk-plugin-profile-data/server/typeDefs.graphql b/plugins/talk-plugin-profile-data/server/typeDefs.graphql index 0029111c3..c785fb2cc 100644 --- a/plugins/talk-plugin-profile-data/server/typeDefs.graphql +++ b/plugins/talk-plugin-profile-data/server/typeDefs.graphql @@ -3,17 +3,55 @@ type User { # lastAccountDownload is the date that the user last requested a comment # download. lastAccountDownload: Date + + # scheduledDeletionDate is the data for which the user account will be deleted + # after. The account may be deleted up to half an hour after this date because + # the job responsible for deleting the scheduled account will only run once + # every half hour. + scheduledDeletionDate: Date } +# RequestDownloadLinkResponse contains the account download errors relating to +# the request for an account download. type RequestDownloadLinkResponse implements Response { # An array of errors relating to the mutation that occurred. errors: [UserError!] } +# RequestAccountDeletionResponse contains the account deletion schedule errors +# relating to schedulding an account for deletion. +type RequestAccountDeletionResponse implements Response { + + # scheduledDeletionDate is the data for which the user account will be deleted + # after. The account may be deleted up to half an hour after this date because + # the job responsible for deleting the scheduled account will only run once + # every half hour. + scheduledDeletionDate: Date + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + +# CancelAccountDeletionResponse contains the account deletion errors relating to +# canceling an account deletion that was scheduled. +type CancelAccountDeletionResponse implements Response { + + # An array of errors relating to the mutation that occurred. + errors: [UserError!] +} + type RootMutation { # requestDownloadLink will request a download link be sent to the primary # users email address. requestDownloadLink: RequestDownloadLinkResponse + + # requestAccountDeletion requests that the current account get deleted. The + # mutation will return the date that the account is scheduled to be deleted. + requestAccountDeletion: RequestAccountDeletionResponse + + # cancelAccountDeletion will cancel a pending account deletion that was + # previously scheduled. + cancelAccountDeletion: CancelAccountDeletionResponse } From 8e34fd1925fe23c745de480c773aa4bdab11af80 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 18 Apr 2018 17:22:39 -0600 Subject: [PATCH 02/97] implemented tombstoning --- .../src/tabs/stream/components/Comment.js | 11 +++- .../stream/components/CommentTombstone.js | 2 + client/coral-framework/utils/index.js | 8 +++ graph/mutators/user.js | 53 +++++++++++-------- graph/resolvers/comment.js | 6 ++- graph/typeDefs.graphql | 5 +- locales/en.yml | 1 + models/schema/comment.js | 8 ++- perms/constants/query.js | 1 + perms/reducers/query.js | 1 + services/migration/helpers.js | 10 +++- 11 files changed, 75 insertions(+), 31 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Comment.js b/client/coral-embed-stream/src/tabs/stream/components/Comment.js index 5df119fbc..e60756f39 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.js @@ -27,6 +27,7 @@ import { getActionSummary, iPerformedThisAction, isCommentActive, + isCommentDeleted, getShallowChanges, } from 'coral-framework/utils'; import t from 'coral-framework/services/i18n'; @@ -742,8 +743,14 @@ export default class Comment extends React.Component { return (
- {this.renderComment()} - {activeReplyBox === comment.id && this.renderReplyBox()} + {isCommentDeleted(comment) ? ( + + ) : ( +
+ {this.renderComment()} + {activeReplyBox === comment.id && this.renderReplyBox()} +
+ )} {this.renderRepliesContainer()}
); diff --git a/client/coral-embed-stream/src/tabs/stream/components/CommentTombstone.js b/client/coral-embed-stream/src/tabs/stream/components/CommentTombstone.js index a10369850..95184dffd 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/CommentTombstone.js +++ b/client/coral-embed-stream/src/tabs/stream/components/CommentTombstone.js @@ -13,6 +13,8 @@ class CommentTombstone extends React.Component { return t('framework.comment_is_ignored'); case 'reject': return t('framework.comment_is_rejected'); + case 'deleted': + return t('framework.comment_is_deleted'); default: return t('framework.comment_is_hidden'); } diff --git a/client/coral-framework/utils/index.js b/client/coral-framework/utils/index.js index 66792b9b3..f69e83bdc 100644 --- a/client/coral-framework/utils/index.js +++ b/client/coral-framework/utils/index.js @@ -1,6 +1,7 @@ import { gql } from 'react-apollo'; import t from 'coral-framework/services/i18n'; import union from 'lodash/union'; +import get from 'lodash/get'; import { capitalize } from 'coral-framework/helpers/strings'; import assignWith from 'lodash/assignWith'; import mapValues from 'lodash/mapValues'; @@ -221,6 +222,13 @@ export function isCommentActive(commentStatus) { return ['NONE', 'ACCEPTED'].indexOf(commentStatus) >= 0; } +export function isCommentDeleted(comment) { + return ( + get(comment, 'body', null) === null || + get(comment, 'deleted_at', null) !== null + ); +} + export function getShallowChanges(a, b) { return union(Object.keys(a), Object.keys(b)).filter(key => a[key] !== b[key]); } diff --git a/graph/mutators/user.js b/graph/mutators/user.js index 0343e1f2e..f5bf3c930 100644 --- a/graph/mutators/user.js +++ b/graph/mutators/user.js @@ -92,7 +92,7 @@ const delUser = async (ctx, id) => { updateBatchSize: 10000, }); - // Remove all actions against comments. + // Remove all actions against this users comments. await transformSingleWithCursor( Action.collection.find({ user_id: user.id, item_type: 'COMMENTS' }), actionDecrTransformer, @@ -111,34 +111,41 @@ const delUser = async (ctx, id) => { .setOptions({ multi: true }) .remove(); - // Removes all the user's reply counts on each of the comments that they - // have commented on. + // For each comment that the user has authored, purge the comment data from it + // and unset their id from those comments. await transformSingleWithCursor( - Comment.collection.aggregate([ - { $match: { author_id: user.id } }, - { - $group: { - _id: '$parent_id', - count: { $sum: 1 }, - }, - }, - ]), - ({ _id: parent_id, count }) => ({ - query: { id: parent_id }, - update: { - $inc: { - reply_count: -1 * count, - }, + Comment.collection.find({ author_id: user.id }), + ({ + id, + asset_id, + status, + parent_id, + reply_count, + created_at, + updated_at, + }) => ({ + query: { id }, + replace: { + id, + body: null, + body_history: [], + asset_id, + author_id: null, + status_history: [], + status, + parent_id, + reply_count, + action_counts: {}, + tags: [], + metadata: {}, + deleted_at: new Date(), + created_at, + updated_at, }, }), Comment ); - // Remove all the user's comments. - await Comment.where({ author_id: user.id }) - .setOptions({ multi: true }) - .remove(); - // Remove the user. await user.remove(); }; diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index 064835f8f..e562c062c 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -4,6 +4,7 @@ const { SEARCH_ACTIONS, SEARCH_COMMENT_STATUS_HISTORY, VIEW_BODY_HISTORY, + VIEW_COMMENT_DELETED_AT, } = require('../../perms/constants'); const { decorateWithTags, @@ -23,7 +24,9 @@ const Comment = { return Comments.get.load(parent_id); }, user({ author_id }, _, { loaders: { Users } }) { - return Users.getByID.load(author_id); + if (author_id) { + return Users.getByID.load(author_id); + } }, replies({ id, asset_id, reply_count }, { query }, { loaders: { Comments } }) { // Don't bother looking up replies if there aren't any there! @@ -83,6 +86,7 @@ decorateWithTags(Comment); decorateWithPermissionCheck(Comment, { actions: [SEARCH_ACTIONS], status_history: [SEARCH_COMMENT_STATUS_HISTORY], + deleted_at: [VIEW_COMMENT_DELETED_AT], }); // Protect privileged fields. diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index f94322344..9a03e2729 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -503,7 +503,7 @@ type Comment { id: ID! # The actual comment data. - body: String! + body: String # The body history of the comment. Requires the `ADMIN` or `MODERATOR` role or # the author. @@ -537,6 +537,9 @@ type Comment { # The status history of the comment. Requires the `ADMIN` or `MODERATOR` role. status_history: [CommentStatusHistory!] + # The date that the comment was deleted at if it was. + deleted_at: Date + # The time when the comment was created created_at: Date! diff --git a/locales/en.yml b/locales/en.yml index 50845b96f..f4c477710 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -258,6 +258,7 @@ en: comment: comment comment_is_ignored: "This comment is hidden because you ignored this user." comment_is_rejected: "You have rejected this comment." + comment_is_deleted: "This comment was deleted." comment_is_hidden: "This comment is not available." comments: comments configure_stream: "Configure" diff --git a/models/schema/comment.js b/models/schema/comment.js index 6ef5434d5..985f5c399 100644 --- a/models/schema/comment.js +++ b/models/schema/comment.js @@ -58,8 +58,6 @@ const Comment = new Schema( }, body: { type: String, - required: [true, 'The body is required.'], - minlength: 2, }, body_history: [BodyHistoryItemSchema], asset_id: String, @@ -89,6 +87,12 @@ const Comment = new Schema( // Tags are added by the self or by administrators. tags: [TagLinkSchema], + // deleted_at stores the date that the given comment was deleted. + deleted_at: { + type: Date, + default: null, + }, + // Additional metadata stored on the field. metadata: { default: {}, diff --git a/perms/constants/query.js b/perms/constants/query.js index 197c5d9f9..0c7f4024d 100644 --- a/perms/constants/query.js +++ b/perms/constants/query.js @@ -11,4 +11,5 @@ module.exports = { VIEW_USER_ROLE: 'VIEW_USER_ROLE', VIEW_USER_EMAIL: 'VIEW_USER_EMAIL', VIEW_BODY_HISTORY: 'VIEW_BODY_HISTORY', + VIEW_COMMENT_DELETED_AT: 'VIEW_COMMENT_DELETED_AT', }; diff --git a/perms/reducers/query.js b/perms/reducers/query.js index ed507139d..5c8b17307 100644 --- a/perms/reducers/query.js +++ b/perms/reducers/query.js @@ -14,6 +14,7 @@ module.exports = (user, perm) => { case types.VIEW_USER_ROLE: case types.VIEW_USER_EMAIL: case types.VIEW_BODY_HISTORY: + case types.VIEW_COMMENT_DELETED_AT: return check(user, ['ADMIN', 'MODERATOR']); case types.LIST_OWN_TOKENS: return check(user, ['ADMIN']); diff --git a/services/migration/helpers.js b/services/migration/helpers.js index 5eb33aadf..49acc78aa 100644 --- a/services/migration/helpers.js +++ b/services/migration/helpers.js @@ -10,8 +10,14 @@ const processUpdates = async (model, updates) => { // Create a new batch operation. const bulk = model.collection.initializeUnorderedBulkOp(); - for (const { query, update } of updates) { - bulk.find(query).updateOne(update); + for (const { query, update, replace } of updates) { + if (update) { + bulk.find(query).updateOne(update); + } else if (replace) { + bulk.find(query).replaceOne(replace); + } else { + throw new Error('invalid update object provided'); + } } // Execute the bulk update operation. From 68461308c68c1cedd3810bc6336daa9c65dd95b2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 19 Apr 2018 13:37:14 -0600 Subject: [PATCH 03/97] pull ignored users from db --- graph/mutators/user.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/graph/mutators/user.js b/graph/mutators/user.js index f5bf3c930..68112e732 100644 --- a/graph/mutators/user.js +++ b/graph/mutators/user.js @@ -111,6 +111,15 @@ const delUser = async (ctx, id) => { .setOptions({ multi: true }) .remove(); + // Remove the user from all other user's ignore lists. + await User.update( + { ignoresUsers: user.id }, + { + $pull: { ignoresUsers: user.id }, + }, + { multi: true } + ); + // For each comment that the user has authored, purge the comment data from it // and unset their id from those comments. await transformSingleWithCursor( From 2e013c33ac1e834bbae94bd470f64cbf18390f21 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 19 Apr 2018 17:19:14 -0600 Subject: [PATCH 04/97] 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 05/97] 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 06/97] 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 07/97] 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 08/97] 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 09/97] 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 10/97] 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 11/97] 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 12/97] 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 { />
- +
+ ); + } +} + +export default DeleteMyAccount; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js new file mode 100644 index 000000000..2f64a3e2e --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { Dialog } from 'plugin-api/beta/client/components/ui'; + +class DeleteMyAccount extends React.Component { + render() { + return Holaa; + } +} + +export default DeleteMyAccount; From 876eb1e413d0048996388ad72d54aae52f7a482a Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 00:17:57 -0300 Subject: [PATCH 18/97] wip --- .../components/DeleteMyAccount.js | 2 +- .../components/DeleteMyAccountDialog.css | 95 +++++++++++++++++++ .../components/DeleteMyAccountDialog.js | 67 ++++++++++++- .../components/StepProgress.css | 9 ++ .../components/StepProgress.js | 17 ++++ 5 files changed, 185 insertions(+), 5 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js index 4b48e15ce..95b11ab49 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js @@ -24,7 +24,7 @@ class DeleteMyAccount extends React.Component { render() { return (
- +

i.itemIcon { + font-size: 1.3em; + } +} + + + + + +/** Step **/ + diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js index 2f64a3e2e..fd0b1e255 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -1,10 +1,69 @@ import React from 'react'; -import { Dialog } from 'plugin-api/beta/client/components/ui'; +import cn from 'classnames'; +import PropTypes from 'prop-types'; +import styles from './DeleteMyAccountDialog.css'; +import { Button, Dialog, Icon } from 'plugin-api/beta/client/components/ui'; +import StepProgress from './StepProgress'; + +const initialState = { step: 0 }; + +class DeleteMyAccountDialog extends React.Component { + state = initialState; + + goToNextStep = () => { + this.setState(state => ({ + step: state.step + 1, + })); + }; + + clear = () => { + this.setState(initialState); + }; -class DeleteMyAccount extends React.Component { render() { - return Holaa; + return ( + + + × + +

Delete My Account

+ +
+

+ You are attempting to delete your account. This means: +

+
    +
  • + + + All of your comments are removed from this site + +
  • +
  • + + + All of your comments are deleted from our database + +
  • +
  • + + + Your username and email address are removed from our system + +
  • +
+
+
+ + +
+
+ ); } } -export default DeleteMyAccount; +DeleteMyAccountDialog.propTypes = { + closeDialog: PropTypes.func.isRequired, +}; + +export default DeleteMyAccountDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css new file mode 100644 index 000000000..90a8a558c --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css @@ -0,0 +1,9 @@ +.step { + &.current { + color: rgba(0, 205, 115, 0.3); + } + + &.completed { + color: #00CD73; + } +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js new file mode 100644 index 000000000..c0c2d9712 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js @@ -0,0 +1,17 @@ +import React from 'react'; +import styles from './StepProgress.css'; +import { Icon } from 'plugin-api/beta/client/components/ui'; + +class StepProgress extends React.Component { + render() { + return ( +
+ + + +
+ ); + } +} + +export default StepProgress; From 867523140c3f70a9cf2161113948f90559f1665c Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 14:09:43 -0300 Subject: [PATCH 19/97] Adding StepProgress component, and all the steps --- .../components/DeleteMyAccountDialog.css | 60 +----------------- .../components/DeleteMyAccountDialog.js | 51 ++++++---------- .../components/DeleteMyAccountFinalStep.js | 40 ++++++++++++ .../components/DeleteMyAccountStep.css | 61 +++++++++++++++++++ .../components/DeleteMyAccountStep0.js | 43 +++++++++++++ .../components/DeleteMyAccountStep1.js | 30 +++++++++ .../components/DeleteMyAccountStep2.js | 27 ++++++++ .../components/DeleteMyAccountStep3.js | 31 ++++++++++ .../components/StepProgress.css | 23 +++++++ .../components/StepProgress.js | 39 ++++++++++-- 10 files changed, 312 insertions(+), 93 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css index 802b63197..db44ebf6d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css @@ -1,7 +1,7 @@ .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; + width: 380px; top: 10px; font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif; font-size: 14px; @@ -26,7 +26,7 @@ } .title { - font-size: 1.3em; + font-size: 1.2em; margin-bottom: 8px; } @@ -36,60 +36,4 @@ margin: 0; } -.button { - color: #787D80; - border-radius: 2px; - background-color: transparent; - height: 30px; - font-size: 0.9em; - line-height: normal; - - &:hover { - background-color: #eaeaea; - } - - &.cancel { - background-color: transparent; - color: #787D80; - } - - &.proceed { - background-color: #3498DB; - color: white; - } -} - -.actions { - text-align: right; -} - -.list { - padding: 0; - margin: 10px 0; - list-style: none; -} - -.item { - display: flex; - margin-bottom: 10px; - - .itemIcon { - flex-grow: 0; - } - - .text { - flex-grow: 1; - padding-left: 10px; - } - - > i.itemIcon { - font-size: 1.3em; - } -} - - - - - -/** Step **/ diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js index fd0b1e255..599816e2d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -1,9 +1,13 @@ import React from 'react'; -import cn from 'classnames'; import PropTypes from 'prop-types'; import styles from './DeleteMyAccountDialog.css'; -import { Button, Dialog, Icon } from 'plugin-api/beta/client/components/ui'; +import { Dialog } from 'plugin-api/beta/client/components/ui'; import StepProgress from './StepProgress'; +import DeleteMyAccountStep0 from './DeleteMyAccountStep0'; +import DeleteMyAccountStep1 from './DeleteMyAccountStep1'; +import DeleteMyAccountStep2 from './DeleteMyAccountStep2'; +import DeleteMyAccountStep3 from './DeleteMyAccountStep3'; +import DeleteMyAccountFinalStep from './DeleteMyAccountFinalStep'; const initialState = { step: 0 }; @@ -21,6 +25,7 @@ class DeleteMyAccountDialog extends React.Component { }; render() { + const { step } = this.state; return ( @@ -28,35 +33,19 @@ class DeleteMyAccountDialog extends React.Component {

Delete My Account

-
-

- You are attempting to delete your account. This means: -

-
    -
  • - - - All of your comments are removed from this site - -
  • -
  • - - - All of your comments are deleted from our database - -
  • -
  • - - - Your username and email address are removed from our system - -
  • -
-
-
- - -
+ {step === 0 && ( + + )} + {step === 1 && ( + + )} + {step === 2 && ( + + )} + {step === 3 && ( + + )} + {step === 4 && }
); } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js new file mode 100644 index 000000000..004270f4d --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js @@ -0,0 +1,40 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import styles from './DeleteMyAccountStep.css'; + +const DeleteMyAccountFinalStep = () => ( +
+

+ Your request has been submitted and confirmation has been sent to the + email address associated with your account. +

+ Your account is scheduled to be deleted at: + + Account Deletion Date and Time + +

+ Changed your mind? Simply sign in to your account again + before this time and click “ + Cancel Account Deletion Request. + ” +

+

+ Tell us why. Wed like to know why you chose to delete + your account. Send us feedback on our comment system by emailing. +

+
+ + + Note: You will be immediately signed out of your account. + +
+
+); + +export default DeleteMyAccountFinalStep; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css new file mode 100644 index 000000000..8984bf7ac --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css @@ -0,0 +1,61 @@ +.list { + padding: 0; + margin: 20px 0; + list-style: none; +} + +.item { + display: flex; + margin-bottom: 20px; + + .itemIcon { + flex-grow: 0; + } + + .text { + flex-grow: 1; + padding-left: 10px; + } + + > i.itemIcon { + font-size: 1.3em; + } +} + +.button { + color: #787D80; + border-radius: 2px; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; + + &:hover { + background-color: #eaeaea; + } + + &.cancel { + background-color: transparent; + color: #787D80; + } + + &.proceed { + background-color: #3498DB; + color: white; + } +} + +.actions { + text-align: right; +} + +.title { + font-size: 1.2em; + margin-bottom: 8px; +} + +.description { + font-size: 1em; + line-height: 20px; + margin: 0; +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js new file mode 100644 index 000000000..ddddf7141 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js @@ -0,0 +1,43 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import styles from './DeleteMyAccountStep.css'; + +const DeleteMyAccountStep0 = () => ( +
+

+ You are attempting to delete your account. This means: +

+
    +
  • + + + All of your comments are removed from this site + +
  • +
  • + + + All of your comments are deleted from our database + +
  • +
  • + + + Your username and email address are removed from our system + +
  • +
+
+ + +
+
+); + +export default DeleteMyAccountStep0; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js new file mode 100644 index 000000000..602bb33b7 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js @@ -0,0 +1,30 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button } from 'plugin-api/beta/client/components/ui'; +import styles from './DeleteMyAccountStep.css'; + +const DeleteMyAccountStep1 = () => ( +
+

When will my account be deleted?

+

+ Your account will be deleted 24 hours after your request has been + submitted. +

+

Can I still write comments until my account is deleted?

+

+ No. Once youve requested account deletion, you can no longer write + comments, reply to comments, or select reactions. +

+
+ + +
+
+); + +export default DeleteMyAccountStep1; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js new file mode 100644 index 000000000..7b069ca3d --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js @@ -0,0 +1,27 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button } from 'plugin-api/beta/client/components/ui'; +import styles from './DeleteMyAccountStep.css'; + +const DeleteMyAccountStep1 = () => ( +
+

+ Before your account is deleted, we recommend you download your comment + history for your records. After your account is deleted, you will be + unable to request your comment history. +

+

To download your comment history go to:

+ My Profile Download My Comment History +
+ + +
+
+); + +export default DeleteMyAccountStep1; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js new file mode 100644 index 000000000..bf3dea674 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js @@ -0,0 +1,31 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button } from 'plugin-api/beta/client/components/ui'; +import styles from './DeleteMyAccountStep.css'; + +const DeleteMyAccountStep1 = () => ( +
+

Are you sure you want to delete your account?

+

+ To confirm you would like to delete your account please type in the + following phrase into the text box below: +

+ +
+ + +
+
+); + +export default DeleteMyAccountStep1; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css index 90a8a558c..68fab06a9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css @@ -1,4 +1,9 @@ .step { + color: #BBBEBF; + background-color: white; + padding: 6px; + z-index: 10; + &.current { color: rgba(0, 205, 115, 0.3); } @@ -6,4 +11,22 @@ &.completed { color: #00CD73; } +} + +.line { + position: absolute; + border: solid 2px #BBBEBF; + width: 100%; + box-sizing: border-box; + margin: 0; + padding: 0; +} + +.container { + display: flex; + position: relative; + justify-content: space-between; + align-items: center; + height: 50px; + margin: 0 20px; } \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js index c0c2d9712..e11bf46d5 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js @@ -1,17 +1,48 @@ import React from 'react'; +import cn from 'classnames'; +import PropTypes from 'prop-types'; import styles from './StepProgress.css'; import { Icon } from 'plugin-api/beta/client/components/ui'; +const CheckItem = ({ current = false, completed = false }) => ( + + + +); + +CheckItem.propTypes = { + current: PropTypes.bool.isRequired, + completed: PropTypes.bool.isRequired, +}; + +const Line = () =>
; + class StepProgress extends React.Component { render() { + const { currentStep, totalSteps } = this.props; return ( -
- - - +
+ {Array.from({ length: totalSteps }).map((_, i) => ( + + ))} +
); } } +StepProgress.propTypes = { + currentStep: PropTypes.number.isRequired, + totalSteps: PropTypes.number.isRequired, +}; + export default StepProgress; From f4cb16e56eb7bdf681f68f35c2af3a853ca1e625 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 14:14:43 -0300 Subject: [PATCH 20/97] styles wip --- .../profile-settings/components/DeleteMyAccountStep0.js | 4 ++-- .../profile-settings/components/DeleteMyAccountStep1.js | 4 ++-- .../profile-settings/components/DeleteMyAccountStep2.js | 4 ++-- .../profile-settings/components/DeleteMyAccountStep3.js | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js index ddddf7141..f81d912ea 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js @@ -3,7 +3,7 @@ import cn from 'classnames'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep0 = () => ( +const DeleteMyAccountStep0 = props => (

You are attempting to delete your account. This means: @@ -32,7 +32,7 @@ const DeleteMyAccountStep0 = () => ( diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js index 602bb33b7..d3b399f44 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js @@ -3,7 +3,7 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep1 = () => ( +const DeleteMyAccountStep1 = props => (

When will my account be deleted?

@@ -19,7 +19,7 @@ const DeleteMyAccountStep1 = () => ( diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js index 7b069ca3d..47c89e4c1 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js @@ -3,7 +3,7 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep1 = () => ( +const DeleteMyAccountStep1 = props => (

Before your account is deleted, we recommend you download your comment @@ -16,7 +16,7 @@ const DeleteMyAccountStep1 = () => ( diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js index bf3dea674..534ea9db8 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js @@ -3,7 +3,7 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep1 = () => ( +const DeleteMyAccountStep1 = props => (

Are you sure you want to delete your account?

@@ -20,7 +20,7 @@ const DeleteMyAccountStep1 = () => ( From bd21d9a1a14a2febf10115f8f5d1be4aa6fdc8a0 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 14:19:43 -0300 Subject: [PATCH 21/97] fix b --- .../client/profile-settings/components/ConfirmChangesDialog.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js index 59eac894f..0031bcb71 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ConfirmChangesDialog.js @@ -44,7 +44,8 @@ class ConfirmChangesDialog extends React.Component { goToNextStep: this.goToNextStep, clear: this.clear, cancel: this.cancel, - next: this.state.step === steps.length ? this.finish : this.continue, + next: + this.state.step === steps.length - 1 ? this.finish : this.continue, }); }); }; From b014225b73bbad8b286340531a3604f50e1d9ae5 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 1 May 2018 12:02:39 -0600 Subject: [PATCH 22/97] fixes for index creation --- models/index.js | 34 +++++++++++++++++++++ models/schema/index.js | 15 +-------- plugin-api/beta/server/getReactionConfig.js | 2 +- services/mongoose.js | 6 +--- 4 files changed, 37 insertions(+), 20 deletions(-) create mode 100644 models/index.js diff --git a/models/index.js b/models/index.js new file mode 100644 index 000000000..c783f43e7 --- /dev/null +++ b/models/index.js @@ -0,0 +1,34 @@ +const { reduce } = require('lodash'); +const { CREATE_MONGO_INDEXES } = require('../config'); + +const Action = require('./action'); +const Asset = require('./asset'); +const Comment = require('./comment'); +const Migration = require('./migration'); +const Setting = require('./setting'); +const User = require('./user'); + +const schema = { Action, Asset, Comment, Migration, Setting, User }; + +// Provide the schema to each of the plugins so that they can add in indexes if +// it is enabled. +if (CREATE_MONGO_INDEXES) { + const plugins = require('../services/plugins'); + + // Remap all of the models to their driver reference via the `collection` + // field. + const collections = reduce( + schema, + (collections, model, modelName) => { + collections[modelName] = model.collection; + return collections; + }, + {} + ); + + // Defer the instantiation of the index caller functions when we're creating + // indexes. + plugins.defer('server', 'indexes', ({ indexes }) => { + indexes(collections); + }); +} diff --git a/models/schema/index.js b/models/schema/index.js index 976b437c0..c33402078 100644 --- a/models/schema/index.js +++ b/models/schema/index.js @@ -1,5 +1,3 @@ -const { CREATE_MONGO_INDEXES } = require('../../config'); - const Action = require('./action'); const Asset = require('./asset'); const Comment = require('./comment'); @@ -7,15 +5,4 @@ const Migration = require('./migration'); const Setting = require('./setting'); const User = require('./user'); -const schema = { Action, Asset, Comment, Migration, Setting, User }; - -// Provide the schema to each of the plugins so that they can add in indexes if -// it is enabled. -if (CREATE_MONGO_INDEXES) { - const plugins = require('../../services/plugins'); - plugins.get('server', 'indexes').map(({ indexes }) => { - indexes(schema); - }); -} - -module.exports = schema; +module.exports = { Action, Asset, Comment, Migration, Setting, User }; diff --git a/plugin-api/beta/server/getReactionConfig.js b/plugin-api/beta/server/getReactionConfig.js index da075d76c..68dc3dd5d 100644 --- a/plugin-api/beta/server/getReactionConfig.js +++ b/plugin-api/beta/server/getReactionConfig.js @@ -128,7 +128,7 @@ function getReactionConfig(reaction) { return { typeDefs, indexes: ({ Comment }) => { - Comment.index( + Comment.ensureIndex( { created_at: 1, [`action_counts.${sc(reaction)}`]: 1, diff --git a/services/mongoose.js b/services/mongoose.js index 4e242cf47..48cd34012 100644 --- a/services/mongoose.js +++ b/services/mongoose.js @@ -63,10 +63,6 @@ module.exports = mongoose; // here. No point also in importing this if we're not actually doing any // indexing now. if (CREATE_MONGO_INDEXES) { - require('../models/action'); - require('../models/asset'); - require('../models/comment'); - require('../models/setting'); - require('../models/user'); + require('../models'); require('./migration'); } From 3bb91f683320f706af312edb7863258c35dbdabd Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 15:43:10 -0300 Subject: [PATCH 23/97] Adding withRequestAccountDeletion, withRequestDownloadLink, withCancelAccountDeletion --- client/coral-framework/graphql/fragments.js | 5 +- client/coral-framework/graphql/mutations.js | 51 +++++++++++++++++++ .../components/DeleteMyAccountDialog.css | 4 +- .../components/DeleteMyAccountFinalStep.js | 24 ++++++--- .../components/DeleteMyAccountStep.css | 47 +++++++++++++++++ .../components/DeleteMyAccountStep1.js | 6 ++- .../components/DeleteMyAccountStep2.js | 8 ++- .../components/DeleteMyAccountStep3.js | 6 ++- 8 files changed, 134 insertions(+), 17 deletions(-) diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index a62fd6d92..f30cb1e63 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -25,6 +25,9 @@ export default { 'UnsuspendUserResponse', 'UpdateAssetSettingsResponse', 'UpdateAssetStatusResponse', - 'UpdateSettingsResponse' + 'UpdateSettingsResponse', + 'RequestAccountDeletionResponse', + 'RequestDownloadLinkResponse', + 'CancelAccountDeletionResponse' ), }; diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index bd31be630..bf412b189 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -623,6 +623,57 @@ export const withUpdateSettings = withMutation( } ); +export const withRequestAccountDeletion = withMutation( + gql` + mutation RequestAccountDeletion { + requestAccountDeletion { + ...RequestAccountDeletionResponse + } + } + `, + { + props: ({ mutate }) => ({ + requestAccountDeletion: () => { + return mutate(); + }, + }), + } +); + +export const withRequestDownloadLink = withMutation( + gql` + mutation RequestDownloadLink { + requestDownloadLink { + ...RequestDownloadLinkResponse + } + } + `, + { + props: ({ mutate }) => ({ + requestDownloadLink: () => { + return mutate(); + }, + }), + } +); + +export const withCancelAccountDeletion = withMutation( + gql` + mutation RequestDownloadLink { + cancelAccountDeletion { + ...CancelAccountDeletionResponse + } + } + `, + { + props: ({ mutate }) => ({ + cancelAccountDeletion: () => { + return mutate(); + }, + }), + } +); + export const withUpdateAssetSettings = withMutation( gql` mutation UpdateAssetSettings($id: ID!, $input: AssetSettingsInput!) { diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css index db44ebf6d..44dcad0cf 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css @@ -34,6 +34,4 @@ font-size: 1em; line-height: 20px; margin: 0; -} - - +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js index 004270f4d..22cf476e5 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js @@ -9,30 +9,40 @@ const DeleteMyAccountFinalStep = () => ( Your request has been submitted and confirmation has been sent to the email address associated with your account.

- Your account is scheduled to be deleted at: - - Account Deletion Date and Time - + +
+ + Your account is scheduled to be deleted at: + + + + Account Deletion Date and Time + +
+

Changed your mind? Simply sign in to your account again before this time and click “ Cancel Account Deletion Request.

+

Tell us why. Wed like to know why you chose to delete your account. Send us feedback on our comment system by emailing.

-
+ +
- + Note: You will be immediately signed out of your account. - +
); diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css index 8984bf7ac..98b73f376 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css @@ -43,10 +43,22 @@ background-color: #3498DB; color: white; } + + &.danger { + background-color: #FA4643; + color: white; + } } .actions { text-align: right; + padding-top: 20px; + + &.columnView { + display: flex; + flex-direction: column; + align-items: center; + } } .title { @@ -58,4 +70,39 @@ font-size: 1em; line-height: 20px; margin: 0; + margin-bottom: 15px; +} + +.box { + display: flex; + flex-direction: column; + margin-bottom: 15px; +} + +.note { + margin: 10px 0; +} + +.subTitle { + font-size: 1em; + margin-bottom: 8px; +} + +.textBox { + background-color: #F1F2F2; + border: none; + width: 100%; + padding: 15px; + box-sizing: border-box; + color: #3B4A53; + font-size: 1em; +} + +.block { + display: block; + margin-top: 2px; +} + +.step { + padding-top: 20px; } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js index d3b399f44..1d26190bc 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js @@ -5,12 +5,14 @@ import styles from './DeleteMyAccountStep.css'; const DeleteMyAccountStep1 = props => (
-

When will my account be deleted?

+

When will my account be deleted?

Your account will be deleted 24 hours after your request has been submitted.

-

Can I still write comments until my account is deleted?

+

+ Can I still write comments until my account is deleted?{' '} +

No. Once youve requested account deletion, you can no longer write comments, reply to comments, or select reactions. diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js index 47c89e4c1..3337c0b94 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js @@ -10,8 +10,12 @@ const DeleteMyAccountStep1 = props => ( history for your records. After your account is deleted, you will be unable to request your comment history.

-

To download your comment history go to:

- My Profile Download My Comment History +

+ To download your comment history go to: + + My Profile {`>`} Download My Comment History + +

+ {scheduledDeletionDate ? ( + + ) : ( + + )}
); } @@ -63,6 +98,7 @@ DeleteMyAccount.propTypes = { requestAccountDeletion: PropTypes.func.isRequired, cancelAccountDeletion: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, + root: PropTypes.object.isRequired, }; export default DeleteMyAccount; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js index 599816e2d..7c7c47d0b 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -24,28 +24,45 @@ class DeleteMyAccountDialog extends React.Component { this.setState(initialState); }; + cancel = () => { + this.clear(); + this.closeDialog(); + }; + render() { const { step } = this.state; return ( - + ×

Delete My Account

{step === 0 && ( - + )} {step === 1 && ( - + )} {step === 2 && ( - + )} {step === 3 && ( - + )} - {step === 4 && } + {step === 4 && }
); } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js index 22cf476e5..764dae302 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js @@ -1,9 +1,10 @@ import React from 'react'; import cn from 'classnames'; +import PropTypes from 'prop-types'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountFinalStep = () => ( +const DeleteMyAccountFinalStep = props => (

Your request has been submitted and confirmation has been sent to the @@ -35,7 +36,7 @@ const DeleteMyAccountFinalStep = () => (

); +DeleteMyAccountFinalStep.propTypes = { + finish: PropTypes.func.isRequired, +}; + export default DeleteMyAccountFinalStep; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js index f81d912ea..901466d3b 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; @@ -29,7 +30,12 @@ const DeleteMyAccountStep0 = props => (
- +
); +DeleteMyAccountStep0.propTypes = { + goToNextStep: PropTypes.func.isRequired, + cancel: PropTypes.func.isRequired, +}; + export default DeleteMyAccountStep0; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js index 1d26190bc..e74611b05 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; @@ -18,7 +19,12 @@ const DeleteMyAccountStep1 = props => ( comments, reply to comments, or select reactions.

- +
); +DeleteMyAccountStep1.propTypes = { + goToNextStep: PropTypes.func.isRequired, + cancel: PropTypes.func.isRequired, +}; + export default DeleteMyAccountStep1; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js index 3337c0b94..8ef14445e 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep1 = props => ( +const DeleteMyAccountStep2 = props => (

Before your account is deleted, we recommend you download your comment @@ -17,7 +18,12 @@ const DeleteMyAccountStep1 = props => (

- +
); -export default DeleteMyAccountStep1; +DeleteMyAccountStep2.propTypes = { + goToNextStep: PropTypes.func.isRequired, + cancel: PropTypes.func.isRequired, +}; + +export default DeleteMyAccountStep2; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js index 8cff542c1..f91ca42c7 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js @@ -1,9 +1,10 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep1 = props => ( +const DeleteMyAccountStep3 = props => (

Are you sure you want to delete your account? @@ -19,7 +20,12 @@ const DeleteMyAccountStep1 = props => ( value="delete" />
- +
); -export default DeleteMyAccountStep1; +DeleteMyAccountStep3.propTypes = { + goToNextStep: PropTypes.func.isRequired, + cancel: PropTypes.func.isRequired, +}; + +export default DeleteMyAccountStep3; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js b/plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js index b88780f1f..a9c033853 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js @@ -12,7 +12,7 @@ const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); const withData = withFragments({ root: gql` - fragment TalkIgnoreUser_IgnoredUserSection_root on RootQuery { + fragment Talk_DeleteMyAccount_root on RootQuery { me { scheduledDeletionDate } From 5eead8b7ee0edb3545b9940284252085bbaa0d97 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 16:32:42 -0300 Subject: [PATCH 26/97] Adding AccountDeletionRequestedSign.js --- .../AccountDeletionRequestedSign.css | 23 ++++++ .../AccountDeletionRequestedSign.js | 26 +++++++ .../components/DeleteMyAccountDialog.js | 2 + .../components/DeleteMyAccountFinalStep.js | 4 +- .../components/DeleteMyAccountStep.css | 7 ++ .../components/DeleteMyAccountStep3.js | 72 +++++++++++-------- 6 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css new file mode 100644 index 000000000..413a3852b --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css @@ -0,0 +1,23 @@ +.container { + border : solid 1px #F26563; + border-radius: 2px; + color: #3B4A53; +} + +.button { + color: #787D80; + border-radius: 2px; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; + + &:hover { + background-color: #eaeaea; + } + + &.secondary { + background-color: #787D80; + color: white; + } +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js new file mode 100644 index 000000000..7d1941fa7 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js @@ -0,0 +1,26 @@ +import React from 'react'; +import cn from 'classnames'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import styles from './AccountDeletionRequestedSign.css'; + +class AccountDeletionRequestedSign extends React.Component { + render() { + return ( +
+

+ Account Deletion Requested +

+

+ A request to delete your account was received on. If you would like to + continue leaving comments, replies or reactions, you may cancel your + request to delete your account below before +

+ +
+ ); + } +} + +export default AccountDeletionRequestedSign; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js index 7c7c47d0b..4e3a1aa99 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -60,6 +60,7 @@ class DeleteMyAccountDialog extends React.Component { )} {step === 4 && } @@ -70,6 +71,7 @@ class DeleteMyAccountDialog extends React.Component { DeleteMyAccountDialog.propTypes = { closeDialog: PropTypes.func.isRequired, + requestAccountDeletion: PropTypes.func.isRequired, }; export default DeleteMyAccountDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js index 764dae302..ccbbf61fa 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js @@ -11,12 +11,12 @@ const DeleteMyAccountFinalStep = props => ( email address associated with your account.

-
+
Your account is scheduled to be deleted at: - + Account Deletion Date and Time
diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css index 98b73f376..53d8ecef8 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css @@ -106,3 +106,10 @@ .step { padding-top: 20px; } + +.scheduledDeletion { + i.timeIcon { + font-size: 1.2em; + padding: 4px; + } +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js index f91ca42c7..54f49f375 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js @@ -4,40 +4,50 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -const DeleteMyAccountStep3 = props => ( -
-

- Are you sure you want to delete your account? -

-

- To confirm you would like to delete your account please type in the - following phrase into the text box below: -

- -
- - -
-
-); +class DeleteMyAccountStep3 extends React.Component { + deleteAndContinue = () => { + this.props.requestAccountDeletion(); + this.props.goToNextStep(); + }; + + render() { + return ( +
+

+ Are you sure you want to delete your account? +

+

+ To confirm you would like to delete your account please type in the + following phrase into the text box below: +

+ +
+ + +
+
+ ); + } +} DeleteMyAccountStep3.propTypes = { goToNextStep: PropTypes.func.isRequired, + requestAccountDeletion: PropTypes.func.isRequired, cancel: PropTypes.func.isRequired, }; From ff7ee2aefc61522cbef173e4e5d3a31fcf7ff3fa Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 17:18:58 -0300 Subject: [PATCH 27/97] Updating cache --- client/coral-framework/graphql/mutations.js | 58 ++++++++++++++++++- locales/en.yml | 1 + plugins/talk-plugin-auth/client/index.js | 8 ++- .../AccountDeletionRequestedSign.css | 23 -------- .../AccountDeletionRequestedSign.js | 26 --------- .../components/DeleteMyAccount.css | 10 ++++ .../components/DeleteMyAccount.js | 17 +++++- .../components/DeleteMyAccountDialog.js | 5 +- .../components/DeleteMyAccountStep3.js | 2 +- .../AccountDeletionRequestedSign.css | 44 ++++++++++++++ .../AccountDeletionRequestedSign.js | 55 ++++++++++++++++++ .../AccountDeletionRequestedSign.js | 25 ++++++++ 12 files changed, 216 insertions(+), 58 deletions(-) delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js create mode 100644 plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.css create mode 100644 plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js create mode 100644 plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index bf412b189..89ffd1130 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -634,7 +634,32 @@ export const withRequestAccountDeletion = withMutation( { props: ({ mutate }) => ({ requestAccountDeletion: () => { - return mutate(); + 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: new Date() }, + }, + }); + + proxy.writeQuery({ + query: CancelAccountDeletionQuery, + data, + }); + }, + }); }, }), } @@ -651,7 +676,9 @@ export const withRequestDownloadLink = withMutation( { props: ({ mutate }) => ({ requestDownloadLink: () => { - return mutate(); + return mutate({ + variables: {}, + }); }, }), } @@ -668,7 +695,32 @@ export const withCancelAccountDeletion = withMutation( { props: ({ mutate }) => ({ cancelAccountDeletion: () => { - return mutate(); + 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, + }); + }, + }); }, }), } diff --git a/locales/en.yml b/locales/en.yml index 04fbc0bcb..5806976a4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -246,6 +246,7 @@ en: ALREADY_EXISTS: "Resource already exists" INVALID_ASSET_URL: "Assert URL is invalid" CANNOT_IGNORE_STAFF: "Cannot ignore Staff members." + DELETION_NOT_SCHEDULED: "Deletion was not scheduled" email: "Not a valid E-Mail" 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/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index b432b05b2..98da589f8 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -5,12 +5,18 @@ import translations from './translations.yml'; import Login from './login/containers/Main'; import reducer from './login/reducer'; import DeleteMyAccount from './profile-settings/containers/DeleteMyAccount'; +import AccountDeletionRequestedSign from './stream/containers/AccountDeletionRequestedSign'; export default { reducer, translations, slots: { - stream: [UserBox, SignInButton, SetUsernameDialog], + stream: [ + AccountDeletionRequestedSign, + UserBox, + SignInButton, + SetUsernameDialog, + ], login: [Login], profileSettings: [DeleteMyAccount], }, diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css deleted file mode 100644 index 413a3852b..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.css +++ /dev/null @@ -1,23 +0,0 @@ -.container { - border : solid 1px #F26563; - border-radius: 2px; - color: #3B4A53; -} - -.button { - color: #787D80; - border-radius: 2px; - background-color: transparent; - height: 30px; - font-size: 0.9em; - line-height: normal; - - &:hover { - background-color: #eaeaea; - } - - &.secondary { - background-color: #787D80; - color: white; - } -} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js deleted file mode 100644 index 7d1941fa7..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/AccountDeletionRequestedSign.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import { Button, Icon } from 'plugin-api/beta/client/components/ui'; -import styles from './AccountDeletionRequestedSign.css'; - -class AccountDeletionRequestedSign extends React.Component { - render() { - return ( -
-

- Account Deletion Requested -

-

- A request to delete your account was received on. If you would like to - continue leaving comments, replies or reactions, you may cancel your - request to delete your account below before -

- -
- ); - } -} - -export default AccountDeletionRequestedSign; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css index 2fe139d52..e524d990a 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css @@ -10,4 +10,14 @@ &: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-auth/client/profile-settings/components/DeleteMyAccount.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js index 0fc06f326..9bc5573a1 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js @@ -1,6 +1,7 @@ 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'; @@ -52,6 +53,7 @@ class DeleteMyAccount extends React.Component {

Delete My Account

+

+ Deleting your account will permanently erase your profile and remove + all your comments from this site. +

{scheduledDeletionDate && `You have already submitted a request to delete your account. - Your account will be deleted on ${scheduledDeletionDate}. You may + Your account will be deleted on ${moment( + scheduledDeletionDate + ).format('MMM Do YYYY, h:mm:ss a')}. You may cancel the request until that time`}

{scheduledDeletionDate ? ( diff --git a/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.css b/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.css new file mode 100644 index 000000000..0dada08b5 --- /dev/null +++ b/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.css @@ -0,0 +1,44 @@ +.container { + border: 1px solid #f26563; + border-radius: 2px; + color: #3b4a53; + padding: 20px 10px; + background-color: rgba(242, 101, 99, 0.1); + margin: 20px 0; +} + +.button { + color: #787D80; + border-radius: 2px; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; + + &:hover { + background-color: #eaeaea; + } + + &.secondary { + background-color: #787D80; + color: white; + } +} + +.title { + margin: 0; + i.icon { + font-size: 1em; + padding: 4px; + } +} + +.description { + margin: 0; + padding-left: 22px; + padding-bottom: 15px; +} + +.actions { + text-align: center; +} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js new file mode 100644 index 000000000..a26d28d21 --- /dev/null +++ b/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js @@ -0,0 +1,55 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import styles from './AccountDeletionRequestedSign.css'; +import { getErrorMessages } from 'coral-framework/utils'; + +class AccountDeletionRequestedSign extends React.Component { + cancelAccountDeletion = async () => { + const { cancelAccountDeletion, notify } = this.props; + try { + await cancelAccountDeletion(); + notify( + 'success', + 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.' + ); + } catch (err) { + notify('error', getErrorMessages(err)); + } + }; + + render() { + return ( +
+

+ Account Deletion + Requested +

+

+ A request to delete your account was received on. +

+

+ If you would like to continue leaving comments, replies or reactions, + you may cancel your request to delete your account below before +

+
+ +
+
+ ); + } +} + +AccountDeletionRequestedSign.propTypes = { + cancelAccountDeletion: PropTypes.func.isRequired, + notify: PropTypes.func.isRequired, + root: PropTypes.object.isRequired, +}; + +export default AccountDeletionRequestedSign; diff --git a/plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js b/plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js new file mode 100644 index 000000000..d842ec43f --- /dev/null +++ b/plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js @@ -0,0 +1,25 @@ +import { compose, gql } from 'react-apollo'; +import { bindActionCreators } from 'redux'; +import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs'; +import AccountDeletionRequestedSign from '../components/AccountDeletionRequestedSign'; +import { notify } from 'coral-framework/actions/notification'; +import { withCancelAccountDeletion } from 'plugin-api/beta/client/hocs'; + +const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); + +const withData = withFragments({ + root: gql` + fragment Talk_AccountDeletionRequestedSignIn_root on RootQuery { + me { + scheduledDeletionDate + } + } + `, +}); + +export default compose( + connect(null, mapDispatchToProps), + withCancelAccountDeletion, + withData, + excludeIf(props => !props.root.me.scheduledDeletionDate) +)(AccountDeletionRequestedSign); From 49fcc1ea43ab948480ed70919ef60110f57fe97c Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 17:30:57 -0300 Subject: [PATCH 28/97] Adding missing slot --- client/coral-embed-stream/src/tabs/stream/containers/Stream.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js index 0a7a1951c..17d3132ea 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -372,6 +372,7 @@ const slots = [ 'streamTabsPrepend', 'streamTabPanes', 'streamFilter', + 'stream', ]; const fragments = { From d5fa7455e5d905aff4126d7fa6b2902ee6fd547e Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 17:55:01 -0300 Subject: [PATCH 29/97] Adding InputField --- .../client/components/ErrorMessage.css | 8 + .../client/components/ErrorMessage.js | 17 ++ .../client/components/InputField.css | 80 +++++++ .../client/components/InputField.js | 94 ++++++++ .../components/ChangePassword.css | 87 +++++++ .../components/ChangePassword.js | 223 ++++++++++++++++++ .../components/ChangeUsername.css | 122 ++++++++++ .../components/ChangeUsername.js | 188 +++++++++++++++ .../components/ChangeUsernameDialog.css | 84 +++++++ .../components/ChangeUsernameDialog.js | 117 +++++++++ .../components/DeleteMyAccountDialog.js | 15 +- .../components/DeleteMyAccountStep3.js | 48 +++- .../components/ErrorMessage.css | 8 + .../components/ErrorMessage.js | 17 ++ .../components/InputField.css | 80 +++++++ .../profile-settings/components/InputField.js | 94 ++++++++ .../containers/ChangePassword.js | 12 + .../containers/ChangeUsername.js | 12 + 18 files changed, 1302 insertions(+), 4 deletions(-) create mode 100644 plugins/talk-plugin-auth/client/components/ErrorMessage.css create mode 100644 plugins/talk-plugin-auth/client/components/ErrorMessage.js create mode 100644 plugins/talk-plugin-auth/client/components/InputField.css create mode 100644 plugins/talk-plugin-auth/client/components/InputField.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.css create mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js create mode 100644 plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js diff --git a/plugins/talk-plugin-auth/client/components/ErrorMessage.css b/plugins/talk-plugin-auth/client/components/ErrorMessage.css new file mode 100644 index 000000000..039ffae30 --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/ErrorMessage.css @@ -0,0 +1,8 @@ +.errorMsg { + color: #FA4643; + font-size: 0.9em; +} + +.warningIcon { + color: #FA4643; +} diff --git a/plugins/talk-plugin-auth/client/components/ErrorMessage.js b/plugins/talk-plugin-auth/client/components/ErrorMessage.js new file mode 100644 index 000000000..f39a8fc08 --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/ErrorMessage.js @@ -0,0 +1,17 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './ErrorMessage.css'; +import { Icon } from 'plugin-api/beta/client/components/ui'; + +const ErrorMessage = ({ children }) => ( +
+ + {children} +
+); + +ErrorMessage.propTypes = { + children: PropTypes.node, +}; + +export default ErrorMessage; diff --git a/plugins/talk-plugin-auth/client/components/InputField.css b/plugins/talk-plugin-auth/client/components/InputField.css new file mode 100644 index 000000000..3442befde --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/InputField.css @@ -0,0 +1,80 @@ + +.detailItem { + margin-bottom: 12px; +} + +.detailItemContainer { + display: flex; +} + +.columnDisplay { + flex-direction: column; + + .detailItemMessage { + padding: 4px 0 0; + } +} + +.detailItemContent { + border: solid 1px #787D80; + border-radius: 2px; + background-color: white; + height: 30px; + display: inline-block; + width: 230px; + display: flex; + box-sizing: border-box; + + > .detailIcon { + font-size: 1.2em; + padding: 0 5px; + color: #787D80; + line-height: 30px; + } + + &.error { + border: solid 2px #FA4643; + } + + &.disabled { + background-color: #E0E0E0; + } +} + +.detailLabel { + color: #4C4C4D; + font-size: 1em; + display: block; + margin-bottom: 4px; +} + +.detailValue { + background: transparent; + border: none; + font-size: 1em; + color: #000; + outline: none; + flex: 1; + height: 100%; + box-sizing: border-box; +} + +.detailItemMessage { + flex-grow: 1; + display: flex; + align-items: center; + padding-left: 6px; + padding-top: 16px; + + .warningIcon, .checkIcon { + font-size: 17px; + } +} + +.checkIcon { + color: #00CD73; +} + +.warningIcon { + color: #FA4643; +} diff --git a/plugins/talk-plugin-auth/client/components/InputField.js b/plugins/talk-plugin-auth/client/components/InputField.js new file mode 100644 index 000000000..26937d5b9 --- /dev/null +++ b/plugins/talk-plugin-auth/client/components/InputField.js @@ -0,0 +1,94 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import styles from './InputField.css'; +import ErrorMessage from './ErrorMessage'; +import { Icon } from 'plugin-api/beta/client/components/ui'; + +const InputField = ({ + id = '', + label = '', + type = 'text', + name = '', + onChange = () => {}, + showError = true, + hasError = false, + errorMsg = '', + children, + columnDisplay = false, + showSuccess = false, + validationType = '', + icon = '', + value = '', + defaultValue = '', + disabled = false, +}) => { + const inputValue = { + ...(value ? { value } : {}), + ...(defaultValue ? { defaultValue } : {}), + }; + + return ( +
+
+ {label && ( + + )} +
+ {icon && } + +
+
+ {!hasError && + showSuccess && + value && } + {hasError && showError && {errorMsg}} +
+
+ {children} +
+ ); +}; + +InputField.propTypes = { + id: PropTypes.string, + disabled: PropTypes.bool, + label: PropTypes.string, + type: PropTypes.string, + name: PropTypes.string.isRequired, + onChange: PropTypes.func, + value: PropTypes.string, + defaultValue: PropTypes.string, + icon: PropTypes.string, + showError: PropTypes.bool, + hasError: PropTypes.bool, + errorMsg: PropTypes.string, + children: PropTypes.node, + columnDisplay: PropTypes.bool, + showSuccess: PropTypes.bool, + validationType: PropTypes.string, +}; + +export default InputField; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css new file mode 100644 index 000000000..6c7f9ae41 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -0,0 +1,87 @@ +.container { + position: relative; + color: #202020; + padding: 10px; + border-radius: 2px; + border: solid 1px transparent; + box-sizing: border-box; + justify-content: space-between; + + &.editing { + border-color: #979797; + background-color: #EDEDED; + } +} + +.actions { + position: absolute; + top: 10px; + right: 10px; + display: flex; + flex-direction: column; + align-items: center; +} + +.title { + color: #202020; + margin: 0 0 20px; +} + +.detailBottomBox { + display: block; + padding-top: 4px; + text-align: right; + width: 280px; +} + +.detailLink { + color: #00538A; + text-decoration: none; + font-size: 0.9em; + &:hover { + cursor: pointer; + } +} + +.button { + border: 1px solid #787d80; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; +} + +.saveButton { + background-color: #3498DB; + border-color: #3498DB; + color: white; + + > i { + font-size: 17px; + } + + &:hover { + background-color: #399ee2; + color: white; + } + + &:disabled { + border-color: #e0e0e0; + + &:hover { + background-color: #e0e0e0; + color: #4f5c67; + cursor: default; + } + } +} + +.cancelButton { + color:#787D80; + margin-top: 6px; + font-size: 0.9em; + + &:hover { + cursor: pointer; + } +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js new file mode 100644 index 000000000..90940728d --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -0,0 +1,223 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import styles from './ChangePassword.css'; +import { Button } from 'plugin-api/beta/client/components/ui'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; +import isEqual from 'lodash/isEqual'; +import { t } from 'plugin-api/beta/client/services'; +import InputField from './InputField'; +import { getErrorMessages } from 'coral-framework/utils'; + +const initialState = { + editing: false, + showErrors: true, + errors: {}, + formData: {}, +}; + +class ChangePassword extends React.Component { + state = initialState; + validKeys = ['oldPassword', 'newPassword', 'confirmNewPassword']; + + onChange = e => { + const { name, value, type } = e.target; + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + this.fieldValidation(value, type, name); + + // Perform equality validation if password fields have changed + if (name === 'newPassword' || name === 'confirmNewPassword') { + this.equalityValidation('newPassword', 'confirmNewPassword'); + } + } + ); + }; + + equalityValidation = (field, field2) => { + const cond = this.state.formData[field] === this.state.formData[field2]; + if (!cond) { + this.addError({ + [field2]: t('talk-plugin-auth.change_password.passwords_dont_match'), + }); + } else { + this.removeError(field2); + } + return cond; + }; + + 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); + } + }; + + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + addError = err => { + this.setState(({ errors }) => ({ + errors: { ...errors, ...err }, + })); + }; + + removeError = errKey => { + this.setState(state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }); + }; + + enableEditing = () => { + this.setState({ + editing: true, + }); + }; + + isSubmitBlocked = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + const formIncomplete = !isEqual( + Object.keys(this.state.formData), + this.validKeys + ); + return formHasErrors || formIncomplete; + }; + + clearForm = () => { + this.setState(initialState); + }; + + onSave = async () => { + const { oldPassword, newPassword } = this.state.formData; + + try { + await this.props.changePassword({ + oldPassword, + newPassword, + }); + this.props.notify( + 'success', + t('talk-plugin-auth.change_password.changed_password_msg') + ); + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + } + + this.clearForm(); + this.disableEditing(); + }; + + disableEditing = () => { + this.setState({ + editing: false, + }); + }; + + cancel = () => { + this.clearForm(); + this.disableEditing(); + }; + + render() { + const { editing, errors } = this.state; + + return ( +
+

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

+ {editing && ( +
+ + + + {t('talk-plugin-auth.change_password.forgot_password')} + + + + + + + )} + {editing ? ( +
+ + + {t('talk-plugin-auth.change_password.cancel')} + +
+ ) : ( +
+ +
+ )} +
+ ); + } +} + +ChangePassword.propTypes = { + changePassword: PropTypes.func.isRequired, + notify: PropTypes.func.isRequired, +}; + +export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css new file mode 100644 index 000000000..5b4631ecf --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css @@ -0,0 +1,122 @@ +.container { + margin-bottom: 20px; + display: flex; + position: relative; + color: #202020; + padding: 10px; + border-radius: 2px; + box-sizing: border-box; + justify-content: space-between; + + &.editing { + background-color: #EDEDED; + } +} + +.content { + flex-grow: 1; +} + +.actions { + flex-grow: 0; + display: flex; + flex-direction: column; + align-items: center; +} + +.email { + margin: 0; +} + +.username { + margin-bottom: 4px; +} + +.button { + border: 1px solid #787d80; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; +} + +.saveButton { + background-color: #3498DB; + border-color: #3498DB; + color: white; + + > i { + font-size: 17px; + } + + &:hover { + background-color: #399ee2; + color: white; + } + + &:disabled { + border-color: #e0e0e0; + + &:hover { + background-color: #e0e0e0; + color: #4f5c67; + cursor: default; + } + } +} + +.cancelButton { + color:#787D80; + margin-top: 6px; + font-size: 0.9em; + + &:hover { + cursor: pointer; + } +} + +.detailLabel { + border: solid 1px #787D80; + border-radius: 2px; + background-color: white; + height: 30px; + display: inline-block; + width: 230px; + display: flex; + + > .detailLabelIcon { + font-size: 1.2em; + padding: 0 5px; + color: #787D80; + line-height: 30px; + } + + &.disabled { + background-color: #E0E0E0; + } +} + +.detailValue { + background: transparent; + border: none; + font-size: 1em; + color: #000; + height: 30px; + outline: none; + flex: 1; +} + +.bottomText { + color: #474747; + font-size: 0.9em; +} + +.detailList { + list-style: none; + margin: 0; + padding: 0; +} + +.detailItem { + margin-bottom: 12px; +} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js new file mode 100644 index 000000000..8188bdfbe --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -0,0 +1,188 @@ +import React from 'react'; +import cn from 'classnames'; +import PropTypes from 'prop-types'; +import styles from './ChangeUsername.css'; +import { Button } from 'plugin-api/beta/client/components/ui'; +import ChangeUsernameDialog from './ChangeUsernameDialog'; +import { t } from 'plugin-api/beta/client/services'; +import InputField from './InputField'; +import { getErrorMessages } from 'coral-framework/utils'; +import { canUsernameBeUpdated } from 'coral-framework/utils/user'; + +const initialState = { + editing: false, + showDialog: false, + formData: {}, +}; + +class ChangeUsername extends React.Component { + state = initialState; + + clearForm = () => { + this.setState(initialState); + }; + + enableEditing = () => { + this.setState({ + editing: true, + }); + }; + + disableEditing = () => { + this.setState({ + editing: false, + }); + }; + + cancel = () => { + this.clearForm(); + this.disableEditing(); + }; + + showDialog = () => { + this.setState({ + showDialog: true, + }); + }; + + onSave = async () => { + this.showDialog(); + }; + + saveChanges = async () => { + const { newUsername } = this.state.formData; + const { changeUsername } = this.props; + + try { + await changeUsername(newUsername); + this.props.notify( + 'success', + t('talk-plugin-auth.change_username.changed_username_success_msg') + ); + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + } + + this.clearForm(); + this.disableEditing(); + }; + + onChange = e => { + const { name, value } = e.target; + + this.setState(state => ({ + formData: { + ...state.formData, + [name]: value, + }, + })); + }; + + closeDialog = () => { + this.setState({ + showDialog: false, + }); + }; + + render() { + const { + username, + emailAddress, + root: { me: { state: { status } } }, + notify, + } = this.props; + const { editing, formData, showDialog } = this.state; + + return ( +
+ + + {editing ? ( +
+
+ + + {t('talk-plugin-auth.change_username.change_username_note')} + + + +
+
+ ) : ( +
+

{username}

+ {emailAddress ? ( +

{emailAddress}

+ ) : null} +
+ )} + {editing ? ( +
+ + + {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/components/ChangeUsernameDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css new file mode 100644 index 000000000..af681d596 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css @@ -0,0 +1,84 @@ +.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; +} + +.bottomNote { + font-size: 0.9em; + line-height: 20px; + padding-top: 10px; + display: block; +} + +.bottomActions { + text-align: right; +} + +.usernamesChange { + 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/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js new file mode 100644 index 000000000..321b36926 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -0,0 +1,117 @@ +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 ChangeUsernameDialog extends React.Component { + state = { + showError: false, + }; + + showError = () => { + this.setState({ + showError: true, + }); + }; + + confirmChanges = async () => { + if (this.formHasError()) { + this.showError(); + return; + } + + if (!this.props.canUsernameBeUpdated) { + this.props.notify( + 'error', + t('talk-plugin-auth.change_username.change_username_attempt') + ); + return; + } + + await this.props.saveChanges(); + this.props.closeDialog(); + }; + + formHasError = () => + this.props.formData.confirmNewUsername !== this.props.formData.newUsername; + + render() { + return ( + + + × + +

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

+
+

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

+
+ + {t('talk-plugin-auth.change_username.old_username')}:{' '} + {this.props.username} + + + {t('talk-plugin-auth.change_username.new_username')}:{' '} + {this.props.formData.newUsername} + +
+
+ + + {t('talk-plugin-auth.change_username.bottom_note')} + + +
+
+ + +
+
+
+ ); + } +} + +ChangeUsernameDialog.propTypes = { + saveChanges: PropTypes.func, + closeDialog: PropTypes.func, + showDialog: PropTypes.bool, + onChange: PropTypes.func, + username: PropTypes.string, + formData: PropTypes.object, + canUsernameBeUpdated: PropTypes.bool.isRequired, + notify: PropTypes.func.isRequired, +}; + +export default ChangeUsernameDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js index b9a1bfc9d..35069384c 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js @@ -9,7 +9,7 @@ import DeleteMyAccountStep2 from './DeleteMyAccountStep2'; import DeleteMyAccountStep3 from './DeleteMyAccountStep3'; import DeleteMyAccountFinalStep from './DeleteMyAccountFinalStep'; -const initialState = { step: 0 }; +const initialState = { step: 0, formData: {} }; class DeleteMyAccountDialog extends React.Component { state = initialState; @@ -29,6 +29,17 @@ class DeleteMyAccountDialog extends React.Component { this.props.closeDialog(); }; + onChange = e => { + const { name, value } = e.target; + + this.setState(state => ({ + formData: { + ...state.formData, + [name]: value, + }, + })); + }; + render() { const { step } = this.state; return ( @@ -58,9 +69,11 @@ class DeleteMyAccountDialog extends React.Component { )} {step === 3 && ( )} {step === 4 && } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js index 63a00243b..45dca8f97 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js @@ -3,13 +3,41 @@ import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; +import InputField from '../../components/InputField'; + +const initialState = { + showError: false, +}; class DeleteMyAccountStep3 extends React.Component { - deleteAndContinue = () => { - this.props.requestAccountDeletion(); + state = initialState; + phrase = 'delete'; + + showError = () => { + this.setState({ + showError: true, + }); + }; + + clear = () => { + this.setState(initialState); + }; + + deleteAndContinue = async () => { + if (this.formHasError()) { + this.showError(); + return; + } + + await this.props.requestAccountDeletion(); + this.clear(); this.props.goToNextStep(); }; + formHasError = () => + !this.props.formData.confirmPhrase || + this.props.formData.confirmPhrase !== this.phrase; + render() { return (
@@ -24,7 +52,19 @@ class DeleteMyAccountStep3 extends React.Component { className={styles.textBox} disabled={true} readOnly={true} - value="delete" + value={this.phrase} + /> +
- - {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 c57acddfc01547a1fc3d7842a0366d272022e78c Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:01:03 -0300 Subject: [PATCH 40/97] Moving gdpr to `talk-plugin-profile-data` --- plugins/talk-plugin-auth/client/index.js | 13 +- .../components/ChangePassword.css | 87 ------- .../components/ChangePassword.js | 223 ------------------ .../components/ChangeUsername.css | 122 ---------- .../components/ChangeUsername.js | 188 --------------- .../components/ChangeUsernameDialog.css | 84 ------- .../components/ChangeUsernameDialog.js | 117 --------- .../components/ErrorMessage.css | 8 - .../components/ErrorMessage.js | 17 -- .../components/InputField.css | 80 ------- .../profile-settings/components/InputField.js | 94 -------- .../containers/ChangePassword.js | 12 - .../containers/ChangeUsername.js | 12 - .../AccountDeletionRequestedSign.css | 0 .../AccountDeletionRequestedSign.js | 0 .../client}/components/DeleteMyAccount.css | 0 .../client}/components/DeleteMyAccount.js | 0 .../components/DeleteMyAccountDialog.css | 0 .../components/DeleteMyAccountDialog.js | 0 .../components/DeleteMyAccountFinalStep.js | 0 .../components/DeleteMyAccountStep.css | 0 .../components/DeleteMyAccountStep0.js | 0 .../components/DeleteMyAccountStep1.js | 0 .../components/DeleteMyAccountStep2.js | 0 .../components/DeleteMyAccountStep3.js | 0 .../client/components/ErrorMessage.css | 0 .../client/components/ErrorMessage.js | 0 .../client/components/InputField.css | 0 .../client/components/InputField.js | 0 .../client}/components/StepProgress.css | 0 .../client}/components/StepProgress.js | 0 .../AccountDeletionRequestedSign.js | 0 .../client}/containers/DeleteMyAccount.js | 0 .../talk-plugin-profile-data/client/index.js | 5 +- 34 files changed, 5 insertions(+), 1057 deletions(-) delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/InputField.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js rename plugins/{talk-plugin-auth/client/stream => talk-plugin-profile-data/client}/components/AccountDeletionRequestedSign.css (100%) rename plugins/{talk-plugin-auth/client/stream => talk-plugin-profile-data/client}/components/AccountDeletionRequestedSign.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccount.css (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccount.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountDialog.css (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountDialog.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountFinalStep.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountStep.css (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountStep0.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountStep1.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountStep2.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/DeleteMyAccountStep3.js (100%) rename plugins/{talk-plugin-auth => talk-plugin-profile-data}/client/components/ErrorMessage.css (100%) rename plugins/{talk-plugin-auth => talk-plugin-profile-data}/client/components/ErrorMessage.js (100%) rename plugins/{talk-plugin-auth => talk-plugin-profile-data}/client/components/InputField.css (100%) rename plugins/{talk-plugin-auth => talk-plugin-profile-data}/client/components/InputField.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/StepProgress.css (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/components/StepProgress.js (100%) rename plugins/{talk-plugin-auth/client/stream => talk-plugin-profile-data/client}/containers/AccountDeletionRequestedSign.js (100%) rename plugins/{talk-plugin-auth/client/profile-settings => talk-plugin-profile-data/client}/containers/DeleteMyAccount.js (100%) diff --git a/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index 0567497ae..13abce1d9 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -4,23 +4,12 @@ import SetUsernameDialog from './stream/containers/SetUsernameDialog'; import translations from './translations.yml'; import Login from './login/containers/Main'; import reducer from './login/reducer'; -import DeleteMyAccount from './profile-settings/containers/DeleteMyAccount'; -import AccountDeletionRequestedSign from './stream/containers/AccountDeletionRequestedSign'; -import ChangePassword from './profile-settings/containers/ChangePassword'; -import ChangeUsername from './profile-settings/containers/ChangeUsername'; export default { reducer, translations, slots: { - stream: [ - AccountDeletionRequestedSign, - UserBox, - SignInButton, - SetUsernameDialog, - ], + stream: [UserBox, SignInButton, SetUsernameDialog], login: [Login], - profileHeader: [ChangeUsername], - profileSettings: [ChangePassword, DeleteMyAccount], }, }; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css deleted file mode 100644 index 6c7f9ae41..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ /dev/null @@ -1,87 +0,0 @@ -.container { - position: relative; - color: #202020; - padding: 10px; - border-radius: 2px; - border: solid 1px transparent; - box-sizing: border-box; - justify-content: space-between; - - &.editing { - border-color: #979797; - background-color: #EDEDED; - } -} - -.actions { - position: absolute; - top: 10px; - right: 10px; - display: flex; - flex-direction: column; - align-items: center; -} - -.title { - color: #202020; - margin: 0 0 20px; -} - -.detailBottomBox { - display: block; - padding-top: 4px; - text-align: right; - width: 280px; -} - -.detailLink { - color: #00538A; - text-decoration: none; - font-size: 0.9em; - &:hover { - cursor: pointer; - } -} - -.button { - border: 1px solid #787d80; - background-color: transparent; - height: 30px; - font-size: 0.9em; - line-height: normal; -} - -.saveButton { - background-color: #3498DB; - border-color: #3498DB; - color: white; - - > i { - font-size: 17px; - } - - &:hover { - background-color: #399ee2; - color: white; - } - - &:disabled { - border-color: #e0e0e0; - - &:hover { - background-color: #e0e0e0; - color: #4f5c67; - cursor: default; - } - } -} - -.cancelButton { - color:#787D80; - margin-top: 6px; - font-size: 0.9em; - - &:hover { - cursor: pointer; - } -} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js deleted file mode 100644 index 90940728d..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ /dev/null @@ -1,223 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import cn from 'classnames'; -import styles from './ChangePassword.css'; -import { Button } from 'plugin-api/beta/client/components/ui'; -import validate from 'coral-framework/helpers/validate'; -import errorMsj from 'coral-framework/helpers/error'; -import isEqual from 'lodash/isEqual'; -import { t } from 'plugin-api/beta/client/services'; -import InputField from './InputField'; -import { getErrorMessages } from 'coral-framework/utils'; - -const initialState = { - editing: false, - showErrors: true, - errors: {}, - formData: {}, -}; - -class ChangePassword extends React.Component { - state = initialState; - validKeys = ['oldPassword', 'newPassword', 'confirmNewPassword']; - - onChange = e => { - const { name, value, type } = e.target; - this.setState( - state => ({ - formData: { - ...state.formData, - [name]: value, - }, - }), - () => { - this.fieldValidation(value, type, name); - - // Perform equality validation if password fields have changed - if (name === 'newPassword' || name === 'confirmNewPassword') { - this.equalityValidation('newPassword', 'confirmNewPassword'); - } - } - ); - }; - - equalityValidation = (field, field2) => { - const cond = this.state.formData[field] === this.state.formData[field2]; - if (!cond) { - this.addError({ - [field2]: t('talk-plugin-auth.change_password.passwords_dont_match'), - }); - } else { - this.removeError(field2); - } - return cond; - }; - - 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); - } - }; - - hasError = err => { - return Object.keys(this.state.errors).indexOf(err) !== -1; - }; - - addError = err => { - this.setState(({ errors }) => ({ - errors: { ...errors, ...err }, - })); - }; - - removeError = errKey => { - this.setState(state => { - const { [errKey]: _, ...errors } = state.errors; - return { - errors, - }; - }); - }; - - enableEditing = () => { - this.setState({ - editing: true, - }); - }; - - isSubmitBlocked = () => { - const formHasErrors = !!Object.keys(this.state.errors).length; - const formIncomplete = !isEqual( - Object.keys(this.state.formData), - this.validKeys - ); - return formHasErrors || formIncomplete; - }; - - clearForm = () => { - this.setState(initialState); - }; - - onSave = async () => { - const { oldPassword, newPassword } = this.state.formData; - - try { - await this.props.changePassword({ - oldPassword, - newPassword, - }); - this.props.notify( - 'success', - t('talk-plugin-auth.change_password.changed_password_msg') - ); - } catch (err) { - this.props.notify('error', getErrorMessages(err)); - } - - this.clearForm(); - this.disableEditing(); - }; - - disableEditing = () => { - this.setState({ - editing: false, - }); - }; - - cancel = () => { - this.clearForm(); - this.disableEditing(); - }; - - render() { - const { editing, errors } = this.state; - - return ( -
-

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

- {editing && ( -
- - - - {t('talk-plugin-auth.change_password.forgot_password')} - - - - - - - )} - {editing ? ( -
- - - {t('talk-plugin-auth.change_password.cancel')} - -
- ) : ( -
- -
- )} -
- ); - } -} - -ChangePassword.propTypes = { - changePassword: PropTypes.func.isRequired, - notify: PropTypes.func.isRequired, -}; - -export default ChangePassword; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css deleted file mode 100644 index 5b4631ecf..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css +++ /dev/null @@ -1,122 +0,0 @@ -.container { - margin-bottom: 20px; - display: flex; - position: relative; - color: #202020; - padding: 10px; - border-radius: 2px; - box-sizing: border-box; - justify-content: space-between; - - &.editing { - background-color: #EDEDED; - } -} - -.content { - flex-grow: 1; -} - -.actions { - flex-grow: 0; - display: flex; - flex-direction: column; - align-items: center; -} - -.email { - margin: 0; -} - -.username { - margin-bottom: 4px; -} - -.button { - border: 1px solid #787d80; - background-color: transparent; - height: 30px; - font-size: 0.9em; - line-height: normal; -} - -.saveButton { - background-color: #3498DB; - border-color: #3498DB; - color: white; - - > i { - font-size: 17px; - } - - &:hover { - background-color: #399ee2; - color: white; - } - - &:disabled { - border-color: #e0e0e0; - - &:hover { - background-color: #e0e0e0; - color: #4f5c67; - cursor: default; - } - } -} - -.cancelButton { - color:#787D80; - margin-top: 6px; - font-size: 0.9em; - - &:hover { - cursor: pointer; - } -} - -.detailLabel { - border: solid 1px #787D80; - border-radius: 2px; - background-color: white; - height: 30px; - display: inline-block; - width: 230px; - display: flex; - - > .detailLabelIcon { - font-size: 1.2em; - padding: 0 5px; - color: #787D80; - line-height: 30px; - } - - &.disabled { - background-color: #E0E0E0; - } -} - -.detailValue { - background: transparent; - border: none; - font-size: 1em; - color: #000; - height: 30px; - outline: none; - flex: 1; -} - -.bottomText { - color: #474747; - font-size: 0.9em; -} - -.detailList { - list-style: none; - margin: 0; - padding: 0; -} - -.detailItem { - margin-bottom: 12px; -} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js deleted file mode 100644 index 8188bdfbe..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ /dev/null @@ -1,188 +0,0 @@ -import React from 'react'; -import cn from 'classnames'; -import PropTypes from 'prop-types'; -import styles from './ChangeUsername.css'; -import { Button } from 'plugin-api/beta/client/components/ui'; -import ChangeUsernameDialog from './ChangeUsernameDialog'; -import { t } from 'plugin-api/beta/client/services'; -import InputField from './InputField'; -import { getErrorMessages } from 'coral-framework/utils'; -import { canUsernameBeUpdated } from 'coral-framework/utils/user'; - -const initialState = { - editing: false, - showDialog: false, - formData: {}, -}; - -class ChangeUsername extends React.Component { - state = initialState; - - clearForm = () => { - this.setState(initialState); - }; - - enableEditing = () => { - this.setState({ - editing: true, - }); - }; - - disableEditing = () => { - this.setState({ - editing: false, - }); - }; - - cancel = () => { - this.clearForm(); - this.disableEditing(); - }; - - showDialog = () => { - this.setState({ - showDialog: true, - }); - }; - - onSave = async () => { - this.showDialog(); - }; - - saveChanges = async () => { - const { newUsername } = this.state.formData; - const { changeUsername } = this.props; - - try { - await changeUsername(newUsername); - this.props.notify( - 'success', - t('talk-plugin-auth.change_username.changed_username_success_msg') - ); - } catch (err) { - this.props.notify('error', getErrorMessages(err)); - } - - this.clearForm(); - this.disableEditing(); - }; - - onChange = e => { - const { name, value } = e.target; - - this.setState(state => ({ - formData: { - ...state.formData, - [name]: value, - }, - })); - }; - - closeDialog = () => { - this.setState({ - showDialog: false, - }); - }; - - render() { - const { - username, - emailAddress, - root: { me: { state: { status } } }, - notify, - } = this.props; - const { editing, formData, showDialog } = this.state; - - return ( -
- - - {editing ? ( -
-
- - - {t('talk-plugin-auth.change_username.change_username_note')} - - - -
-
- ) : ( -
-

{username}

- {emailAddress ? ( -

{emailAddress}

- ) : null} -
- )} - {editing ? ( -
- - - {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/components/ChangeUsernameDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css deleted file mode 100644 index af681d596..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css +++ /dev/null @@ -1,84 +0,0 @@ -.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; -} - -.bottomNote { - font-size: 0.9em; - line-height: 20px; - padding-top: 10px; - display: block; -} - -.bottomActions { - text-align: right; -} - -.usernamesChange { - 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/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js deleted file mode 100644 index 321b36926..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ /dev/null @@ -1,117 +0,0 @@ -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 ChangeUsernameDialog extends React.Component { - state = { - showError: false, - }; - - showError = () => { - this.setState({ - showError: true, - }); - }; - - confirmChanges = async () => { - if (this.formHasError()) { - this.showError(); - return; - } - - if (!this.props.canUsernameBeUpdated) { - this.props.notify( - 'error', - t('talk-plugin-auth.change_username.change_username_attempt') - ); - return; - } - - await this.props.saveChanges(); - this.props.closeDialog(); - }; - - formHasError = () => - this.props.formData.confirmNewUsername !== this.props.formData.newUsername; - - render() { - return ( - - - × - -

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

-
-

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

-
- - {t('talk-plugin-auth.change_username.old_username')}:{' '} - {this.props.username} - - - {t('talk-plugin-auth.change_username.new_username')}:{' '} - {this.props.formData.newUsername} - -
-
- - - {t('talk-plugin-auth.change_username.bottom_note')} - - -
-
- - -
-
-
- ); - } -} - -ChangeUsernameDialog.propTypes = { - saveChanges: PropTypes.func, - closeDialog: PropTypes.func, - showDialog: PropTypes.bool, - onChange: PropTypes.func, - username: PropTypes.string, - formData: PropTypes.object, - canUsernameBeUpdated: PropTypes.bool.isRequired, - notify: PropTypes.func.isRequired, -}; - -export default ChangeUsernameDialog; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css deleted file mode 100644 index abcf692fe..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css +++ /dev/null @@ -1,8 +0,0 @@ -.errorMsg { - color: #FA4643; - font-size: 0.9em; -} - -.warningIcon { - color: #FA4643; -} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js deleted file mode 100644 index f39a8fc08..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import styles from './ErrorMessage.css'; -import { Icon } from 'plugin-api/beta/client/components/ui'; - -const ErrorMessage = ({ children }) => ( -
- - {children} -
-); - -ErrorMessage.propTypes = { - children: PropTypes.node, -}; - -export default ErrorMessage; diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css deleted file mode 100644 index cd6015e47..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css +++ /dev/null @@ -1,80 +0,0 @@ - -.detailItem { - margin-bottom: 12px; -} - -.detailItemContainer { - display: flex; -} - -.columnDisplay { - flex-direction: column; - - .detailItemMessage { - padding: 4px 0 0; - } -} - -.detailItemContent { - border: solid 1px #787D80; - border-radius: 2px; - background-color: white; - height: 30px; - display: inline-block; - width: 230px; - display: flex; - box-sizing: border-box; - - > .detailIcon { - font-size: 1.2em; - padding: 0 5px; - color: #787D80; - line-height: 30px; - } - - &.error { - border: solid 2px #FA4643; - } - - &.disabled { - background-color: #E0E0E0; - } -} - -.detailLabel { - color: #4C4C4D; - font-size: 1em; - display: block; - margin-bottom: 4px; -} - -.detailValue { - background: transparent; - border: none; - font-size: 1em; - color: #000; - outline: none; - flex: 1; - height: 100%; - box-sizing: border-box; -} - -.detailItemMessage { - flex-grow: 1; - display: flex; - align-items: center; - padding-left: 6px; - padding-top: 16px; - - .warningIcon, .checkIcon { - font-size: 17px; - } -} - -.checkIcon { - color: #00CD73; -} - -.warningIcon { - color: #FA4643; -} \ No newline at end of file diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js deleted file mode 100644 index 34c314c20..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import cn from 'classnames'; -import styles from './InputField.css'; -import ErrorMessage from './ErrorMessage'; -import { Icon } from 'plugin-api/beta/client/components/ui'; - -const InputField = ({ - id = '', - label = '', - type = 'text', - name = '', - onChange = () => {}, - showError = true, - hasError = false, - errorMsg = '', - children, - columnDisplay = false, - showSuccess = false, - validationType = '', - icon = '', - value = '', - defaultValue = '', - disabled = false, -}) => { - const inputValue = { - ...(value ? { value } : {}), - ...(defaultValue ? { defaultValue } : {}), - }; - - return ( -
-
- {label && ( - - )} -
- {icon && } - -
-
- {!hasError && - showSuccess && - value && } - {hasError && showError && {errorMsg}} -
-
- {children} -
- ); -}; - -InputField.propTypes = { - id: PropTypes.string, - disabled: PropTypes.bool, - label: PropTypes.string, - type: PropTypes.string, - name: PropTypes.string.isRequired, - onChange: PropTypes.func, - value: PropTypes.string, - defaultValue: PropTypes.string, - icon: PropTypes.string, - showError: PropTypes.bool, - hasError: PropTypes.bool, - errorMsg: PropTypes.string, - children: PropTypes.node, - columnDisplay: PropTypes.bool, - showSuccess: PropTypes.bool, - validationType: PropTypes.string, -}; - -export default InputField; diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.js deleted file mode 100644 index 1322a2940..000000000 --- a/plugins/talk-plugin-auth/client/profile-settings/containers/ChangePassword.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 ChangePassword from '../components/ChangePassword'; -import { notify } from 'coral-framework/actions/notification'; -import { withChangePassword } from 'plugin-api/beta/client/hocs'; - -const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); - -export default compose(connect(null, mapDispatchToProps), withChangePassword)( - ChangePassword -); 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/stream/components/AccountDeletionRequestedSign.css b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.css similarity index 100% rename from plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.css rename to plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.css diff --git a/plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js similarity index 100% rename from plugins/talk-plugin-auth/client/stream/components/AccountDeletionRequestedSign.js rename to plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.css rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccount.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.css rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountDialog.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountFinalStep.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep.css rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep0.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep1.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep2.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/DeleteMyAccountStep3.js rename to plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js diff --git a/plugins/talk-plugin-auth/client/components/ErrorMessage.css b/plugins/talk-plugin-profile-data/client/components/ErrorMessage.css similarity index 100% rename from plugins/talk-plugin-auth/client/components/ErrorMessage.css rename to plugins/talk-plugin-profile-data/client/components/ErrorMessage.css diff --git a/plugins/talk-plugin-auth/client/components/ErrorMessage.js b/plugins/talk-plugin-profile-data/client/components/ErrorMessage.js similarity index 100% rename from plugins/talk-plugin-auth/client/components/ErrorMessage.js rename to plugins/talk-plugin-profile-data/client/components/ErrorMessage.js diff --git a/plugins/talk-plugin-auth/client/components/InputField.css b/plugins/talk-plugin-profile-data/client/components/InputField.css similarity index 100% rename from plugins/talk-plugin-auth/client/components/InputField.css rename to plugins/talk-plugin-profile-data/client/components/InputField.css diff --git a/plugins/talk-plugin-auth/client/components/InputField.js b/plugins/talk-plugin-profile-data/client/components/InputField.js similarity index 100% rename from plugins/talk-plugin-auth/client/components/InputField.js rename to plugins/talk-plugin-profile-data/client/components/InputField.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css b/plugins/talk-plugin-profile-data/client/components/StepProgress.css similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.css rename to plugins/talk-plugin-profile-data/client/components/StepProgress.css diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js b/plugins/talk-plugin-profile-data/client/components/StepProgress.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/components/StepProgress.js rename to plugins/talk-plugin-profile-data/client/components/StepProgress.js diff --git a/plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js similarity index 100% rename from plugins/talk-plugin-auth/client/stream/containers/AccountDeletionRequestedSign.js rename to plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js similarity index 100% rename from plugins/talk-plugin-auth/client/profile-settings/containers/DeleteMyAccount.js rename to plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js diff --git a/plugins/talk-plugin-profile-data/client/index.js b/plugins/talk-plugin-profile-data/client/index.js index fee9f2129..91664ac23 100644 --- a/plugins/talk-plugin-profile-data/client/index.js +++ b/plugins/talk-plugin-profile-data/client/index.js @@ -1,10 +1,13 @@ import DownloadCommentHistory from './containers/DownloadCommentHistory'; +import DeleteMyAccount from './containers/DeleteMyAccount'; +import AccountDeletionRequestedSign from './AccountDeletionRequestedSign'; import translations from './translations.yml'; import graphql from './graphql'; export default { slots: { - profileSettings: [DownloadCommentHistory], + stream: [AccountDeletionRequestedSign], + profileSettings: [DownloadCommentHistory, DeleteMyAccount], }, translations, ...graphql, From 58cc078d256c8e6242f61490b888a99ae18c0549 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:03:21 -0300 Subject: [PATCH 41/97] Moving gdpr to `talk-plugin-profile-data` --- .../client/components/DeleteMyAccountStep3.js | 2 +- plugins/talk-plugin-profile-data/client/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js index 45dca8f97..3205cd225 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; -import InputField from '../../components/InputField'; +import InputField from './InputField'; const initialState = { showError: false, diff --git a/plugins/talk-plugin-profile-data/client/index.js b/plugins/talk-plugin-profile-data/client/index.js index 91664ac23..bbd30b660 100644 --- a/plugins/talk-plugin-profile-data/client/index.js +++ b/plugins/talk-plugin-profile-data/client/index.js @@ -1,6 +1,6 @@ import DownloadCommentHistory from './containers/DownloadCommentHistory'; import DeleteMyAccount from './containers/DeleteMyAccount'; -import AccountDeletionRequestedSign from './AccountDeletionRequestedSign'; +import AccountDeletionRequestedSign from './containers/AccountDeletionRequestedSign'; import translations from './translations.yml'; import graphql from './graphql'; From 8dcaf8ea4caf34dcad7eb065032f702dfa229f97 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 14:08:29 -0300 Subject: [PATCH 42/97] 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 43/97] 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 44/97] 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 45/97] 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 46/97] 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 47/97] 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 45c75f3c48ded2b393cfa7453e95e0362cad5084 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Wed, 2 May 2018 15:22:17 -0400 Subject: [PATCH 48/97] Update version to 4.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c7e9a78c1..9fe31aa39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "talk", - "version": "4.3.2", + "version": "4.4.0", "description": "A better commenting experience from Mozilla, The New York Times, and the Washington Post. https://coralproject.net", "main": "app.js", "private": true, From c7db780582a3c2fc9af25ec0138ab5bbce5b58ab Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 16:46:20 -0300 Subject: [PATCH 49/97] 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 50/97] 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 ccb62263c190432135a9878ea55de60415cee099 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 20:08:29 -0300 Subject: [PATCH 51/97] checking me null --- .../client/containers/AccountDeletionRequestedSign.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js index d842ec43f..9ac152743 100644 --- a/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js +++ b/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js @@ -21,5 +21,5 @@ export default compose( connect(null, mapDispatchToProps), withCancelAccountDeletion, withData, - excludeIf(props => !props.root.me.scheduledDeletionDate) + excludeIf(({ root: { me } }) => !me || !me.scheduledDeletionDate) )(AccountDeletionRequestedSign); From fff6e1c2317e581befdb1c252fde1ba56022ef5f Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 10:24:43 -0300 Subject: [PATCH 52/97] Review changes --- client/coral-framework/graphql/mutations.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 19d133872..cc6b35fa6 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -1,6 +1,7 @@ import { gql } from 'react-apollo'; import withMutation from '../hocs/withMutation'; import update from 'immutability-helper'; +import moment from 'moment'; function convertItemType(item_type) { switch (item_type) { @@ -658,7 +659,7 @@ export const withRequestAccountDeletion = withMutation( return mutate({ variables: {}, update: proxy => { - const CancelAccountDeletionQuery = gql` + const RequestAccountDeletionQuery = gql` query Talk_CancelAccountDeletion { me { id @@ -667,16 +668,22 @@ export const withRequestAccountDeletion = withMutation( } `; - const prev = proxy.readQuery({ query: CancelAccountDeletionQuery }); + const prev = proxy.readQuery({ + query: RequestAccountDeletionQuery, + }); + + const scheduledDeletionDate = moment() + .add(12, 'hours') + .toDate(); const data = update(prev, { me: { - scheduledDeletionDate: { $set: new Date() }, + scheduledDeletionDate: { $set: scheduledDeletionDate }, }, }); proxy.writeQuery({ - query: CancelAccountDeletionQuery, + query: RequestAccountDeletionQuery, data, }); }, From a42135c3bb6067e44264833283bf0219c6b5e822 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 08:39:34 -0600 Subject: [PATCH 53/97] merge bug --- .../server/mutators.js | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/plugins/talk-plugin-profile-data/server/mutators.js b/plugins/talk-plugin-profile-data/server/mutators.js index b1756a34b..d3785c951 100644 --- a/plugins/talk-plugin-profile-data/server/mutators.js +++ b/plugins/talk-plugin-profile-data/server/mutators.js @@ -129,6 +129,17 @@ async function cancelDeletion({ user, connectors: { models: { User } } }) { ); } +// downloadUser will return the download file url that can be used to directly +// download the archive. +async function downloadUser(ctx, userID) { + if (ctx.user.role !== 'ADMIN') { + throw new ErrNotAuthorized(); + } + + const { downloadFileURL } = await generateDownloadLinks(ctx, userID); + return downloadFileURL; +} + module.exports = ctx => ctx.user ? { @@ -136,6 +147,7 @@ module.exports = ctx => requestDownloadLink: () => sendDownloadLink(ctx), requestDeletion: () => requestDeletion(ctx), cancelDeletion: () => cancelDeletion(ctx), + download: userID => downloadUser(ctx, userID), }, } : { @@ -143,22 +155,6 @@ module.exports = ctx => requestDownloadLink: () => Promise.reject(new ErrNotAuthorized()), requestDeletion: () => Promise.reject(new ErrNotAuthorized()), cancelDeletion: () => Promise.reject(new ErrNotAuthorized()), + download: () => Promise.reject(new ErrNotAuthorized()), }, }; -// downloadUser will return the download file url that can be used to directly -// download the archive. -async function downloadUser(ctx, userID) { - const { downloadFileURL } = await generateDownloadLinks(ctx, userID); - return downloadFileURL; -} - -module.exports = ctx => ({ - User: { - requestDownloadLink: () => sendDownloadLink(ctx), - download: - // Only ADMIN users can execute an account download. - ctx.user && ctx.user.role === 'ADMIN' - ? userID => downloadUser(ctx, userID) - : () => Promise.reject(new ErrNotAuthorized()), - }, -}); From 225a04fed1473c60e98e37d68a67de4556da2f94 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 10:53:16 -0400 Subject: [PATCH 54/97] Copy fixes --- .../client/components/DeleteMyAccountFinalStep.js | 9 ++------- .../client/components/DeleteMyAccountStep1.js | 2 +- .../client/components/DeleteMyAccountStep3.js | 2 +- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js index ccbbf61fa..4cda90347 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js @@ -22,10 +22,8 @@ const DeleteMyAccountFinalStep = props => (

- Changed your mind? Simply sign in to your account again - before this time and click “ - Cancel Account Deletion Request. - ” + Changed your mind? Simply go to your account again before + this time and click “Cancel Account Deletion Request.

@@ -41,9 +39,6 @@ const DeleteMyAccountFinalStep = props => ( > Done - - Note: You will be immediately signed out of your account. -

); diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js index e74611b05..ace020c65 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js @@ -15,7 +15,7 @@ const DeleteMyAccountStep1 = props => ( Can I still write comments until my account is deleted?{' '}

- No. Once youve requested account deletion, you can no longer write + No. Once you have requested account deletion, you can no longer write comments, reply to comments, or select reactions.

diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js index 3205cd225..4c87bbcf2 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js @@ -56,7 +56,7 @@ class DeleteMyAccountStep3 extends React.Component { /> Date: Thu, 3 May 2018 08:59:26 -0600 Subject: [PATCH 55/97] moved hoc's into plugin --- client/coral-framework/graphql/mutations.js | 110 ------------------ plugin-api/beta/client/hocs/index.js | 3 - .../AccountDeletionRequestedSign.js | 2 +- .../client/containers/DeleteMyAccount.js | 2 +- .../client/mutations.js | 104 ++++++++++++++++- 5 files changed, 101 insertions(+), 120 deletions(-) diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index cc6b35fa6..228911d4a 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -1,7 +1,6 @@ import { gql } from 'react-apollo'; import withMutation from '../hocs/withMutation'; import update from 'immutability-helper'; -import moment from 'moment'; function convertItemType(item_type) { switch (item_type) { @@ -645,115 +644,6 @@ export const withChangePassword = 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(12, 'hours') - .toDate(); - - const data = update(prev, { - me: { - scheduledDeletionDate: { $set: scheduledDeletionDate }, - }, - }); - - proxy.writeQuery({ - query: RequestAccountDeletionQuery, - data, - }); - }, - }); - }, - }), - } -); - -export const withRequestDownloadLink = withMutation( - gql` - mutation RequestDownloadLink { - requestDownloadLink { - ...RequestDownloadLinkResponse - } - } - `, - { - props: ({ mutate }) => ({ - requestDownloadLink: () => { - return mutate({ - variables: {}, - }); - }, - }), - } -); - -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, - }); - }, - }); - }, - }), - } -); - export const withUpdateAssetSettings = withMutation( gql` mutation UpdateAssetSettings($id: ID!, $input: AssetSettingsInput!) { diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index e86c96606..d7ca5fce9 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -25,9 +25,6 @@ export { withUnbanUser, withStopIgnoringUser, withSetCommentStatus, - withRequestAccountDeletion, - withRequestDownloadLink, - withCancelAccountDeletion, withChangePassword, withChangeUsername, } from 'coral-framework/graphql/mutations'; diff --git a/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js index 9ac152743..9866045a3 100644 --- a/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js +++ b/plugins/talk-plugin-profile-data/client/containers/AccountDeletionRequestedSign.js @@ -3,7 +3,7 @@ import { bindActionCreators } from 'redux'; import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs'; import AccountDeletionRequestedSign from '../components/AccountDeletionRequestedSign'; import { notify } from 'coral-framework/actions/notification'; -import { withCancelAccountDeletion } from 'plugin-api/beta/client/hocs'; +import { withCancelAccountDeletion } from '../mutations'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); diff --git a/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js index a9c033853..84d0b9a5c 100644 --- a/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js @@ -6,7 +6,7 @@ import { notify } from 'coral-framework/actions/notification'; import { withRequestAccountDeletion, withCancelAccountDeletion, -} from 'plugin-api/beta/client/hocs'; +} from '../mutations'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); diff --git a/plugins/talk-plugin-profile-data/client/mutations.js b/plugins/talk-plugin-profile-data/client/mutations.js index a370c9ff0..d39802808 100644 --- a/plugins/talk-plugin-profile-data/client/mutations.js +++ b/plugins/talk-plugin-profile-data/client/mutations.js @@ -1,19 +1,113 @@ import { withMutation } from 'plugin-api/beta/client/hocs'; import { gql } from 'react-apollo'; +import update from 'immutability-helper'; +import moment from 'moment'; export const withRequestDownloadLink = withMutation( gql` - mutation DownloadCommentHistory { + mutation RequestDownloadLink { requestDownloadLink { - errors { - translation_key - } + ...RequestDownloadLinkResponse } } `, { props: ({ mutate }) => ({ - requestDownloadLink: () => mutate({ variables: {} }), + requestDownloadLink: () => { + return mutate({ + variables: {}, + }); + }, + }), + } +); + +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(12, '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 ee0f734705b1c423088457b85b0ecd7073667fea Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 09:13:44 -0600 Subject: [PATCH 56/97] cleaned up download mutations --- client/coral-framework/graphql/fragments.js | 3 --- plugin-api/beta/client/utils/index.js | 1 + .../components/DownloadCommentHistory.js | 22 ++++++++++++++----- .../containers/DownloadCommentHistory.js | 9 +++++++- .../client/graphql.js | 10 ++++++++- .../client/mutations.js | 6 +---- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index 94021d133..c5704f719 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -26,9 +26,6 @@ export default { 'UpdateAssetSettingsResponse', 'UpdateAssetStatusResponse', 'UpdateSettingsResponse', - 'RequestAccountDeletionResponse', - 'RequestDownloadLinkResponse', - 'CancelAccountDeletionResponse', 'ChangePasswordResponse' ), }; diff --git a/plugin-api/beta/client/utils/index.js b/plugin-api/beta/client/utils/index.js index 3fe742569..aeb9841f9 100644 --- a/plugin-api/beta/client/utils/index.js +++ b/plugin-api/beta/client/utils/index.js @@ -8,4 +8,5 @@ export { getErrorMessages, getDefinitionName, getShallowChanges, + createDefaultResponseFragments, } from 'coral-framework/utils'; diff --git a/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js b/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js index 06fa1fa89..398e2a640 100644 --- a/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js +++ b/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import { t } from 'plugin-api/beta/client/services'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DownloadCommentHistory.css'; +import { getErrorMessages } from 'coral-framework/utils'; export const readableDuration = durAsHours => { const durAsDays = Math.ceil(durAsHours / 24); @@ -19,14 +20,25 @@ export const readableDuration = durAsHours => { class DownloadCommentHistory extends Component { static propTypes = { requestDownloadLink: PropTypes.func.isRequired, + notify: PropTypes.func.isRequired, root: PropTypes.object.isRequired, }; + requestDownloadLink = async () => { + const { requestDownloadLink, notify } = this.props; + try { + await requestDownloadLink(); + notify( + 'success', + 'Account Download Preparing - Check your email shortly for a download link' + ); + } catch (err) { + notify('error', getErrorMessages(err)); + } + }; + render() { - const { - root: { me: { lastAccountDownload } }, - requestDownloadLink, - } = this.props; + const { root: { me: { lastAccountDownload } } } = this.props; const now = new Date(); const lastAccountDownloadDate = @@ -52,7 +64,7 @@ class DownloadCommentHistory extends Component {

)} {canRequestDownload ? ( -
diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js index 9bc5573a1..28ead86de 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js @@ -6,6 +6,7 @@ import styles from './DeleteMyAccount.css'; import { Button } from 'plugin-api/beta/client/components/ui'; import DeleteMyAccountDialog from './DeleteMyAccountDialog'; import { getErrorMessages } from 'coral-framework/utils'; +import { t } from 'plugin-api/beta/client/services'; const initialState = { showDialog: false }; @@ -30,7 +31,7 @@ class DeleteMyAccount extends React.Component { await cancelAccountDeletion(); notify( 'success', - 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.' + t('talk-plugin-profile-data.delete_request.account_deletion_requested') ); } catch (err) { notify('error', getErrorMessages(err)); @@ -41,7 +42,10 @@ class DeleteMyAccount extends React.Component { const { requestAccountDeletion, notify } = this.props; try { await requestAccountDeletion(); - notify('success', 'Account Deletion Requested'); + notify( + 'success', + t('talk-plugin-profile-data.delete_request.account_deletion_requested') + ); } catch (err) { notify('error', getErrorMessages(err)); } @@ -62,7 +66,7 @@ class DeleteMyAccount extends React.Component { 'talk-plugin-auth--delete-my-account-description' )} > - Delete My Account + {t('talk-plugin-profile-data.delete_request.delete_my_account')}

- Deleting your account will permanently erase your profile and remove - all your comments from this site. + {t( + 'talk-plugin-profile-data.delete_request.delete_my_account_description' + )}

{scheduledDeletionDate && - `You have already submitted a request to delete your account. - Your account will be deleted on ${moment( - scheduledDeletionDate - ).format('MMM Do YYYY, h:mm:ss a')}. You may - cancel the request until that time`} + t( + 'talk-plugin-profile-data.delete_request.already_submitted_request_description', + moment(scheduledDeletionDate).format('MMM Do YYYY, h:mm:ss a') + )}

{scheduledDeletionDate ? ( ) : ( )}
diff --git a/plugins/talk-plugin-profile-data/client/translations.yml b/plugins/talk-plugin-profile-data/client/translations.yml index ee6dc4e51..e0b275224 100644 --- a/plugins/talk-plugin-profile-data/client/translations.yml +++ b/plugins/talk-plugin-profile-data/client/translations.yml @@ -10,3 +10,13 @@ en: days: "{0} days" hour: "{0} hour" day: "{0} day" + delete_request: + account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.' + account_deletion_requested: 'Account Deletion Requested' + received_on: "A request to delete your account was received on " + cancel_request_description: "If you would like to continue leaving comments, replies or reactions, you may cancel your request to delete your account below" + before: "before" + cancel_account_deletion_request: "Cancel Account Deletion Request" + delete_my_account: "Delete My Account" + delete_my_account_description: "Deleting your account will permanently erase your profile and remove all your comments from this site." + already_submitted_request_description: "You have already submitted a request to delete your account. Your account will be deleted on {0}. You may cancel the request until that time" \ No newline at end of file From 0caa82c1c4ba14783808fc8a5741803f0da3048b Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 11:59:27 -0400 Subject: [PATCH 62/97] Typo --- .../client/components/DeleteMyAccountFinalStep.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js index d3604d1ae..ebf7200b6 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js @@ -30,8 +30,8 @@ const DeleteMyAccountFinalStep = props => (

- Tell us why. Wed like to know why you chose to delete - your account. Send us feedback on our comment system by emailing. + Tell us why. We would like to know why you chose to + delete your account. Send us feedback on our comment system by emailing.

From 8b35f2300a184254758c79f86debc85348275038 Mon Sep 17 00:00:00 2001 From: Cristian Date: Thu, 3 May 2018 13:06:47 -0300 Subject: [PATCH 63/97] Added TALK_ prefix to constants RECAPTCHA_WINDOW and RECAPTCHA_INCORRECT_TRIGGER --- config.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config.js b/config.js index 7eb7f9280..6a1f999a7 100644 --- a/config.js +++ b/config.js @@ -213,10 +213,11 @@ const CONFIG = { RECAPTCHA_SECRET: process.env.TALK_RECAPTCHA_SECRET, // RECAPTCHA_WINDOW is the rate limit's time interval - RECAPTCHA_WINDOW: process.env.RECAPTCHA_WINDOW || '10m', + RECAPTCHA_WINDOW: process.env.TALK_RECAPTCHA_WINDOW || '10m', // After RECAPTCHA_INCORRECT_TRIGGER incorrect attempts, recaptcha will be required. - RECAPTCHA_INCORRECT_TRIGGER: process.env.RECAPTCHA_INCORRECT_TRIGGER || 5, + RECAPTCHA_INCORRECT_TRIGGER: + process.env.TALK_RECAPTCHA_INCORRECT_TRIGGER || 5, // WEBSOCKET_LIVE_URI is the absolute url to the live endpoint. WEBSOCKET_LIVE_URI: process.env.TALK_WEBSOCKET_LIVE_URI || null, From 6485b1f080e4c0b81d05ddf5c9ed1e9df000c262 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 10:02:33 -0600 Subject: [PATCH 64/97] added email to final step --- .../src/routes/Configure/components/OrganizationSettings.js | 2 +- .../client/components/DeleteMyAccount.js | 6 +++++- .../client/components/DeleteMyAccountDialog.js | 4 +++- .../client/components/DeleteMyAccountFinalStep.js | 6 +++++- .../client/containers/DeleteMyAccount.js | 3 +++ plugins/talk-plugin-profile-data/client/mutations.js | 1 - 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js index f3daeffc2..3505ef7b5 100644 --- a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js +++ b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js @@ -57,7 +57,7 @@ class OrganizationSettings extends React.Component { } const updater = { organizationContactEmail: { $set: email } }; - const errorUpdater = { organizationEmail: { $set: error } }; + const errorUpdater = { organizationContactEmail: { $set: error } }; this.props.updatePending({ updater, errorUpdater }); }; diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js index 982437de0..dc95c4b9e 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js @@ -48,7 +48,10 @@ class DeleteMyAccount extends React.Component { }; render() { - const { me: { scheduledDeletionDate } } = this.props.root; + const { + me: { scheduledDeletionDate }, + settings: { organizationContactEmail }, + } = this.props.root; return (

@@ -81,6 +81,7 @@ class DeleteMyAccountDialog extends React.Component { {step === 4 && ( )} @@ -94,6 +95,7 @@ DeleteMyAccountDialog.propTypes = { closeDialog: PropTypes.func.isRequired, requestAccountDeletion: PropTypes.func.isRequired, scheduledDeletionDate: PropTypes.string, + organizationContactEmail: PropTypes.string.isRequired, }; export default DeleteMyAccountDialog; diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js index ebf7200b6..75a0b3aeb 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountFinalStep.js @@ -31,7 +31,10 @@ const DeleteMyAccountFinalStep = props => (

Tell us why. We would like to know why you chose to - delete your account. Send us feedback on our comment system by emailing. + delete your account. Send us feedback on our comment system by emailing{' '} + + {props.organizationContactEmail} + .

@@ -49,6 +52,7 @@ const DeleteMyAccountFinalStep = props => ( DeleteMyAccountFinalStep.propTypes = { finish: PropTypes.func.isRequired, scheduledDeletionDate: PropTypes.string.isRequired, + organizationContactEmail: PropTypes.string.isRequired, }; export default DeleteMyAccountFinalStep; diff --git a/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js index 84d0b9a5c..0a81107f5 100644 --- a/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/containers/DeleteMyAccount.js @@ -16,6 +16,9 @@ const withData = withFragments({ me { scheduledDeletionDate } + settings { + organizationContactEmail + } } `, }); diff --git a/plugins/talk-plugin-profile-data/client/mutations.js b/plugins/talk-plugin-profile-data/client/mutations.js index d2a8881b8..c7ca68950 100644 --- a/plugins/talk-plugin-profile-data/client/mutations.js +++ b/plugins/talk-plugin-profile-data/client/mutations.js @@ -32,7 +32,6 @@ export const withRequestAccountDeletion = withMutation( return mutate({ variables: {}, update: proxy => { - debugger; const RequestAccountDeletionQuery = gql` query Talk_CancelAccountDeletion { me { From 375f1bb6b1ab2413977ee7bcd711705db39e509c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 10:07:27 -0600 Subject: [PATCH 65/97] copy fixes --- .../AccountDeletionRequestedSign.js | 4 +-- .../client/components/DeleteMyAccount.js | 26 +++++++++---------- .../components/DeleteMyAccountFinalStep.js | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js index 31f65ffa7..f1d85e4e6 100644 --- a/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js +++ b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js @@ -24,11 +24,11 @@ class AccountDeletionRequestedSign extends React.Component { const { me: { scheduledDeletionDate } } = this.props.root; const deletionScheduledFor = moment(scheduledDeletionDate).format( - 'MMM Do YYYY, h:mm:ss a' + 'MMM Do YYYY, h:mm a' ); const deletionScheduledOn = moment(scheduledDeletionDate) .subtract(24, 'hours') - .format('MMM Do YYYY, h:mm:ss a'); + .format('MMM Do YYYY, h:mm a'); return (
diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js index dc95c4b9e..1c7c12d16 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js @@ -78,19 +78,19 @@ class DeleteMyAccount extends React.Component { Deleting your account will permanently erase your profile and remove all your comments from this site.

-

- {scheduledDeletionDate && - `You have already submitted a request to delete your account. - Your account will be deleted on ${moment( - scheduledDeletionDate - ).format('MMM Do YYYY, h:mm:ss a')}. You may - cancel the request until that time`} -

+ {scheduledDeletionDate && ( +

+ You have already submitted a request to delete your account. Your + account will be deleted on{' '} + {moment(scheduledDeletionDate).format('MMM Do YYYY, h:mm a')}. You + may cancel the request until that time. +

+ )} {scheduledDeletionDate ? (
From f6d3f4cb14a8ebb24657bc686068222c550f3fb2 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 13:32:52 -0300 Subject: [PATCH 66/97] translations --- .../components/DeleteMyAccountDialog.js | 5 ++- .../components/DeleteMyAccountFinalStep.js | 31 +++++++++++++------ .../client/components/DeleteMyAccountStep0.js | 13 ++++---- .../client/components/DeleteMyAccountStep1.js | 21 +++++++------ .../client/components/DeleteMyAccountStep2.js | 13 ++++---- .../client/components/DeleteMyAccountStep3.js | 18 ++++++----- .../components/DownloadCommentHistory.js | 5 +-- .../client/translations.yml | 30 +++++++++++++++++- 8 files changed, 91 insertions(+), 45 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js index 35069384c..f6ab9c2ce 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.js @@ -8,6 +8,7 @@ import DeleteMyAccountStep1 from './DeleteMyAccountStep1'; import DeleteMyAccountStep2 from './DeleteMyAccountStep2'; import DeleteMyAccountStep3 from './DeleteMyAccountStep3'; import DeleteMyAccountFinalStep from './DeleteMyAccountFinalStep'; +import { t } from 'plugin-api/beta/client/services'; const initialState = { step: 0, formData: {} }; @@ -47,7 +48,9 @@ class DeleteMyAccountDialog extends React.Component { × -

Delete My Account

+

+ {t('talk-plugin-profile-data.delete_request.delete_my_account')} +

{step === 0 && ( (

- Your request has been submitted and confirmation has been sent to the - email address associated with your account. + {t( + 'talk-plugin-profile-data.delete_request.your_request_submitted_description' + )}

- Your account is scheduled to be deleted at: + {t( + 'talk-plugin-profile-data.delete_request.your_account_deletion_scheduled' + )} - Account Deletion Date and Time + {0}

- Changed your mind? Simply go to your account again before - this time and click “Cancel Account Deletion Request.” + + {' '} + {t('talk-plugin-profile-data.delete_request.changed_your_mind')} + {' '} + {t('talk-plugin-profile-data.delete_request.simply_go_to')} “ + {t( + 'talk-plugin-profile-data.delete_request.cancel_account_deletion_request' + )}. +

- Tell us why. Wed like to know why you chose to delete - your account. Send us feedback on our comment system by emailing. + + {t('talk-plugin-profile-data.delete_request.tell_us_why')}. + {' '} + {t('talk-plugin-profile-data.delete_request.feedback_copy')}

@@ -37,7 +50,7 @@ const DeleteMyAccountFinalStep = props => ( onClick={props.finish} full > - Done + {t('talk-plugin-profile-data.delete_request.done')}
diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js index 901466d3b..468c96e94 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep0.js @@ -3,29 +3,30 @@ import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; +import { t } from 'plugin-api/beta/client/services'; const DeleteMyAccountStep0 = props => (

- You are attempting to delete your account. This means: + {t('talk-plugin-profile-data.delete_request.you_are_attempting')}

  • - All of your comments are removed from this site + {t('talk-plugin-profile-data.delete_request.item_1')}
  • - All of your comments are deleted from our database + {t('talk-plugin-profile-data.delete_request.item_2')}
  • - Your username and email address are removed from our system + {t('talk-plugin-profile-data.delete_request.item_3')}
@@ -34,13 +35,13 @@ const DeleteMyAccountStep0 = props => ( className={cn(styles.button, styles.cancel)} onClick={props.cancel} > - Cancel + {t('talk-plugin-profile-data.delete_request.cancel')}
diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js index ace020c65..7408df688 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js @@ -3,33 +3,34 @@ import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; +import { t } from 'plugin-api/beta/client/services'; const DeleteMyAccountStep1 = props => (
-

When will my account be deleted?

-

- Your account will be deleted 24 hours after your request has been - submitted. -

- Can I still write comments until my account is deleted?{' '} + {t('talk-plugin-profile-data.delete_request.step1.subtitle')}

- No. Once you have requested account deletion, you can no longer write - comments, reply to comments, or select reactions. + {t('talk-plugin-profile-data.delete_request.step1.description')} +

+

+ {t('talk-plugin-profile-data.delete_request.step1.subtitle_2')} +

+

+ {t('talk-plugin-profile-data.delete_request.step1.description_2')}

diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js index 8ef14445e..8976c7dcd 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep2.js @@ -3,18 +3,17 @@ import PropTypes from 'prop-types'; import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; +import { t } from 'plugin-api/beta/client/services'; const DeleteMyAccountStep2 = props => (

- Before your account is deleted, we recommend you download your comment - history for your records. After your account is deleted, you will be - unable to request your comment history. + {t('talk-plugin-profile-data.delete_request.step2.description')}

- To download your comment history go to: + {t('talk-plugin-profile-data.delete_request.step2.to_download')} - My Profile {`>`} Download My Comment History + {t('talk-plugin-profile-data.delete_request.step2.path')}

@@ -22,13 +21,13 @@ const DeleteMyAccountStep2 = props => ( className={cn(styles.button, styles.cancel)} onClick={props.cancel} > - Cancel + {t('talk-plugin-profile-data.delete_request.step2.cancel')}
diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js index 4c87bbcf2..dfbe9bf1f 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep3.js @@ -4,6 +4,7 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; import InputField from './InputField'; +import { t } from 'plugin-api/beta/client/services'; const initialState = { showError: false, @@ -42,11 +43,10 @@ class DeleteMyAccountStep3 extends React.Component { return (

- Are you sure you want to delete your account? + {t('talk-plugin-profile-data.delete_request.step3.subtitle')}

- To confirm you would like to delete your account please type in the - following phrase into the text box below: + {t('talk-plugin-profile-data.delete_request.step3.description')}

@@ -71,13 +75,13 @@ class DeleteMyAccountStep3 extends React.Component { className={cn(styles.button, styles.cancel)} onClick={this.props.cancel} > - Cancel + {t('talk-plugin-profile-data.delete_request.cancel')}

diff --git a/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js b/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js index 398e2a640..feff6b582 100644 --- a/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js +++ b/plugins/talk-plugin-profile-data/client/components/DownloadCommentHistory.js @@ -28,10 +28,7 @@ class DownloadCommentHistory extends Component { const { requestDownloadLink, notify } = this.props; try { await requestDownloadLink(); - notify( - 'success', - 'Account Download Preparing - Check your email shortly for a download link' - ); + notify('success', t('download_request.download_preparing')); } catch (err) { notify('error', getErrorMessages(err)); } diff --git a/plugins/talk-plugin-profile-data/client/translations.yml b/plugins/talk-plugin-profile-data/client/translations.yml index e0b275224..839154446 100644 --- a/plugins/talk-plugin-profile-data/client/translations.yml +++ b/plugins/talk-plugin-profile-data/client/translations.yml @@ -10,6 +10,7 @@ en: days: "{0} days" hour: "{0} hour" day: "{0} day" + download_preparing: "Account Download Preparing - Check your email shortly for a download link" delete_request: account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.' account_deletion_requested: 'Account Deletion Requested' @@ -19,4 +20,31 @@ en: cancel_account_deletion_request: "Cancel Account Deletion Request" delete_my_account: "Delete My Account" delete_my_account_description: "Deleting your account will permanently erase your profile and remove all your comments from this site." - already_submitted_request_description: "You have already submitted a request to delete your account. Your account will be deleted on {0}. You may cancel the request until that time" \ No newline at end of file + already_submitted_request_description: "You have already submitted a request to delete your account. Your account will be deleted on {0}. You may cancel the request until that time" + your_request_submitted_description: "Your request has been submitted and confirmation has been sent to the email address associated with your account." + your_account_deletion_scheduled: "Your account is scheduled to be deleted at:" + changed_your_mind: "Changed your mind?" + simply_go_to: "Simply go to your account again before this time and click" + tell_us_why: "Tell us why" + feedback_copy: "We'd like to know why you chose to delete your account. Send us feedback on our comment system by emailing." + done: "Done" + cancel: "Cancel" + proceed: "Proceed" + input_is_not_correct: "The input is not correct" + you_are_attempting: "You are attempting to delete your account. This means:" + item_1: "All of your comments are removed from this site" + item_2: "All of your comments are deleted from our database" + item_3: "Your username and email address are removed from our system" + step1: + subtitle: "When will my account be deleted?" + description: "Your account will be deleted 24 hours after your request has been submitted." + subtitle_2: "Can I still write comments until my account is deleted?" + description_2: "No. Once you have requested account deletion, you can no longer write comments, reply to comments, or select reactions." + step2: + description: "Before your account is deleted, we recommend you download your comment history for your records. After your account is deleted, you will be unable to request your comment history." + to_download: "To download your comment history go to:" + path: "My Profile > Download My Comment History" + step3: + subtitle: "Are you sure you want to delete your account?" + description: "To confirm you would like to delete your account please type in the following phrase into the text box below:" + type_to_confirm: "Type phrase below to confirm" From 0e20ddb2fde76907314eca3aafde9968d5481160 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 10:40:06 -0600 Subject: [PATCH 67/97] added docs --- docs/source/02-02-advanced-configuration.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/source/02-02-advanced-configuration.md b/docs/source/02-02-advanced-configuration.md index b2ad29ad0..5b638401d 100644 --- a/docs/source/02-02-advanced-configuration.md +++ b/docs/source/02-02-advanced-configuration.md @@ -316,6 +316,18 @@ default to providing only a time based lockout. Refer to [reCAPTCHA](https://www.google.com/recaptcha/intro/index.html) for information on getting an account setup. +## TALK_RECAPTCHA_WINDOW + +The rate limit time interval that there can be [TALK_RECAPTCHA_INCORRECT_TRIGGER](#talk_recaptcha_incorrect_trigger) incorrect attempts until the reCAPTCHA is +marked as required, parsed by +[ms](https://www.npmjs.com/package/ms). (Default `10m`) + +## TALK_RECAPTCHA_INCORRECT_TRIGGER + +The number of times that an incorrect login can be entered before within a time +perioud indicated by [TALK_RECAPTCHA_WINDOW](#talk_recaptcha_window) until the +reCAPTCHA is marked as required. (Default `5`) + ## TALK_REDIS_CLIENT_CONFIGURATION Configuration overrides for the redis client configuration in a JSON encoded @@ -531,4 +543,4 @@ Sets the logging level for the context logger (from [Bunyan](https://github.com/ A JSON string representing the configuration passed to the [fetch](https://www.npmjs.com/package/node-fetch) call for the scraper. It can be used to set an authorization header, or change the user agent. (Default -`{}`) \ No newline at end of file +`{}`) From 287cff289b8b66b121b99d7418bccf963843ce72 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Thu, 3 May 2018 13:04:05 -0400 Subject: [PATCH 68/97] Update copy to reflect ability to take action up until account is deleted --- plugins/talk-plugin-profile-data/client/translations.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/talk-plugin-profile-data/client/translations.yml b/plugins/talk-plugin-profile-data/client/translations.yml index 2a0c9e334..c5fbb8485 100644 --- a/plugins/talk-plugin-profile-data/client/translations.yml +++ b/plugins/talk-plugin-profile-data/client/translations.yml @@ -12,10 +12,10 @@ en: day: "{0} day" download_preparing: "Account Download Preparing - Check your email shortly for a download link" delete_request: - account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled. You may now write comments, reply to comments, and select reactions.' + account_deletion_cancelled: 'Account Deletion Request Cancelled - Your request to delete your account has been cancelled."' account_deletion_requested: 'Account Deletion Requested' received_on: "A request to delete your account was received on " - cancel_request_description: "If you would like to continue leaving comments, replies or reactions, you may cancel your request to delete your account below" + cancel_request_description: "If you would like to reactivate your account, you may cancel your request to delete your account below" before: "before" cancel_account_deletion_request: "Cancel Account Deletion Request" delete_my_account: "Delete My Account" @@ -40,7 +40,7 @@ en: subtitle: "When will my account be deleted?" description: "Your account will be deleted 24 hours after your request has been submitted." subtitle_2: "Can I still write comments until my account is deleted?" - description_2: "No. Once you have requested account deletion, you can no longer write comments, reply to comments, or select reactions." + description_2: "Yes, you can still comment, reply, and react to comments until the 24 hours expires." step_2: description: "Before your account is deleted, we recommend you download your comment history for your records. After your account is deleted, you will be unable to request your comment history." to_download: "To download your comment history go to:" From 06b08756e7b89fa7f8accea5bebc118026bb3b8a Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 3 May 2018 11:36:07 -0600 Subject: [PATCH 69/97] added durations to configuration file --- .../AccountDeletionRequestedSign.js | 3 ++- .../client/components/DeleteMyAccountStep1.js | 5 ++-- .../components/DownloadCommentHistory.js | 6 +++-- .../client/translations.yml | 6 ++--- plugins/talk-plugin-profile-data/config.json | 4 +++ .../server/mutators.js | 26 +++++++++++++------ 6 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 plugins/talk-plugin-profile-data/config.json diff --git a/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js index 60e4d4bc6..e0d5ab255 100644 --- a/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js +++ b/plugins/talk-plugin-profile-data/client/components/AccountDeletionRequestedSign.js @@ -6,6 +6,7 @@ import moment from 'moment'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import styles from './AccountDeletionRequestedSign.css'; import { getErrorMessages } from 'coral-framework/utils'; +import { scheduledDeletionDelayHours } from '../../config.json'; class AccountDeletionRequestedSign extends React.Component { cancelAccountDeletion = async () => { @@ -25,7 +26,7 @@ class AccountDeletionRequestedSign extends React.Component { 'MMM Do YYYY, h:mm a' ); const deletionScheduledOn = moment(scheduledDeletionDate) - .subtract(24, 'hours') + .subtract(scheduledDeletionDelayHours, 'hours') .format('MMM Do YYYY, h:mm a'); return ( diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js index dc137e41e..491c962cf 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountStep1.js @@ -4,16 +4,17 @@ import cn from 'classnames'; import { Button } from 'plugin-api/beta/client/components/ui'; import styles from './DeleteMyAccountStep.css'; import { t } from 'plugin-api/beta/client/services'; +import { scheduledDeletionDelayHours } from '../../config.json'; const DeleteMyAccountStep1 = props => (

{t('delete_request.step_1.subtitle')}

- {t('delete_request.step_1.description')} + {t('delete_request.step_1.description', scheduledDeletionDelayHours)}

{t('delete_request.step_1.subtitle_2')}

- {t('delete_request.step_1.description_2')} + {t('delete_request.step_1.description_2', scheduledDeletionDelayHours)}

) : ( - )} 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 96/97] 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 97/97] 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; }