Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forgot password feature #15579 #95

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
22 changes: 1 addition & 21 deletions client/styles/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,7 @@ a {
}
}

#loginsubmitbutton {
width: 40%;
display: block;
height: 30px;
margin: 0px auto;
background-color: #2ecc71;
margin-top: 20px;
margin-bottom: 35px;
border-radius: 5px;
cursor: pointer;
text-align: center;
font-weight: 600;
color: white;
padding-top: 5px;

&:hover {
background-color: #4cd785;
}
}

#registersubmitbutton {
#loginsubmitbutton, #registersubmitbutton, #forgotsubmitbutton {
width: 40%;
display: block;
height: 30px;
Expand Down
4 changes: 4 additions & 0 deletions client/views/login/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ <h1 class="formtitle">Login</h1>
<input type="password" id="passwordbox" class="input" placeholder="Password...">
<div class="modalbottommessage">
Don't have an account? <p class="modalemphasis" id="registeremphasis">Register</p>
<br>
<p class="modalemphasis" id="forgotemphasis">
Forgot Password
</p>
</div>
<div id="loginsubmitbutton">
Login
Expand Down
12 changes: 12 additions & 0 deletions client/views/login/login.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import $ from 'jquery'

function showError(reason, parentElement, nextElement) {
if (typeof currentError !== 'undefined') {
Blaze.remove(currentError);
Expand Down Expand Up @@ -42,6 +44,16 @@ Template.login.events({
}, 10);
});
},
'click #forgotemphasis': function (event, template) {
$('.formcontainer').fadeOut(400);
$('#darker').fadeOut(400, () => {
Blaze.remove(popoverTemplate);
window.setTimeout(() => {
const parentNode = document.getElementById('nav');
popoverTemplate = Blaze.render(Template.resetpwd, parentNode);
}, 10);
});
},
'keypress #passwordbox': function (event, template) {
// eslint-disable-next-line no-param-reassign
event.which = event.which || event.keyCode;
Expand Down
37 changes: 37 additions & 0 deletions client/views/resetpwd/resetpwd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template name="resetpwd">
{{#if resetPassword}}
<div class="newpwdbox">
<div class="newpwdnav">
<a id="navHome" class="link" title="Home"><i class="fa fa-home"></i></a>
</div>
<h1 class="formtitle">Change password</h1>
<div class="newpwdform">
<input type="password" pattern=".{6,30}" id="newpasswordbox" class="input" placeholder="New password..." autocomplete="off">
<input type="password" id="newpasswordconfirm" class="input" placeholder="Confirm password..." autocomplete="off">
<div id="newpwdsubmitbutton">
Change
</div>
</div>
</div>
<div id="pwdchangemessage">Your password has been changed successfully. Redirecting to homepage...</div>
{{else}}
<div id="darker">
</div>
<div class="formcontainer">
{{> close_button}}
<h1 class="formtitle">Forgot Password</h1>
<div class="modaltopmessage">
Enter your email to receive the password reset link.
</div>
<div class="inputcontainer">
<input type="text" id="loginemail" spellcheck="false" class="input" placeholder="Email...">
<p id="mailSentMessage">&#10004; Check your inbox</p>
<img src="/loading.gif" id="newPwdLoadingSpinner">
<div id="forgotsubmitbutton">
Send Email
</div>
</div>
</div>
{{/if}}

</template>
103 changes: 103 additions & 0 deletions client/views/resetpwd/resetpwd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import $ from 'jquery';

Accounts.onResetPasswordLink((token, done) => {
Router.go('resetpwd');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you writing this manually instead of using one of the packages suggested in the Meteor docs?

});

if (Accounts._resetPasswordToken) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't have code that's sitting outside functions like this. I think this is only getting run when the file is first imported.

Session.set('resetPasswordVar', Accounts._resetPasswordToken);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to do it this way, you could set both the token and the done callback as elements in the Session object up after line 3.

}

function showChangePwdError(reason, parentElement, nextElement) {
if (typeof currentError !== 'undefined') {
Blaze.remove(currentError);
}
const parentNode = $('.' + parentElement)[0];
const nextNode = $('.' + nextElement)[0];
currentError = Blaze.renderWithData(Template.form_error, reason, parentNode, nextNode);
}

Template.resetpwd.onRendered(() => {
$('.formcontainer').hide().fadeIn(400);
$('#darker').hide().fadeIn(400);
});

Template.resetpwd.helpers({
resetPassword() {
return Session.get('resetPasswordVar');
},
});

Template.resetpwd.events({
'keypress #newpasswordconfirm': function (event, template) {
event.which = event.which || event.keyCode;
if (event.which === 13) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set 13 to a named constant so we know which key it is without having to look it up.

event.preventDefault();
$('#newpwdsubmitbutton').click();
}
},
'keypress #loginemail': function (event, template) {
event.which = event.which || event.keyCode;
if (event.which === 13) {
event.preventDefault();
$('#forgotsubmitbutton').click();
}
},
'click #forgotsubmitbutton': function (event, template) {
$('#mailSentMessage').css('display', 'none');
const email = $('#loginemail').val();
$('#newPwdLoadingSpinner').css('display', 'block');
Accounts.forgotPassword({ email: email }, function (e) {
$('#newPwdLoadingSpinner').css('display', 'none');
if (e) {
const errorMessage = [
{ reason: 'User not found', message: "The email address that you've entered doesn't match any account." },
{ reason: 'Internal server error', message: 'Please check your internet connection.' },
];
const in1 = errorMessage.findIndex(x => x.reason === e.reason);
if (in1 === -1) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be more readable as if (Object.keys(errorMessage).includes(e.reason)) { (and then switch the condition).

showChangePwdError(e.reason, 'formcontainer', 'inputcontainer');
} else {
showChangePwdError(errorMessage[in1].message, 'formcontainer', 'inputcontainer');
}
} else {
$('#mailSentMessage').css('display', 'block');
}
});
},
'click #newpwdsubmitbutton': function (event, template) {
const newPass = $('#newpasswordbox').val();
const newPassConfirm = $('#newpasswordconfirm').val();
if (!$('#newpasswordbox')[0].checkValidity()) {
showChangePwdError('Password must be between 6 and 30 characters', 'newpwdbox', 'newpwdform');
return false;
} else if (newPass !== newPassConfirm) {
showChangePwdError('Passwords do not match', 'newpwdbox', 'newpwdform');
return false;
}
Accounts.resetPassword(Session.get('resetPasswordVar'), newPass, function (e) {
if (e) {
const errorMessage = [
{ reason: 'Token expired', message: 'This link is expired.' },
{ reason: 'Internal server error', message: 'Please check your internet connection.' },
];
const in1 = errorMessage.findIndex(x => x.reason === e.reason);
if (in1 === -1) {
showChangePwdError(e.reason, 'newpwdbox', 'newpwdform');
} else {
showChangePwdError(errorMessage[in1].message, 'newpwdbox', 'newpwdform');
}
} else {
$('.newpwdbox').css('display', 'none');
$('#pwdchangemessage').css('display', 'block');
setTimeout(() => {
Session.set('resetPasswordVar', null);
Router.go('/');
}, 3000);
}
});
},
'click #navHome': function (event, template) {
Router.go('/');
},
});
75 changes: 75 additions & 0 deletions client/views/resetpwd/resetpwd.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
.newpwdbox {
text-align: center;
}

.newpwdnav {
height: 50px;
background-color: #293340;
margin-bottom: 50px;
}

.newpwdnav > #navHome > .fa-home {
font-size: 2em;
padding: 10px;
}

