Skip to content

Commit

Permalink
Add resend verification email page
Browse files Browse the repository at this point in the history
  • Loading branch information
thostetler committed Jun 22, 2024
1 parent ab35031 commit 4c6f866
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/js/apps/discovery/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ define([
if (
subView &&
!_.contains(
['login', 'register', 'reset-password-1', 'reset-password-2'],
['login', 'register', 'reset-password-1', 'reset-password-2', 'resend-verification-email'],
subView
)
) {
Expand Down
1 change: 1 addition & 0 deletions src/js/components/api_targets.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ define([], function () {
LOGIN: 'accounts/user/login',
LOGOUT: 'accounts/user/logout',
VERIFY: 'accounts/verify',
RESEND_VERIFY: `accounts/user/{email}/verify`,
RESET_PASSWORD: 'accounts/user/reset-password',
CHANGE_PASSWORD: 'accounts/user/change-password',
CHANGE_EMAIL: 'accounts/user/change-email',
Expand Down
53 changes: 53 additions & 0 deletions src/js/components/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,58 @@ define([
});
},


/**
* Resend verification email
* @param {string} email
*/
resendVerificationEmail: function(email) {
const self = this;
this.sendRequestWithNewCSRF(function(csrfToken) {
const request = new ApiRequest({
target: ApiTargets.RESEND_VERIFY.replace('{email}', email),
query: new ApiQuery({}),
options: {
type: 'PUT',
headers: { 'X-CSRFToken': csrfToken },
done: function() {
const pubsub = self.getPubSub();
pubsub.publish(
pubsub.USER_ANNOUNCEMENT,
'resend_verification_email_success'
);
},
fail: function(xhr) {
const pubsub = self.getPubSub();
const error = utils.extractErrorMessageFromAjax(
xhr,
'error unknown'
);
const message = `Resending verification email was unsuccessful (${error})`;
pubsub.publish(
pubsub.ALERT,
new ApiFeedback({
code: 0,
msg: message,
type: 'danger',
fade: true,
})
);
pubsub.publish(
pubsub.USER_ANNOUNCEMENT,
'resend_verification_email_fail',
message
);
},
},
});

return this.getBeeHive()
.getService('Api')
.request(request);
});
},

setChangeToken: function(token) {
this.model.set('resetPasswordToken', token);
},
Expand Down Expand Up @@ -365,6 +417,7 @@ define([
resetPassword1: 'sends an email to account',
resetPassword2: 'updates the password',
setChangeToken: 'the router stores the token to reset password here',
resendVerificationEmail: 'resends the verification email',
},
});

Expand Down
5 changes: 4 additions & 1 deletion src/js/widgets/authentication/templates/log-in.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
</div>

<div style="display: flex; justify-content: center;">
<strong>Don't have an account yet?&nbsp;<a class="show-register">Register</a></strong>
<strong>Don't have an account yet?&nbsp;<button type="button" href="#" class="btn btn-link show-register">Register</button></strong>
</div>
<div style="display: flex; justify-content: center; align-items: center">
<div style="margin-right: 1rem"></div> <button type="button" class="btn btn-link show-resend-verification-email">Resend verification email?</button>
</div>
</form>

Expand Down
2 changes: 1 addition & 1 deletion src/js/widgets/authentication/templates/register.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
<strong>Already have an account?&nbsp;<a class="show-login">Login</a></strong>
</div>

<div class="form-group" style="margin-top: 2rem">
<div class="form-group" style="margin-top: 2rem; display: flex; justify-content: center">
<div class="g-recaptcha">
<small class="recaptcha-msg">This site is protected by reCAPTCHA and the Google
<a href="https://policies.google.com/privacy" target="_blank" rel="noreferrer">Privacy Policy</a> and
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div class="panel panel-default">
<div class="panel-heading">Resend Verification Email</div>
<form class="panel-body">
<div class="form-group has-feedback">
<label for="email" class="control-label">Email address</label>
<input type="email" class="form-control" id="email" name="email" placeholder="Enter email" required>
<span class="help-block no-show s-help-block"></span>
</div>
<button type="submit" class="btn btn-primary">Resend Verification Email</button>
</form>
<div style="margin-top: 1rem; text-align: center;">
<button type="button" class="btn btn-link show-login">Back to Login</button>
</div>

{{#if hasError}}
<div class="row">
<div class="col-sm-10 col-sm-offset-1 text-center">
<div class="alert alert-danger">
<p>{{errorMsg}}</p>
<p><a class="link" id="dismiss-error">Dismiss</a></p>
</div>
</div>
</div>
{{/if}}
</div>
100 changes: 90 additions & 10 deletions src/js/widgets/authentication/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ define([
'hbs!js/widgets/authentication/templates/container',
'hbs!js/widgets/authentication/templates/reset-password-1',
'hbs!js/widgets/authentication/templates/reset-password-2',
'hbs!js/widgets/authentication/templates/resend-verification-email',
'js/components/user',
'analytics',
'backbone-validation',
Expand All @@ -26,8 +27,9 @@ define([
ContainerTemplate,
ResetPassword1Template,
ResetPassword2Template,
ResendVerificationEmail,
User,
analytics
analytics,
) {
// Creating module level variable since I can't figure out best way to pass this value into a subview from the model
// This value should be always available, and unchanging, so should be safe to set like this here
Expand All @@ -54,11 +56,11 @@ define([
if (typeof formName === 'string') {
window.grecaptcha.ready(() =>
window.grecaptcha
.execute(siteKey, { action: `auth/${formName}` })
.then((token) => {
this.model.set('g-recaptcha-response', token);
FormFunctions.triggerSubmit.apply(this, arguments);
})
.execute(siteKey, { action: `auth/${formName}` })
.then((token) => {
this.model.set('g-recaptcha-response', token);
FormFunctions.triggerSubmit.apply(this, arguments);
}),
);
} else {
FormFunctions.triggerSubmit.apply(this, arguments);
Expand Down Expand Up @@ -301,6 +303,39 @@ define([
},
});

const ResendVerificationModel = FormModel.extend({
skipReset: ['email'],
validation: {
email: {
required: true,
pattern: 'email',
msg: '(A valid email is required)',
},
},

target: 'RESEND_VERIFY',
method: 'PUT',
});

const ResendVerificationView = FormView.extend({
template: ResendVerificationEmail,

className: 'resend-verification',

bindings: {
'input[name=email]': {
observe: 'email',
setOptions: {
validate: true,
},
},
},

onRender: function() {
this.activateValidation();
},
});

var StateModel = Backbone.Model.extend({
defaults: function() {
return {
Expand All @@ -317,6 +352,7 @@ define([
this.registerModel = new RegisterModel();
this.resetPassword1Model = new ResetPassword1Model();
this.resetPassword2Model = new ResetPassword2Model();
this.resendVerificationModel = new ResendVerificationModel();
},

modelEvents: { 'change:subView': 'renderSubView' },
Expand All @@ -331,6 +367,8 @@ define([
'click .show-login': 'navigateToLoginForm',
'click .show-register': 'navigateToRegisterForm',
'click .show-reset-password-1': 'navigateToResetPassword1Form',
'click .show-resend-verification-email':
'navigateToResendVerificationForm',
},

onRender: function() {
Expand All @@ -348,6 +386,8 @@ define([
this.showResetPasswordForm1();
} else if (subView === 'reset-password-2') {
this.showResetPasswordForm2();
} else if (subView === 'resend-verification-email') {
this.showResendVerificationForm();
}
},

Expand Down Expand Up @@ -399,11 +439,28 @@ define([
this.container.show(view);
},

showResendVerificationForm: function(error) {
const view = new ResendVerificationView({ model: this.resendVerificationModel });

// show error message
if (error) {
view.model.set({ hasError: true, errorMsg: error });
}

view.on('submit-form', this.forwardSubmit, this);
this.container.show(view);
},

showRegisterSuccessView: function() {
var view = new SuccessView({ title: 'Registration Successful' });
this.container.show(view);
},

showResendVerificationSuccessView: function() {
var view = new SuccessView({ title: 'Verification Email Sent Successfully' });
this.container.show(view);
},

showResetPasswordSuccessView: function() {
var view = new SuccessView({ title: 'Password Reset Successful' });
this.container.show(view);
Expand All @@ -428,12 +485,17 @@ define([
this.listenTo(
this.view,
'navigateToRegisterForm',
this.navigateToRegisterForm
this.navigateToRegisterForm,
);
this.listenTo(
this.view,
'navigateToResetPassword1Form',
this.navigateToResetPassword1Form
this.navigateToResetPassword1Form,
);
this.listenTo(
this.view,
'navigateToResendVerificationForm',
this.navigateToResendVerificationForm
);

this.nextNav = null;
Expand All @@ -459,6 +521,10 @@ define([
this._navigate({ subView: 'reset-password-1' });
},

navigateToResendVerificationForm: function() {
this._navigate({ subView: 'resend-verification-email' });
},

_navigate: function(opts) {
var pubsub = this.getPubSub();
pubsub.publish(pubsub.NAVIGATE, 'authentication-page', opts);
Expand Down Expand Up @@ -523,6 +589,17 @@ define([
auth_error: msg,
});
break;
case 'resend_verification_email_success':
this.view.showResendVerificationSuccessView();
this.fireAnalytics('resend-verification', {
auth_result: 'resend_verification_email_success',
});
break;
case 'resend_verification_email_fail':
this.fireAnalytics('resend-verification', {
auth_result: 'resend_verification_email_fail',
});
break;
}
},

Expand All @@ -547,11 +624,14 @@ define([
}
});
break;
case 'RESET_PASSWORD': {
case 'RESET_PASSWORD':
model.method === 'POST'
? session.resetPassword1(model.toJSON())
: session.resetPassword2(model.toJSON());
}
break;
case 'RESEND_VERIFY':
session.resendVerificationEmail(model.get('email'));
break;
}
},

Expand Down
1 change: 1 addition & 0 deletions test/mocha/js/components/session.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ define([
'resetPassword1',
'resetPassword2',
'setChangeToken',
'resendVerificationEmail',
'__facade__',
'mixIn',
]);
Expand Down

0 comments on commit 4c6f866

Please sign in to comment.