From ba9f034bfbba573e75000ed723cfb805cb83bec0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 16 Apr 2018 17:37:08 -0600 Subject: [PATCH 001/244] Allow a user to change their own username --- models/action.js | 4 +- perms/reducers/mutation.js | 21 ++- services/users.js | 133 ++++++++++++------ test/server/graph/mutations/changeUsername.js | 2 +- test/server/services/users.js | 58 ++++++++ 5 files changed, 172 insertions(+), 46 deletions(-) diff --git a/models/action.js b/models/action.js index f3414f3ea..773bccf7e 100644 --- a/models/action.js +++ b/models/action.js @@ -22,8 +22,8 @@ const ActionSchema = new Schema( item_id: String, user_id: String, - // The element that summaries will additionally group on in addtion to their action_type, item_type, and - // item_id. + // The element that summaries will additionally group on in addition to + // their action_type, item_type, and item_id. group_id: String, // Additional metadata stored on the field. diff --git a/perms/reducers/mutation.js b/perms/reducers/mutation.js index d0841ef99..f063fe1c2 100644 --- a/perms/reducers/mutation.js +++ b/perms/reducers/mutation.js @@ -1,4 +1,5 @@ -const { isString } = require('lodash'); +const { get, isString } = require('lodash'); +const moment = require('moment'); const { check } = require('../utils'); const types = require('../constants'); @@ -12,8 +13,22 @@ module.exports = (user, perm) => { isString(user.password) && user.password.length > 0 ); - case types.CHANGE_USERNAME: - return user.status.username.status === 'REJECTED'; + + case types.CHANGE_USERNAME: { + // Only users who have their usernames rejected or those users who + // not changed their usernames within 14 days can change their usernames. + const now = moment(); + return ( + user.status.username.status === 'REJECTED' || + get(user, 'status.username.history', []) + .filter(({ status }) => status === 'CHANGED') + .every(({ created_at }) => + moment(created_at) + .add(14, 'days') + .isAfter(now) + ) + ); + } case types.SET_USERNAME: return user.status.username.status === 'UNSET'; diff --git a/services/users.js b/services/users.js index 657be737a..b860acfeb 100644 --- a/services/users.js +++ b/services/users.js @@ -1,4 +1,5 @@ const uuid = require('uuid'); +const moment = require('moment'); const bcrypt = require('bcryptjs'); const { ErrMaxRateLimit, @@ -234,57 +235,64 @@ class Users { return user; } - static async _setUsername( - id, - username, - fromStatus, - toStatus, - assignedBy, - resetAllowed = false - ) { + static async setUsername(id, username, assignedBy) { try { + const oldestEditTime = moment().subtract(14, 'days'); + + // A username can be set if: + // + // - The previous status was 'UNSET' + // - The username has not been changed within the last 14 days. const query = { id, - 'status.username.status': fromStatus, - }; - if (!resetAllowed) { - query.username = { $ne: username }; - } - - let user = await User.findOneAndUpdate( - query, - { - $set: { - username, - lowercaseUsername: username.toLowerCase(), - 'status.username.status': toStatus, + $or: [ + { + 'status.username.status': 'UNSET', }, - $push: { - 'status.username.history': { - status: toStatus, - assigned_by: assignedBy, - created_at: Date.now(), + { + 'status.username.status': { $in: ['APPROVED', 'SET'] }, + 'status.username.history.created_at': { + $not: { + $gte: oldestEditTime, + }, }, }, + ], + }; + + const update = { + $set: { + username, + lowercaseUsername: username.toLowerCase(), + 'status.username.status': 'SET', }, - { - new: true, - } - ); + $push: { + 'status.username.history': { + status: 'SET', + assigned_by: assignedBy, + created_at: Date.now(), + }, + }, + }; + + let user = await User.findOneAndUpdate(query, update, { + new: true, + }); if (!user) { user = await Users.findById(id); if (user === null) { throw new ErrNotFound(); } - if (user.status.username.status !== fromStatus) { + if ( + !['UNSET', 'APPROVED', 'SET'].includes(user.status.username.status) || + !user.status.username.history.every(({ created_at }) => + oldestEditTime.isAfter(created_at) + ) + ) { throw new ErrPermissionUpdateUsername(); } - if (!resetAllowed && user.username === username) { - throw new ErrSameUsernameProvided(); - } - throw new Error('edit username failed for an unexpected reason'); } @@ -298,12 +306,57 @@ class Users { } } - static async setUsername(id, username, assignedBy) { - return Users._setUsername(id, username, 'UNSET', 'SET', assignedBy, true); - } - static async changeUsername(id, username, assignedBy) { - return Users._setUsername(id, username, 'REJECTED', 'CHANGED', assignedBy); + try { + const query = { + id, + username: { $ne: username }, + 'status.username.status': 'REJECTED', + }; + + const update = { + $set: { + username, + lowercaseUsername: username.toLowerCase(), + 'status.username.status': 'CHANGED', + }, + $push: { + 'status.username.history': { + status: 'CHANGED', + assigned_by: assignedBy, + created_at: Date.now(), + }, + }, + }; + + let user = await User.findOneAndUpdate(query, update, { + new: true, + }); + if (!user) { + user = await Users.findById(id); + if (user === null) { + throw new ErrNotFound(); + } + + if (user.status.username.status !== 'REJECTED') { + throw new ErrPermissionUpdateUsername(); + } + + if (user.username === username) { + throw new ErrSameUsernameProvided(); + } + + throw new Error('edit username failed for an unexpected reason'); + } + + return user; + } catch (err) { + if (err.code === 11000) { + throw new ErrUsernameTaken(); + } + + throw err; + } } /** diff --git a/test/server/graph/mutations/changeUsername.js b/test/server/graph/mutations/changeUsername.js index eaff85434..a5c3daed8 100644 --- a/test/server/graph/mutations/changeUsername.js +++ b/test/server/graph/mutations/changeUsername.js @@ -89,7 +89,7 @@ describe('graph.mutations.changeUsername', () => { expect(res.data.changeUsername.errors).to.have.length(1); expect(res.data.changeUsername.errors[0]).to.have.property( 'translation_key', - 'NOT_AUTHORIZED' + 'EDIT_USERNAME_NOT_AUTHORIZED' ); // Set the user to the desired status. diff --git a/test/server/services/users.js b/test/server/services/users.js index e8a0172f7..a7d7475e9 100644 --- a/test/server/services/users.js +++ b/test/server/services/users.js @@ -2,6 +2,8 @@ const UsersService = require('../../../services/users'); const SettingsService = require('../../../services/settings'); const mailer = require('../../../services/mailer'); const Context = require('../../../graph/context'); +const timekeeper = require('timekeeper'); +const moment = require('moment'); const chai = require('chai'); chai.use(require('chai-as-promised')); @@ -303,6 +305,62 @@ describe('services.UsersService', () => { } }); }); + + if (func === 'setUsername') { + it('should let a user set their username from UNSET', async () => { + const user = mockUsers[0]; + + // Set the user to the desired status. + await UsersService.setUsernameStatus(user.id, 'UNSET'); + await UsersService.setUsername(user.id, 'new_username', null); + }); + + describe('time based', () => { + afterEach(() => { + timekeeper.reset(); + }); + + ['SET', 'APPROVED'].forEach(status => { + it(`should not allow users to change their username if it was changed within 14 of today from ${status}`, async () => { + const user = mockUsers[0]; + + // Set the user to the desired status. + await UsersService.setUsernameStatus(user.id, status); + + timekeeper.travel( + moment() + .add(5, 'days') + .toDate() + ); + + try { + await UsersService.setUsername(user.id, 'new_username', null); + throw new Error('edit was processed successfully'); + } catch (err) { + expect(err).have.property( + 'translation_key', + 'EDIT_USERNAME_NOT_AUTHORIZED' + ); + } + }); + + it(`allows users to change their username if it was changed 14 days before today from ${status}`, async () => { + const user = mockUsers[0]; + + // Set the user to the desired status. + await UsersService.setUsernameStatus(user.id, status); + + timekeeper.travel( + moment() + .add(15, 'days') + .toDate() + ); + + await UsersService.setUsername(user.id, 'new_username', null); + }); + }); + }); + } }); describe('#isValidUsername', () => { From 2adec1bc344137ba2383b62820c70c30542658ec Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 18 Apr 2018 13:13:41 -0600 Subject: [PATCH 002/244] 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 003/244] 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 b60e62f9769bf78f47d09d684d69180537bb624c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 19 Apr 2018 09:21:12 -0600 Subject: [PATCH 004/244] small fixes for db logic --- services/users.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/users.js b/services/users.js index b860acfeb..a3301be10 100644 --- a/services/users.js +++ b/services/users.js @@ -237,7 +237,9 @@ class Users { static async setUsername(id, username, assignedBy) { try { - const oldestEditTime = moment().subtract(14, 'days'); + const oldestEditTime = moment() + .subtract(14, 'days') + .toDate(); // A username can be set if: // @@ -252,9 +254,7 @@ class Users { { 'status.username.status': { $in: ['APPROVED', 'SET'] }, 'status.username.history.created_at': { - $not: { - $gte: oldestEditTime, - }, + $lte: oldestEditTime, }, }, ], From 68461308c68c1cedd3810bc6336daa9c65dd95b2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 19 Apr 2018 13:37:14 -0600 Subject: [PATCH 005/244] 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 006/244] 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 007/244] 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 008/244] 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 009/244] 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 010/244] 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 011/244] 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 15817712c07af7d22d9082d98c81e37c3f4aa3c3 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 24 Apr 2018 13:58:28 -0300 Subject: [PATCH 012/244] Introducing profileHeader slot --- .../src/tabs/profile/components/Profile.js | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/profile/components/Profile.js b/client/coral-embed-stream/src/tabs/profile/components/Profile.js index 0bc90be0a..e73ebe455 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Profile.js +++ b/client/coral-embed-stream/src/tabs/profile/components/Profile.js @@ -4,13 +4,31 @@ import Slot from 'coral-framework/components/Slot'; import styles from './Profile.css'; import TabPanel from '../containers/TabPanel'; +const DefaultProfileHeader = ({ username, emailAddress }) => ( +
+

{username}

+ {emailAddress ?

{emailAddress}

: null} +
+); + +DefaultProfileHeader.propTypes = { + username: PropTypes.string, + emailAddress: PropTypes.string, +}; + const Profile = ({ username, emailAddress, root, slotPassthrough }) => { return (
-
-

{username}

- {emailAddress ?

{emailAddress}

: null} -
+
From 89114ecd13aad5fde9b19eae618bc6ec2daabe56 Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 24 Apr 2018 14:13:24 -0300 Subject: [PATCH 013/244] Adding withChangeUsername to plugin hocs, wip and more --- plugin-api/beta/client/hocs/index.js | 1 + plugins/talk-plugin-auth/client/index.js | 2 + .../components/ChangeUsername.css | 20 ++++++++ .../components/ChangeUsername.js | 51 +++++++++++++++++++ .../containers/ChangeUsername.js | 12 +++++ 5 files changed, 86 insertions(+) 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/containers/ChangeUsername.js diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index 41ede8445..d7ca5fce9 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -26,5 +26,6 @@ export { withStopIgnoringUser, withSetCommentStatus, withChangePassword, + withChangeUsername, } from 'coral-framework/graphql/mutations'; export { compose } from 'recompose'; diff --git a/plugins/talk-plugin-auth/client/index.js b/plugins/talk-plugin-auth/client/index.js index 039f0f936..8fedb8033 100644 --- a/plugins/talk-plugin-auth/client/index.js +++ b/plugins/talk-plugin-auth/client/index.js @@ -5,6 +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'; export default { reducer, @@ -12,6 +13,7 @@ export default { slots: { stream: [UserBox, SignInButton, SetUsernameDialog], login: [Login], + profileHeader: [ChangeUsername], profileSettings: [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..c28cc163c --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css @@ -0,0 +1,20 @@ +.container { + margin-bottom: 20px; +} + +.email { + margin: 0; +} + +.username { + margin-bottom: 4px; +} + +.actions { + position: absolute; + top: 10px; + right: 10px; + display: flex; + flex-direction: column; + align-items: center; +} \ No newline at end of file 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..59eadb1c4 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -0,0 +1,51 @@ +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'; + +const initialState = { + editing: false, +}; + +class ChangeUsername extends React.Component { + state = initialState; + + render() { + const { username, emailAddress } = this.props; + return ( +
+
+

{username}

+ {emailAddress ?

{emailAddress}

: null} +
+
+ + + Cancel + +
+
+ +
+
+ ); + } +} + +ChangeUsername.propTypes = { + changeUsername: 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 new file mode 100644 index 000000000..87e1e18b5 --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/containers/ChangeUsername.js @@ -0,0 +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 { 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 +); From 3bd2d0b3fcfd89e63c2f62cb0a2bcf91262d2ab2 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Tue, 24 Apr 2018 17:17:57 -0400 Subject: [PATCH 014/244] Small fix --- docs/source/03-03-product-guide-moderator-features.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/03-03-product-guide-moderator-features.md b/docs/source/03-03-product-guide-moderator-features.md index 9fbda6a18..abb2c454a 100644 --- a/docs/source/03-03-product-guide-moderator-features.md +++ b/docs/source/03-03-product-guide-moderator-features.md @@ -170,8 +170,9 @@ moderators. All your team and commenters show in the People sub-tab. From here, you can manage your team members’ roles (Admins, Moderators, Staff), as well as search -for commenters and take action on them (e.g. Ban/Un-ban, Suspend, etc.). ### -Configure +for commenters and take action on them (e.g. Ban/Un-ban, Suspend, etc.). + +### Configure See [Configuring Talk](/talk/configuring-talk/). From 2bc6687957214611a22fc85aaa1d74cf71eba710 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Wed, 25 Apr 2018 11:09:54 -0400 Subject: [PATCH 015/244] Use email vs e-mail --- locales/en.yml | 8 ++++---- plugins/talk-plugin-auth/client/translations.yml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index f8b9b9ce2..d7ad006cb 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -236,7 +236,7 @@ en: RATE_LIMIT_EXCEEDED: "Rate limit exceeded" USERNAME_IN_USE: "Username already in use" USERNAME_REQUIRED: "Must input a username" - EMAIL_NOT_VERIFIED: "E-mail address not verified" + EMAIL_NOT_VERIFIED: "Email address not verified" EDIT_WINDOW_ENDED: "You can no longer edit this comment. The time window to do so has expired." EDIT_USERNAME_NOT_AUTHORIZED: "You do not have permission to update your username." SAME_USERNAME_PROVIDED: "You must submit a different username." @@ -252,8 +252,8 @@ en: 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." - email_not_verified: "E-mail address {0} not verified." - email_password: "E-mail and/or password combination incorrect." + email_not_verified: "Email address {0} not verified." + email_password: "Email and/or password combination incorrect." organization_name: "Organization name must only contain letters or numbers." organization_contact_email: "Organization email is not valid." password: "Password must be at least 8 characters" @@ -441,7 +441,7 @@ en: title_reject: "We noticed you rejected a username" suspend_user: "Suspend User" yes_suspend: "Yes suspend" - email_message_reject: "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment, like, or flag content until you rewrite your username. Please e-mail us if you have any questions or concerns." + email_message_reject: "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment, like, or flag content until you rewrite your username. Please email us if you have any questions or concerns." write_message: "Write a message" send: Send thank_you: "We value your safety and feedback. A moderator will review your report." diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index 915aee1c7..73c10b867 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -58,7 +58,7 @@ da: sign_in: "Sign in" sign_in_to_join: "Sign in to join the conversation" or: "Or" - email: "E-mail Address" + email: "Email Address" password: "Password" forgot_your_pass: "Forgot your password?" need_an_account: "Need an account?" @@ -101,7 +101,7 @@ en: sign_in: "Sign in" sign_in_to_join: "Sign in to join the conversation" or: "Or" - email: "E-mail Address" + email: "Email Address" password: "Password" forgot_your_pass: "Forgot your password?" need_an_account: "Need an account?" @@ -342,7 +342,7 @@ pt_BR: sign_in: "Sign in" sign_in_to_join: "Sign in to join the conversation" or: "Or" - email: "E-mail Address" + email: "Email Address" password: "Password" forgot_your_pass: "Forgot your password?" need_an_account: "Need an account?" From 754b5c5fbb6216e8344e744a7fb10ba49e9af1e7 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 25 Apr 2018 12:20:51 -0300 Subject: [PATCH 016/244] Adding Dialog, styles and more --- .../components/ChangePassword.css | 2 +- .../components/ChangeUsername.css | 121 ++++++++++++- .../components/ChangeUsername.js | 170 +++++++++++++++--- .../components/ChangeUsernameDialog.css | 82 +++++++++ .../components/ChangeUsernameDialog.js | 57 ++++++ 5 files changed, 398 insertions(+), 34 deletions(-) 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 diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css index e94247ac1..6c7f9ae41 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.css @@ -47,7 +47,7 @@ border: 1px solid #787d80; background-color: transparent; height: 30px; - font-size: 1em; + font-size: 0.9em; line-height: normal; } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css index c28cc163c..8ab9eb5cd 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css @@ -1,20 +1,123 @@ .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 { +.username { margin-bottom: 4px; +} + +.button { + border: 1px solid #787d80; + background-color: transparent; + height: 30px; + font-size: 0.9em; + line-height: normal; } -.actions { - position: absolute; - top: 10px; - right: 10px; - display: flex; - flex-direction: column; - align-items: center; -} \ No newline at end of file +.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; + display: block; +} + +.detailList { + list-style: none; + margin: 0; + padding: 0; +} + +.detailItem { + margin-bottom: 8px; +} 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 59eadb1c4..42349e3e9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -2,41 +2,163 @@ 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 { Icon, Button } from 'plugin-api/beta/client/components/ui'; +import ChangeUsernameDialog from './ChangeUsernameDialog'; const initialState = { editing: false, + formData: {}, + showDialog: false, }; 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(); + // this.clearForm(); + // this.disableEditing(); + }; + + onChange = e => { + const { name, value } = e.target; + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + console.log(this.state.formData); + // Validation + // this.fieldValidation(value, type, name); + // // Perform equality validation if password fields have changed + // if (name === 'newPassword' || name === 'confirmNewPassword') { + // this.equalityValidation('newPassword', 'confirmNewPassword'); + // } + } + ); + }; + + closeDialog = () => { + this.setState({ + showDialog: false, + }); + }; + render() { const { username, emailAddress } = this.props; + const { editing } = this.state; + + console.log('loading xxxx'); + return ( -
-
-

{username}

- {emailAddress ?

{emailAddress}

: null} -
-
- - - Cancel - -
-
- -
+
+ + + {editing ? ( +
+
    +
  • + + + Usernames can be changed every 14 days + +
  • +
  • + +
  • +
+
+ ) : ( +
+

{username}

+ {emailAddress ? ( +

{emailAddress}

+ ) : null} +
+ )} + + {editing ? ( +
+ + + Cancel + +
+ ) : ( +
+ +
+ )}
); } 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..b3c4524fe --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css @@ -0,0 +1,82 @@ +.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; +} + +.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..e0c08ec3e --- /dev/null +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -0,0 +1,57 @@ +import React from 'react'; +import cn from 'classnames'; +import styles from './ChangeUsernameDialog.css'; +import InputField from './InputField'; +import Form from './Form'; +import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; + +class ChangeUsernameDialog extends React.Component { + render() { + return ( + + + × + +

Confirm Username Change

+
+

+ You are attempting to change your username. Your new username will + appear on all of your past and future comments. +

+
+ + Old Username: {this.props.username} + + + New Username: {this.props.formData.newUsername} + +
+
+ + + Note: You will not be able to change your username again for 14 + days + + +
+
+ + +
+
+
+ ); + } +} + +export default ChangeUsernameDialog; From a79d71da7d78b634c8095303e4adfe03db8c967b Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 25 Apr 2018 12:53:03 -0300 Subject: [PATCH 017/244] Full functionality, needs translation --- .../components/ChangeUsername.css | 3 +- .../components/ChangeUsername.js | 11 +++--- .../components/ChangeUsernameDialog.css | 2 ++ .../components/ChangeUsernameDialog.js | 34 ++++++++++++++++++- .../components/ErrorMessage.css | 1 - .../components/InputField.css | 16 +++++++-- .../profile-settings/components/InputField.js | 14 ++++++-- 7 files changed, 68 insertions(+), 13 deletions(-) diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css index 8ab9eb5cd..5b4631ecf 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.css @@ -109,7 +109,6 @@ .bottomText { color: #474747; font-size: 0.9em; - display: block; } .detailList { @@ -119,5 +118,5 @@ } .detailItem { - margin-bottom: 8px; + 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 index 42349e3e9..a146ea5f9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -43,8 +43,10 @@ class ChangeUsername extends React.Component { onSave = async () => { this.showDialog(); - // this.clearForm(); - // this.disableEditing(); + }; + + saveChanges = async () => { + // savechanges }; onChange = e => { @@ -78,8 +80,6 @@ class ChangeUsername extends React.Component { const { username, emailAddress } = this.props; const { editing } = this.state; - console.log('loading xxxx'); - return (
Save diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css index b3c4524fe..af681d596 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.css @@ -46,6 +46,8 @@ .bottomNote { font-size: 0.9em; line-height: 20px; + padding-top: 10px; + display: block; } .bottomActions { diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js index e0c08ec3e..b337af007 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -6,6 +6,28 @@ import Form from './Form'; import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; class ChangeUsernameDialog extends React.Component { + state = { + showErrors: false, + }; + + showErrors = () => { + this.setState({ + showErrors: true, + }); + }; + + confirmChanges = async () => { + if (this.formHasError()) { + this.showErrors(); + } else { + // await this.props.saveChanges + this.props.closeDialog(); + } + }; + + formHasError = () => + this.props.formData.confirmNewUsername !== this.props.formData.newUsername; + render() { return ( Note: You will not be able to change your username again for 14 @@ -46,7 +73,12 @@ class ChangeUsernameDialog extends React.Component {
- +
diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css index d7a1b6d45..abcf692fe 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ErrorMessage.css @@ -1,6 +1,5 @@ .errorMsg { color: #FA4643; - padding-left: 4px; font-size: 0.9em; } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css index be25a44b9..b2648e116 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css @@ -7,6 +7,14 @@ display: flex; } +.columnDisplay { + flex-direction: column; + + .detailItemMessage { + padding: 4px 0 0; + } +} + .detailItemContent { min-width: 280px; } @@ -28,13 +36,17 @@ color: #979797; box-sizing: border-box; width: 100%; + + &.error { + border-color: #FA4643; + } } .detailItemMessage { flex-grow: 1; display: flex; align-items: center; - padding-left: 2px; + padding-left: 6px; padding-top: 16px; .warningIcon, .checkIcon { @@ -48,4 +60,4 @@ .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 index ed9c394ee..5818bfd2c 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js @@ -1,5 +1,6 @@ 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'; @@ -15,10 +16,16 @@ const InputField = ({ hasError = false, errorMsg = '', children, + columnDisplay = false, + showSuccess = true, }) => { return (
  • -
    +
    {!hasError && + showSuccess && value && } {hasError && showError && {errorMsg}}
    @@ -55,6 +63,8 @@ InputField.propTypes = { hasError: PropTypes.bool, errorMsg: PropTypes.string, children: PropTypes.node, + columnDisplay: PropTypes.bool, + showSuccess: PropTypes.bool, }; export default InputField; From aefac2056edb1037444a7f80b6f4a8b02cc85e95 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 25 Apr 2018 13:36:00 -0300 Subject: [PATCH 018/244] wip more validations --- .../components/ChangeUsername.js | 61 ++++++++++++++++--- .../components/ChangeUsernameDialog.js | 1 + .../profile-settings/components/InputField.js | 5 +- 3 files changed, 57 insertions(+), 10 deletions(-) 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 a146ea5f9..d9f2fc15d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -4,11 +4,15 @@ import PropTypes from 'prop-types'; import styles from './ChangeUsername.css'; import { Icon, Button } from 'plugin-api/beta/client/components/ui'; import ChangeUsernameDialog from './ChangeUsernameDialog'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; +import { t } from 'plugin-api/beta/client/services'; const initialState = { editing: false, - formData: {}, showDialog: false, + errors: {}, + formData: {}, }; class ChangeUsername extends React.Component { @@ -49,8 +53,50 @@ class ChangeUsername extends React.Component { // savechanges }; + 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 }, + }), + () => { + console.log(this.state); + } + ); + }; + + removeError = errKey => { + this.setState( + state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }, + () => { + console.log(this.state); + } + ); + }; + onChange = e => { - const { name, value } = e.target; + const { name, value, type, dataset: { validationType } } = e.target; + this.setState( state => ({ formData: { @@ -59,13 +105,9 @@ class ChangeUsername extends React.Component { }, }), () => { - console.log(this.state.formData); - // Validation - // this.fieldValidation(value, type, name); - // // Perform equality validation if password fields have changed - // if (name === 'newPassword' || name === 'confirmNewPassword') { - // this.equalityValidation('newPassword', 'confirmNewPassword'); - // } + const fieldType = !validationType ? type : validationType; + this.fieldValidation(value, fieldType, name); + // the username cannot be the same } ); }; @@ -103,6 +145,7 @@ class ChangeUsername extends React.Component { Note: You will not be able to change your username again for 14 diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js index 5818bfd2c..511b89227 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js @@ -18,6 +18,7 @@ const InputField = ({ children, columnDisplay = false, showSuccess = true, + validationType = '', }) => { return (
  • @@ -34,10 +35,11 @@ const InputField = ({ id={id} type={type} name={name} - className={cn(styles.detailValue, styles.error)} + className={cn(styles.detailValue, { [styles.error]: hasError })} onChange={onChange} value={value} autoComplete="off" + data-validation-type={validationType} />
    @@ -65,6 +67,7 @@ InputField.propTypes = { children: PropTypes.node, columnDisplay: PropTypes.bool, showSuccess: PropTypes.bool, + validationType: PropTypes.string, }; export default InputField; From dd9a9d5882577a8360f7e902d5aaba2034fe4224 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Wed, 25 Apr 2018 15:30:40 -0400 Subject: [PATCH 019/244] Remove refs to talk-plugin-profile-settings --- .gitignore | 1 - docs/source/api/slots.md | 3 +-- docs/source/integrating/configuring-comment-stream.md | 4 ---- docs/source/integrating/notifications.md | 4 ---- 4 files changed, 1 insertion(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index e8cb92653..0cab02aeb 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,6 @@ 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-remember-sort !plugins/talk-plugin-respect diff --git a/docs/source/api/slots.md b/docs/source/api/slots.md index da57c0ad6..a2e7cc04d 100644 --- a/docs/source/api/slots.md +++ b/docs/source/api/slots.md @@ -33,8 +33,7 @@ By default, Talk has various plugins provided by default. We can see this in `pl "talk-plugin-sort-most-respected", "talk-plugin-sort-newest", "talk-plugin-sort-oldest", - "talk-plugin-viewing-options", - "talk-plugin-profile-settings" + "talk-plugin-viewing-options" ] } ``` diff --git a/docs/source/integrating/configuring-comment-stream.md b/docs/source/integrating/configuring-comment-stream.md index 110560de0..613535a13 100644 --- a/docs/source/integrating/configuring-comment-stream.md +++ b/docs/source/integrating/configuring-comment-stream.md @@ -65,10 +65,6 @@ First, you'll enable `talk-plugin-author-menu`, as this houses the Ignore button And then we will enable the Ignore User plugin: `talk-plugin-ignore-user`. -And finally, we will need to enable Profile Settings; this is the tab on My Profile > Settings where commenters can manage their Ignored Users list. - -`talk-plugin-profile-settings` - ### Featured Comments To enable the featuring of comments, you'll need to activate `talk-plugin-featured-comments`. If you would like the Featured Comments tab to be the default tab you land on for the stream, you will need to set the default tab ENV variable: diff --git a/docs/source/integrating/notifications.md b/docs/source/integrating/notifications.md index 470632907..a5f625083 100644 --- a/docs/source/integrating/notifications.md +++ b/docs/source/integrating/notifications.md @@ -36,10 +36,6 @@ Adding the `talk-plugin-notifications` plugin will also enable the `notification See https://github.com/coralproject/talk/blob/8b669a31c551a042f0f079d8cfc16825673eb8f0/plugins/talk-plugin-notifications-reply/index.js for an example. -### Commenter Notification Settings - -Note that notifications REQUIRE the `talk-plugin-profile-settings` plugin; this is where on My Profile commenters will enable and manage their notification settings. - ### Notification Categories Talk currently supports the following Notifications options out of the box: From 8f6691f7a4ea9448d55675fc74a5414f46ecfb0e Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 26 Apr 2018 11:15:18 -0300 Subject: [PATCH 020/244] InputField refactor --- .../components/ChangeUsername.js | 44 ++++++++----------- .../components/ChangeUsernameDialog.js | 12 ++--- .../components/InputField.css | 39 ++++++++++------ .../profile-settings/components/InputField.js | 41 ++++++++++++----- 4 files changed, 81 insertions(+), 55 deletions(-) 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 d9f2fc15d..b5bd8916b 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -7,6 +7,7 @@ import ChangeUsernameDialog from './ChangeUsernameDialog'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; import { t } from 'plugin-api/beta/client/services'; +import InputField from './InputField'; const initialState = { editing: false, @@ -139,34 +140,27 @@ class ChangeUsername extends React.Component { {editing ? (
      -
    • - + Usernames can be changed every 14 days -
    • -
    • - -
    • + +
    ) : ( diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js index d5e50b4e8..22c74bce3 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -7,18 +7,18 @@ import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; class ChangeUsernameDialog extends React.Component { state = { - showErrors: false, + showError: false, }; - showErrors = () => { + showError = () => { this.setState({ - showErrors: true, + showError: true, }); }; confirmChanges = async () => { if (this.formHasError()) { - this.showErrors(); + this.showError(); } else { // await this.props.saveChanges this.props.closeDialog(); @@ -59,9 +59,9 @@ class ChangeUsernameDialog extends React.Component { type="text" onChange={this.props.onChange} value={this.props.formData.confirmNewUsername} - hasError={this.formHasError() && this.state.showErrors} + hasError={this.formHasError() && this.state.showError} errorMsg={'Username does not match'} - showErrors={this.state.showErrors} + showError={this.state.showError} columnDisplay showSuccess={false} validationType="username" diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css index b2648e116..f76970045 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css @@ -16,7 +16,24 @@ } .detailItemContent { - min-width: 280px; + border: solid 1px #787D80; + border-radius: 2px; + background-color: white; + height: 30px; + display: inline-block; + width: 230px; + display: flex; + + > .detailIcon { + font-size: 1.2em; + padding: 0 5px; + color: #787D80; + line-height: 30px; + } + + &.disabled { + background-color: #E0E0E0; + } } .detailLabel { @@ -27,19 +44,13 @@ } .detailValue { - padding: 6px 2px; - border: solid 1px #979797; - display: block; - font-size: 1.1em; - border-radius: 2px; - background-color: #ffffff; - color: #979797; - box-sizing: border-box; - width: 100%; - - &.error { - border-color: #FA4643; - } + background: transparent; + border: none; + font-size: 1em; + color: #000; + height: 30px; + outline: none; + flex: 1; } .detailItemMessage { diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js index 511b89227..7fa9a368a 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js @@ -11,35 +11,53 @@ const InputField = ({ type = 'text', name = '', onChange = () => {}, - value = '', showError = true, hasError = false, errorMsg = '', children, columnDisplay = false, - showSuccess = true, + showSuccess = false, validationType = '', + icon = '', + value = '', + defaultValue = '', + disabled = false, }) => { + const inputValue = { + ...(value ? { value } : {}), + ...(defaultValue ? { defaultValue } : {}), + }; + return ( -
  • +
    -
    + {label && ( + )} +
    + {icon && }
    @@ -50,17 +68,20 @@ const InputField = ({
    {children} -
  • + ); }; InputField.propTypes = { - id: PropTypes.string.isRequired, - label: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, + id: PropTypes.string, + disabled: PropTypes.boolean, + 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, From 2db9489646a9f87de1a68d6c809ef4d9d3b2c2cc Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 26 Apr 2018 11:15:35 -0300 Subject: [PATCH 021/244] Adding translations --- .../components/ChangePassword.js | 5 +- .../components/ChangeUsername.js | 79 ++++--------------- .../components/ChangeUsernameDialog.js | 14 +++- .../profile-settings/components/Form.css | 5 -- .../profile-settings/components/Form.js | 16 ---- .../talk-plugin-auth/client/translations.yml | 7 ++ 6 files changed, 34 insertions(+), 92 deletions(-) delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/Form.css delete mode 100644 plugins/talk-plugin-auth/client/profile-settings/components/Form.js diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js index 3479b5dd9..90940728d 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangePassword.js @@ -7,7 +7,6 @@ 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 Form from './Form'; import InputField from './InputField'; import { getErrorMessages } from 'coral-framework/utils'; @@ -148,7 +147,7 @@ class ChangePassword extends React.Component { {t('talk-plugin-auth.change_password.change_password')} {editing && ( -
    + - + )} {editing ? (
    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 b5bd8916b..4fcca70fd 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -2,17 +2,14 @@ import React from 'react'; import cn from 'classnames'; import PropTypes from 'prop-types'; import styles from './ChangeUsername.css'; -import { Icon, Button } from 'plugin-api/beta/client/components/ui'; +import { Button } from 'plugin-api/beta/client/components/ui'; import ChangeUsernameDialog from './ChangeUsernameDialog'; -import validate from 'coral-framework/helpers/validate'; -import errorMsj from 'coral-framework/helpers/error'; import { t } from 'plugin-api/beta/client/services'; import InputField from './InputField'; const initialState = { editing: false, showDialog: false, - errors: {}, formData: {}, }; @@ -54,63 +51,15 @@ class ChangeUsername extends React.Component { // savechanges }; - 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 }, - }), - () => { - console.log(this.state); - } - ); - }; - - removeError = errKey => { - this.setState( - state => { - const { [errKey]: _, ...errors } = state.errors; - return { - errors, - }; - }, - () => { - console.log(this.state); - } - ); - }; - onChange = e => { - const { name, value, type, dataset: { validationType } } = e.target; + const { name, value } = e.target; - this.setState( - state => ({ - formData: { - ...state.formData, - [name]: value, - }, - }), - () => { - const fieldType = !validationType ? type : validationType; - this.fieldValidation(value, fieldType, name); - // the username cannot be the same - } - ); + this.setState(state => ({ + formData: { + ...state.formData, + [name]: value, + }, + })); }; closeDialog = () => { @@ -139,7 +88,7 @@ class ChangeUsername extends React.Component { {editing ? (
    -
      +
      - Usernames can be changed every 14 days + {t('talk-plugin-auth.change_username.change_username_note')} -
    +
    ) : (
    @@ -180,10 +129,10 @@ class ChangeUsername extends React.Component { onClick={this.onSave} disabled={!this.state.formData.newUsername} > - Save + {t('talk-plugin-auth.change_username.save')} - Cancel + {t('talk-plugin-auth.change_username.cancel')}
    ) : ( @@ -193,7 +142,7 @@ class ChangeUsername extends React.Component { icon="settings" onClick={this.enableEditing} > - Edit Profile + {t('talk-plugin-auth.change_username.edit_profile')} )} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js index 22c74bce3..a561106c9 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -1,8 +1,8 @@ import React from 'react'; +import PropTypes from 'prop-types'; import cn from 'classnames'; import styles from './ChangeUsernameDialog.css'; import InputField from './InputField'; -import Form from './Form'; import { Button, Dialog } from 'plugin-api/beta/client/components/ui'; class ChangeUsernameDialog extends React.Component { @@ -51,7 +51,7 @@ class ChangeUsernameDialog extends React.Component { New Username: {this.props.formData.newUsername} -
    + -
    +
    diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index 84dc4e320..0d05d45c5 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -145,6 +145,12 @@ en: 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" de: talk-plugin-auth: login: From ba7de6bf81f2cb96095a5a5061119451aee2fec8 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 26 Apr 2018 11:25:40 -0300 Subject: [PATCH 023/244] Translations --- .../client/profile-settings/components/ChangeUsername.js | 5 ++++- .../profile-settings/components/ChangeUsernameDialog.js | 2 +- .../client/profile-settings/components/InputField.css | 4 ++++ .../client/profile-settings/components/InputField.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) 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 4fcca70fd..fbc8bfb1b 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -127,7 +127,10 @@ class ChangeUsername extends React.Component { className={cn(styles.button, styles.saveButton)} icon="save" onClick={this.onSave} - disabled={!this.state.formData.newUsername} + disabled={ + !this.state.formData.newUsername && + this.state.formData.newUsername !== username + } > {t('talk-plugin-auth.change_username.save')} diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js index 244dba00a..5bcc43241 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsernameDialog.js @@ -92,7 +92,7 @@ class ChangeUsernameDialog extends React.Component { ChangeUsernameDialog.propTypes = { closeDialog: PropTypes.func, - showDialog: PropTypes.func, + showDialog: PropTypes.bool, onChange: PropTypes.func, username: PropTypes.string, formData: PropTypes.object, diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css index f76970045..ff0b47cf1 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.css @@ -31,6 +31,10 @@ line-height: 30px; } + &.error { + border: solid 2px #FA4643; + } + &.disabled { background-color: #E0E0E0; } diff --git a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js index 7fa9a368a..34c314c20 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/InputField.js @@ -74,7 +74,7 @@ const InputField = ({ InputField.propTypes = { id: PropTypes.string, - disabled: PropTypes.boolean, + disabled: PropTypes.bool, label: PropTypes.string, type: PropTypes.string, name: PropTypes.string.isRequired, From 8643b1fbf2b49dcc93b2307451c8e93a23b94375 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Thu, 26 Apr 2018 17:52:03 +0200 Subject: [PATCH 024/244] Decrease font-size and padding in Flag Comment popup a bit. --- client/coral-embed-stream/style/default.css | 4 ++-- client/coral-ui/components/PopupMenu.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 98416d68d..b9330ba62 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -177,8 +177,8 @@ button.comment__action-button[disabled], } .talk-plugin-flags-popup-header { - font-weight: bolder; - font-size: 1.33rem; + font-weight: bold; + font-size: 1rem; margin-bottom: 10px; } diff --git a/client/coral-ui/components/PopupMenu.css b/client/coral-ui/components/PopupMenu.css index 35544fbad..e6a084736 100644 --- a/client/coral-ui/components/PopupMenu.css +++ b/client/coral-ui/components/PopupMenu.css @@ -9,7 +9,7 @@ box-sizing: border-box; background: white; border-radius: 3px; - padding: 20px 10px; + padding: 10px 10px; z-index: 300; right: 1%; } From ab02b1b6ca5ecce778f2f7bb785a34120c1a3c47 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 26 Apr 2018 17:00:08 -0300 Subject: [PATCH 025/244] No empty username, no same username --- .../client/profile-settings/components/ChangeUsername.js | 5 ++--- .../client/profile-settings/components/InputField.css | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) 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 fbc8bfb1b..8423ed403 100644 --- a/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js +++ b/plugins/talk-plugin-auth/client/profile-settings/components/ChangeUsername.js @@ -120,7 +120,6 @@ class ChangeUsername extends React.Component { ) : null} )} - {editing ? (
    + + +
    + + + ); + } +} + +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 037/244] 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 038/244] 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 051/244] 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 8d1d96884ea709564c2f3c67f4cd62194cf9c0b1 Mon Sep 17 00:00:00 2001 From: Andrew Losowsky Date: Tue, 1 May 2018 09:08:58 -0400 Subject: [PATCH 052/244] small wording change changed 'Customize' for 'Change' (more plain English) --- locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.yml b/locales/en.yml index a95f2dc13..ff0d7e487 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -123,7 +123,7 @@ en: custom_css_url: "Custom CSS URL" custom_css_url_desc: "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external." days: Days - description: "Customize the comment settings on this story." + description: "Change the comment settings on this story." domain_list_text: "Enter the domains you would like to permit for Talk e.g. your local staging and production environments (ex. localhost:3000 staging.domain.com domain.com)." domain_list_title: "Permitted Domains" edit_info: "Edit Info" From 9310a4734d940ac825889dde2523b9747b942291 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:16:41 +0200 Subject: [PATCH 053/244] Fix viewing/editing empty org contact email --- .../src/routes/Configure/components/OrganizationSettings.js | 3 +-- client/coral-framework/utils/index.js | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js index 2bbe1a230..f3daeffc2 100644 --- a/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js +++ b/client/coral-admin/src/routes/Configure/components/OrganizationSettings.js @@ -84,7 +84,6 @@ class OrganizationSettings extends React.Component { render() { const { settings, slotPassthrough, canSave } = this.props; const hasErrors = this.state.errors.length; - return (

    {t('configure.organization_info_copy')}

    @@ -125,7 +124,7 @@ class OrganizationSettings extends React.Component { [styles.editable]: this.state.editing, })} onChange={this.updateEmail} - value={settings.organizationContactEmail} + value={settings.organizationContactEmail || ''} id={t('configure.organization_contact_email')} readOnly={!this.state.editing} /> diff --git a/client/coral-framework/utils/index.js b/client/coral-framework/utils/index.js index 66792b9b3..8dc8fe113 100644 --- a/client/coral-framework/utils/index.js +++ b/client/coral-framework/utils/index.js @@ -237,7 +237,11 @@ export function getTotalReactionsCount(actionSummaries) { // Like lodash merge but does not recurse into arrays. export function mergeExcludingArrays(objValue, srcValue) { - if (typeof srcValue === 'object' && !Array.isArray(srcValue)) { + if ( + typeof srcValue === 'object' && + !Array.isArray(srcValue) && + srcValue !== null + ) { return assignWith({}, objValue, srcValue, mergeExcludingArrays); } return srcValue; From e8cd938b65059b21b77bd5f169ee180c258df86c Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:18:17 +0200 Subject: [PATCH 054/244] Move next route out of state --- .../src/routes/Configure/containers/Configure.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 7f0951154..73e643343 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -20,7 +20,7 @@ import OrganizationSettings from './OrganizationSettings'; import { withRouter } from 'react-router'; class ConfigureContainer extends React.Component { - state = { nextRoute: '' }; + nextRoute = ''; savePending = async () => { await this.props.updateSettings(this.props.pending); @@ -40,10 +40,9 @@ class ConfigureContainer extends React.Component { }; gotoNextRoute = () => { - const { nextRoute } = this.state; - if (nextRoute) { - this.props.router.push(nextRoute); - this.setState({ nextRoute: '' }); + if (this.nextRoute) { + this.props.router.push(this.nextRoute); + this.nextRoute = ''; } }; @@ -51,7 +50,7 @@ class ConfigureContainer extends React.Component { const nextRoute = `/admin/configure/${section}`; if (this.shouldShowSaveDialog()) { - await this.setState({ nextRoute }); + this.nextRoute = nextRoute; this.props.showSaveDialog(); } else { // Just go to the section @@ -65,7 +64,7 @@ class ConfigureContainer extends React.Component { routeLeave = ({ pathname }) => { if (this.shouldShowSaveDialog()) { - this.setState({ nextRoute: pathname }); + this.nextRoute = pathname; this.props.showSaveDialog(); return false; } From fd3f5e511625a83d451547f05840834e878ed657 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:19:47 +0200 Subject: [PATCH 055/244] Cleanup leave hook --- .../src/routes/Configure/containers/Configure.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 73e643343..4910a2ec4 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -21,6 +21,7 @@ import { withRouter } from 'react-router'; class ConfigureContainer extends React.Component { nextRoute = ''; + unregisterLeaveHook = null; savePending = async () => { await this.props.updateSettings(this.props.pending); @@ -71,7 +72,14 @@ class ConfigureContainer extends React.Component { }; componentDidMount() { - this.props.router.setRouteLeaveHook(this.props.route, this.routeLeave); + this.unregisterLeaveHook = this.props.router.setRouteLeaveHook( + this.props.route, + this.routeLeave + ); + } + + componentWillUnmount() { + this.unregisterLeaveHook(); } render() { From 2af3a94ce476d6aab1cfbfaa966b15a459f82858 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:29:40 +0200 Subject: [PATCH 056/244] No dialog when switching sections --- .../src/routes/Configure/containers/Configure.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 4910a2ec4..6cba60524 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -49,14 +49,7 @@ class ConfigureContainer extends React.Component { handleSectionChange = async section => { const nextRoute = `/admin/configure/${section}`; - - if (this.shouldShowSaveDialog()) { - this.nextRoute = nextRoute; - this.props.showSaveDialog(); - } else { - // Just go to the section - this.props.router.push(nextRoute); - } + this.props.router.push(nextRoute); }; shouldShowSaveDialog = () => { From 68b1670a55c7832a0e146880ecf2e37b2e315525 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:33:21 +0200 Subject: [PATCH 057/244] Prevent reload or closing tab or window with pending data --- .../src/routes/Configure/containers/Configure.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index 6cba60524..c4b8bc0ca 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -52,12 +52,20 @@ class ConfigureContainer extends React.Component { this.props.router.push(nextRoute); }; - shouldShowSaveDialog = () => { + navigationPrompt = e => { + if (this.hasPendingData()) { + const confirmationMessage = 'Changes that you made may not be saved.'; + e.returnValue = confirmationMessage; // Gecko, Trident, Chrome 34+ + return confirmationMessage; // Gecko, WebKit, Chrome <34 + } + }; + + hasPendingData = () => { return !!Object.keys(this.props.pending).length; }; routeLeave = ({ pathname }) => { - if (this.shouldShowSaveDialog()) { + if (this.hasPendingData()) { this.nextRoute = pathname; this.props.showSaveDialog(); return false; @@ -69,10 +77,12 @@ class ConfigureContainer extends React.Component { this.props.route, this.routeLeave ); + window.addEventListener('beforeunload', this.navigationPrompt); } componentWillUnmount() { this.unregisterLeaveHook(); + window.removeEventListener('beforeunload', this.navigationPrompt); } render() { From b2988e540e4a8370839e31bffcd67cf7559170fc Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:48:52 +0200 Subject: [PATCH 058/244] Move mutation logic to coral-admin --- client/coral-admin/src/graphql/index.js | 31 +++++++++++++++++++++ client/coral-framework/graphql/mutations.js | 31 --------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/client/coral-admin/src/graphql/index.js b/client/coral-admin/src/graphql/index.js index 95595c265..3874e6c94 100644 --- a/client/coral-admin/src/graphql/index.js +++ b/client/coral-admin/src/graphql/index.js @@ -291,5 +291,36 @@ export default { }, }, }), + SetCommentStatus: ({ variables: { status } }) => ({ + updateQueries: { + CoralAdmin_UserDetail: prev => { + const increment = { + rejectedComments: { + $apply: count => (count < prev.totalComments ? count + 1 : count), + }, + }; + + const decrement = { + rejectedComments: { + $apply: count => (count > 0 ? count - 1 : 0), + }, + }; + + // If rejected then increment rejectedComments by one + if (status === 'REJECTED') { + const updated = update(prev, increment); + return updated; + } + + // If approved then decrement rejectedComments by one + if (status === 'ACCEPTED') { + const updated = update(prev, decrement); + return updated; + } + + return prev; + }, + }, + }), }, }; diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 228911d4a..995ca1720 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -1,6 +1,5 @@ import { gql } from 'react-apollo'; import withMutation from '../hocs/withMutation'; -import update from 'immutability-helper'; function convertItemType(item_type) { switch (item_type) { @@ -168,36 +167,6 @@ export const withSetCommentStatus = withMutation( errors: null, }, }, - updateQueries: { - CoralAdmin_UserDetail: prev => { - const increment = { - rejectedComments: { - $apply: count => - count < prev.totalComments ? count + 1 : count, - }, - }; - - const decrement = { - rejectedComments: { - $apply: count => (count > 0 ? count - 1 : 0), - }, - }; - - // If rejected then increment rejectedComments by one - if (status === 'REJECTED') { - const updated = update(prev, increment); - return updated; - } - - // If approved then decrement rejectedComments by one - if (status === 'ACCEPTED') { - const updated = update(prev, decrement); - return updated; - } - - return prev; - }, - }, update: proxy => { const fragment = gql` fragment Talk_SetCommentStatus_Comment on Comment { From d07b77b8f7ab6e07cf1e53ef43c0140eb0f3f29c Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 16:49:44 +0200 Subject: [PATCH 059/244] Remove forgotten console.log --- client/coral-admin/src/components/UserDetail.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index e45e3f095..5dabc5b6f 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -96,8 +96,6 @@ class UserDetail extends React.Component { bulkReject, } = this.props; - console.log(rejectedComments, totalComments); - // if totalComments is 0, you're dividing by zero let rejectedPercent = rejectedComments / totalComments * 100; From 74821a4d4c36094d81204d8a088f7315e3efab67 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 1 May 2018 18:14:07 +0200 Subject: [PATCH 060/244] Readd save dialog on section change --- .../src/routes/Configure/containers/Configure.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/client/coral-admin/src/routes/Configure/containers/Configure.js b/client/coral-admin/src/routes/Configure/containers/Configure.js index c4b8bc0ca..3d2789974 100644 --- a/client/coral-admin/src/routes/Configure/containers/Configure.js +++ b/client/coral-admin/src/routes/Configure/containers/Configure.js @@ -49,7 +49,13 @@ class ConfigureContainer extends React.Component { handleSectionChange = async section => { const nextRoute = `/admin/configure/${section}`; - this.props.router.push(nextRoute); + if (this.hasPendingData()) { + this.nextRoute = nextRoute; + this.props.showSaveDialog(); + } else { + // Just go to the section + this.props.router.push(nextRoute); + } }; navigationPrompt = e => { From 867523140c3f70a9cf2161113948f90559f1665c Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 1 May 2018 14:09:43 -0300 Subject: [PATCH 061/244] 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 062/244] 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 063/244] 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 06682225c892802ba36af4afdfdab54333974621 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Tue, 1 May 2018 13:25:33 -0400 Subject: [PATCH 064/244] Fix error message --- locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.yml b/locales/en.yml index ff0d7e487..393d01e23 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -250,7 +250,7 @@ en: ALREADY_EXISTS: "Resource already exists" INVALID_ASSET_URL: "Assert URL is invalid" CANNOT_IGNORE_STAFF: "Cannot ignore Staff members." - email: "Not a valid E-Mail" + 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." email_not_verified: "Email address {0} not verified." From b014225b73bbad8b286340531a3604f50e1d9ae5 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 1 May 2018 12:02:39 -0600 Subject: [PATCH 065/244] 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 066/244] 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 069/244] 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 070/244] 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 071/244] 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 072/244] 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 083/244] 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 084/244] 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 085/244] 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 086/244] 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 087/244] 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 088/244] 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 089/244] 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 090/244] 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 091/244] 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 092/244] 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 093/244] 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 b04fc1faf896242ea128f78d731850d885908694 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 18:15:04 -0300 Subject: [PATCH 094/244] wip --- client/coral-framework/graphql/mutations.js | 44 +++++ plugin-api/beta/client/hocs/index.js | 1 + .../client/components/ErrorMessage.css | 8 + .../client/components/ErrorMessage.js | 17 ++ .../client/components/InputField.css | 80 ++++++++ .../client/components/InputField.js | 94 ++++++++++ .../components/AddEmailAddressDialog.css | 74 ++++++++ .../components/AddEmailAddressDialog.js | 177 ++++++++++++++++++ .../containers/AddEmailAddressDialog.js | 26 +++ .../talk-plugin-local-auth/client/index.js | 2 + 10 files changed, 523 insertions(+) create mode 100644 plugins/talk-plugin-facebook-auth/client/components/ErrorMessage.css create mode 100644 plugins/talk-plugin-facebook-auth/client/components/ErrorMessage.js create mode 100644 plugins/talk-plugin-facebook-auth/client/components/InputField.css create mode 100644 plugins/talk-plugin-facebook-auth/client/components/InputField.js create mode 100644 plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css create mode 100644 plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js create mode 100644 plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js diff --git a/client/coral-framework/graphql/mutations.js b/client/coral-framework/graphql/mutations.js index 29ec3fc96..dd54d0438 100644 --- a/client/coral-framework/graphql/mutations.js +++ b/client/coral-framework/graphql/mutations.js @@ -321,6 +321,50 @@ const SetUsernameFragment = gql` } `; +export const withAttachLocalAuth = withMutation( + gql` + mutation AttachLocalAuth($input: AttachLocalAuthInput!) { + attachLocalAuth(input: $input) { + ...AttachLocalAuthResponse + } + } + `, + { + props: ({ mutate }) => ({ + attachLocalAuth: input => { + return mutate({ + variables: { + input, + }, + update: proxy => { + const AttachLocalAuthQuery = gql` + query Talk_AttachLocalAuth { + me { + id + email + } + } + `; + + const prev = proxy.readQuery({ query: AttachLocalAuthQuery }); + + const data = update(prev, { + me: { + email: { $set: input.email }, + }, + }); + + proxy.writeQuery({ + query: AttachLocalAuthQuery, + data, + }); + }, + }); + }, + }), + } +); + export const withUpdateEmailAddress = withMutation( gql` mutation UpdateEmailAddress($input: UpdateEmailAddressInput!) { diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js index d33e7acc9..910969227 100644 --- a/plugin-api/beta/client/hocs/index.js +++ b/plugin-api/beta/client/hocs/index.js @@ -28,5 +28,6 @@ export { withChangePassword, withChangeUsername, withUpdateEmailAddress, + withAttachLocalAuth, } from 'coral-framework/graphql/mutations'; export { compose } from 'recompose'; diff --git a/plugins/talk-plugin-facebook-auth/client/components/ErrorMessage.css b/plugins/talk-plugin-facebook-auth/client/components/ErrorMessage.css new file mode 100644 index 000000000..039ffae30 --- /dev/null +++ b/plugins/talk-plugin-facebook-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-facebook-auth/client/components/ErrorMessage.js b/plugins/talk-plugin-facebook-auth/client/components/ErrorMessage.js new file mode 100644 index 000000000..f39a8fc08 --- /dev/null +++ b/plugins/talk-plugin-facebook-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-facebook-auth/client/components/InputField.css b/plugins/talk-plugin-facebook-auth/client/components/InputField.css new file mode 100644 index 000000000..3442befde --- /dev/null +++ b/plugins/talk-plugin-facebook-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-facebook-auth/client/components/InputField.js b/plugins/talk-plugin-facebook-auth/client/components/InputField.js new file mode 100644 index 000000000..26937d5b9 --- /dev/null +++ b/plugins/talk-plugin-facebook-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-local-auth/client/components/AddEmailAddressDialog.css b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css new file mode 100644 index 000000000..7fa3ce78c --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css @@ -0,0 +1,74 @@ +.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: 400px; + top: 50%; + transform: translateY(-50%); + padding: 20px; + border-radius: 4px; + font-family: Helvetica,Helvetica Neue,Verdana,sans-serif; +} + +.title { + font-size: 1.2em; + margin-bottom: 8px; +} + +.description { + font-size: 1em; + line-height: 20px; + margin: 0; + margin-bottom: 15px; +} + +.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; + } + + &.danger { + background-color: #FA4643; + color: white; + } +} \ No newline at end of file diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js new file mode 100644 index 000000000..4468d7865 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -0,0 +1,177 @@ +import React from 'react'; +import isEqual from 'lodash/isEqual'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import styles from './AddEmailAddressDialog.css'; +import { Button, Dialog, Icon } from 'plugin-api/beta/client/components/ui'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; +import InputField from './InputField'; +import { getErrorMessages } from 'coral-framework/utils'; + +const initialState = { + showErrors: false, + errors: {}, + formData: {}, +}; + +class AddEmailAddressDialog extends React.Component { + state = initialState; + validKeys = ['emailAddress', 'confirmEmailAddress']; + + onChange = e => { + const { name, value, type } = e.target; + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + this.fieldValidation(value, type, name); + } + ); + }; + + fieldValidation = (value, type, name) => { + if (!value.length) { + this.addError({ + [name]: 'Field is required', + }); + } else if (!validate[type](value)) { + this.addError({ [name]: errorMsj[type] }); + } else { + this.removeError(name); + } + }; + + addError = err => { + this.setState(({ errors }) => ({ + errors: { ...errors, ...err }, + })); + }; + + removeError = errKey => { + this.setState(state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }); + }; + + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + formHasError = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + const formIncomplete = !isEqual( + Object.keys(this.state.formData), + this.validKeys + ); + return formHasErrors || formIncomplete; + }; + + showError = () => { + this.setState({ + showError: true, + }); + }; + + confirmChanges = async () => { + if (this.formHasError()) { + this.showError(); + return; + } + + const { emailAddress } = this.state.formData; + const { attachLocalAuth } = this.props; + + try { + await attachLocalAuth({ + email: emailAddress, + }); + this.props.notify('success', 'Email Added!'); + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + } + }; + + render() { + const { errors, formData, showErrors } = this.state; + return ( + +

    Add an Email Address

    +

    + For your added security, we require users to add an email address to + their accounts. Your email address will be used to: +

    +
      +
    • + + + Receive updates regarding any changes to your account (email + address, username, password, etc.) + +
    • +
    • + + + Allow you to download your comments. + +
    • +
    • + + + Send comment notifications that you have chosen to receive. + +
    • +
    + + + +
    + ); + } +} + +AddEmailAddressDialog.propTypes = { + attachLocalAuth: PropTypes.func.isRequired, + notify: PropTypes.func.isRequired, +}; + +export default AddEmailAddressDialog; diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js new file mode 100644 index 000000000..639236ea5 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -0,0 +1,26 @@ +import { compose, gql } from 'react-apollo'; +import { bindActionCreators } from 'redux'; +import { connect, withFragments } from 'plugin-api/beta/client/hocs'; +import AddEmailAddressDialog from '../components/AddEmailAddressDialog'; +import { notify } from 'coral-framework/actions/notification'; + +import { withAttachLocalAuth } from 'plugin-api/beta/client/hocs'; + +const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); + +const withData = withFragments({ + root: gql` + fragment TalkPluginLocalAuth_AddEmailAddressDialog_root on RootQuery { + me { + id + email + } + } + `, +}); + +export default compose( + connect(null, mapDispatchToProps), + withAttachLocalAuth, + withData +)(AddEmailAddressDialog); diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index c669effaa..ce5816583 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -1,4 +1,5 @@ import ChangePassword from './containers/ChangePassword'; +import AddEmailAddressDialog from './containers/AddEmailAddressDialog'; import Profile from './containers/Profile'; import translations from './translations.yml'; @@ -7,5 +8,6 @@ export default { slots: { profileHeader: [Profile], profileSettings: [ChangePassword], + stream: [AddEmailAddressDialog], }, }; From 3b2deeb00772611a75bb37e23d51d70b4bbca8d2 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 18:35:15 -0300 Subject: [PATCH 095/244] Checking if email verification is required --- .../components/AddEmailAddressDialog.js | 106 ++++++------------ .../client/components/AddEmailContent.js | 84 ++++++++++++++ .../client/components/EmailAddressAdded.js | 18 +++ .../client/components/VerifyEmailAddress.js | 20 ++++ .../containers/AddEmailAddressDialog.js | 3 + 5 files changed, 160 insertions(+), 71 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/client/components/AddEmailContent.js create mode 100644 plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js create mode 100644 plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index 4468d7865..b801a70da 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -1,15 +1,18 @@ import React from 'react'; import isEqual from 'lodash/isEqual'; import PropTypes from 'prop-types'; -import cn from 'classnames'; -import styles from './AddEmailAddressDialog.css'; -import { Button, Dialog, Icon } from 'plugin-api/beta/client/components/ui'; +import { Dialog } from 'plugin-api/beta/client/components/ui'; import validate from 'coral-framework/helpers/validate'; import errorMsj from 'coral-framework/helpers/error'; -import InputField from './InputField'; import { getErrorMessages } from 'coral-framework/utils'; +import styles from './AddEmailAddressDialog.css'; + +import AddEmailContent from './AddEmailContent'; +import VerifyEmailAddress from './VerifyEmailAddress'; +import EmailAddressAdded from './EmailAddressAdded'; const initialState = { + step: 0, showErrors: false, errors: {}, formData: {}, @@ -17,7 +20,7 @@ const initialState = { class AddEmailAddressDialog extends React.Component { state = initialState; - validKeys = ['emailAddress', 'confirmEmailAddress']; + validKeys = ['emailAddress', 'confirmEmailAddress', 'confirmPassword']; onChange = e => { const { name, value, type } = e.target; @@ -74,96 +77,56 @@ class AddEmailAddressDialog extends React.Component { return formHasErrors || formIncomplete; }; - showError = () => { + showErrors = () => { this.setState({ - showError: true, + showErrors: true, }); }; confirmChanges = async () => { if (this.formHasError()) { - this.showError(); + this.showErrors(); return; } - const { emailAddress } = this.state.formData; + const { emailAddress, confirmPassword } = this.state.formData; const { attachLocalAuth } = this.props; try { await attachLocalAuth({ email: emailAddress, + password: confirmPassword, }); this.props.notify('success', 'Email Added!'); + this.goToNextStep(); } catch (err) { this.props.notify('error', getErrorMessages(err)); } }; + goToNextStep = () => { + this.setState(({ step }) => ({ + step: step + 1, + })); + }; + render() { - const { errors, formData, showErrors } = this.state; + const { errors, formData, showErrors, step } = this.state; + const { root: { settings } } = this.props; return ( -

    Add an Email Address

    -

    - For your added security, we require users to add an email address to - their accounts. Your email address will be used to: -

    -
      -
    • - - - Receive updates regarding any changes to your account (email - address, username, password, etc.) - -
    • -
    • - - - Allow you to download your comments. - -
    • -
    • - - - Send comment notifications that you have chosen to receive. - -
    • -
    - - - + {step === 0 && ( + + )} + {step === 1 && !settings.requireEmailConfirmation ? ( + + ) : ( + + )}
    ); } @@ -172,6 +135,7 @@ class AddEmailAddressDialog extends React.Component { AddEmailAddressDialog.propTypes = { attachLocalAuth: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, + root: PropTypes.func.isRequired, }; export default AddEmailAddressDialog; diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js new file mode 100644 index 000000000..a2b14c5fd --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -0,0 +1,84 @@ +import React from 'react'; +import styles from './AddEmailAddressDialog.css'; +import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import cn from 'classnames'; +import InputField from './InputField'; + +const AddEmailContent = ({ formData, errors, showErrors }) => ( +
    +

    Add an Email Address

    +

    + For your added security, we require users to add an email address to their + accounts. Your email address will be used to: +

    +
      +
    • + + + Receive updates regarding any changes to your account (email address, + username, password, etc.) + +
    • +
    • + + + Allow you to download your comments. + +
    • +
    • + + + Send comment notifications that you have chosen to receive. + +
    • +
    + + + + +
    +); + +export default AddEmailContent; diff --git a/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js b/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js new file mode 100644 index 000000000..9d3e875d5 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js @@ -0,0 +1,18 @@ +import React from 'react'; +import styles from './AddEmailAddressDialog.css'; + +const EmailAddressAdded = () => ( +
    +

    Email Address Added

    +

    + Your email address has been added to your account. +

    + Need to change your email address? +

    + You can change your account settings by visiting{' '} + My Profile {'>'} Settings. +

    +
    +); + +export default EmailAddressAdded; diff --git a/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js b/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js new file mode 100644 index 000000000..8d9d207b7 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js @@ -0,0 +1,20 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styles from './AddEmailAddressDialog.css'; + +const VerifyEmailAddress = ({ emailAddress }) => ( +
    +

    Verify Your Email Address

    +

    + We’ve sent an email to {emailAddress} to verify your account. You must + verify your email address so that it can be used for account change + confirmations and notifications. +

    +
    +); + +VerifyEmailAddress.propTypes = { + emailAddress: PropTypes.string, +}; + +export default VerifyEmailAddress; diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 639236ea5..9732383ce 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -15,6 +15,9 @@ const withData = withFragments({ id email } + settings { + requireEmailConfirmation + } } `, }); From 1bf440c4a6f0f652682ae6cd1ea01079525bec19 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 18:43:06 -0300 Subject: [PATCH 096/244] Changes --- .../components/AddEmailAddressDialog.js | 14 ++- .../client/components/AddEmailContent.js | 107 ++++++++++-------- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index b801a70da..e5226eae0 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -120,13 +120,15 @@ class AddEmailAddressDialog extends React.Component { formData={formData} errors={errors} showErrors={showErrors} + confirmChanges={this.confirmChanges} /> )} - {step === 1 && !settings.requireEmailConfirmation ? ( - - ) : ( - - )} + {step === 1 && + !settings.requireEmailConfirmation && } + {step === 1 && + settings.requireEmailConfirmation && ( + + )}
    ); } @@ -135,7 +137,7 @@ class AddEmailAddressDialog extends React.Component { AddEmailAddressDialog.propTypes = { attachLocalAuth: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, - root: PropTypes.func.isRequired, + root: PropTypes.object.isRequired, }; export default AddEmailAddressDialog; diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index a2b14c5fd..cb127520f 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -1,10 +1,11 @@ import React from 'react'; +import PropTypes from 'prop-types'; import styles from './AddEmailAddressDialog.css'; import { Button, Icon } from 'plugin-api/beta/client/components/ui'; import cn from 'classnames'; import InputField from './InputField'; -const AddEmailContent = ({ formData, errors, showErrors }) => ( +const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => (

    Add an Email Address

    @@ -32,53 +33,65 @@ const AddEmailContent = ({ formData, errors, showErrors }) => ( - - - - +

    + + + + +
    ); +AddEmailContent.propTypes = { + formData: PropTypes.object.isRequired, + errors: PropTypes.object.isRequired, + showErrors: PropTypes.bool.isRequired, + confirmChanges: PropTypes.func.isRequired, +}; + export default AddEmailContent; From 09d20257acc71172d8cd727dfaf23a447758eaae Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 18:46:41 -0300 Subject: [PATCH 097/244] Changes --- .../client/components/AddEmailAddressDialog.css | 6 ++++++ .../client/components/AddEmailContent.js | 10 +++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css index 7fa3ce78c..1e711f5cb 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css @@ -52,9 +52,15 @@ height: 30px; font-size: 0.9em; line-height: normal; + width: 100%; + display: inline-block; + text-align: center; + line-height: 30px; + font-size: 1em; &:hover { background-color: #eaeaea; + cursor: pointer; } &.cancel { diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index cb127520f..dcd0d9496 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import styles from './AddEmailAddressDialog.css'; -import { Button, Icon } from 'plugin-api/beta/client/components/ui'; +import { Icon } from 'plugin-api/beta/client/components/ui'; import cn from 'classnames'; import InputField from './InputField'; @@ -76,13 +76,9 @@ const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => ( columnDisplay showSuccess={false} /> - + ); From cdae2796a5dcfa61fe2e06ba1039f0b74548337a Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 18:48:52 -0300 Subject: [PATCH 098/244] Changes --- .../talk-plugin-local-auth/client/components/AddEmailContent.js | 2 +- plugins/talk-plugin-local-auth/client/components/InputField.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index dcd0d9496..8ff5db689 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -42,7 +42,7 @@ const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => ( onChange={this.onChange} defaultValue="" hasError={!formData.emailAddress || errors.emailAddress} - errorMsg={errors.emailAddress} + errorMsg={'Invalid email address'} showError={showErrors} columnDisplay showSuccess={false} diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.js b/plugins/talk-plugin-local-auth/client/components/InputField.js index 34c314c20..26937d5b9 100644 --- a/plugins/talk-plugin-local-auth/client/components/InputField.js +++ b/plugins/talk-plugin-local-auth/client/components/InputField.js @@ -43,7 +43,7 @@ const InputField = ({
    From ccb62263c190432135a9878ea55de60415cee099 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 20:08:29 -0300 Subject: [PATCH 099/244] 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 478770f6c6a0c1836a0b8eef8fb2819337aef7b1 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 20:41:32 -0300 Subject: [PATCH 100/244] Changes --- client/coral-framework/graphql/fragments.js | 3 ++- .../client/components/AddEmailAddressDialog.js | 13 +++++++++---- .../client/components/AddEmailContent.js | 18 +++++++++++++----- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/client/coral-framework/graphql/fragments.js b/client/coral-framework/graphql/fragments.js index bf75fa1a8..778214b8b 100644 --- a/client/coral-framework/graphql/fragments.js +++ b/client/coral-framework/graphql/fragments.js @@ -27,6 +27,7 @@ export default { 'UpdateAssetStatusResponse', 'UpdateSettingsResponse', 'ChangePasswordResponse', - 'UpdateEmailAddressResponse' + 'UpdateEmailAddressResponse', + 'AttachLocalAuthResponse' ), }; diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index e5226eae0..c5b816e85 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -1,5 +1,6 @@ import React from 'react'; -import isEqual from 'lodash/isEqual'; +import isMatch from 'lodash/isEqual'; +import isEqualWith from 'lodash/isEqual'; import PropTypes from 'prop-types'; import { Dialog } from 'plugin-api/beta/client/components/ui'; import validate from 'coral-framework/helpers/validate'; @@ -20,7 +21,7 @@ const initialState = { class AddEmailAddressDialog extends React.Component { state = initialState; - validKeys = ['emailAddress', 'confirmEmailAddress', 'confirmPassword']; + validKeys = ['emailAddress', 'confirmPassword', 'confirmEmailAddress']; onChange = e => { const { name, value, type } = e.target; @@ -70,10 +71,12 @@ class AddEmailAddressDialog extends React.Component { formHasError = () => { const formHasErrors = !!Object.keys(this.state.errors).length; - const formIncomplete = !isEqual( + const formIncomplete = !isEqualWith( Object.keys(this.state.formData), - this.validKeys + this.validKeys, + isMatch ); + return formHasErrors || formIncomplete; }; @@ -113,6 +116,7 @@ class AddEmailAddressDialog extends React.Component { render() { const { errors, formData, showErrors, step } = this.state; const { root: { settings } } = this.props; + return ( {step === 0 && ( @@ -121,6 +125,7 @@ class AddEmailAddressDialog extends React.Component { errors={errors} showErrors={showErrors} confirmChanges={this.confirmChanges} + onChange={this.onChange} /> )} {step === 1 && diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index 8ff5db689..40edeea2a 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -5,7 +5,13 @@ import { Icon } from 'plugin-api/beta/client/components/ui'; import cn from 'classnames'; import InputField from './InputField'; -const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => ( +const AddEmailContent = ({ + formData, + errors, + showErrors, + confirmChanges, + onChange, +}) => (

    Add an Email Address

    @@ -33,13 +39,14 @@ const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => ( -

    + + ( label="Confirm Email Address:" name="confirmEmailAddress" type="email" - onChange={this.onChange} + onChange={onChange} defaultValue="" hasError={ !formData.emailAddress || @@ -68,7 +75,7 @@ const AddEmailContent = ({ formData, errors, showErrors, confirmChanges }) => ( label="Insert Password" name="confirmPassword" type="password" - onChange={this.onChange} + onChange={onChange} defaultValue="" hasError={!formData.confirmPassword} errorMsg={'Confirm Password'} @@ -88,6 +95,7 @@ AddEmailContent.propTypes = { errors: PropTypes.object.isRequired, showErrors: PropTypes.bool.isRequired, confirmChanges: PropTypes.func.isRequired, + onChange: PropTypes.func.isRequired, }; export default AddEmailContent; From 59cac9db8b3c08791354722f18c4af6e3389688e Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 20:58:34 -0300 Subject: [PATCH 101/244] Adding reducer --- .../talk-plugin-local-auth/client/actions.js | 9 ++++++++ .../components/AddEmailAddressDialog.css | 8 ++++--- .../components/AddEmailAddressDialog.js | 14 ++++++++---- .../client/components/AddEmailContent.js | 13 +++++++---- .../client/components/EmailAddressAdded.js | 13 ++++++++++- .../client/components/InputField.css | 3 ++- .../client/components/VerifyEmailAddress.js | 11 ++++++++-- .../client/constants.js | 4 ++++ .../containers/AddEmailAddressDialog.js | 6 ++++- .../talk-plugin-local-auth/client/index.js | 2 ++ .../talk-plugin-local-auth/client/reducer.js | 22 +++++++++++++++++++ 11 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/client/actions.js create mode 100644 plugins/talk-plugin-local-auth/client/constants.js create mode 100644 plugins/talk-plugin-local-auth/client/reducer.js diff --git a/plugins/talk-plugin-local-auth/client/actions.js b/plugins/talk-plugin-local-auth/client/actions.js new file mode 100644 index 000000000..4786b92c8 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/actions.js @@ -0,0 +1,9 @@ +import * as actions from './constants'; + +export const showAddEmailDialog = () => ({ + type: actions.SHOW_ADD_EMAIL_DIALOG, +}); + +export const hideAddEmailDialog = () => ({ + type: actions.HIDE_ADD_EMAIL_DIALOG, +}); diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css index 1e711f5cb..41b531147 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.css @@ -1,17 +1,19 @@ .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: 400px; + width: 320px; top: 50%; transform: translateY(-50%); padding: 20px; border-radius: 4px; font-family: Helvetica,Helvetica Neue,Verdana,sans-serif; + color:#3B4A53; } .title { - font-size: 1.2em; - margin-bottom: 8px; + font-size: 1.3em; + margin: 15px 0; + text-align: center; } .description { diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index c5b816e85..253e3ac62 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -115,10 +115,10 @@ class AddEmailAddressDialog extends React.Component { render() { const { errors, formData, showErrors, step } = this.state; - const { root: { settings } } = this.props; + const { root: { settings }, showAddEmailDialog } = this.props; return ( - + {step === 0 && ( )} {step === 1 && - !settings.requireEmailConfirmation && } + !settings.requireEmailConfirmation && ( + {}} /> + )} {step === 1 && settings.requireEmailConfirmation && ( - + {}} + /> )} ); @@ -143,6 +148,7 @@ AddEmailAddressDialog.propTypes = { attachLocalAuth: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, root: PropTypes.object.isRequired, + showAddEmailDialog: PropTypes.bool.isRequired, }; export default AddEmailAddressDialog; diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index 40edeea2a..0d3411ff3 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -72,7 +72,7 @@ const AddEmailContent = ({ /> - - Add Email Address - +
    ); diff --git a/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js b/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js index 9d3e875d5..ef74f4b8b 100644 --- a/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js +++ b/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js @@ -1,7 +1,9 @@ import React from 'react'; +import cn from 'classnames'; +import PropTypes from 'prop-types'; import styles from './AddEmailAddressDialog.css'; -const EmailAddressAdded = () => ( +const EmailAddressAdded = ({ done }) => (

    Email Address Added

    @@ -12,7 +14,16 @@ const EmailAddressAdded = () => ( You can change your account settings by visiting{' '} My Profile {'>'} Settings.

    +
    ); +EmailAddressAdded.propTypes = { + done: PropTypes.func.isRequired, +}; + export default EmailAddressAdded; diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.css b/plugins/talk-plugin-local-auth/client/components/InputField.css index cd6015e47..befc94f18 100644 --- a/plugins/talk-plugin-local-auth/client/components/InputField.css +++ b/plugins/talk-plugin-local-auth/client/components/InputField.css @@ -42,10 +42,11 @@ } .detailLabel { - color: #4C4C4D; + color: #4c4c4d; font-size: 1em; display: block; margin-bottom: 4px; + font-weight: bold; } .detailValue { diff --git a/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js b/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js index 8d9d207b7..9a3e6ae89 100644 --- a/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js +++ b/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js @@ -1,8 +1,9 @@ import React from 'react'; +import cn from 'classnames'; import PropTypes from 'prop-types'; import styles from './AddEmailAddressDialog.css'; -const VerifyEmailAddress = ({ emailAddress }) => ( +const VerifyEmailAddress = ({ emailAddress, done }) => (

    Verify Your Email Address

    @@ -10,11 +11,17 @@ const VerifyEmailAddress = ({ emailAddress }) => ( verify your email address so that it can be used for account change confirmations and notifications.

    +
    ); VerifyEmailAddress.propTypes = { - emailAddress: PropTypes.string, + emailAddress: PropTypes.string.isRequired, + done: PropTypes.func.isRequired, }; export default VerifyEmailAddress; diff --git a/plugins/talk-plugin-local-auth/client/constants.js b/plugins/talk-plugin-local-auth/client/constants.js new file mode 100644 index 000000000..927816e0e --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/constants.js @@ -0,0 +1,4 @@ +const prefix = 'TALK_AUTH_LOCAL'; + +export const SHOW_ADD_EMAIL_DIALOG = `${prefix}_SHOW_ADD_EMAIL_DIALOG`; +export const HIDE_ADD_EMAIL_DIALOG = `${prefix}_HIDE_ADD_EMAIL_DIALOG`; diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 9732383ce..62c637d71 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -22,8 +22,12 @@ const withData = withFragments({ `, }); +const mapStateToProps = ({ talkPluginLocalAuth: state }) => ({ + showAddEmailDialog: state.showAddEmailDialog, +}); + export default compose( - connect(null, mapDispatchToProps), + connect(mapStateToProps, mapDispatchToProps), withAttachLocalAuth, withData )(AddEmailAddressDialog); diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index ce5816583..126ea72c6 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -2,8 +2,10 @@ import ChangePassword from './containers/ChangePassword'; import AddEmailAddressDialog from './containers/AddEmailAddressDialog'; import Profile from './containers/Profile'; import translations from './translations.yml'; +import reducer from './reducer'; export default { + reducer, translations, slots: { profileHeader: [Profile], diff --git a/plugins/talk-plugin-local-auth/client/reducer.js b/plugins/talk-plugin-local-auth/client/reducer.js new file mode 100644 index 000000000..586bbf759 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/reducer.js @@ -0,0 +1,22 @@ +import * as actions from './constants'; + +const initialState = { + showAddEmailDialog: true, +}; + +export default function reducer(state = initialState, action) { + switch (action.type) { + case actions.SHOW_ADD_EMAIL_DIALOG: + return { + ...state, + showAddEmailDialog: true, + }; + case actions.HIDE_ADD_EMAIL_DIALOG: + return { + ...state, + showAddEmailDialog: false, + }; + default: + return state; + } +} From a649bd8252528472985b0d35ae073928ee7fb008 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 2 May 2018 21:01:08 -0300 Subject: [PATCH 102/244] done - but translations --- .../talk-plugin-local-auth/client/actions.js | 9 -------- .../client/constants.js | 4 ---- .../containers/AddEmailAddressDialog.js | 11 ++++------ .../talk-plugin-local-auth/client/index.js | 2 -- .../talk-plugin-local-auth/client/reducer.js | 22 ------------------- 5 files changed, 4 insertions(+), 44 deletions(-) delete mode 100644 plugins/talk-plugin-local-auth/client/actions.js delete mode 100644 plugins/talk-plugin-local-auth/client/constants.js delete mode 100644 plugins/talk-plugin-local-auth/client/reducer.js diff --git a/plugins/talk-plugin-local-auth/client/actions.js b/plugins/talk-plugin-local-auth/client/actions.js deleted file mode 100644 index 4786b92c8..000000000 --- a/plugins/talk-plugin-local-auth/client/actions.js +++ /dev/null @@ -1,9 +0,0 @@ -import * as actions from './constants'; - -export const showAddEmailDialog = () => ({ - type: actions.SHOW_ADD_EMAIL_DIALOG, -}); - -export const hideAddEmailDialog = () => ({ - type: actions.HIDE_ADD_EMAIL_DIALOG, -}); diff --git a/plugins/talk-plugin-local-auth/client/constants.js b/plugins/talk-plugin-local-auth/client/constants.js deleted file mode 100644 index 927816e0e..000000000 --- a/plugins/talk-plugin-local-auth/client/constants.js +++ /dev/null @@ -1,4 +0,0 @@ -const prefix = 'TALK_AUTH_LOCAL'; - -export const SHOW_ADD_EMAIL_DIALOG = `${prefix}_SHOW_ADD_EMAIL_DIALOG`; -export const HIDE_ADD_EMAIL_DIALOG = `${prefix}_HIDE_ADD_EMAIL_DIALOG`; diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 62c637d71..7ab887183 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -1,6 +1,6 @@ import { compose, gql } from 'react-apollo'; import { bindActionCreators } from 'redux'; -import { connect, withFragments } from 'plugin-api/beta/client/hocs'; +import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs'; import AddEmailAddressDialog from '../components/AddEmailAddressDialog'; import { notify } from 'coral-framework/actions/notification'; @@ -22,12 +22,9 @@ const withData = withFragments({ `, }); -const mapStateToProps = ({ talkPluginLocalAuth: state }) => ({ - showAddEmailDialog: state.showAddEmailDialog, -}); - export default compose( - connect(mapStateToProps, mapDispatchToProps), + connect(null, mapDispatchToProps), withAttachLocalAuth, - withData + withData, + excludeIf(({ root: { me } }) => !me || me.email) )(AddEmailAddressDialog); diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index 126ea72c6..ce5816583 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -2,10 +2,8 @@ import ChangePassword from './containers/ChangePassword'; import AddEmailAddressDialog from './containers/AddEmailAddressDialog'; import Profile from './containers/Profile'; import translations from './translations.yml'; -import reducer from './reducer'; export default { - reducer, translations, slots: { profileHeader: [Profile], diff --git a/plugins/talk-plugin-local-auth/client/reducer.js b/plugins/talk-plugin-local-auth/client/reducer.js deleted file mode 100644 index 586bbf759..000000000 --- a/plugins/talk-plugin-local-auth/client/reducer.js +++ /dev/null @@ -1,22 +0,0 @@ -import * as actions from './constants'; - -const initialState = { - showAddEmailDialog: true, -}; - -export default function reducer(state = initialState, action) { - switch (action.type) { - case actions.SHOW_ADD_EMAIL_DIALOG: - return { - ...state, - showAddEmailDialog: true, - }; - case actions.HIDE_ADD_EMAIL_DIALOG: - return { - ...state, - showAddEmailDialog: false, - }; - default: - return state; - } -} From fff6e1c2317e581befdb1c252fde1ba56022ef5f Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 10:24:43 -0300 Subject: [PATCH 103/244] 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 a9132c13539dc6ef2c6f401970ed5ea7865c2d26 Mon Sep 17 00:00:00 2001 From: okbel Date: Thu, 3 May 2018 11:07:58 -0300 Subject: [PATCH 104/244] stream fragment --- .../coral-embed-stream/src/tabs/stream/containers/Stream.js | 1 + .../client/components/AddEmailAddressDialog.js | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) 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 = { diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index 253e3ac62..691915c0f 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -115,10 +115,10 @@ class AddEmailAddressDialog extends React.Component { render() { const { errors, formData, showErrors, step } = this.state; - const { root: { settings }, showAddEmailDialog } = this.props; + const { root: { settings } } = this.props; return ( - + {step === 0 && ( Date: Thu, 3 May 2018 08:39:34 -0600 Subject: [PATCH 105/244] 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 106/244] 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 107/244] 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 108/244] 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 115/244] 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 116/244] 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 117/244] 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 118/244] 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 119/244] 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 120/244] 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 121/244] 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 122/244] 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 151/244] 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 152/244] 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; } From eabcbc36c64cda59810a89967cb958fe55377a03 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 4 May 2018 13:34:20 -0300 Subject: [PATCH 153/244] forgot password --- .../client/components/ChangePassword.js | 23 ++++++++++++++- .../client/containers/ChangePassword.js | 29 +++++++++++++++---- .../client/translations.yml | 2 ++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js index e5535b8ba..04d420d22 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js @@ -125,6 +125,23 @@ class ChangePassword extends React.Component { this.disableEditing(); }; + onForgotPassword = async () => { + const { root: { me: { email } } } = this.props; + + try { + await this.props.forgotPassword(email); + this.props.notify( + 'success', + t('talk-plugin-local-auth.change_password.forgot_password_sent') + ); + } catch (err) { + this.props.notify('error', getErrorMessages(err)); + } + + this.clearForm(); + this.disableEditing(); + }; + disableEditing = () => { this.setState({ editing: false, @@ -166,7 +183,10 @@ class ChangePassword extends React.Component { showErrors > - + {t('talk-plugin-local-auth.change_password.forgot_password')} @@ -223,6 +243,7 @@ class ChangePassword extends React.Component { ChangePassword.propTypes = { changePassword: PropTypes.func.isRequired, + forgotPassword: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, }; diff --git a/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js b/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js index 1322a2940..dfcf4a143 100644 --- a/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js @@ -1,12 +1,29 @@ -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 ChangePassword from '../components/ChangePassword'; import { notify } from 'coral-framework/actions/notification'; -import { withChangePassword } from 'plugin-api/beta/client/hocs'; +import { + withChangePassword, + withForgotPassword, +} from 'plugin-api/beta/client/hocs'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); -export default compose(connect(null, mapDispatchToProps), withChangePassword)( - ChangePassword -); +const withData = withFragments({ + root: gql` + fragment TalkPluginLocalAuth_ChangePassword_root on RootQuery { + me { + id + email + } + } + `, +}); + +export default compose( + connect(null, mapDispatchToProps), + withChangePassword, + withForgotPassword, + withData +)(ChangePassword); diff --git a/plugins/talk-plugin-local-auth/client/translations.yml b/plugins/talk-plugin-local-auth/client/translations.yml index d3b323f54..0c3216009 100644 --- a/plugins/talk-plugin-local-auth/client/translations.yml +++ b/plugins/talk-plugin-local-auth/client/translations.yml @@ -9,6 +9,7 @@ en: cancel: "Cancel" edit: "Edit" changed_password_msg: "Changed Password - Your password has been successfully changed" + forgot_password_sent: "Forgot Password - We sent you an email to recover your password" change_username: change_username_note: "Usernames can be changed every 14 days" save: "Save" @@ -46,6 +47,7 @@ es: cancel: "Cancelar" edit: "Editar" changed_password_msg: "Contraseña Actualizada - Tu contraseña ha sido exitosamente actualizada" + forgot_password_sent: "Contraseña Olvidada - Te enviamos un email para recuperar tu contraseña" change_username: change_username_note: "El usuario puede ser cambiado cada 14 días" save: "Guardar" From 9a8f0e98a43afb16cfbf1f4961a127827c0902f1 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 4 May 2018 11:16:53 -0600 Subject: [PATCH 154/244] Username Change Fixes --- .../components/ChangeEmailContentDialog.js | 10 +- .../components/ChangeUsernameContentDialog.js | 25 ++- .../client/components/Profile.css | 28 ++-- .../client/components/Profile.js | 149 ++++++++++-------- .../client/containers/Profile.js | 4 +- .../client/translations.yml | 11 +- 6 files changed, 120 insertions(+), 107 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index 4bc15757e..438acc398 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -16,7 +16,8 @@ class ChangeEmailContentDialog extends React.Component { }); }; - confirmChanges = async () => { + confirmChanges = async e => { + e.preventDefault(); await this.props.save(); this.props.next(); }; @@ -44,7 +45,7 @@ class ChangeEmailContentDialog extends React.Component { {this.props.formData.newEmail}
    -
    + {t('talk-plugin-local-auth.change_email.cancel')} -
    diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js index 894bdcbd6..917d77782 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js @@ -16,7 +16,9 @@ class ChangeUsernameContentDialog extends React.Component { }); }; - confirmChanges = async () => { + confirmChanges = async e => { + e.preventDefault(); + if (this.formHasError()) { this.showError(); return; @@ -60,7 +62,7 @@ class ChangeUsernameContentDialog extends React.Component { {this.props.formData.newUsername}
    - + +
    + + +
    -
    - - -
    ); diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.css b/plugins/talk-plugin-local-auth/client/components/Profile.css index 5b4631ecf..dcdbdd2ae 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.css +++ b/plugins/talk-plugin-local-auth/client/components/Profile.css @@ -7,30 +7,38 @@ border-radius: 2px; box-sizing: border-box; justify-content: space-between; - - &.editing { + + &.editing { background-color: #EDEDED; } } +.wrapper { + display: flex; + position: relative; + box-sizing: inherit; + justify-content: inherit; + flex-grow: 1; +} + .content { flex-grow: 1; -} +} .actions { flex-grow: 0; display: flex; flex-direction: column; align-items: center; -} +} .email { margin: 0; } -.username { +.username { margin-bottom: 4px; -} +} .button { border: 1px solid #787d80; @@ -48,7 +56,7 @@ > i { font-size: 17px; } - + &:hover { background-color: #399ee2; color: white; @@ -82,13 +90,13 @@ height: 30px; display: inline-block; width: 230px; - display: flex; + display: flex; > .detailLabelIcon { font-size: 1.2em; padding: 0 5px; color: #787D80; - line-height: 30px; + line-height: 30px; } &.disabled { @@ -115,7 +123,7 @@ list-style: none; margin: 0; padding: 0; -} +} .detailItem { margin-bottom: 12px; diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 949923e77..85c1f1295 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -50,8 +50,12 @@ class Profile extends React.Component { }); }; - onSave = async () => { - this.showDialog(); + onSave = async e => { + e.preventDefault(); + + if (this.isSaveEnabled()) { + this.showDialog(); + } }; addError = err => { @@ -121,10 +125,10 @@ class Profile extends React.Component { saveUsername = async () => { const { newUsername } = this.state.formData; - const { changeUsername } = this.props; + const { setUsername } = this.props; try { - await changeUsername(this.props.root.me.id, newUsername); + await setUsername(newUsername); this.props.notify( 'success', t('talk-plugin-local-auth.change_username.changed_username_success_msg') @@ -163,6 +167,8 @@ class Profile extends React.Component { } = this.props; const { editing, formData, showDialog } = this.state; + const usernameCanBeUpdated = canUsernameBeUpdated(status); + return (
    - + {usernameCanBeUpdated && ( + + )} {editing ? ( -
    -
    - - - {t( - 'talk-plugin-local-auth.change_username.change_username_note' - )} - - - +
    +
    +
    + + + {t( + 'talk-plugin-local-auth.change_username.change_username_note' + )} + + + +
    -
    +
    + + + {t('talk-plugin-local-auth.change_username.cancel')} + +
    + ) : ( -
    -

    {username}

    - {email ?

    {email}

    : null} -
    - )} - {editing ? ( -
    - - - {t('talk-plugin-local-auth.change_username.cancel')} - -
    - ) : ( -
    - +
    +
    +

    {username}

    + {email ?

    {email}

    : null} +
    +
    + +
    )}
    @@ -263,9 +273,8 @@ class Profile extends React.Component { Profile.propTypes = { updateEmailAddress: PropTypes.func.isRequired, - changeUsername: PropTypes.func.isRequired, + setUsername: PropTypes.func.isRequired, root: PropTypes.object.isRequired, - changeUsername: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, username: PropTypes.string, emailAddress: PropTypes.string, diff --git a/plugins/talk-plugin-local-auth/client/containers/Profile.js b/plugins/talk-plugin-local-auth/client/containers/Profile.js index e1ed99ef6..ccfca72ae 100644 --- a/plugins/talk-plugin-local-auth/client/containers/Profile.js +++ b/plugins/talk-plugin-local-auth/client/containers/Profile.js @@ -3,7 +3,7 @@ import { bindActionCreators } from 'redux'; import { connect, withFragments } from 'plugin-api/beta/client/hocs'; import Profile from '../components/Profile'; import { notify } from 'coral-framework/actions/notification'; -import { withChangeUsername } from 'plugin-api/beta/client/hocs'; +import { withSetUsername } from 'plugin-api/beta/client/hocs'; import { withUpdateEmailAddress } from '../hocs'; const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); @@ -33,7 +33,7 @@ const withData = withFragments({ export default compose( connect(null, mapDispatchToProps), - withChangeUsername, + withSetUsername, withUpdateEmailAddress, withData )(Profile); diff --git a/plugins/talk-plugin-local-auth/client/translations.yml b/plugins/talk-plugin-local-auth/client/translations.yml index 2b46a0464..059e497db 100644 --- a/plugins/talk-plugin-local-auth/client/translations.yml +++ b/plugins/talk-plugin-local-auth/client/translations.yml @@ -22,19 +22,18 @@ en: 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" + 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." 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" + 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." add_email: add_email_address: "Add Email Address" enter_email_address: "Enter Email Address:" @@ -52,7 +51,7 @@ en: verify: title: "Verify Your Email Address" description: "We’ve sent an email to {0} to verify your account. You must verify your email address so that it can be used for account change confirmations and notifications." - added: + added: title: "Email Address Added" description: "Your email address has been added to your account." subtitle: "Need to change your email address?" @@ -82,4 +81,4 @@ es: 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 + change_username_attempt: "El usuario no puede ser actualizado. Los usuarios pueden ser cambiados cada 14 días." From 4bc8a167a4a2446ecb334992b2d6fa6ff45fd702 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 4 May 2018 19:29:05 +0200 Subject: [PATCH 155/244] Styling tweaks --- .../client/components/ChangePassword.css | 9 ++++--- .../client/components/Profile.css | 27 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css index 0df8eb409..c1c6c9c7c 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.css +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.css @@ -5,22 +5,25 @@ border: solid 1px transparent; box-sizing: border-box; justify-content: space-between; + margin: 16px 0; &.editing { padding: 10px; - border-color: #979797; background-color: #EDEDED; .actions { top: 10px; right: 10px; } + .title { + margin-bottom: 1em; + } } } .actions { position: absolute; - top: 0px; + top: -6px; right: 0px; display: flex; flex-direction: column; @@ -29,7 +32,7 @@ .title { color: #202020; - margin: 0 0 20px; + margin: 0; } .detailBottomBox { diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.css b/plugins/talk-plugin-local-auth/client/components/Profile.css index 5b4631ecf..30b75f451 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.css +++ b/plugins/talk-plugin-local-auth/client/components/Profile.css @@ -1,36 +1,39 @@ .container { - margin-bottom: 20px; + margin-top: 6px; + margin-bottom: 12px; display: flex; position: relative; color: #202020; - padding: 10px; + padding: 5px; border-radius: 2px; box-sizing: border-box; justify-content: space-between; - - &.editing { + + &.editing { + padding: 10px; background-color: #EDEDED; } } .content { flex-grow: 1; -} +} .actions { flex-grow: 0; display: flex; flex-direction: column; align-items: center; -} +} .email { margin: 0; } -.username { +.username { + margin-top: 0; margin-bottom: 4px; -} +} .button { border: 1px solid #787d80; @@ -48,7 +51,7 @@ > i { font-size: 17px; } - + &:hover { background-color: #399ee2; color: white; @@ -82,13 +85,13 @@ height: 30px; display: inline-block; width: 230px; - display: flex; + display: flex; > .detailLabelIcon { font-size: 1.2em; padding: 0 5px; color: #787D80; - line-height: 30px; + line-height: 30px; } &.disabled { @@ -115,7 +118,7 @@ list-style: none; margin: 0; padding: 0; -} +} .detailItem { margin-bottom: 12px; From d41984f171e0b00dfdb1e4670b5340597b184136 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 4 May 2018 19:32:29 +0200 Subject: [PATCH 156/244] Remove unused field --- .../talk-plugin-local-auth/client/containers/ChangePassword.js | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js b/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js index dfcf4a143..11bd5c5fb 100644 --- a/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/containers/ChangePassword.js @@ -14,7 +14,6 @@ const withData = withFragments({ root: gql` fragment TalkPluginLocalAuth_ChangePassword_root on RootQuery { me { - id email } } From 2a5075f434d21394a86e6977e3c6ce895ecb4681 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 4 May 2018 11:33:06 -0600 Subject: [PATCH 157/244] Form update --- .../client/components/ChangePassword.js | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js index 04d420d22..8f86fff48 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js @@ -105,7 +105,13 @@ class ChangePassword extends React.Component { this.setState(initialState); }; - onSave = async () => { + onSave = async e => { + e.preventDefault(); + + if (this.isSubmitBlocked()) { + return; + } + const { oldPassword, newPassword } = this.state.formData; try { @@ -169,8 +175,11 @@ class ChangePassword extends React.Component {

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

    - {editing && ( -
    + {editing ? ( + +
    + + + {t('talk-plugin-local-auth.change_password.cancel')} + +
    - )} - {editing ? ( -
    - - - {t('talk-plugin-local-auth.change_password.cancel')} - -
    ) : (
    + +
    -
    - - -
    ); From 7a7dcdd7c63744e577cd69e2407fd914f28d660b Mon Sep 17 00:00:00 2001 From: Jero Date: Fri, 4 May 2018 16:35:24 -0300 Subject: [PATCH 159/244] corrections in spanish translations --- locales/es.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/locales/es.yml b/locales/es.yml index 702f6b9e0..a6d35ef0d 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -63,10 +63,10 @@ es: reactions: 'reacciones' story: 'Artículo' flagged_usernames: - notify_approved: '{0} nombre de usuario aprobado {1}' - notify_rejected: '{0} nombre de usuario rechazado {1}' - notify_flagged: '{0} nombre de usuario reportado {1}' - notify_changed: 'El usuario {0} cambio su nombre de usuario por {1}' + notify_approved: '{0} ha aprobado el nombre de usuario {1}' + notify_rejected: '{0} ha rechazado el nombre de usuario {1}' + notify_flagged: '{0} ha reportado el nombre de usuario {1}' + notify_changed: 'El usuario {0} ha modificado su nombre de usuario por {1}' community: account_creation_date: "Fecha de creación de la cuenta" active: Activa @@ -194,9 +194,9 @@ es: minutes_plural: "minutos" email: suspended: - subject: "Su cuenta fue suspendida" + subject: "Su cuenta ha sido suspendida" banned: - subject: "Su cuenta fue bloqueada" + subject: "Su cuenta ha sido bloqueada" body: "De acuerdo con las guías de comunidad de The Coral Project, su cuenta a sido bloqueada. No podrá hacer comentarios, reportar o entrar en contacto con nuestra comunidad." confirm: has_been_requested: "Un correo de confirmación ha sido pedido para la siguiente cuenta:" @@ -306,11 +306,11 @@ es: actions: Acciones all: todos all_streams: "Todos los Hilos" - notify_edited: '{0} comentarios editados "{1}"' - notify_accepted: '{0} comentarios aceptados "{1}"' - notify_rejected: '{0} comentarios rechazados "{1}"' - notify_flagged: '{0} comentarios reportados "{1}"' - notify_reset: '{0} resetear el status de comentarios "{1}"' + notify_edited: '{0} ha editado el comentario "{1}"' + notify_accepted: '{0} ha aceptado el comentario "{1}"' + notify_rejected: '{0} ha rechazado el comentario "{1}"' + notify_flagged: '{0} ha reportado el comentario "{1}"' + notify_reset: '{0} ha reseteado el status del comentario "{1}"' approve: "Aprobar" approved: "Aprobado" ban_user: "Bloquear" From 4312b8d02468e7d235f832eddf09b398cf683d86 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Fri, 4 May 2018 17:49:40 -0300 Subject: [PATCH 160/244] bug --- .../client/components/ChangePassword.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js index 8f86fff48..1b7b97dfc 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js @@ -160,7 +160,7 @@ class ChangePassword extends React.Component { }; render() { - const { editing, errors } = this.state; + const { editing, errors, showErrors } = this.state; return (
    - + {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 917d77782..3e7107922 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameContentDialog.js @@ -84,7 +84,11 @@ class ChangeUsernameContentDialog extends React.Component {
    - - -
    - - - ); - } -} - -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-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 85c1f1295..e5d0276c7 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -2,7 +2,7 @@ import React from 'react'; import cn from 'classnames'; import PropTypes from 'prop-types'; import styles from './Profile.css'; -import { Button } from 'plugin-api/beta/client/components/ui'; +import { Button, BareButton } from 'plugin-api/beta/client/components/ui'; import { t } from 'plugin-api/beta/client/services'; import InputField from './InputField'; import { getErrorMessages } from 'coral-framework/utils'; @@ -244,9 +244,13 @@ class Profile extends React.Component { > {t('talk-plugin-local-auth.change_username.save')} - + {t('talk-plugin-local-auth.change_username.cancel')} - + ) : ( From 06abccabb4de53832a12f504e7c1c01b3ef788d3 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 7 May 2018 18:26:37 +0200 Subject: [PATCH 165/244] Fix InputField controlled / uncontrolled mode --- .../client/components/ChangePassword.js | 6 +++++- .../client/components/InputField.js | 8 ++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js index 8f86fff48..a375e90a4 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangePassword.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangePassword.js @@ -14,7 +14,11 @@ const initialState = { editing: false, showErrors: true, errors: {}, - formData: {}, + formData: { + oldPassword: '', + newPassword: '', + confirmNewPassword: '', + }, }; class ChangePassword extends React.Component { diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.js b/plugins/talk-plugin-local-auth/client/components/InputField.js index 930c15582..7dca22197 100644 --- a/plugins/talk-plugin-local-auth/client/components/InputField.js +++ b/plugins/talk-plugin-local-auth/client/components/InputField.js @@ -19,13 +19,13 @@ const InputField = ({ showSuccess = false, validationType = '', icon = '', - value = '', - defaultValue = '', + value, + defaultValue, disabled = false, }) => { const inputValue = { - ...(value ? { value } : {}), - ...(defaultValue ? { defaultValue } : {}), + ...(value !== undefined ? { value } : {}), + ...(defaultValue !== undefined ? { defaultValue } : {}), }; return ( From 46e5efbd559c02c6cae73589ef6e461de856f0f0 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 7 May 2018 15:00:55 -0300 Subject: [PATCH 166/244] validation for password input in change email --- .../components/ChangeEmailContentDialog.js | 19 ++++++++++++------- .../client/components/Profile.js | 7 +++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index 1f1719444..b80529d82 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -18,10 +18,18 @@ class ChangeEmailContentDialog extends React.Component { confirmChanges = async e => { e.preventDefault(); + + if (this.formHasError()) { + this.showError(); + return; + } + await this.props.save(); this.props.next(); }; + formHasError = () => this.props.hasError('confirmPassword'); + render() { return (
    @@ -53,15 +61,10 @@ class ChangeEmailContentDialog extends React.Component { type="password" onChange={this.props.onChange} defaultValue="" - hasError={ - !this.props.formData.confirmPassword && this.state.showError - } - errorMsg={t( - 'talk-plugin-local-auth.change_email.incorrect_password' - )} + hasError={this.props.hasError('confirmPassword')} + errorMsg={this.props.getError('confirmPassword')} showError={this.state.showError} columnDisplay - showSuccess={false} />
    - -
    - -
    - - - {/* TODO: translate string */} - Contains Link - - -
    - - +
    + +
    + + + {/* TODO: translate string */} + Contains Link + + +
    + + +
    -
    - + + ) : ( + + )}
    @@ -152,7 +157,7 @@ UserDetailComment.propTypes = { comment: PropTypes.shape({ id: PropTypes.string.isRequired, status: PropTypes.string.isRequired, - body: PropTypes.string.isRequired, + body: PropTypes.string, actions: PropTypes.array, created_at: PropTypes.string.isRequired, asset: PropTypes.shape({ diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index 28dcf8ca8..137bd9381 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -13,6 +13,7 @@ import IfHasLink from 'coral-admin/src/components/IfHasLink'; import cn from 'classnames'; import ApproveButton from 'coral-admin/src/components/ApproveButton'; import RejectButton from 'coral-admin/src/components/RejectButton'; +import CommentDeletedTombstone from '../../../components/CommentDeletedTombstone'; import t, { timeago } from 'coral-framework/services/i18n'; @@ -133,48 +134,52 @@ class Comment extends React.Component { )}
    - -
    -
    - -
    - - {t('comment.view_context')} - + {comment.body ? ( + + -
    - - - {/* TODO: translate string */} - Contains Link - - -
    - - +
    + + + {/* TODO: translate string */} + Contains Link + + +
    + + +
    +
    -
    -
    -
    + + ) : ( + + )}
    { + this.setState({ + showError: true, + }); + }; + + confirmChanges = async () => { + if (this.formHasError()) { + this.showError(); + return; + } + + if (!this.props.canUsernameBeUpdated) { + this.props.notify( + 'error', + t('talk-plugin-local-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-local-auth.change_username.confirm_username_change')} +

    +
    +

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

    +
    + + {t('talk-plugin-local-auth.change_username.old_username')}:{' '} + {this.props.username} + + + {t('talk-plugin-local-auth.change_username.new_username')}:{' '} + {this.props.formData.newUsername} + +
    +
    + + + {t('talk-plugin-local-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; From e9c18faf32bd9641f30bc42d3801d272455bf2de Mon Sep 17 00:00:00 2001 From: okbel Date: Tue, 8 May 2018 11:30:33 -0300 Subject: [PATCH 183/244] Deleted Comment display in Queues --- .../src/components/CommentDeletedTombstone.js | 3 +- .../src/components/UserDetailComment.js | 97 ++++++++-------- .../routes/Moderation/components/Comment.css | 4 + .../routes/Moderation/components/Comment.js | 105 ++++++++++-------- 4 files changed, 120 insertions(+), 89 deletions(-) diff --git a/client/coral-admin/src/components/CommentDeletedTombstone.js b/client/coral-admin/src/components/CommentDeletedTombstone.js index db9a609b1..c04e97b88 100644 --- a/client/coral-admin/src/components/CommentDeletedTombstone.js +++ b/client/coral-admin/src/components/CommentDeletedTombstone.js @@ -1,8 +1,9 @@ import React from 'react'; import styles from './CommentDeletedTombstone.css'; +import t from 'coral-framework/services/i18n'; const CommentDeletedTombstone = () => ( -
    The comment was deleted.
    +
    {t('framework.comment_is_deleted')}
    ); export default CommentDeletedTombstone; diff --git a/client/coral-admin/src/components/UserDetailComment.js b/client/coral-admin/src/components/UserDetailComment.js index f7a500203..41fb87b28 100644 --- a/client/coral-admin/src/components/UserDetailComment.js +++ b/client/coral-admin/src/components/UserDetailComment.js @@ -44,6 +44,19 @@ class UserDetailComment extends React.Component { body: comment.body, }; + if (!comment.body) { + return ( +
  • + +
  • + ); + } + return (
  • }
  • - {comment.body ? ( - -
    -
    - +
    + +
    + + + {/* TODO: translate string */} + Contains Link + + + -
    - - - {/* TODO: translate string */} - Contains Link - - -
    - - -
    - - ) : ( - - )} +
    +
    diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.css b/client/coral-admin/src/routes/Moderation/components/Comment.css index 2dc03a503..0f8f91a97 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.css +++ b/client/coral-admin/src/routes/Moderation/components/Comment.css @@ -85,6 +85,10 @@ font-weight: 300; } +.deleted { + background-color: #f0f0f0; +} + .moderateArticle { font-size: 14px; margin: 10px 0; diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index 137bd9381..97cdf9443 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -76,6 +76,27 @@ class Comment extends React.Component { asset: comment.asset, }; + if (!comment.body) { + return ( +
  • + +
  • + ); + } + return (
  • )}
  • - {comment.body ? ( - -
    - - -
    - - - {/* TODO: translate string */} - Contains Link - - -
    - - -
    - + +
    + - - ) : ( - - )} + +
    + + + {/* TODO: translate string */} + Contains Link + + +
    + + +
    + +
    +
    +
    Date: Tue, 8 May 2018 11:33:39 -0300 Subject: [PATCH 184/244] removing extra --- .../components/ChangeUsernameDialog.css | 84 ------------ .../client/components/ChangeUsernameDialog.js | 120 ------------------ 2 files changed, 204 deletions(-) delete mode 100644 plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.css delete mode 100644 plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.css b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.css deleted file mode 100644 index af681d596..000000000 --- a/plugins/talk-plugin-local-auth/client/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-local-auth/client/components/ChangeUsernameDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js deleted file mode 100644 index 097168b06..000000000 --- a/plugins/talk-plugin-local-auth/client/components/ChangeUsernameDialog.js +++ /dev/null @@ -1,120 +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-local-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-local-auth.change_username.confirm_username_change')} -

    -
    -

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

    -
    - - {t('talk-plugin-local-auth.change_username.old_username')}:{' '} - {this.props.username} - - - {t('talk-plugin-local-auth.change_username.new_username')}:{' '} - {this.props.formData.newUsername} - -
    -
    - - - {t('talk-plugin-local-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; From 231dfe7997545f65425a213ce4c14e404f527b46 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 09:32:14 -0600 Subject: [PATCH 185/244] Fixes for notifications --- .../index.js | 56 +++++++++++++------ .../server/NotificationManager.js | 5 +- 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/plugins/talk-plugin-notifications-category-reply/index.js b/plugins/talk-plugin-notifications-category-reply/index.js index cce258daa..627d50ff8 100644 --- a/plugins/talk-plugin-notifications-category-reply/index.js +++ b/plugins/talk-plugin-notifications-category-reply/index.js @@ -1,17 +1,23 @@ const { get, map } = require('lodash'); const path = require('path'); -const handle = async (ctx, comment) => { +const commentAddedHandler = async (ctx, comment) => { // Check to see if this reply is visible. if (!comment.visible) { - ctx.log.info('comment was not visible, not sending notification'); + ctx.log.info( + { commentID: comment.id }, + 'comment was not visible, not sending notification' + ); return; } // Check to see if this is a reply to an existing comment. const parentID = get(comment, 'parent_id', null); - if (parentID === null) { - ctx.log.info('could not get parent comment id'); + if (!parentID) { + ctx.log.info( + { commentID: comment.id }, + 'could not get parent comment id, comment must be a top level comment' + ); return; } @@ -40,42 +46,60 @@ const handle = async (ctx, comment) => { return; } + const parentComment = get(reply, 'data.comment'); + if (!parentComment) { + ctx.log.info({ parentID }, 'could not get parent comment'); + return; + } + // Check if the user has notifications enabled. const enabled = get( - reply, - 'data.comment.user.notificationSettings.onReply', + parentComment, + 'user.notificationSettings.onReply', false ); if (!enabled) { + ctx.log.error( + 'parent comment author does not have notification category enabled' + ); return; } - const userID = get(reply, 'data.comment.user.id', null); - if (!userID) { - ctx.log.info('could not get parent comment user id'); + const parentAuthor = get(parentComment, 'user', null); + if (!parentAuthor) { + ctx.log.info('could not get parent author'); return; } - // Pull out the author of the new comment. + // Pull out the author of the new comment. This was outputted from Mongo, so + // we have to pull it out of the `author_id` field. const authorID = get(comment, 'author_id'); // Check to see if this is yourself replying to yourself, if that's the case // don't send a notification. - if (userID === authorID) { + if (parentAuthor.id === authorID) { ctx.log.info('user id of parent comment is the same as the new comment'); return; } // Check to see if this user is ignoring the user who replied to their // comment. - if (map(get(comment, 'user.ignoredUsers', []), 'id').indexOf(authorID)) { - ctx.log.info('parent user has ignored the author of the new comment'); + const ignoredUsers = map(get(parentAuthor, 'ignoredUsers', []), 'id'); + if (ignoredUsers.includes(authorID)) { + ctx.log.info( + { parentAuthorID: parentAuthor.id, authorID }, + 'parent user has ignored the author of the new comment' + ); return; } // The user does have notifications for replied comments enabled, queue the // notification to be sent. - return { userID, date: comment.created_at, context: comment.id }; + return { + userID: parentAuthor.id, + date: comment.created_at, + context: comment.id, + }; }; const hydrate = async (ctx, category, context) => { @@ -133,7 +157,7 @@ const commentAcceptedHandleAdapter = (ctx, comment) => { } // Delegate to the handle function. - return handle(ctx, comment); + return commentAddedHandler(ctx, comment); }; module.exports = { @@ -155,7 +179,7 @@ module.exports = { translations: path.join(__dirname, 'translations.yml'), notifications: [ { - handle, + handle: commentAddedHandler, category: 'reply', event: 'commentAdded', hydrate, diff --git a/plugins/talk-plugin-notifications/server/NotificationManager.js b/plugins/talk-plugin-notifications/server/NotificationManager.js index eb90dd48b..63af8efdb 100644 --- a/plugins/talk-plugin-notifications/server/NotificationManager.js +++ b/plugins/talk-plugin-notifications/server/NotificationManager.js @@ -32,7 +32,10 @@ const handleHandlers = (ctx, handlers, ...args) => // Attempt to create a notification out of it. const notification = await handle(ctx, ...args); if (!notification) { - ctx.log.info('no notification deemed by event handler'); + ctx.log.info( + { category, event }, + 'no notification deemed by event handler' + ); return; } From 74dbfda63368538ed9b82131ba0af058d67c0fd6 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 11:53:49 -0600 Subject: [PATCH 186/244] Exclude deleted comments --- .../Moderation/containers/Moderation.js | 2 ++ graph/loaders/comments.js | 34 +++++++++++++------ graph/typeDefs.graphql | 11 +++++- services/comments.js | 12 +++++-- 4 files changed, 45 insertions(+), 14 deletions(-) diff --git a/client/coral-admin/src/routes/Moderation/containers/Moderation.js b/client/coral-admin/src/routes/Moderation/containers/Moderation.js index f35255732..c908404cb 100644 --- a/client/coral-admin/src/routes/Moderation/containers/Moderation.js +++ b/client/coral-admin/src/routes/Moderation/containers/Moderation.js @@ -432,6 +432,7 @@ const withModQueueQuery = withQuery( ${Object.keys(queueConfig).map( queue => ` ${queue}: comments(query: { + excludeDeleted: true, statuses: ${ queueConfig[queue].statuses ? `[${queueConfig[queue].statuses.join(', ')}],` @@ -458,6 +459,7 @@ const withModQueueQuery = withQuery( ${Object.keys(queueConfig).map( queue => ` ${queue}Count: commentCount(query: { + excludeDeleted: true, statuses: ${ queueConfig[queue].statuses ? `[${queueConfig[queue].statuses.join(', ')}],` diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index 37d40a219..b42a636bc 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -94,6 +94,7 @@ const getCommentCountByQuery = (ctx, options) => { author_id, tags, action_type, + excludeDeleted, } = options; // If user queries for statuses other than NONE and/or ACCEPTED statuses, it needs @@ -120,6 +121,12 @@ const getCommentCountByQuery = (ctx, options) => { query.merge({ author_id }); } + if (excludeDeleted) { + // The null query matches documents that either contain the `deleted_at` + // field whose value is null or that do not contain the `deleted_at` field. + query.merge({ deleted_at: null }); + } + if (ctx.user != null && ctx.user.can(SEARCH_OTHERS_COMMENTS) && action_type) { query.merge({ [`action_counts.${sc(action_type.toLowerCase())}`]: { @@ -328,11 +335,12 @@ const getCommentsByQuery = async ( sortOrder, sortBy, excludeIgnored, + excludeDeleted, tags, action_type, } ) => { - let comments = CommentModel.find(); + const query = CommentModel.find(); // Enforce that the limit must be gte 0 if this option is not true. if (!ALLOW_NO_LIMIT_QUERIES && limit < 0) { @@ -350,11 +358,17 @@ const getCommentsByQuery = async ( } if (statuses) { - comments = comments.where({ status: { $in: statuses } }); + query.merge({ status: { $in: statuses } }); + } + + if (excludeDeleted) { + // The null query matches documents that either contain the `deleted_at` + // field whose value is null or that do not contain the `deleted_at` field. + query.merge({ deleted_at: null }); } if (ctx.user != null && ctx.user.can(SEARCH_OTHERS_COMMENTS) && action_type) { - comments = comments.where({ + query.merge({ [`action_counts.${sc(action_type.toLowerCase())}`]: { $gt: 0, }, @@ -362,7 +376,7 @@ const getCommentsByQuery = async ( } if (ids) { - comments = comments.find({ + query.merge({ id: { $in: ids, }, @@ -370,7 +384,7 @@ const getCommentsByQuery = async ( } if (tags) { - comments = comments.find({ + query.merge({ 'tags.tag.name': { $in: tags, }, @@ -383,17 +397,17 @@ const getCommentsByQuery = async ( (ctx.user.can(SEARCH_OTHERS_COMMENTS) || ctx.user.id === author_id) && author_id != null ) { - comments = comments.where({ author_id }); + query.merge({ author_id }); } if (asset_id) { - comments = comments.where({ asset_id }); + query.merge({ asset_id }); } // We perform the undefined check because, null, is a valid state for the // search to be with, which indicates that it is at depth 0. if (parent_id !== undefined) { - comments = comments.where({ parent_id }); + query.merge({ parent_id }); } if ( @@ -402,12 +416,12 @@ const getCommentsByQuery = async ( ctx.user.ignoresUsers && ctx.user.ignoresUsers.length > 0 ) { - comments = comments.where({ + query.merge({ author_id: { $nin: ctx.user.ignoresUsers }, }); } - return executeWithSort(ctx, comments, { cursor, sortOrder, sortBy, limit }); + return executeWithSort(ctx, query, { cursor, sortOrder, sortBy, limit }); }; /** diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index b5c193e3d..03c97ce58 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -418,6 +418,9 @@ input CommentsQuery { # Exclude comments ignored by the requesting user excludeIgnored: Boolean + + # excludeDeleted when true will exclude deleted comments from the response. + excludeDeleted: Boolean = false } input RepliesQuery { @@ -434,6 +437,9 @@ input RepliesQuery { # Exclude comments ignored by the requesting user excludeIgnored: Boolean + + # excludeDeleted when true will exclude deleted comments from the response. + excludeDeleted: Boolean = false } # CommentCountQuery allows the ability to query comment counts by specific @@ -463,6 +469,9 @@ input CommentCountQuery { # Filter by a specific tag name. tags: [String!] + + # excludeDeleted when true will exclude deleted comments from the count. + excludeDeleted: Boolean = false } # UserCountQuery allows the ability to query user counts by specific @@ -519,7 +528,7 @@ type Comment { replies(query: RepliesQuery = {}): CommentConnection! # replyCount is the number of replies with a depth of 1. Only direct replies - # to this comment are counted. + # to this comment are counted. Deleted comments are included in this count. replyCount: Int # Actions completed on the parent. Requires the `ADMIN` role. diff --git a/services/comments.js b/services/comments.js index 4b436b5f4..19b611089 100644 --- a/services/comments.js +++ b/services/comments.js @@ -39,9 +39,12 @@ module.exports = { const created_at = new Date(); // Check to see if we are replying to a comment, and if that comment is - // visible. + // visible and that it's not deleted. if (parent_id !== null) { - const parent = await CommentModel.findOne({ id: parent_id }); + const parent = await CommentModel.findOne({ + id: parent_id, + deleted_at: null, + }); if (parent === null || !parent.visible) { throw new ErrParentDoesNotVisible(); } @@ -94,6 +97,7 @@ module.exports = { status: { $in: EDITABLE_STATUSES, }, + deleted_at: null, }; // Establish the edit window (if it exists) and add the condition to the @@ -186,8 +190,10 @@ module.exports = { */ pushStatus: async (id, status, assigned_by = null) => { const created_at = new Date(); + + // Update the comment unless the comment was deleted. const originalComment = await CommentModel.findOneAndUpdate( - { id }, + { id, deleted_at: null }, { $push: { status_history: { From e14af46c68c9a7fcad6fcaa58a4ea4aaa651db85 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 12:02:04 -0600 Subject: [PATCH 187/244] prevent actions against deleted comments --- graph/mutators/action.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index d759449b0..5557e1a9b 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -14,8 +14,15 @@ const getActionItem = async (ctx, { item_id, item_type }) => { const { loaders: { Comments, Users } } = ctx; switch (item_type) { - case 'COMMENTS': - return Comments.get.load(item_id); + case 'COMMENTS': { + // Get a comment by ID, unless the comment is deleted, then return null. + const comment = await Comments.get.load(item_id); + if (comment.deleted_at) { + return null; + } + + return comment; + } case 'USERS': return Users.getByID.load(item_id); default: From 7b86ec7d0a5ae915aa1af68929c822140b1a7320 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 12:06:52 -0600 Subject: [PATCH 188/244] Update translations.yml --- plugins/talk-plugin-profile-data/client/translations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/translations.yml b/plugins/talk-plugin-profile-data/client/translations.yml index e139cfb57..d1fdccb73 100644 --- a/plugins/talk-plugin-profile-data/client/translations.yml +++ b/plugins/talk-plugin-profile-data/client/translations.yml @@ -1,7 +1,7 @@ en: download_request: section_title: "Download My Comment History" - you_will_get_a_copy: "You will recieve an email with a link to download your comment history. You can make" + you_will_get_a_copy: "You will receive an email with a link to download your comment history. You can make" download_rate: "one download request every {0} days" most_recent_request: "Your most recent request" request: "Request Comment History" From a1edbcf974e10986ec15613563b7f00080f66143 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 14:01:04 -0600 Subject: [PATCH 189/244] disallow adding a tag to a deleted comment --- services/tags.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/tags.js b/services/tags.js index b4e70cb29..18cf5869f 100644 --- a/services/tags.js +++ b/services/tags.js @@ -163,6 +163,11 @@ class TagsService { }, }; + if (item_type === 'COMMENT') { + // Don't allow adding tags to deleted comments. + query.deleted_at = null; + } + // If ownership verification is required, ensure that the person that is // assigning the tag is the same person that owns the comment. if (ownershipCheck) { From 17a0297911754e2049453aa9a7ad4878f4252094 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 14:02:47 -0600 Subject: [PATCH 190/244] fixed bug.. --- services/tags.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/tags.js b/services/tags.js index 18cf5869f..49d271c0b 100644 --- a/services/tags.js +++ b/services/tags.js @@ -13,6 +13,10 @@ const updateModel = async (item_type, query, update) => { switch (item_type) { case 'COMMENTS': Model = Comment; + + // Don't allow adding tags to deleted comments. + query.deleted_at = null; + break; case 'ASSETS': Model = Asset; @@ -163,11 +167,6 @@ class TagsService { }, }; - if (item_type === 'COMMENT') { - // Don't allow adding tags to deleted comments. - query.deleted_at = null; - } - // If ownership verification is required, ensure that the person that is // assigning the tag is the same person that owns the comment. if (ownershipCheck) { From 8c29b0f1d44326ecbb13a735607f0d3197a881b9 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 15:20:56 -0600 Subject: [PATCH 191/244] fix for delete --- graph/mutators/user.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/graph/mutators/user.js b/graph/mutators/user.js index 8b9afc206..7422f2290 100644 --- a/graph/mutators/user.js +++ b/graph/mutators/user.js @@ -70,15 +70,25 @@ const setRole = (ctx, id, role) => { /** * transforms a specific action to a removal action on the target model. */ -const actionDecrTransformer = ({ item_id, action_type, group_id }) => ({ - query: { id: item_id }, - update: { +const actionDecrTransformer = ({ item_id, action_type, group_id }) => { + const update = { $inc: { [`action_counts.${action_type.toLowerCase()}`]: -1, - [`action_counts.${action_type.toLowerCase()}_${group_id.toLowerCase()}`]: -1, }, - }, -}); + }; + + if (group_id) { + // If the action had a groupID, also decrement that key. + update.$inc[ + `action_counts.${action_type.toLowerCase()}_${group_id.toLowerCase()}` + ] = -1; + } + + return { + query: { id: item_id }, + update, + }; +}; // delUser will delete a given user with the specified id. const delUser = async (ctx, id) => { From 1815bd4d75275e8008ecb90f58f51820f463692b Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 15:30:12 -0600 Subject: [PATCH 192/244] fix translation copy --- .../client/components/DeleteMyAccount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js index bbada134f..179fa0193 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccount.js @@ -27,7 +27,7 @@ class DeleteMyAccount extends React.Component { const { cancelAccountDeletion, notify } = this.props; try { await cancelAccountDeletion(); - notify('success', t('delete_request.account_deletion_requested')); + notify('success', t('delete_request.account_deletion_cancelled')); } catch (err) { notify('error', getErrorMessages(err)); } From 7348bfc7c9f8c95fb414c6067efc180049eea888 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 8 May 2018 15:46:24 -0600 Subject: [PATCH 193/244] fixed error --- .../client/containers/IgnoreUserConfirmation.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js index 5aa834034..efd4cd366 100644 --- a/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js +++ b/plugins/talk-plugin-ignore-user/client/containers/IgnoreUserConfirmation.js @@ -10,16 +10,22 @@ import { bindActionCreators } from 'redux'; import { closeMenu } from 'plugins/talk-plugin-author-menu/client/actions'; import { notify } from 'plugin-api/beta/client/actions/notification'; import { t } from 'plugin-api/beta/client/services'; +import { getErrorMessages } from 'coral-framework/utils'; class IgnoreUserConfirmationContainer extends React.Component { - ignoreUser = () => { + ignoreUser = async () => { const { ignoreUser, notify, comment, closeMenu } = this.props; - ignoreUser(comment.user.id).then(() => { + + try { + await ignoreUser(comment.user.id); notify( 'success', t('talk-plugin-ignore-user.notify_success', comment.user.username) ); - }); + } catch (err) { + notify('error', getErrorMessages(err)); + } + closeMenu(); }; From b50fde619e436f9db1ea466c09776fae7199fa42 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Tue, 8 May 2018 23:46:33 +0200 Subject: [PATCH 194/244] Pass postDontAgree to replies --- .../src/tabs/stream/components/AllCommentsPane.js | 2 +- .../coral-embed-stream/src/tabs/stream/components/Comment.js | 4 +++- .../coral-embed-stream/src/tabs/stream/containers/Stream.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js b/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js index 9aa2b8a4c..eae72c749 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js +++ b/client/coral-embed-stream/src/tabs/stream/components/AllCommentsPane.js @@ -214,7 +214,7 @@ AllCommentsPane.propTypes = { asset: PropTypes.object, currentUser: PropTypes.object, postFlag: PropTypes.func, - postDontAgree: PropTypes.func, + postDontAgree: PropTypes.func.isRequired, loadNewReplies: PropTypes.func, deleteAction: PropTypes.func, showSignInDialog: PropTypes.func, 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 8b1524839..32778f7ea 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Comment.js @@ -184,7 +184,7 @@ export default class Comment extends React.Component { maxCharCount: PropTypes.number, root: PropTypes.object, loadMore: PropTypes.func, - postDontAgree: PropTypes.func, + postDontAgree: PropTypes.func.isRequired, animateEnter: PropTypes.bool, commentClassNames: PropTypes.array, comment: PropTypes.object.isRequired, @@ -410,6 +410,7 @@ export default class Comment extends React.Component { charCountEnable, showSignInDialog, liveUpdates, + postDontAgree, emit, } = this.props; return ( @@ -440,6 +441,7 @@ export default class Comment extends React.Component { key={reply.id} comment={reply} emit={emit} + postDontAgree={postDontAgree} /> ); })} 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 17d3132ea..f1a973f03 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -265,7 +265,7 @@ StreamContainer.propTypes = { commentClassNames: PropTypes.array, setActiveStreamTab: PropTypes.func, postFlag: PropTypes.func, - postDontAgree: PropTypes.func, + postDontAgree: PropTypes.func.isRequired, deleteAction: PropTypes.func, showSignInDialog: PropTypes.func, currentUser: PropTypes.object, From 8be4300ff4449cfdfa6126cdd4a031afb0b0ad17 Mon Sep 17 00:00:00 2001 From: Clint Brown Date: Wed, 9 May 2018 17:41:16 +1000 Subject: [PATCH 195/244] Fix My Profile story title link behavior --- .../coral-embed-stream/src/tabs/profile/components/Comment.css | 1 + client/coral-embed-stream/src/tabs/profile/components/Comment.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/tabs/profile/components/Comment.css b/client/coral-embed-stream/src/tabs/profile/components/Comment.css index 9004a1e6c..c2bf841d5 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Comment.css +++ b/client/coral-embed-stream/src/tabs/profile/components/Comment.css @@ -31,6 +31,7 @@ font-weight: bold; font-size: 12px; color: #757575; + cursor: pointer; } .commentSummary { diff --git a/client/coral-embed-stream/src/tabs/profile/components/Comment.js b/client/coral-embed-stream/src/tabs/profile/components/Comment.js index 171172dab..84293096b 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/profile/components/Comment.js @@ -76,7 +76,6 @@ class Comment extends React.Component {
    {t('common.story')}:{' '} From 1517611c9ed4a36c47211effdae0f0a2a5894c13 Mon Sep 17 00:00:00 2001 From: Kim Gardner Date: Wed, 9 May 2018 11:00:02 -0400 Subject: [PATCH 196/244] Update tombstone copy --- locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.yml b/locales/en.yml index e293fb40b..9a26fbdb6 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -274,7 +274,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_deleted: "This commenter has deleted their account." comment_is_hidden: "This comment is not available." comments: comments configure_stream: "Configure" From 0ded5c72e98799a4cba0959985e7a8e529593776 Mon Sep 17 00:00:00 2001 From: okbel Date: Wed, 9 May 2018 14:23:22 -0300 Subject: [PATCH 197/244] adding media --- .../client/components/DeleteMyAccountDialog.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css index 2735474da..26087c534 100644 --- a/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css +++ b/plugins/talk-plugin-profile-data/client/components/DeleteMyAccountDialog.css @@ -1,12 +1,19 @@ +@custom-media --small-viewport (min-width: 425px); + .dialog { + width: calc(100% - 50px); 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: 380px; + top: 10px; font-family: Helvetica, 'Helvetica Neue', Verdana, sans-serif; font-size: 14px; border-radius: 4px; padding: 20px; + + @media (--small-viewport) { + width: 380px; + } } .close { From 4426be5f397d6529f6dd94cb5915bebc5c37041d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 13:56:05 -0600 Subject: [PATCH 198/244] improved dev experience, fixed css order --- client/coral-admin/src/components/App.css | 9 +++ client/coral-admin/src/components/App.js | 1 + middleware/staticTemplate.js | 8 ++- package.json | 1 + public/css/dev.css | 5 ++ routes/dev/assets.js | 45 ++++++++----- routes/dev/index.js | 2 - services/assets.js | 6 -- views/admin.ejs | 9 +-- views/dev/article.ejs | 80 ++++++++++------------- views/dev/articles.ejs | 50 ++++++++++---- views/embed/stream.ejs | 1 + views/login.ejs | 1 + views/partials/account.ejs | 3 +- views/partials/custom-css.ejs | 1 + views/partials/dev-nav.ejs | 8 +++ views/partials/dev.ejs | 5 ++ views/partials/head.ejs | 3 - yarn.lock | 15 +++++ 19 files changed, 158 insertions(+), 95 deletions(-) create mode 100644 client/coral-admin/src/components/App.css create mode 100644 public/css/dev.css create mode 100644 views/partials/custom-css.ejs create mode 100644 views/partials/dev-nav.ejs create mode 100644 views/partials/dev.ejs diff --git a/client/coral-admin/src/components/App.css b/client/coral-admin/src/components/App.css new file mode 100644 index 000000000..1404a9293 --- /dev/null +++ b/client/coral-admin/src/components/App.css @@ -0,0 +1,9 @@ +html, body, #root, #root > div { + min-height: 100%; +} + +body { + margin: 0; + background-color: #FAFAFA; + font-family: 'Roboto', sans-serif; +} diff --git a/client/coral-admin/src/components/App.js b/client/coral-admin/src/components/App.js index 52535f91a..a7ab1e336 100644 --- a/client/coral-admin/src/components/App.js +++ b/client/coral-admin/src/components/App.js @@ -1,5 +1,6 @@ import React from 'react'; import ToastContainer from './ToastContainer'; +import './App.css'; import 'material-design-lite'; import AppRouter from '../AppRouter'; diff --git a/middleware/staticTemplate.js b/middleware/staticTemplate.js index f16caaea9..d8137693e 100644 --- a/middleware/staticTemplate.js +++ b/middleware/staticTemplate.js @@ -94,9 +94,13 @@ const createResolveFactory = (() => { module.exports = async (req, res, next) => { try { - // Attach the custom css url. - const { customCssUrl } = await SettingsService.select('customCssUrl'); + // Attach the custom css url and organization name. + const { customCssUrl, organizationName } = await SettingsService.select( + 'customCssUrl', + 'organizationName' + ); res.locals.customCssUrl = customCssUrl; + res.locals.organizationName = organizationName; } catch (err) { console.warn(err); } diff --git a/package.json b/package.json index f6ff46a59..01b671dde 100644 --- a/package.json +++ b/package.json @@ -219,6 +219,7 @@ "babel-plugin-dynamic-import-node": "^1.1.0", "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", "browserstack-local": "^1.3.0", + "casual": "^1.5.19", "chai": "^3.5.0", "chai-as-promised": "^6.0.0", "chai-datetime": "^1.5.0", diff --git a/public/css/dev.css b/public/css/dev.css new file mode 100644 index 000000000..73ccaed2c --- /dev/null +++ b/public/css/dev.css @@ -0,0 +1,5 @@ +.container { + width: auto; + max-width: 680px; + padding: 0 15px; +} diff --git a/routes/dev/assets.js b/routes/dev/assets.js index cb1f27e43..aea0628e3 100644 --- a/routes/dev/assets.js +++ b/routes/dev/assets.js @@ -1,49 +1,58 @@ const express = require('express'); const router = express.Router(); - -const errors = require('../../errors'); -const Assets = require('../../services/assets'); - -const body = - 'Lorem ipsum dolor sponge amet, consectetur adipiscing clam. Ut lobortis sollicitudin pillar a ornare. Curabitur dignissim vestibulum cay non rhoncus. Cras laoreet ante vel nunc hendrerit, shelf imperdiet neque egestas. Suspendisse aliquet iaculis fermentum. Talk volutpat, tellus posuere laoreet consequat, mi lacus laoreet massa, sed vehicula mauris velit non lectus. Integer non trust nec neque congue faucibus porttitor sit amet elkhorn.'; +const casual = require('casual'); +const { ErrNotFound } = require('../../errors'); +const Asset = require('../../models/asset'); router.get('/id/:asset_id', async (req, res, next) => { try { - const asset = await Assets.findById(req.params.asset_id); + const asset = await Asset.findOne({ id: req.params.asset_id }); if (asset === null) { - return next(errors.ErrNotFound); + throw new ErrNotFound(); } res.render('dev/article', { title: asset.title, asset_id: asset.id, asset_url: asset.url, - body: '', - basePath: '/client/embed/stream', }); } catch (err) { return next(err); } }); +router.get('/random', (req, res) => { + const title = casual.title; + + res.redirect(`./title/${title.replace(/ /g, '-')}`); +}); + router.get('/title/:asset_title', (req, res) => { - return res.render('dev/article', { + res.render('dev/article', { title: req.params.asset_title.split('-').join(' '), asset_url: '', asset_id: null, - body: body, - basePath: '/client/embed/stream', }); }); router.get('/', async (req, res, next) => { - let skip = req.query.skip ? parseInt(req.query.skip) : 0; - let limit = req.query.limit ? parseInt(req.query.limit) : 25; - try { - const assets = await Assets.all(skip, limit); + const skip = req.query.skip ? parseInt(req.query.skip) : 0; + const limit = req.query.limit ? parseInt(req.query.limit) : 6; + + const [assets, count] = await Promise.all([ + Asset.find({}) + .sort({ created_at: 1 }) + .limit(limit) + .skip(skip), + Asset.count(), + ]); + res.render('dev/articles', { - assets: assets, + skip, + limit, + count, + assets, }); } catch (err) { return next(err); diff --git a/routes/dev/index.js b/routes/dev/index.js index ac72db254..58daca583 100644 --- a/routes/dev/index.js +++ b/routes/dev/index.js @@ -16,8 +16,6 @@ router.get('/', staticTemplate, async (req, res) => { title: 'Coral Talk', asset_url: '', asset_id: '', - body: '', - basePath: '/static/embed/stream', }); } }); diff --git a/services/assets.js b/services/assets.js index 794145eb3..5f1fa989d 100644 --- a/services/assets.js +++ b/services/assets.js @@ -232,11 +232,5 @@ module.exports = class AssetsService { await AssetModel.remove({ id: srcAssetID, }); - - // That's it! - } - - static all(limit = undefined) { - return AssetModel.find({}).limit(limit); } }; diff --git a/views/admin.ejs b/views/admin.ejs index b8f775d79..89cc150f7 100644 --- a/views/admin.ejs +++ b/views/admin.ejs @@ -3,16 +3,11 @@ Talk - Coral Admin - + <%- include partials/head %> - - - <%- include partials/head %> + <%- include partials/custom-css %>
    diff --git a/views/dev/article.ejs b/views/dev/article.ejs index 8abfc34af..008d3989e 100644 --- a/views/dev/article.ejs +++ b/views/dev/article.ejs @@ -8,53 +8,45 @@ - - <%= title %> + <%- include ../partials/dev %> -
    -

    <%= title %>

    -

    <%= body %>

    -

    Admin - All Assets

    -
    - + -
    + * You can listen to events using the example below. + * The argument passed is the event emitter from + * https://github.com/asyncly/EventEmitter2 + * + * events: function(events) { + * events.onAny(function(eventName, data) { + * console.log(eventName, data); + * }); + * }, + */ + plugins_config: { + /** + * You can disable rendering slot components of a plugin by doing: + * + * 'talk-plugin-love': { + * disable_components: true, + * }, + */ + test: 'data', + debug: false + } + }) + +
    diff --git a/views/dev/articles.ejs b/views/dev/articles.ejs index 0ce684029..3a67b53c5 100644 --- a/views/dev/articles.ejs +++ b/views/dev/articles.ejs @@ -1,14 +1,40 @@ - -

    - Asset list -

    -<% assets.forEach(function (asset) { %> - <%= asset.url %>
    -<% }) %> -

    - (For dev use only. FYI, you can: ?skip=100&limit=25) -

    - - + + All Assets + <%- include ../partials/dev %> + + + <%- include ../partials/dev-nav %> +
    +
    +

    All Assets

    + <%= skip + 1 %> - <%= skip + assets.length %> of <%= count %> +
    +
    + <% if (skip === 0) { %> Create a random article<% } %> + <% assets.forEach(function (asset) { %> + +
    +
    <%= asset.title %>
    + Created <%= asset.created_at.toLocaleString('en-US') %> +
    + <%= asset.url %> +
    + <% }) %> +
    + <% if (count !== assets.length) { %> + + <% } %> +
    + diff --git a/views/embed/stream.ejs b/views/embed/stream.ejs index 2027f6069..a1c708b55 100644 --- a/views/embed/stream.ejs +++ b/views/embed/stream.ejs @@ -5,6 +5,7 @@ <%- include ../partials/head %> + <%- include ../partials/custom-css %>
    diff --git a/views/login.ejs b/views/login.ejs index c5a86c2fb..671b25c83 100644 --- a/views/login.ejs +++ b/views/login.ejs @@ -6,6 +6,7 @@ <%- include partials/head %> + <%- include partials/custom-css %>
    diff --git a/views/partials/account.ejs b/views/partials/account.ejs index 79857baf0..ff2166816 100644 --- a/views/partials/account.ejs +++ b/views/partials/account.ejs @@ -1,3 +1,4 @@ -<%- include ./head %> +<%- include head %> +<%- include custom-css %> diff --git a/views/partials/custom-css.ejs b/views/partials/custom-css.ejs new file mode 100644 index 000000000..d453c37e1 --- /dev/null +++ b/views/partials/custom-css.ejs @@ -0,0 +1 @@ +<% if (locals.customCssUrl) { %><% } %> diff --git a/views/partials/dev-nav.ejs b/views/partials/dev-nav.ejs new file mode 100644 index 000000000..0d6d067d6 --- /dev/null +++ b/views/partials/dev-nav.ejs @@ -0,0 +1,8 @@ + diff --git a/views/partials/dev.ejs b/views/partials/dev.ejs new file mode 100644 index 000000000..691b548e5 --- /dev/null +++ b/views/partials/dev.ejs @@ -0,0 +1,5 @@ + + + + + diff --git a/views/partials/head.ejs b/views/partials/head.ejs index e848b3909..dc3df7103 100644 --- a/views/partials/head.ejs +++ b/views/partials/head.ejs @@ -18,9 +18,6 @@ -<%_ if (locals.customCssUrl) { _%> - -<%_ } _%> <%- include data %> diff --git a/yarn.lock b/yarn.lock index 5cf363b6e..f0da6d006 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1828,6 +1828,13 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" +casual@^1.5.19: + version "1.5.19" + resolved "https://registry.yarnpkg.com/casual/-/casual-1.5.19.tgz#66fac46f7ae463f468f5913eb139f9c41c58bbf2" + dependencies: + mersenne-twister "^1.0.1" + moment "^2.15.2" + center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -7154,6 +7161,10 @@ merge@^1.1.3: version "1.2.0" resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da" +mersenne-twister@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" + metascraper-author@^3.9.2: version "3.9.2" resolved "https://registry.yarnpkg.com/metascraper-author/-/metascraper-author-3.9.2.tgz#ff2020ac428f59a875d655df3b0d4bea171fde19" @@ -7436,6 +7447,10 @@ moment@^2.10.3: version "2.19.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.1.tgz#56da1a2d1cbf01d38b7e1afc31c10bcfa1929167" +moment@^2.15.2: + version "2.22.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" + mongodb-core@2.1.17: version "2.1.17" resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.17.tgz#a418b337a14a14990fb510b923dee6a813173df8" From 55a9c1e6b4a64e5a85556b48c7da4072b636edf9 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:05:16 -0600 Subject: [PATCH 199/244] added link to graphiql --- public/css/dev.css | 4 ++++ views/partials/dev-nav.ejs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/public/css/dev.css b/public/css/dev.css index 73ccaed2c..2fd6c1982 100644 --- a/public/css/dev.css +++ b/public/css/dev.css @@ -3,3 +3,7 @@ max-width: 680px; padding: 0 15px; } + +.graphiql em { + font-family: georgia; +} diff --git a/views/partials/dev-nav.ejs b/views/partials/dev-nav.ejs index 0d6d067d6..088c52c20 100644 --- a/views/partials/dev-nav.ejs +++ b/views/partials/dev-nav.ejs @@ -2,7 +2,7 @@ <%= organizationName %> Organization
    Admin - Development + GraphiQL All Assets
    From 302cab8ca02150f1329cd217b65b0d503cdaa6dc Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:12:27 -0600 Subject: [PATCH 200/244] added header to graphiql --- views/api/graphiql.ejs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/views/api/graphiql.ejs b/views/api/graphiql.ejs index b6d609de6..8007569b3 100644 --- a/views/api/graphiql.ejs +++ b/views/api/graphiql.ejs @@ -5,13 +5,17 @@ GraphiQL + <%- include ../partials/dev %> @@ -20,6 +24,8 @@ + <%- include ../partials/dev-nav %> +
    - \ No newline at end of file + From 969206f9057ffac2c9b68e110014128b018846c2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:14:48 -0600 Subject: [PATCH 201/244] copy adjustment --- views/dev/articles.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/views/dev/articles.ejs b/views/dev/articles.ejs index 3a67b53c5..1b07ed116 100644 --- a/views/dev/articles.ejs +++ b/views/dev/articles.ejs @@ -8,7 +8,7 @@

    All Assets

    - <%= skip + 1 %> - <%= skip + assets.length %> of <%= count %> + <%= skip + 1 %> - <%= skip + assets.length %> of <%= count %> Assets
    <% if (skip === 0) { %> Create a random article<% } %> From 51525de679c3957d583d6b85ad8bf02398556ff5 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:17:43 -0600 Subject: [PATCH 202/244] fixed set-role description --- bin/cli-users | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/cli-users b/bin/cli-users index a01980a20..bf34cce97 100755 --- a/bin/cli-users +++ b/bin/cli-users @@ -328,7 +328,7 @@ program .action(searchUsers); program - .command('set-role ') + .command('set-role ') .description('sets the role on a user') .action(setUserRole); From 9af3772087198b9645d5fcfb2733c5f01966b419 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:28:04 -0600 Subject: [PATCH 203/244] Added json output for assets list - Fixes #1597 --- bin/cli-assets | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/bin/cli-assets b/bin/cli-assets index 210b9f22e..62c996412 100755 --- a/bin/cli-assets +++ b/bin/cli-assets @@ -23,23 +23,33 @@ util.onshutdown([() => mongoose.disconnect()]); /** * Lists all the assets registered in the database. */ -async function listAssets() { +async function listAssets(opts) { try { let assets = await AssetModel.find({}).sort({ created_at: 1 }); - let table = new Table({ - head: ['ID', 'Title', 'URL'], - }); + switch (opts.format) { + case 'json': { + console.log(JSON.stringify(assets, null, 2)); + break; + } + default: { + let table = new Table({ + head: ['ID', 'Title', 'URL'], + }); - assets.forEach(asset => { - table.push([ - asset.id, - asset.title ? asset.title : '', - asset.url ? asset.url : '', - ]); - }); + assets.forEach(asset => { + table.push([ + asset.id, + asset.title ? asset.title : '', + asset.url ? asset.url : '', + ]); + }); + + console.log(table.toString()); + break; + } + } - console.log(table.toString()); util.shutdown(); } catch (e) { console.error(e); @@ -202,6 +212,12 @@ async function rewrite(search, replace, options) { program .command('list') + .option( + '--format ', + 'Specify the output format [table]', + /^(table|json)$/i, + 'table' + ) .description('list all the assets in the database') .action(listAssets); From ca3d56def87d1e478fb44a3d29ce82d1dd47ad1d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 9 May 2018 14:40:24 -0600 Subject: [PATCH 204/244] asset refresh patched --- bin/cli-assets | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/bin/cli-assets b/bin/cli-assets index 62c996412..5c1afb741 100755 --- a/bin/cli-assets +++ b/bin/cli-assets @@ -59,12 +59,13 @@ async function listAssets(opts) { async function refreshAssets(ageString) { try { - const now = new Date().getTime(); - const ageMs = parseDuration(ageString); - const age = new Date(now - ageMs); + const query = AssetModel.find({}, { id: 1 }); + if (ageString) { + // An age was specified, so filter only those assets. + const ageMs = parseDuration(ageString); + const age = new Date(Date.now() - ageMs); - let assets = await AssetModel.find( - { + query.merge({ $or: [ { scraped: { @@ -75,16 +76,28 @@ async function refreshAssets(ageString) { scraped: null, }, ], - }, - { id: 1 } - ); + }); + } // Create a graph context. const ctx = Context.forSystem(); + // Load the assets. + const cursor = query.cursor(); + // Queue all the assets for scraping. - await Promise.all(assets.map(({ id }) => scraper.create(ctx, id))); - console.log('Assets were queued to be scraped'); + const promises = []; + + let asset = await cursor.next(); + while (asset) { + promises.push(scraper.create(ctx, asset.id)); + asset = await cursor.next(); + } + + await Promise.all(promises); + + console.log(`${promises.length} Assets were queued to be scraped.`); + util.shutdown(); } catch (e) { console.error(e); @@ -222,7 +235,7 @@ program .action(listAssets); program - .command('refresh ') + .command('refresh [age]') .description('queues the assets that exceed the age requested') .action(refreshAssets); From a092a197cffeb3a8a1591a2af4332effaadb7e3f Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Wed, 9 May 2018 23:45:53 +0200 Subject: [PATCH 205/244] Check correct email --- plugins/talk-plugin-local-auth/client/components/Profile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/Profile.js b/plugins/talk-plugin-local-auth/client/components/Profile.js index 2b2d4be11..c3b09aab2 100644 --- a/plugins/talk-plugin-local-auth/client/components/Profile.js +++ b/plugins/talk-plugin-local-auth/client/components/Profile.js @@ -114,11 +114,11 @@ class Profile extends React.Component { isSaveEnabled = () => { const { formData } = this.state; - const { emailAddress, username } = this.props; + const { root: { me: { username, email } } } = this.props; const formHasErrors = !!Object.keys(this.state.errors).length; const validUsername = formData.newUsername && formData.newUsername !== username; - const validEmail = formData.newEmail && formData.newEmail !== emailAddress; + const validEmail = formData.newEmail && formData.newEmail !== email; return !formHasErrors && (validUsername || validEmail); }; From 2554b261100ab80d0f38e8c83bdfb78cded75dd6 Mon Sep 17 00:00:00 2001 From: Andrew Losowsky Date: Thu, 10 May 2018 10:21:44 -0400 Subject: [PATCH 206/244] Corrections and clarity Fixed the incorrect thresholds and made the description clearer --- docs/source/03-07-product-guide-trust.md | 44 ++++++++++++++---------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/docs/source/03-07-product-guide-trust.md b/docs/source/03-07-product-guide-trust.md index c27c59dcc..961cf843d 100644 --- a/docs/source/03-07-product-guide-trust.md +++ b/docs/source/03-07-product-guide-trust.md @@ -3,47 +3,53 @@ title: Trust permalink: /trust/ --- -Trust is a set of components within Talk that incorporate automated moderation -features based on a user's previous behavior. +Trust is a set of components within Talk that incorporate basic automated moderation features based on a user's previous behavior. ## User Karma Score -Using Trust’s calculations, Talk will automatically pre-moderate comments of -users who have a negative karma score. All users start out with a `0` neutral -karma score. If they have a comment approved by a moderator, their score -increases by `1`; if they have a comment rejected by a moderator, it decreases -by `1`. When a commenter is labeled as Unreliable, their comments must be -moderated before they are posted. +Using Trust’s calculations, Talk will automatically hold back, move to the Reported queue, and tag with a 'History' marker, any comments by users who have an Unreliable karma score. (This is for sites who practice post-moderation. If you set pre-moderation of all comments sitewide, this feature has limited use.) -When a commenter has one comment rejected, their next comment must be moderated -once in order to post freely again. If they instead get rejected again, then -they must have two of their comments approved in order to get added back to the -queue. +All users start out with a Neutral karma score (`0`). If they have a comment approved by a moderator, their score increases by `1`; if they have a comment rejected by a moderator, it decreases by `1`. When a commenter's score is labeled as Unreliable, their comments must be approved from the Reported queue before they are posted. Commenters are shown a message stating that a moderator will review their comment shortly. Here are the default thresholds: ```text --2 and lower: Unreliable --1 to +2: Neutral -+3 and higher: Reliable +-1 and lower: Unreliable +0 to +1: Neutral ++1 and higher: Reliable (we don't do anything with this label right now) ``` -You can configure your own Trust thresholds by using [TRUST_THRESHOLD](/talk/advanced-configuration/#trust-thresholds) in your -configuration. +So in this case, when a new commenter has their first comment rejected, their user karma score becomes `-1`, which triggers the Unreliable threshhold, and they must then have a comment approved by a moderator in order to post freely again. Until that occurs, all of their comments will be held back temporarily in the Reported queue, marked with a `History` tag. + +If their next comment is also rejected, their user karma score is now `-2`, and they must have two comments approved in order to reach a Neutral score, and post without pre-approval. + +We strongly recommend not telling your community how this system works, or where the threshholds lie. Firstly, they might try to game the system to meet approval, and secondly, it makes it harder for you to change the threshhold in the future. We suggest using language such as "We hold back comments for approval for a variety of reasons, including content, account history, and more." + +If you see that a high proportion of first-time commenters on your site are abusive, you might want to change the threshhold to `0`, at least temporarily. You can configure your own Trust thresholds by using [TRUST_THRESHOLD](/talk/advanced-configuration/#trust-thresholds) in your site configuration. ## Reliable and Unreliable Flaggers Trust also calculates how reliable users are in terms of the comments they report. This information is displayed to moderators in the User History drawer, -which is accessed by clicking on a user’s name in the Admin. +which is accessed by clicking on a user’s name in the Admin. Currently, no other action is taken based on this score. If a user's reports mostly match what moderators reject, their Report status will display to moderators as Reliable in the user information drawer. If a user's reports mostly differ from what moderators reject, their Report status will show as Unreliable. -If we don't have enough reports to make a call, or the reports even out, their +If Talk doesn't have enough reports to make a call, or the reports even out, their status is Neutral. +Here are the default thresholds: + +```text +-1 and lower: Unreliable +0 to +1: Neutral ++2 and higher: Reliable +``` +You can configure your own Trust thresholds by using [TRUST_THRESHOLD](/talk/advanced-configuration/#trust-thresholds) in your +configuration. + Note: Report Karma doesn't include reports of "I don't agree with this comment". From 2e37f78705dbaafd27202ea054dde01773f0fd57 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 10 May 2018 13:31:00 -0600 Subject: [PATCH 207/244] Email Attach Fixes --- client/coral-framework/components/Popup.js | 16 ++++++++++----- .../talk-plugin-local-auth/client/actions.js | 9 +++++++++ .../components/AddEmailAddressDialog.js | 20 ++++++++++++++++--- .../client/components/AddEmailContent.js | 9 +++------ .../client/constants.js | 4 ++++ .../containers/AddEmailAddressDialog.js | 16 +++++++++++---- .../talk-plugin-local-auth/client/index.js | 4 +++- .../talk-plugin-local-auth/client/reducer.js | 20 +++++++++++++++++++ plugins/talk-plugin-local-auth/index.js | 2 +- .../server/translations.yml | 9 --------- .../{client => }/translations.yml | 10 +++++++++- 11 files changed, 89 insertions(+), 30 deletions(-) create mode 100644 plugins/talk-plugin-local-auth/client/actions.js create mode 100644 plugins/talk-plugin-local-auth/client/constants.js create mode 100644 plugins/talk-plugin-local-auth/client/reducer.js delete mode 100644 plugins/talk-plugin-local-auth/server/translations.yml rename plugins/talk-plugin-local-auth/{client => }/translations.yml (91%) diff --git a/client/coral-framework/components/Popup.js b/client/coral-framework/components/Popup.js index 53d8f7cd8..339ddb806 100644 --- a/client/coral-framework/components/Popup.js +++ b/client/coral-framework/components/Popup.js @@ -37,7 +37,8 @@ export default class Popup extends Component { this.onBlur(); }; - // Use `onunload` instead of `onbeforeunload` which is not supported in IOS Safari. + // Use `onunload` instead of `onbeforeunload` which is not supported in iOS + // Safari. this.ref.onunload = () => { this.onUnload(); @@ -46,10 +47,15 @@ export default class Popup extends Component { } this.resetCallbackInterval = setInterval(() => { - if (this.ref && this.ref.onload === null) { - clearInterval(this.resetCallbackInterval); - this.resetCallbackInterval = null; - this.setCallbacks(); + try { + if (this.ref && this.ref.onload === null) { + clearInterval(this.resetCallbackInterval); + this.resetCallbackInterval = null; + this.setCallbacks(); + } + } catch (err) { + // We could be getting a security exception here if the login page + // gets redirected to another domain to authenticate. } }, 50); diff --git a/plugins/talk-plugin-local-auth/client/actions.js b/plugins/talk-plugin-local-auth/client/actions.js new file mode 100644 index 000000000..9f2c9cfed --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/actions.js @@ -0,0 +1,9 @@ +import * as actions from './constants'; + +export const startAttach = () => ({ + type: actions.STARTED_ATTACH, +}); + +export const finishAttach = () => ({ + type: actions.FINISH_ATTACH, +}); diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index dc7e0d974..76131c895 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -45,6 +45,10 @@ class AddEmailAddressDialog extends React.Component { ), }; + componentDidMount() { + this.props.startAttach(); + } + onChange = e => { const { name, value } = e.target; this.setState( @@ -99,7 +103,13 @@ class AddEmailAddressDialog extends React.Component { }); }; - confirmChanges = async () => { + finish = () => { + this.props.finishAttach(); + }; + + confirmChanges = async e => { + e.preventDefault(); + if (!this.validate()) { this.showErrors(); return; @@ -113,6 +123,8 @@ class AddEmailAddressDialog extends React.Component { email: emailAddress, password: confirmPassword, }); + + // TODO: translate this.props.notify('success', 'Email Added!'); this.goToNextStep(); } catch (err) { @@ -143,13 +155,13 @@ class AddEmailAddressDialog extends React.Component { )} {step === 1 && !settings.requireEmailConfirmation && ( - {}} /> + )} {step === 1 && settings.requireEmailConfirmation && ( {}} + done={this.finish} /> )} @@ -161,6 +173,8 @@ AddEmailAddressDialog.propTypes = { attachLocalAuth: PropTypes.func.isRequired, notify: PropTypes.func.isRequired, root: PropTypes.object.isRequired, + startAttach: PropTypes.func.isRequired, + finishAttach: PropTypes.func.isRequired, }; export default AddEmailAddressDialog; diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js index 8d3fc308f..de296c812 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js @@ -41,7 +41,7 @@ const AddEmailContent = ({ -
    +
    diff --git a/plugins/talk-plugin-local-auth/client/constants.js b/plugins/talk-plugin-local-auth/client/constants.js new file mode 100644 index 000000000..86f5242f7 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/constants.js @@ -0,0 +1,4 @@ +const prefix = 'TALK_LOCAL_AUTH'; + +export const STARTED_ATTACH = `${prefix}_STARTED_ATTACH`; +export const FINISH_ATTACH = `${prefix}_FINISH_ATTACH`; diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 841dc8420..4cc80d022 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -3,10 +3,15 @@ import { bindActionCreators } from 'redux'; import { connect, withFragments, excludeIf } from 'plugin-api/beta/client/hocs'; import AddEmailAddressDialog from '../components/AddEmailAddressDialog'; import { notify } from 'coral-framework/actions/notification'; - import { withAttachLocalAuth } from '../hocs'; +import { startAttach, finishAttach } from '../actions'; -const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch); +const mapStateToProps = ({ talkPluginLocalAuth: state }) => ({ + inProgress: state.inProgress, +}); + +const mapDispatchToProps = dispatch => + bindActionCreators({ notify, startAttach, finishAttach }, dispatch); const withData = withFragments({ root: gql` @@ -23,8 +28,11 @@ const withData = withFragments({ }); export default compose( - connect(null, mapDispatchToProps), + connect(mapStateToProps, mapDispatchToProps), withAttachLocalAuth, withData, - excludeIf(({ root: { me } }) => !me || me.email) + excludeIf( + ({ root: { me }, inProgress }) => + !((me && !me.email) || (me && me.email && inProgress)) + ) )(AddEmailAddressDialog); diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js index 9c89e0490..a4dc01ac2 100644 --- a/plugins/talk-plugin-local-auth/client/index.js +++ b/plugins/talk-plugin-local-auth/client/index.js @@ -1,10 +1,12 @@ import ChangePassword from './containers/ChangePassword'; import AddEmailAddressDialog from './containers/AddEmailAddressDialog'; import Profile from './containers/Profile'; -import translations from './translations.yml'; +import translations from '../translations.yml'; import graphql from './graphql'; +import reducer from './reducer'; export default { + reducer, translations, slots: { profileHeader: [Profile], diff --git a/plugins/talk-plugin-local-auth/client/reducer.js b/plugins/talk-plugin-local-auth/client/reducer.js new file mode 100644 index 000000000..403a84814 --- /dev/null +++ b/plugins/talk-plugin-local-auth/client/reducer.js @@ -0,0 +1,20 @@ +import * as actions from './constants'; + +const initialState = { + inProgress: false, +}; + +export default function reducer(state = initialState, action) { + switch (action.type) { + case actions.STARTED_ATTACH: + return { + inProgress: true, + }; + case actions.FINISH_ATTACH: + return { + inProgress: false, + }; + default: + return state; + } +} diff --git a/plugins/talk-plugin-local-auth/index.js b/plugins/talk-plugin-local-auth/index.js index 7e4ee6a3c..fabe1dd2b 100644 --- a/plugins/talk-plugin-local-auth/index.js +++ b/plugins/talk-plugin-local-auth/index.js @@ -4,7 +4,7 @@ const mutators = require('./server/mutators'); const path = require('path'); module.exports = { - translations: path.join(__dirname, 'server', 'translations.yml'), + translations: path.join(__dirname, 'translations.yml'), typeDefs, mutators, resolvers, diff --git a/plugins/talk-plugin-local-auth/server/translations.yml b/plugins/talk-plugin-local-auth/server/translations.yml deleted file mode 100644 index d81de6c6d..000000000 --- a/plugins/talk-plugin-local-auth/server/translations.yml +++ /dev/null @@ -1,9 +0,0 @@ -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}. # 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. - INCORRECT_PASSWORD: Provided password was incorrect. diff --git a/plugins/talk-plugin-local-auth/client/translations.yml b/plugins/talk-plugin-local-auth/translations.yml similarity index 91% rename from plugins/talk-plugin-local-auth/client/translations.yml rename to plugins/talk-plugin-local-auth/translations.yml index fcb80782a..7180268ea 100644 --- a/plugins/talk-plugin-local-auth/client/translations.yml +++ b/plugins/talk-plugin-local-auth/translations.yml @@ -1,4 +1,12 @@ 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}. # 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. + INCORRECT_PASSWORD: Provided password was incorrect. talk-plugin-local-auth: change_password: change_password: "Change Password" @@ -43,7 +51,7 @@ en: email_does_not_match: "Email Address does not match" insert_password: "Insert Password:" required_field: "This field is required" - done: "done" + done: "Done" content: title: "Add an Email Address" description: "For your added security, we require users to add an email address to their accounts. Your email address will be used to:" From e0cada5bde50f7b61a3e8bfd13b4040042eb92a9 Mon Sep 17 00:00:00 2001 From: Andrew Losowsky Date: Thu, 10 May 2018 13:44:03 -0700 Subject: [PATCH 208/244] Update 03-07-product-guide-trust.md --- docs/source/03-07-product-guide-trust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/03-07-product-guide-trust.md b/docs/source/03-07-product-guide-trust.md index 961cf843d..72248e7d1 100644 --- a/docs/source/03-07-product-guide-trust.md +++ b/docs/source/03-07-product-guide-trust.md @@ -16,7 +16,7 @@ Here are the default thresholds: ```text -1 and lower: Unreliable 0 to +1: Neutral -+1 and higher: Reliable (we don't do anything with this label right now) ++2 and higher: Reliable (we don't do anything with this label right now) ``` So in this case, when a new commenter has their first comment rejected, their user karma score becomes `-1`, which triggers the Unreliable threshhold, and they must then have a comment approved by a moderator in order to post freely again. Until that occurs, all of their comments will be held back temporarily in the Reported queue, marked with a `History` tag. From 631206f3603431d3456f445aff22f418738f48df Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 May 2018 00:30:12 +0200 Subject: [PATCH 209/244] Disable autofocus on IOS Safari, prevent zoom on narrow screens --- plugins/talk-plugin-rich-text/client/components/Editor.css | 7 +++++++ plugins/talk-plugin-rich-text/client/components/Editor.js | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-rich-text/client/components/Editor.css b/plugins/talk-plugin-rich-text/client/components/Editor.css index 2259d01a3..be2646121 100644 --- a/plugins/talk-plugin-rich-text/client/components/Editor.css +++ b/plugins/talk-plugin-rich-text/client/components/Editor.css @@ -1,5 +1,12 @@ +@custom-media --narrow-viewport (max-width: 420px); + .commentContent { composes: content from "./CommentContent.css"; + + /* Prevent zoom on narrow viewports */ + @media (--narrow-viewport) { + font-size: 16px; + } } .placeholder { diff --git a/plugins/talk-plugin-rich-text/client/components/Editor.js b/plugins/talk-plugin-rich-text/client/components/Editor.js index e09931d38..089900e1a 100644 --- a/plugins/talk-plugin-rich-text/client/components/Editor.js +++ b/plugins/talk-plugin-rich-text/client/components/Editor.js @@ -8,6 +8,7 @@ import RTE from './rte/RTE'; import { Icon } from 'plugin-api/beta/client/components/ui'; import { Bold, Italic, Blockquote } from './rte/features'; import { t } from 'plugin-api/beta/client/services'; +import bowser from 'bowser'; class Editor extends React.Component { ref = null; @@ -40,7 +41,7 @@ class Editor extends React.Component { } }); } - if (this.props.isReply) { + if (this.props.isReply && !bowser.ios) { this.ref.focus(); } } From 2d1b675234578b5d7b11d9df2ddc406d37d480fa Mon Sep 17 00:00:00 2001 From: Mendel Konikov Date: Thu, 10 May 2018 21:01:26 -0400 Subject: [PATCH 210/244] Update download page copy --- plugins/talk-plugin-profile-data/translations.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/talk-plugin-profile-data/translations.yml b/plugins/talk-plugin-profile-data/translations.yml index 39b810cca..51555d305 100644 --- a/plugins/talk-plugin-profile-data/translations.yml +++ b/plugins/talk-plugin-profile-data/translations.yml @@ -7,7 +7,7 @@ en: date: "When you wrote the comment" url: "The permalink URL for the comment" body: "The comment text" - asset_url: "The URL on the article or story where the comment appears" + asset_url: "The URL of the article or story where the comment appears" confirm: "Download My Comment History" email: download: @@ -17,7 +17,7 @@ en: delete: subject: "Your account for {0} is scheduled to be deleted" body: | - A request to delete your account was received. Your account is scheduled for deletion on {1}. + A request to delete your account was received. Your account is scheduled for deletion on {1}. After that time all of your comments will be removed from the site, all of your comments will be removed from our database, and your username and email address will be removed from our system. From b73620bcb0de6ef33f10b8491e486fe9be6cfe73 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 20 Apr 2018 10:00:52 +0200 Subject: [PATCH 211/244] WIP --- .gitignore | 1 + .../plugin/talk-plugin-global-switchoff.md | 25 ++++++++ .../client/.eslintrc.json | 23 ++++++++ .../client/components/GlobalSwitchoff.js | 59 +++++++++++++++++++ .../client/components/styles.css | 0 .../client/index.js | 9 +++ .../client/translations.yml | 8 +++ plugins/talk-plugin-global-switchoff/index.js | 11 ++++ .../server/index.js | 1 + .../server/resolvers.js | 10 ++++ .../server/typeDefs.graphql | 10 ++++ 11 files changed, 157 insertions(+) create mode 100644 docs/source/plugin/talk-plugin-global-switchoff.md create mode 100644 plugins/talk-plugin-global-switchoff/client/.eslintrc.json create mode 100644 plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js create mode 100644 plugins/talk-plugin-global-switchoff/client/components/styles.css create mode 100644 plugins/talk-plugin-global-switchoff/client/index.js create mode 100644 plugins/talk-plugin-global-switchoff/client/translations.yml create mode 100644 plugins/talk-plugin-global-switchoff/index.js create mode 100644 plugins/talk-plugin-global-switchoff/server/index.js create mode 100644 plugins/talk-plugin-global-switchoff/server/resolvers.js create mode 100644 plugins/talk-plugin-global-switchoff/server/typeDefs.graphql diff --git a/.gitignore b/.gitignore index 24022b9d7..ce5146929 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ plugins/* !plugins/talk-plugin-facebook-auth !plugins/talk-plugin-featured-comments !plugins/talk-plugin-flag-details +!plugins/talk-plugin-global-switchoff !plugins/talk-plugin-google-auth !plugins/talk-plugin-ignore-user !plugins/talk-plugin-like diff --git a/docs/source/plugin/talk-plugin-global-switchoff.md b/docs/source/plugin/talk-plugin-global-switchoff.md new file mode 100644 index 000000000..317fb4b3b --- /dev/null +++ b/docs/source/plugin/talk-plugin-global-switchoff.md @@ -0,0 +1,25 @@ +--- +title: talk-plugin-global-switchoff +permalink: /plugin/talk-plugin-global-switchoff/ +layout: plugin +plugin: + name: talk-plugin-global-switchoff + provides: + - Client + - Server +--- + +Add a switch to the settings page that disables commenting globally. + +## Installation + +TBD + +Add `"talk-plugin-global-switchoff"` to the `plugins.json` in your Talk installation. +This plugin provides a server and a client side implementation. + +## Server implementation + +### How does this work? + +TODO diff --git a/plugins/talk-plugin-global-switchoff/client/.eslintrc.json b/plugins/talk-plugin-global-switchoff/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js new file mode 100644 index 000000000..a5150ed10 --- /dev/null +++ b/plugins/talk-plugin-global-switchoff/client/components/GlobalSwitchoff.js @@ -0,0 +1,59 @@ +import React from 'react'; +import { gql } from 'react-apollo'; +import ConfigureCard from 'coral-framework/components/ConfigureCard'; +import MarkdownEditor from 'coral-framework/components/MarkdownEditor'; +import t from 'coral-framework/services/i18n'; +import { withFragments } from 'plugin-api/beta/client/hocs'; +import cn from 'classnames'; +import styles from './styles.css'; + +const plugin = 'talk-plugin-global-switchoff'; + +class GlobalSwitchoff extends React.Component { + updateGlobalSwitchoffEnable = () => { + const updater = { + globalSwitchoffEnable: { + $set: !this.props.settings.globalSwitchoffEnable, + }, + }; + this.props.updatePending({ updater }); + }; + + updateGlobalSwitchoffMessage = () => {}; + + render() { + const { settings } = this.props; + return ( + +

    {t(plugin + '.setting_desc')}

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

    {t('configure.global_switchoff_desc')}

    +
    + +
    +
    ) : ( -

    {asset.settings.closedMessage}

    +
    + {asset.isClosed ? ( +

    {asset.settings.closedMessage}

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

    {t(plugin + '.setting_desc')}

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

    {t('configure.global_switchoff_desc')}

    +

    {t('configure.disable_commenting_desc')}

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

    {asset.settings.closedMessage}

    ) : ( - + )}
    )} diff --git a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js index 99878a9b9..d6ca27558 100644 --- a/client/coral-embed-stream/src/tabs/stream/containers/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/containers/Stream.js @@ -434,8 +434,8 @@ const fragments = { questionBoxIcon closedTimeout closedMessage - globalSwitchoffEnable - globalSwitchoffMessage + disableCommenting + disableCommentingMessage charCountEnable charCount requireEmailConfirmation diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index dda86291f..07947af6e 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -837,12 +837,12 @@ type Settings { # closed. closedMessage: String - # globalSwitchoffEnable will disable commenting site-wide. - globalSwitchoffEnable: Boolean + # disableCommenting will disable commenting site-wide. + disableCommenting: Boolean - # globalSwitchoffMessage will be shown above the comment stream while + # disableCommentingMessage will be shown above the comment stream while # commenting is disabled site-wide. - globalSwitchoffMessage: String + disableCommentingMessage: String # editCommentWindowLength is the length of time (in milliseconds) after a # comment is posted that it can still be edited by the author. @@ -1307,12 +1307,12 @@ input UpdateSettingsInput { # closed. closedMessage: String - # globalSwitchoffEnable will disable commenting site-wide. - globalSwitchoffEnable: Boolean + # disableCommenting will disable commenting site-wide. + disableCommenting: Boolean - # globalSwitchoffMessage will be shown above the comment stream while + # disableCommentingMessage will be shown above the comment stream while # commenting is disabled site-wide. - globalSwitchoffMessage: String + disableCommentingMessage: String # charCountEnable is true when the character count restriction is enabled. charCountEnable: Boolean diff --git a/locales/de.yml b/locales/de.yml index 00cbb007c..15404856c 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -121,6 +121,8 @@ de: custom_css_url_desc: "URL eines CSS-Stylesheets zum Überschreiben des Standard-Designs" days: Tage description: "Als Administrator können Sie die Einstellungen für den Kommentarbereich dieses Artikels anpassen:" + disable_commenting_title: "Kommentieren global deaktivieren" + disable_commenting_desc: "Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist." domain_list_text: "Geben Sie Domains an, für die diese Talk-Instanz freigegeben werden soll, z.B. für lokale Test- oder Produktionsumgebungen (Bsp.: localhost:3000 staging.domain.com domain.com)." domain_list_title: "Zugelassene Domains" edit_comment_timeframe_heading: "Zeitlimit zur Bearbeitung von Kommentaren" @@ -136,8 +138,6 @@ de: enable_premod_links_description: "Moderatoren müssen jeden Kommentar, der einen Link enthält, freigeben, bevor er veröffentlicht wird." enable_questionbox: "Stellen Sie den Lesern eine Frage" enable_questionbox_description: "Diese Frage erscheint am Anfang des Kommentarbereichs. Regen Sie eine Diskussion an." - global_switchoff_title: "Kommentieren global deaktivieren" - global_switchoff_desc: "Verfassen Sie eine Nachricht, die angezeigt wird, solange das Kommentieren deaktiviert ist." hours: Stunden include_comment_stream: "Einleitung zum Kommentarbereich" include_comment_stream_desc: "Verfassen Sie eine Einleitung, die über jedem Kommentarbereich erscheint. Nützlich z.B. für Community-Richtlinien." diff --git a/locales/en.yml b/locales/en.yml index eae0e43c9..283ec4301 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -124,6 +124,8 @@ en: custom_css_url_desc: "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external." days: Days description: "Change the comment settings on this story." + disable_commenting_title: "Deactivate commenting site-wide" + disable_commenting_desc: "Write a message that will be displayed while commenting is deactivated." domain_list_text: "Enter the domains you would like to permit for Talk e.g. your local staging and production environments (ex. localhost:3000 staging.domain.com domain.com)." domain_list_title: "Permitted Domains" edit_info: "Edit Info" @@ -140,8 +142,6 @@ en: enable_premod_links_description: "Moderators must approve any comment containing a link before it is published." enable_questionbox: "Ask Readers a Question" enable_questionbox_description: "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc." - global_switchoff_title: "Deactivate commenting site-wide" - global_switchoff_desc: "Write a message that will be displayed while commenting is deactivated." hours: Hours include_comment_stream: "Include Comment Stream Description for Readers" include_comment_stream_desc: "Write a message to be added to the top of your comment stream. Pose a topic include community guidelines etc." diff --git a/models/schema/setting.js b/models/schema/setting.js index a896c797e..d75bed29e 100644 --- a/models/schema/setting.js +++ b/models/schema/setting.js @@ -66,11 +66,11 @@ const Setting = new Schema( type: String, default: 'Expired', }, - globalSwitchoffEnable: { + disableCommenting: { type: Boolean, default: false, }, - globalSwitchoffMessage: { + disableCommentingMessage: { type: String, default: '', }, diff --git a/services/moderation/phases/commentingDisabled.js b/services/moderation/phases/commentingDisabled.js index 8c62d5d98..060da473c 100644 --- a/services/moderation/phases/commentingDisabled.js +++ b/services/moderation/phases/commentingDisabled.js @@ -3,7 +3,7 @@ const { ErrCommentingDisabled } = require('../../../errors'); // This phase checks to see if commenting is site-wide disabled. module.exports = (ctx, comment, { asset }) => { // Check to see if the asset has closed commenting... - if (asset.settings.globalSwitchoffEnable) { - throw new ErrCommentingDisabled(asset.settings.globalSwitchoffMessage); + if (asset.settings.disableCommenting) { + throw new ErrCommentingDisabled(asset.settings.disableCommentingMessage); } }; diff --git a/test/server/graph/mutations/createComment.js b/test/server/graph/mutations/createComment.js index 373045efc..662404bf2 100644 --- a/test/server/graph/mutations/createComment.js +++ b/test/server/graph/mutations/createComment.js @@ -194,7 +194,7 @@ describe('graph.mutations.createComment', () => { beforeEach(() => AssetModel.create({ id: '123', - settings: { globalSwitchoffEnable: disabled }, + settings: { disableCommenting: disabled }, }) ); From 1236e7a5048385f1c9dc7e8ddd42713fb53fc9ed Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Fri, 11 May 2018 12:52:44 +0200 Subject: [PATCH 219/244] Disable/hide the reply buttons when commenting is disabled. --- .../coral-embed-stream/src/tabs/stream/components/Stream.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/tabs/stream/components/Stream.js b/client/coral-embed-stream/src/tabs/stream/components/Stream.js index 2b7396720..a07f8ff8b 100644 --- a/client/coral-embed-stream/src/tabs/stream/components/Stream.js +++ b/client/coral-embed-stream/src/tabs/stream/components/Stream.js @@ -182,7 +182,9 @@ class Stream extends React.Component { setActiveReplyBox={setActiveReplyBox} activeReplyBox={activeReplyBox} notify={notify} - disableReply={asset.isClosed} + disableReply={ + asset.isClosed || asset.settings.disableCommenting + } postComment={postComment} currentUser={currentUser} postFlag={postFlag} From f57f8397feddc79c2ceb3da240fd2b18b6f2c29b Mon Sep 17 00:00:00 2001 From: Mendel Konikov Date: Fri, 11 May 2018 11:01:15 -0400 Subject: [PATCH 220/244] Capitalize "Information" --- locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/en.yml b/locales/en.yml index 9a26fbdb6..36cf956b4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -162,7 +162,7 @@ en: suspect_word_title: "Suspect words list" suspect_word_text: "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list." tech_settings: "Tech Settings" - organization_information: "Organization information" + organization_information: "Organization Information" organization_info_copy: "We use this information in email notifications generated by Talk. This connects the messages to your organization, and provides a way for users to contact you if they have an issue with their account." organization_info_copy_2: "We recommend creating a generic email account (eg. community@yournewsroom.com) for this purpose. This means it can remain consistent over time, and doesn't expose a name that users could target if their account were blocked." organization_details: "Organization Details" From fc5621a06042de9b0ca42d3da720e4cfcbde1477 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 May 2018 17:12:28 +0200 Subject: [PATCH 221/244] Add reference to story --- plugins/talk-plugin-rich-text/client/components/Editor.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/talk-plugin-rich-text/client/components/Editor.js b/plugins/talk-plugin-rich-text/client/components/Editor.js index 089900e1a..99d2be617 100644 --- a/plugins/talk-plugin-rich-text/client/components/Editor.js +++ b/plugins/talk-plugin-rich-text/client/components/Editor.js @@ -41,6 +41,8 @@ class Editor extends React.Component { } }); } + + // Skip IOS due to a bug, see https://www.pivotaltracker.com/story/show/157434928 if (this.props.isReply && !bowser.ios) { this.ref.focus(); } From 29ffe287cdb7afdd6f9c954bccc6b2cefcc92153 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 11 May 2018 09:21:55 -0600 Subject: [PATCH 222/244] Delete package-lock.json --- package-lock.json | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index d6105c594..000000000 --- a/package-lock.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "talk", - "version": "4.3.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" - }, - "react-side-effect": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.5.tgz", - "integrity": "sha512-Z2ZJE4p/jIfvUpiUMRydEVpQRf2f8GMHczT6qLcARmX7QRb28JDBTpnM2g/i5y/p7ZDEXYGHWg0RbhikE+hJRw==", - "requires": { - "exenv": "1.2.2", - "shallowequal": "1.0.2" - } - }, - "shallowequal": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.0.2.tgz", - "integrity": "sha512-zlVXeVUKvo+HEv1e2KQF/csyeMKx2oHvatQ9l6XjCUj3agvC8XGf6R9HvIPDSmp8FNPvx7b5kaEJTRi7CqxtEw==" - } - } -} From 42d4abf8426b499bc9722c7ac1a2ea5f29b7fc2c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 11 May 2018 09:33:18 -0600 Subject: [PATCH 223/244] review updates --- plugins/talk-plugin-local-auth/client/actions.js | 2 +- .../client/components/AddEmailAddressDialog.js | 6 ++++-- plugins/talk-plugin-local-auth/client/constants.js | 2 +- plugins/talk-plugin-local-auth/client/reducer.js | 2 +- plugins/talk-plugin-local-auth/translations.yml | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/actions.js b/plugins/talk-plugin-local-auth/client/actions.js index 9f2c9cfed..972e1f6fd 100644 --- a/plugins/talk-plugin-local-auth/client/actions.js +++ b/plugins/talk-plugin-local-auth/client/actions.js @@ -1,7 +1,7 @@ import * as actions from './constants'; export const startAttach = () => ({ - type: actions.STARTED_ATTACH, + type: actions.START_ATTACH, }); export const finishAttach = () => ({ diff --git a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js index 76131c895..a5bfd7096 100644 --- a/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js @@ -124,8 +124,10 @@ class AddEmailAddressDialog extends React.Component { password: confirmPassword, }); - // TODO: translate - this.props.notify('success', 'Email Added!'); + this.props.notify( + 'success', + t('talk-plugin-local-auth.add_email.added.alert') + ); this.goToNextStep(); } catch (err) { this.props.notify('error', getErrorMessages(err)); diff --git a/plugins/talk-plugin-local-auth/client/constants.js b/plugins/talk-plugin-local-auth/client/constants.js index 86f5242f7..d410a10fa 100644 --- a/plugins/talk-plugin-local-auth/client/constants.js +++ b/plugins/talk-plugin-local-auth/client/constants.js @@ -1,4 +1,4 @@ const prefix = 'TALK_LOCAL_AUTH'; -export const STARTED_ATTACH = `${prefix}_STARTED_ATTACH`; +export const START_ATTACH = `${prefix}_START_ATTACH`; export const FINISH_ATTACH = `${prefix}_FINISH_ATTACH`; diff --git a/plugins/talk-plugin-local-auth/client/reducer.js b/plugins/talk-plugin-local-auth/client/reducer.js index 403a84814..11666e505 100644 --- a/plugins/talk-plugin-local-auth/client/reducer.js +++ b/plugins/talk-plugin-local-auth/client/reducer.js @@ -6,7 +6,7 @@ const initialState = { export default function reducer(state = initialState, action) { switch (action.type) { - case actions.STARTED_ATTACH: + case actions.START_ATTACH: return { inProgress: true, }; diff --git a/plugins/talk-plugin-local-auth/translations.yml b/plugins/talk-plugin-local-auth/translations.yml index 7180268ea..5fd2264e6 100644 --- a/plugins/talk-plugin-local-auth/translations.yml +++ b/plugins/talk-plugin-local-auth/translations.yml @@ -67,6 +67,7 @@ en: subtitle: "Need to change your email address?" description_2: "You can change your account settings by visiting" path: "My Profile > Settings" + alert: "Email Added!" es: talk-plugin-local-auth: change_password: From faa0ee8ceb2f6ef1504906e4e49060bffe1ce465 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 11 May 2018 10:22:45 -0600 Subject: [PATCH 224/244] added global wrap --- client/coral-admin/src/components/App.css | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/client/coral-admin/src/components/App.css b/client/coral-admin/src/components/App.css index 1404a9293..39c7cf942 100644 --- a/client/coral-admin/src/components/App.css +++ b/client/coral-admin/src/components/App.css @@ -1,9 +1,11 @@ -html, body, #root, #root > div { - min-height: 100%; -} +:global { + html, body, #root, #root > div { + min-height: 100%; + } -body { - margin: 0; - background-color: #FAFAFA; - font-family: 'Roboto', sans-serif; + body { + margin: 0; + background-color: #FAFAFA; + font-family: 'Roboto', sans-serif; + } } From 622b79b4910a74bf2d3303d7050d73018bdec9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Curcio?= Date: Fri, 11 May 2018 13:22:48 -0300 Subject: [PATCH 225/244] Removing unnecessary functions --- .../src/tabs/profile/components/Comment.js | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/client/coral-embed-stream/src/tabs/profile/components/Comment.js b/client/coral-embed-stream/src/tabs/profile/components/Comment.js index 84293096b..c9bdcb0ac 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/profile/components/Comment.js @@ -11,16 +11,6 @@ import { getTotalReactionsCount } from 'coral-framework/utils'; import t from 'coral-framework/services/i18n'; class Comment extends React.Component { - goToStory = () => { - this.props.navigate(this.props.comment.asset.url); - }; - - goToConversation = () => { - this.props.navigate( - `${this.props.comment.asset.url}?commentId=${this.props.comment.id}` - ); - }; - render() { const { comment, root } = this.props; const reactionCount = getTotalReactionsCount(comment.action_summaries); @@ -76,7 +66,7 @@ class Comment extends React.Component {
    {t('common.story')}:{' '} {comment.asset.title ? comment.asset.title : comment.asset.url} @@ -86,7 +76,7 @@ class Comment extends React.Component {
    • - + {t('view_conversation')} From a571cf830d554a686c761d85d3384f021ee2b0a0 Mon Sep 17 00:00:00 2001 From: okbel Date: Fri, 11 May 2018 13:32:55 -0300 Subject: [PATCH 226/244] Adding target --- .../src/tabs/profile/components/Comment.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/tabs/profile/components/Comment.js b/client/coral-embed-stream/src/tabs/profile/components/Comment.js index c9bdcb0ac..badeb4262 100644 --- a/client/coral-embed-stream/src/tabs/profile/components/Comment.js +++ b/client/coral-embed-stream/src/tabs/profile/components/Comment.js @@ -67,6 +67,7 @@ class Comment extends React.Component { {t('common.story')}:{' '} {comment.asset.title ? comment.asset.title : comment.asset.url} @@ -76,7 +77,13 @@ class Comment extends React.Component {
      • - + {t('view_conversation')} From f018ccf33ee894ed75c097070b623cfb71de038c Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 May 2018 18:38:41 +0200 Subject: [PATCH 227/244] Prevent showing add email address dialog when usernam is not set --- .../client/containers/AddEmailAddressDialog.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 4cc80d022..d8ccd18b0 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -19,6 +19,13 @@ const withData = withFragments({ me { id email + state { + status { + username { + status + } + } + } } settings { requireEmailConfirmation @@ -33,6 +40,7 @@ export default compose( withData, excludeIf( ({ root: { me }, inProgress }) => + me.state.status.username.status === 'UNSET' || !((me && !me.email) || (me && me.email && inProgress)) ) )(AddEmailAddressDialog); From 6cf4203c9b7ca9db28ec253ef469ddeb45398cea Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 11 May 2018 11:38:54 -0600 Subject: [PATCH 228/244] Update translations.yml --- plugins/talk-plugin-local-auth/translations.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/translations.yml b/plugins/talk-plugin-local-auth/translations.yml index 5fd2264e6..7f67e33bd 100644 --- a/plugins/talk-plugin-local-auth/translations.yml +++ b/plugins/talk-plugin-local-auth/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}. # TODO: update translation + body: Your email address has been changed from {0} to {1}. If you did not request 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. From f0dcd844a787d5309b90509806389ddfccba4455 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 May 2018 20:44:45 +0200 Subject: [PATCH 229/244] Fix excludeIf condition --- .../client/containers/AddEmailAddressDialog.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index d8ccd18b0..44ee17df7 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -40,7 +40,8 @@ export default compose( withData, excludeIf( ({ root: { me }, inProgress }) => + !me || me.state.status.username.status === 'UNSET' || - !((me && !me.email) || (me && me.email && inProgress)) + (me.email && !inProgress) ) )(AddEmailAddressDialog); From 7d8d5a6115ef0b77103c39143368f6655f7f46ee Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 11 May 2018 20:46:32 +0200 Subject: [PATCH 230/244] Use lodash get --- .../client/containers/AddEmailAddressDialog.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js index 44ee17df7..f6de3b39c 100644 --- a/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js +++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js @@ -5,6 +5,7 @@ import AddEmailAddressDialog from '../components/AddEmailAddressDialog'; import { notify } from 'coral-framework/actions/notification'; import { withAttachLocalAuth } from '../hocs'; import { startAttach, finishAttach } from '../actions'; +import get from 'lodash/get'; const mapStateToProps = ({ talkPluginLocalAuth: state }) => ({ inProgress: state.inProgress, @@ -41,7 +42,7 @@ export default compose( excludeIf( ({ root: { me }, inProgress }) => !me || - me.state.status.username.status === 'UNSET' || + get(me, 'state.status.username.status') === 'UNSET' || (me.email && !inProgress) ) )(AddEmailAddressDialog); From 1f7c4e58a1ebd6c3abd9579498a7c0c3746ac087 Mon Sep 17 00:00:00 2001 From: okbel Date: Mon, 14 May 2018 13:31:24 -0300 Subject: [PATCH 231/244] sepatate state --- .../components/ChangeEmailContentDialog.js | 92 +++++++++++++++++-- .../client/components/Profile.js | 7 +- 2 files changed, 85 insertions(+), 14 deletions(-) diff --git a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js index f29dd8d86..b0fdeb14d 100644 --- a/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js +++ b/plugins/talk-plugin-local-auth/client/components/ChangeEmailContentDialog.js @@ -4,10 +4,77 @@ import styles from './ChangeEmailContentDialog.css'; import InputField from './InputField'; import { Button } from 'plugin-api/beta/client/components/ui'; import { t } from 'plugin-api/beta/client/services'; +import validate from 'coral-framework/helpers/validate'; +import errorMsj from 'coral-framework/helpers/error'; + +const initialState = { + showError: false, + formData: {}, + errors: {}, +}; class ChangeEmailContentDialog extends React.Component { - state = { - showError: false, + state = initialState; + + clearForm = () => { + this.setState(initialState); + }; + + addError = err => { + this.setState(({ errors }) => ({ + errors: { ...errors, ...err }, + })); + }; + + removeError = errKey => { + this.setState(state => { + const { [errKey]: _, ...errors } = state.errors; + return { + errors, + }; + }); + }; + + fieldValidation = (value, type, name) => { + if (!value.length) { + this.addError({ + [name]: t('talk-plugin-local-auth.change_password.required_field'), + }); + } else if (!validate[type](value)) { + this.addError({ [name]: errorMsj[type] }); + } else { + this.removeError(name); + } + }; + + onChange = e => { + const { name, value, type, dataset } = e.target; + const validationType = dataset.validationType || type; + + this.setState( + state => ({ + formData: { + ...state.formData, + [name]: value, + }, + }), + () => { + this.fieldValidation(value, validationType, name); + } + ); + }; + + hasError = err => { + return Object.keys(this.state.errors).indexOf(err) !== -1; + }; + + isSaveEnabled = () => { + const formHasErrors = !!Object.keys(this.state.errors).length; + return !formHasErrors; + }; + + getError = errorKey => { + return this.state.errors[errorKey]; }; showError = () => { @@ -16,24 +83,31 @@ class ChangeEmailContentDialog extends React.Component { }); }; + cancel = () => { + this.clearForm(); + this.disableEditing(); + }; + confirmChanges = async e => { e.preventDefault(); + const { confirmPassword = '' } = this.state.formData; + if (this.formHasError()) { this.showError(); return; } - await this.props.save(); + await this.props.save(confirmPassword); this.props.next(); }; - formHasError = () => this.props.hasError('confirmPassword'); + formHasError = () => this.hasError('confirmPassword'); render() { return (
        - + ×

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