.input {
width: 300px!important;
}

#newpwdsubmitbutton {
width: 200px;
display: block;
height: 30px;
margin: 0px auto;
background-color: #2ecc71;
margin-top: 20px;
margin-bottom: 10px;
border-radius: 5px;
cursor: pointer;
text-align: center;
font-weight: 600;
color: white;
padding-top: 5px;

&:hover {
background-color: #4cd785;
}
}

#forgotsubmitbutton {
margin-bottom: 10px !important;
}

.newpwdbox > h1 {
margin-bottom: 20px;
}

.newpwdbox > .error {
max-width: 420px;
display: inline-block;
}

#newPwdLoadingSpinner {
width: 12%;
display: inline-block;
margin-left: 44%;
display: none;
}

#mailSentMessage {
color: #42a1f4;
background-color: #fff;
width: 50%;
margin-left: 25%;
text-align: center;
display: none;
}

#pwdchangemessage {
display: none;
width: 300px;
text-align: center;
width: 100%;
font-size: 1.5em;
}
4 changes: 4 additions & 0 deletions lib/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,7 @@ Router.route('/rss/:tablename', {
this.response.end(xmlData);
},
});

Router.route('resetpwd', {
template: 'resetpwd',
});
2 changes: 1 addition & 1 deletion server/methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Meteor.methods({
$set: newValues,
}, (error, count, status) => {
if (error) {
errorKey = error.invalidKeys[0].name;
const errorKey = error.invalidKeys[0].name;
throw new Meteor.Error(errorKey);
}
});
Expand Down