Allows very simple mail adapters
- Fix nasty bug when updating users email and sending verification
This commit is contained in:
@@ -150,10 +150,67 @@ describe("Email Verification", () => {
|
||||
user.set("email", "cool_guy@parse.com");
|
||||
return user.save();
|
||||
}).then((user) => {
|
||||
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
|
||||
return user.fetch();
|
||||
}).then(() => {
|
||||
expect(user.get('emailVerified')).toEqual(false);
|
||||
// Wait as on update emai, we need to fetch the username
|
||||
setTimeout(function(){
|
||||
expect(emailAdapter.sendVerificationEmail).toHaveBeenCalled();
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
},
|
||||
error: function(userAgain, error) {
|
||||
fail('Failed to save user');
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('does send with a simple adapter', done => {
|
||||
var calls = 0;
|
||||
var emailAdapter = {
|
||||
sendMail: function(options){
|
||||
expect(options.to).toBe('cool_guy@parse.com');
|
||||
if (calls == 0) {
|
||||
expect(options.subject).toEqual('Please verify your e-mail for My Cool App');
|
||||
expect(options.text.match(/verify_email/)).not.toBe(null);
|
||||
} else if (calls == 1) {
|
||||
expect(options.subject).toEqual('Password Reset for My Cool App');
|
||||
expect(options.text.match(/request_password_reset/)).not.toBe(null);
|
||||
}
|
||||
calls++;
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
setServerConfiguration({
|
||||
serverURL: 'http://localhost:8378/1',
|
||||
appId: 'test',
|
||||
appName: 'My Cool App',
|
||||
javascriptKey: 'test',
|
||||
dotNetKey: 'windows',
|
||||
clientKey: 'client',
|
||||
restAPIKey: 'rest',
|
||||
masterKey: 'test',
|
||||
collectionPrefix: 'test_',
|
||||
fileKey: 'test',
|
||||
verifyUserEmails: true,
|
||||
emailAdapter: emailAdapter,
|
||||
});
|
||||
var user = new Parse.User();
|
||||
user.setPassword("asdf");
|
||||
user.setUsername("zxcv");
|
||||
user.set("email", "cool_guy@parse.com");
|
||||
user.signUp(null, {
|
||||
success: function(user) {
|
||||
expect(calls).toBe(1);
|
||||
user.fetch()
|
||||
.then((user) => {
|
||||
return user.save();
|
||||
}).then((user) => {
|
||||
return Parse.User.requestPasswordReset("cool_guy@parse.com");
|
||||
}).then(() => {
|
||||
expect(calls).toBe(2);
|
||||
done();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
|
||||
/*
|
||||
Mail Adapter prototype
|
||||
A MailAdapter should implement at least sendMail()
|
||||
*/
|
||||
export class MailAdapter {
|
||||
sendVerificationEmail(options) {}
|
||||
sendPasswordResetEmail(options) {}
|
||||
/*
|
||||
* A method for sending mail
|
||||
* @param options would have the parameters
|
||||
* - to: the recipient
|
||||
* - text: the raw text of the message
|
||||
* - subject: the subject of the email
|
||||
*/
|
||||
sendMail(options) {}
|
||||
|
||||
/* You can implement those methods if you want
|
||||
* to provide HTML templates etc...
|
||||
*/
|
||||
// sendVerificationEmail({ link, appName, user }) {}
|
||||
// sendPasswordResetEmail({ link, appName, user }) {}
|
||||
}
|
||||
|
||||
export default MailAdapter;
|
||||
|
||||
@@ -25,31 +25,6 @@ let SimpleMailgunAdapter = mailgunOptions => {
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
sendVerificationEmail: ({ link, user, appName, }) => {
|
||||
let verifyMessage =
|
||||
"Hi,\n\n" +
|
||||
"You are being asked to confirm the e-mail address " + user.email + " with " + appName + "\n\n" +
|
||||
"" +
|
||||
"Click here to confirm it:\n" + link;
|
||||
return sendMail({
|
||||
to:user.email,
|
||||
subject: 'Please verify your e-mail for ' + appName,
|
||||
text: verifyMessage
|
||||
});
|
||||
},
|
||||
|
||||
sendPasswordResetEmail: ({link,user, appName}) => {
|
||||
let message =
|
||||
"Hi,\n\n" +
|
||||
"You requested to reset your password for " + appName + ".\n\n" +
|
||||
"" +
|
||||
"Click here to reset it:\n" + link;
|
||||
return sendMail({
|
||||
to:user.email,
|
||||
subject: 'Password Reset for ' + appName,
|
||||
text: message
|
||||
});
|
||||
},
|
||||
sendMail: sendMail
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import MailAdapter from '../Adapters/Email/MailAdapter';
|
||||
|
||||
var DatabaseAdapter = require('../DatabaseAdapter');
|
||||
var RestWrite = require('../RestWrite');
|
||||
var RestQuery = require('../RestQuery');
|
||||
var hash = require('../password').hash;
|
||||
var Auth = require('../Auth');
|
||||
|
||||
@@ -84,20 +85,47 @@ export class UserController extends AdaptableController {
|
||||
});
|
||||
}
|
||||
|
||||
getUserIfNeeded(user) {
|
||||
if (user.username && user.email) {
|
||||
return Promise.resolve(user);
|
||||
}
|
||||
var where = {};
|
||||
if (user.username) {
|
||||
where.username = user.username;
|
||||
}
|
||||
if (user.email) {
|
||||
where.email = user.email;
|
||||
}
|
||||
|
||||
var query = new RestQuery(this.config, Auth.master(this.config), '_User', where);
|
||||
return query.execute().then(function(result){
|
||||
if (result.results.length != 1) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return result.results[0];
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
sendVerificationEmail(user) {
|
||||
if (!this.shouldVerifyEmails) {
|
||||
return;
|
||||
}
|
||||
|
||||
const token = encodeURIComponent(user._email_verify_token);
|
||||
const username = encodeURIComponent(user.username);
|
||||
|
||||
let link = `${this.config.verifyEmailURL}?token=${token}&username=${username}`;
|
||||
this.adapter.sendVerificationEmail({
|
||||
appName: this.config.appName,
|
||||
link: link,
|
||||
user: inflate('_User', user),
|
||||
// We may need to fetch the user in case of update email
|
||||
this.getUserIfNeeded(user).then((user) => {
|
||||
const token = encodeURIComponent(user._email_verify_token);
|
||||
const username = encodeURIComponent(user.username);
|
||||
let link = `${this.config.verifyEmailURL}?token=${token}&username=${username}`;
|
||||
let options = {
|
||||
appName: this.config.appName,
|
||||
link: link,
|
||||
user: inflate('_User', user),
|
||||
};
|
||||
if (this.adapter.sendVerificationEmail) {
|
||||
this.adapter.sendVerificationEmail(options);
|
||||
} else {
|
||||
this.adapter.sendMail(this.defaultVerificationEmail(options));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -134,11 +162,23 @@ export class UserController extends AdaptableController {
|
||||
const token = encodeURIComponent(user._perishable_token);
|
||||
const username = encodeURIComponent(user.username);
|
||||
let link = `${this.config.requestResetPasswordURL}?token=${token}&username=${username}`
|
||||
this.adapter.sendPasswordResetEmail({
|
||||
appName: this.config.appName,
|
||||
link: link,
|
||||
user: inflate('_User', user),
|
||||
});
|
||||
|
||||
if (!user.username) {
|
||||
console.log('No username...');
|
||||
}
|
||||
|
||||
let options = {
|
||||
appName: this.config.appName,
|
||||
link: link,
|
||||
user: inflate('_User', user),
|
||||
};
|
||||
|
||||
if (this.adapter.sendPasswordResetEmail) {
|
||||
this.adapter.sendPasswordResetEmail(options);
|
||||
} else {
|
||||
this.adapter.sendMail(this.defaultResetPasswordEmail(options));
|
||||
}
|
||||
|
||||
return Promise.resolve(user);
|
||||
});
|
||||
}
|
||||
@@ -148,6 +188,26 @@ export class UserController extends AdaptableController {
|
||||
return updateUserPassword(username, token, password, this.config);
|
||||
});
|
||||
}
|
||||
|
||||
defaultVerificationEmail({link, user, appName, }) {
|
||||
let text = "Hi,\n\n" +
|
||||
"You are being asked to confirm the e-mail address " + user.email + " with " + appName + "\n\n" +
|
||||
"" +
|
||||
"Click here to confirm it:\n" + link;
|
||||
let to = user.get("email");
|
||||
let subject = 'Please verify your e-mail for ' + appName;
|
||||
return { text, to, subject };
|
||||
}
|
||||
|
||||
defaultResetPasswordEmail({link, user, appName, }) {
|
||||
let text = "Hi,\n\n" +
|
||||
"You requested to reset your password for " + appName + ".\n\n" +
|
||||
"" +
|
||||
"Click here to reset it:\n" + link;
|
||||
let to = user.get("email");
|
||||
let subject = 'Password Reset for ' + appName;
|
||||
return { text, to, subject };
|
||||
}
|
||||
}
|
||||
|
||||
// Mark this private
|
||||
|
||||
Reference in New Issue
Block a user