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;
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/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/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 {
diff --git a/plugin-api/beta/client/hocs/index.js b/plugin-api/beta/client/hocs/index.js
index d33e7acc9..d7ca5fce9 100644
--- a/plugin-api/beta/client/hocs/index.js
+++ b/plugin-api/beta/client/hocs/index.js
@@ -27,6 +27,5 @@ export {
withSetCommentStatus,
withChangePassword,
withChangeUsername,
- withUpdateEmailAddress,
} 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..41b531147
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.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: 50%;
+ transform: translateY(-50%);
+ padding: 20px;
+ border-radius: 4px;
+ font-family: Helvetica,Helvetica Neue,Verdana,sans-serif;
+ color:#3B4A53;
+}
+
+.title {
+ font-size: 1.3em;
+ margin: 15px 0;
+ text-align: center;
+}
+
+.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;
+ width: 100%;
+ display: inline-block;
+ text-align: center;
+ line-height: 30px;
+ font-size: 1em;
+
+ &:hover {
+ background-color: #eaeaea;
+ cursor: pointer;
+ }
+
+ &.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..691915c0f
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/components/AddEmailAddressDialog.js
@@ -0,0 +1,153 @@
+import React from 'react';
+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';
+import errorMsj from 'coral-framework/helpers/error';
+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: {},
+};
+
+class AddEmailAddressDialog extends React.Component {
+ state = initialState;
+ validKeys = ['emailAddress', 'confirmPassword', '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 = !isEqualWith(
+ Object.keys(this.state.formData),
+ this.validKeys,
+ isMatch
+ );
+
+ return formHasErrors || formIncomplete;
+ };
+
+ showErrors = () => {
+ this.setState({
+ showErrors: true,
+ });
+ };
+
+ confirmChanges = async () => {
+ if (this.formHasError()) {
+ this.showErrors();
+ return;
+ }
+
+ 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, step } = this.state;
+ const { root: { settings } } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+AddEmailAddressDialog.propTypes = {
+ attachLocalAuth: PropTypes.func.isRequired,
+ notify: 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
new file mode 100644
index 000000000..4a2ce7430
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/components/AddEmailContent.js
@@ -0,0 +1,106 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './AddEmailAddressDialog.css';
+import { Icon } from 'plugin-api/beta/client/components/ui';
+import cn from 'classnames';
+import InputField from './InputField';
+import { t } from 'plugin-api/beta/client/services';
+
+const AddEmailContent = ({
+ formData,
+ errors,
+ showErrors,
+ confirmChanges,
+ onChange,
+}) => (
+
+
+ {t('talk-plugin-local-auth.add_email.content.title')}
+
+
+ {t('talk-plugin-local-auth.add_email.content.description')}
+
+
+ -
+
+
+ {t('talk-plugin-local-auth.add_email.content.item_1')}
+
+
+ -
+
+
+ {t('talk-plugin-local-auth.add_email.content.item_2')}
+
+
+ -
+
+
+ {t('talk-plugin-local-auth.add_email.content.item_3')}
+
+
+
+
+
+
+);
+
+AddEmailContent.propTypes = {
+ formData: PropTypes.object.isRequired,
+ errors: PropTypes.object.isRequired,
+ showErrors: PropTypes.bool.isRequired,
+ confirmChanges: PropTypes.func.isRequired,
+ onChange: PropTypes.func.isRequired,
+};
+
+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..6d5775f3c
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/components/EmailAddressAdded.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import cn from 'classnames';
+import PropTypes from 'prop-types';
+import styles from './AddEmailAddressDialog.css';
+import { t } from 'plugin-api/beta/client/services';
+
+const EmailAddressAdded = ({ done }) => (
+
+
+ {t('talk-plugin-local-auth.add_email.added.title')}
+
+
+ {t('talk-plugin-local-auth.add_email.added.description')}
+
+
{t('talk-plugin-local-auth.add_email.added.subtitle')}
+
+ {t('talk-plugin-local-auth.add_email.added.description_2')}{' '}
+ {t('talk-plugin-local-auth.add_email.added.path')}.
+
+
+
+);
+
+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 d0dc51494..fae31c80a 100644
--- a/plugins/talk-plugin-local-auth/client/components/InputField.css
+++ b/plugins/talk-plugin-local-auth/client/components/InputField.css
@@ -62,6 +62,7 @@
flex: 1;
height: 100%;
box-sizing: border-box;
+ padding: 0 6px;
}
.detailItemMessage {
@@ -81,4 +82,4 @@
.warningIcon {
color: #FA4643;
-}
\ No newline at end of file
+}
diff --git a/plugins/talk-plugin-local-auth/client/components/InputField.js b/plugins/talk-plugin-local-auth/client/components/InputField.js
index 944f5e7cf..930c15582 100644
--- a/plugins/talk-plugin-local-auth/client/components/InputField.js
+++ b/plugins/talk-plugin-local-auth/client/components/InputField.js
@@ -44,7 +44,7 @@ const InputField = ({
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..cc1ff3626
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/components/VerifyEmailAddress.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import cn from 'classnames';
+import PropTypes from 'prop-types';
+import styles from './AddEmailAddressDialog.css';
+import { t } from 'plugin-api/beta/client/services';
+
+const VerifyEmailAddress = ({ emailAddress, done }) => (
+
+
+ {t('talk-plugin-local-auth.add_email.verify.title')}
+
+
+ {t('talk-plugin-local-auth.add_email.verify.description', emailAddress)}
+
+
+
+);
+
+VerifyEmailAddress.propTypes = {
+ emailAddress: PropTypes.string.isRequired,
+ done: PropTypes.func.isRequired,
+};
+
+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
new file mode 100644
index 000000000..841dc8420
--- /dev/null
+++ b/plugins/talk-plugin-local-auth/client/containers/AddEmailAddressDialog.js
@@ -0,0 +1,30 @@
+import { compose, gql } from 'react-apollo';
+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';
+
+const mapDispatchToProps = dispatch => bindActionCreators({ notify }, dispatch);
+
+const withData = withFragments({
+ root: gql`
+ fragment TalkPluginLocalAuth_AddEmailAddressDialog_root on RootQuery {
+ me {
+ id
+ email
+ }
+ settings {
+ requireEmailConfirmation
+ }
+ }
+ `,
+});
+
+export default compose(
+ connect(null, mapDispatchToProps),
+ withAttachLocalAuth,
+ withData,
+ excludeIf(({ root: { me } }) => !me || me.email)
+)(AddEmailAddressDialog);
diff --git a/plugins/talk-plugin-local-auth/client/hocs/index.js b/plugins/talk-plugin-local-auth/client/hocs/index.js
index bcd439af2..573fa6b10 100644
--- a/plugins/talk-plugin-local-auth/client/hocs/index.js
+++ b/plugins/talk-plugin-local-auth/client/hocs/index.js
@@ -1,6 +1,50 @@
+import { withMutation } from 'plugin-api/beta/client/hocs';
import { gql } from 'react-apollo';
import update from 'immutability-helper';
-import withMutation from 'coral-framework/hocs/withMutation';
+
+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`
diff --git a/plugins/talk-plugin-local-auth/client/index.js b/plugins/talk-plugin-local-auth/client/index.js
index d5f9f8636..9c89e0490 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';
import graphql from './graphql';
@@ -8,6 +9,7 @@ export default {
slots: {
profileHeader: [Profile],
profileSettings: [ChangePassword],
+ stream: [AddEmailAddressDialog],
},
...graphql,
};
diff --git a/plugins/talk-plugin-local-auth/client/translations.yml b/plugins/talk-plugin-local-auth/client/translations.yml
index 0c3216009..b41ad5302 100644
--- a/plugins/talk-plugin-local-auth/client/translations.yml
+++ b/plugins/talk-plugin-local-auth/client/translations.yml
@@ -36,6 +36,29 @@ en:
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:"
+ invalid_email_address: "Invalid Email address"
+ confirm_email_address: "Confirm Email Address:"
+ email_does_not_match: "Email Address does not match"
+ insert_password: "Insert Password:"
+ 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:"
+ item_1: "Receive updates regarding any changes to your account (email address, username, password, etc.)"
+ item_2: "Allow you to download your comments."
+ item_3: "Send comment notifications that you have chosen to receive."
+ 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:
+ title: "Email Address Added"
+ description: "Your email address has been added to your account."
+ subtitle: "Need to change your email address?"
+ description_2: "You can change your account settings by visiting"
+ path: "My Profile > Settings"
es:
talk-plugin-local-auth:
change_password:
diff --git a/plugins/talk-plugin-local-auth/server/mutators.js b/plugins/talk-plugin-local-auth/server/mutators.js
index 6798584f5..389574d2d 100644
--- a/plugins/talk-plugin-local-auth/server/mutators.js
+++ b/plugins/talk-plugin-local-auth/server/mutators.js
@@ -5,7 +5,6 @@ const {
ErrIncorrectPassword,
} = require('./errors');
const { get } = require('lodash');
-const bcrypt = require('bcryptjs');
// hasLocalProfile checks a user's profiles to see if they already have a local
// profile associated with their account.
@@ -89,7 +88,7 @@ async function attachUserLocalAuth(ctx, email, password) {
await Users.isValidPassword(password);
// Hash the new password.
- const hashedPassword = await bcrypt.hash(password, 10);
+ const hashedPassword = await Users.hashPassword(password);
try {
// Associate the account with the user.
diff --git a/services/users.js b/services/users.js
index d5486b3f8..061fae6fb 100644
--- a/services/users.js
+++ b/services/users.js
@@ -560,7 +560,7 @@ class Users {
throw new ErrPasswordTooShort();
}
- const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
+ const hashedPassword = await Users.hashPassword(password);
return User.update(
{ id },
@@ -637,7 +637,7 @@ class Users {
Users.isValidPassword(password),
]);
- const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
+ const hashedPassword = await Users.hashPassword(password);
let user = new User({
username,
@@ -814,6 +814,10 @@ class Users {
return { user, redirect, version };
}
+ static async hashPassword(password) {
+ return bcrypt.hash(password, SALT_ROUNDS);
+ }
+
// TODO: update doc
static async resetPassword(token, password) {
const { user, redirect, version } = await this.verifyPasswordResetToken(
@@ -824,7 +828,7 @@ class Users {
throw new ErrPasswordTooShort();
}
- const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
+ const hashedPassword = await Users.hashPassword(password);
// Update the user's password.
await User.update(