Remote method /user/:id/verify
This commit adds: - user.prototype.verify(verifyOptions, options, cb) - remote method /user/:id/verify - User.getVerifyOptions() The remote method can be used to replay the sending of a user identity/email verification message. `getVerifyOptions()` can be fully customized programmatically or partially customized using user model's `.settings.verifyOptions` `getVerifyOptions()` is called under the hood when calling the /user/:id/verify remote method `getVerifyOptions()` can also be used to ease the building of identity verifyOptions: ```js var verifyOptions = { type: 'email', from: 'noreply@example.com' template: 'verify.ejs', redirect: '/', generateVerificationToken: function (user, options, cb) { cb('random-token'); } }; user.verify(verifyOptions); ``` NOTE: the `User.login()` has been modified to return the userId when failing due to unverified identity/email. This userId can then be used to call the /user/:id/verify remote method.
This commit is contained in:
parent
b96605c63a
commit
b9fbf51b27
|
@ -183,10 +183,16 @@ module.exports = function(User) {
|
|||
*
|
||||
* ```js
|
||||
* User.login({username: 'foo', password: 'bar'}, function (err, token) {
|
||||
* console.log(token.id);
|
||||
* });
|
||||
* console.log(token.id);
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* If the `emailVerificationRequired` flag is set for the inherited user model
|
||||
* and the email has not yet been verified then the method will return a 401
|
||||
* error that will contain the user's id. This id can be used to call the
|
||||
* `api/verify` remote method to generate a new email verification token and
|
||||
* send back the related email to the user.
|
||||
*
|
||||
* @param {Object} credentials username/password or email/password
|
||||
* @param {String[]|String} [include] Optionally set it to "user" to include
|
||||
* the user info
|
||||
|
@ -273,6 +279,9 @@ module.exports = function(User) {
|
|||
err = new Error(g.f('login failed as the email has not been verified'));
|
||||
err.statusCode = 401;
|
||||
err.code = 'LOGIN_FAILED_EMAIL_NOT_VERIFIED';
|
||||
err.details = {
|
||||
userId: user.id,
|
||||
};
|
||||
fn(err);
|
||||
} else {
|
||||
if (user.createAccessToken.length === 2) {
|
||||
|
@ -527,42 +536,152 @@ module.exports = function(User) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Verify a user's identity by sending them a confirmation email.
|
||||
* Returns default verification options to use when calling User.prototype.verify()
|
||||
* from remote method /user/:id/verify.
|
||||
*
|
||||
* NOTE: the User.getVerifyOptions() method can also be used to ease the
|
||||
* building of identity verification options.
|
||||
*
|
||||
* ```js
|
||||
* var verifyOptions = {
|
||||
* type: 'email',
|
||||
* from: noreply@example.com,
|
||||
* template: 'verify.ejs',
|
||||
* redirect: '/',
|
||||
* tokenGenerator: function (user, cb) { cb("random-token"); }
|
||||
* };
|
||||
* var verifyOptions = MyUser.getVerifyOptions();
|
||||
* user.verify(verifyOptions);
|
||||
* ```
|
||||
*
|
||||
* user.verify(verifyOptions, options, next);
|
||||
* This is the full list of possible params, with example values
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* type: 'email',
|
||||
* mailer: {
|
||||
* send(verifyOptions, options, cb) {
|
||||
* // send the email
|
||||
* cb(err, result);
|
||||
* }
|
||||
* },
|
||||
* to: 'test@email.com',
|
||||
* from: 'noreply@email.com'
|
||||
* subject: 'verification email subject',
|
||||
* text: 'Please verify your email by opening this link in a web browser',
|
||||
* headers: {'Mime-Version': '1.0'},
|
||||
* template: 'path/to/template.ejs',
|
||||
* templateFn: function(verifyOptions, options, cb) {
|
||||
* cb(null, 'some body template');
|
||||
* }
|
||||
* redirect: '/',
|
||||
* verifyHref: 'http://localhost:3000/api/user/confirm',
|
||||
* host: 'localhost'
|
||||
* protocol: 'http'
|
||||
* port: 3000,
|
||||
* restApiRoot= '/api',
|
||||
* generateVerificationToken: function (user, options, cb) {
|
||||
* cb(null, 'random-token');
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* NOTE: param `to` internally defaults to user's email but can be overriden for
|
||||
* test purposes or advanced customization.
|
||||
*
|
||||
* Static default params can be modified in your custom user model json definition
|
||||
* using `settings.verifyOptions`. Any default param can be programmatically modified
|
||||
* like follows:
|
||||
*
|
||||
* ```js
|
||||
* customUserModel.getVerifyOptions = function() {
|
||||
* const base = MyUser.base.getVerifyOptions();
|
||||
* return Object.assign({}, base, {
|
||||
* // custom values
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Usually you should only require to modify a subset of these params
|
||||
* See `User.verify()` and `User.prototype.verify()` doc for params reference
|
||||
* and their default values.
|
||||
*/
|
||||
|
||||
User.getVerifyOptions = function() {
|
||||
const verifyOptions = {
|
||||
type: 'email',
|
||||
from: 'noreply@example.com',
|
||||
};
|
||||
return this.settings.verifyOptions || verifyOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify a user's identity by sending them a confirmation message.
|
||||
* NOTE: Currently only email verification is supported
|
||||
*
|
||||
* ```js
|
||||
* var verifyOptions = {
|
||||
* type: 'email',
|
||||
* from: 'noreply@example.com'
|
||||
* template: 'verify.ejs',
|
||||
* redirect: '/',
|
||||
* generateVerificationToken: function (user, options, cb) {
|
||||
* cb('random-token');
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* user.verify(verifyOptions);
|
||||
* ```
|
||||
*
|
||||
* NOTE: the User.getVerifyOptions() method can also be used to ease the
|
||||
* building of identity verification options.
|
||||
*
|
||||
* ```js
|
||||
* var verifyOptions = MyUser.getVerifyOptions();
|
||||
* user.verify(verifyOptions);
|
||||
* ```
|
||||
*
|
||||
* @options {Object} verifyOptions
|
||||
* @property {String} type Must be 'email'.
|
||||
* @property {String} type Must be `'email'` in the current implementation.
|
||||
* @property {Function} mailer A mailer function with a static `.send() method.
|
||||
* The `.send()` method must accept the verifyOptions object, the method's
|
||||
* remoting context options object and a callback function with `(err, email)`
|
||||
* as parameters.
|
||||
* Defaults to provided `userModel.email` function, or ultimately to LoopBack's
|
||||
* own mailer function.
|
||||
* @property {String} to Email address to which verification email is sent.
|
||||
* @property {String} from Sender email addresss, for example
|
||||
* `'noreply@myapp.com'`.
|
||||
* Defaults to user's email. Can also be overriden to a static value for test
|
||||
* purposes.
|
||||
* @property {String} from Sender email address
|
||||
* For example `'noreply@example.com'`.
|
||||
* @property {String} subject Subject line text.
|
||||
* Defaults to `'Thanks for Registering'` or a local equivalent.
|
||||
* @property {String} text Text of email.
|
||||
* @property {String} template Name of template that displays verification
|
||||
* page, for example, `'verify.ejs'.
|
||||
* Defaults to `'Please verify your email by opening this link in a web browser:`
|
||||
* followed by the verify link.
|
||||
* @property {Object} headers Email headers. None provided by default.
|
||||
* @property {String} template Relative path of template that displays verification
|
||||
* page. Defaults to `'../../templates/verify.ejs'`.
|
||||
* @property {Function} templateFn A function generating the email HTML body
|
||||
* from `verify()` options object and generated attributes like `options.verifyHref`.
|
||||
* It must accept the option object and a callback function with `(err, html)`
|
||||
* as parameters
|
||||
* from `verify()` options object and generated attributes like `options.verifyHref`.
|
||||
* It must accept the verifyOptions object, the method's remoting context options
|
||||
* object and a callback function with `(err, html)` as parameters.
|
||||
* A default templateFn function is provided, see `createVerificationEmailBody()`
|
||||
* for implementation details.
|
||||
* @property {String} redirect Page to which user will be redirected after
|
||||
* they verify their email, for example `'/'` for root URI.
|
||||
* they verify their email. Defaults to `'/'`.
|
||||
* @property {String} verifyHref The link to include in the user's verify message.
|
||||
* Defaults to an url analog to:
|
||||
* `http://host:port/restApiRoot/userRestPath/confirm?uid=userId&redirect=/``
|
||||
* @property {String} host The API host. Defaults to app's host or `localhost`.
|
||||
* @property {String} protocol The API protocol. Defaults to `'http'`.
|
||||
* @property {Number} port The API port. Defaults to app's port or `3000`.
|
||||
* @property {String} restApiRoot The API root path. Defaults to app's restApiRoot
|
||||
* or `'/api'`
|
||||
* @property {Function} generateVerificationToken A function to be used to
|
||||
* generate the verification token. It must accept the user object and a
|
||||
* callback function. This function should NOT add the token to the user
|
||||
* object, instead simply execute the callback with the token! User saving
|
||||
* and email sending will be handled in the `verify()` method.
|
||||
* @param {Object} options remote context options.
|
||||
* generate the verification token.
|
||||
* It must accept the verifyOptions object, the method's remoting context options
|
||||
* object and a callback function with `(err, hexStringBuffer)` as parameters.
|
||||
* This function should NOT add the token to the user object, instead simply
|
||||
* execute the callback with the token! User saving and email sending will be
|
||||
* handled in the `verify()` method.
|
||||
* A default token generation function is provided, see `generateVerificationToken()`
|
||||
* for implementation details.
|
||||
* @callback {Function} cb Callback function.
|
||||
* @param {Object} options remote context options.
|
||||
* @param {Error} err Error object.
|
||||
* @param {Object} object Contains email, token, uid.
|
||||
* @promise
|
||||
|
@ -585,9 +704,11 @@ module.exports = function(User) {
|
|||
|
||||
// Set a default template generation function if none provided
|
||||
verifyOptions.templateFn = verifyOptions.templateFn || createVerificationEmailBody;
|
||||
|
||||
// Set a default token generation function if none provided
|
||||
verifyOptions.generateVerificationToken = verifyOptions.generateVerificationToken ||
|
||||
User.generateVerificationToken;
|
||||
|
||||
// Set a default mailer function if none provided
|
||||
verifyOptions.mailer = verifyOptions.mailer || userModel.email ||
|
||||
registry.getModelByType(loopback.Email);
|
||||
|
@ -654,10 +775,8 @@ module.exports = function(User) {
|
|||
function sendEmail(user) {
|
||||
verifyOptions.verifyHref += '&token=' + user.verificationToken;
|
||||
verifyOptions.verificationToken = user.verificationToken;
|
||||
|
||||
verifyOptions.text = verifyOptions.text || g.f('Please verify your email by opening ' +
|
||||
'this link in a web browser:\n\t%s', verifyOptions.verifyHref);
|
||||
|
||||
verifyOptions.text = verifyOptions.text.replace(/\{href\}/g, verifyOptions.verifyHref);
|
||||
|
||||
// argument "options" is passed depending on templateFn function requirements
|
||||
|
@ -1003,10 +1122,22 @@ module.exports = function(User) {
|
|||
}
|
||||
);
|
||||
|
||||
UserModel.remoteMethod(
|
||||
'prototype.verify',
|
||||
{
|
||||
description: 'Trigger user\'s identity verification with configured verifyOptions',
|
||||
accepts: [
|
||||
{arg: 'verifyOptions', type: 'object', http: ctx => this.getVerifyOptions()},
|
||||
{arg: 'options', type: 'object', http: 'optionsFromRequest'},
|
||||
],
|
||||
http: {verb: 'post'},
|
||||
}
|
||||
);
|
||||
|
||||
UserModel.remoteMethod(
|
||||
'confirm',
|
||||
{
|
||||
description: 'Confirm a user registration with email verification token.',
|
||||
description: 'Confirm a user registration with identity verification token.',
|
||||
accepts: [
|
||||
{arg: 'uid', type: 'string', required: true},
|
||||
{arg: 'token', type: 'string', required: true},
|
||||
|
|
|
@ -70,6 +70,13 @@
|
|||
"permission": "ALLOW",
|
||||
"property": "replaceById"
|
||||
},
|
||||
{
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW",
|
||||
"property": "verify",
|
||||
"accessType": "EXECUTE"
|
||||
},
|
||||
{
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
|
|
|
@ -854,7 +854,7 @@ describe('User', function() {
|
|||
User.settings.emailVerificationRequired = false;
|
||||
});
|
||||
|
||||
it('Require valid and complete credentials for email verification error', function(done) {
|
||||
it('requires valid and complete credentials for email verification', function(done) {
|
||||
User.login({email: validCredentialsEmail}, function(err, accessToken) {
|
||||
// strongloop/loopback#931
|
||||
// error message should be "login failed"
|
||||
|
@ -862,12 +862,15 @@ describe('User', function() {
|
|||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
// as login is failing because of invalid credentials it should to return
|
||||
// the user id in the error message
|
||||
assert.equal(err.details, undefined);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Require valid and complete credentials for email verification error - promise variant',
|
||||
it('requires valid and complete credentials for email verification - promise variant',
|
||||
function(done) {
|
||||
User.login({email: validCredentialsEmail})
|
||||
.then(function(accessToken) {
|
||||
|
@ -879,34 +882,30 @@ describe('User', function() {
|
|||
assert(err && !/verified/.test(err.message),
|
||||
'expecting "login failed" error message, received: "' + err.message + '"');
|
||||
assert.equal(err.code, 'LOGIN_FAILED');
|
||||
|
||||
assert.equal(err.details, undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Login a user by without email verification', function(done) {
|
||||
User.login(validCredentials, function(err, accessToken) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 'LOGIN_FAILED_EMAIL_NOT_VERIFIED');
|
||||
|
||||
done();
|
||||
});
|
||||
it('does not login a user with unverified email but provides userId', function() {
|
||||
return User.login(validCredentials).then(
|
||||
function(user) {
|
||||
throw new Error('User.login() should have failed');
|
||||
},
|
||||
function(err, accessToken) {
|
||||
err = Object.assign({}, err);
|
||||
expect(err).to.eql({
|
||||
statusCode: 401,
|
||||
code: 'LOGIN_FAILED_EMAIL_NOT_VERIFIED',
|
||||
details: {
|
||||
userId: validCredentialsUser.pk,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('Login a user by without email verification - promise variant', function(done) {
|
||||
User.login(validCredentials)
|
||||
.then(function(err, accessToken) {
|
||||
done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 'LOGIN_FAILED_EMAIL_NOT_VERIFIED');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Login a user by with email verification', function(done) {
|
||||
it('login a user with verified email', function(done) {
|
||||
User.login(validCredentialsEmailVerified, function(err, accessToken) {
|
||||
assertGoodToken(accessToken, validCredentialsEmailVerifiedUser);
|
||||
|
||||
|
@ -914,7 +913,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Login a user by with email verification - promise variant', function(done) {
|
||||
it('login a user with verified email - promise variant', function(done) {
|
||||
User.login(validCredentialsEmailVerified)
|
||||
.then(function(accessToken) {
|
||||
assertGoodToken(accessToken, validCredentialsEmailVerifiedUser);
|
||||
|
@ -926,7 +925,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Login a user over REST when email verification is required', function(done) {
|
||||
it('login a user over REST when email verification is required', function(done) {
|
||||
request(app)
|
||||
.post('/test-users/login')
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -944,7 +943,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Login user over REST require complete and valid credentials ' +
|
||||
it('login user over REST require complete and valid credentials ' +
|
||||
'for email verification error message',
|
||||
function(done) {
|
||||
request(app)
|
||||
|
@ -967,7 +966,10 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Login a user over REST without email verification when it is required', function(done) {
|
||||
it('login a user over REST without email verification when it is required', function(done) {
|
||||
// make sure the app is configured in production mode
|
||||
app.set('remoting', {errorHandler: {debug: false, log: false}});
|
||||
|
||||
request(app)
|
||||
.post('/test-users/login')
|
||||
.expect('Content-Type', /json/)
|
||||
|
@ -977,7 +979,19 @@ describe('User', function() {
|
|||
if (err) return done(err);
|
||||
|
||||
var errorResponse = res.body.error;
|
||||
assert.equal(errorResponse.code, 'LOGIN_FAILED_EMAIL_NOT_VERIFIED');
|
||||
|
||||
// extracting code and details error response
|
||||
let errorExcerpts = {
|
||||
code: errorResponse.code,
|
||||
details: errorResponse.details,
|
||||
};
|
||||
|
||||
expect(errorExcerpts).to.eql({
|
||||
code: 'LOGIN_FAILED_EMAIL_NOT_VERIFIED',
|
||||
details: {
|
||||
userId: validCredentialsUser.pk,
|
||||
},
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
@ -1511,7 +1525,7 @@ describe('User', function() {
|
|||
}
|
||||
});
|
||||
|
||||
describe('Verification', function() {
|
||||
describe('Identity verification', function() {
|
||||
describe('user.verify(verifyOptions, options, cb)', function() {
|
||||
const ctxOptions = {testFlag: true};
|
||||
let verifyOptions;
|
||||
|
@ -1524,7 +1538,44 @@ describe('User', function() {
|
|||
};
|
||||
});
|
||||
|
||||
it('Verify a user\'s email address', function(done) {
|
||||
describe('User.getVerifyOptions()', function() {
|
||||
it('returns default verify options', function(done) {
|
||||
const verifyOptions = User.getVerifyOptions();
|
||||
expect(verifyOptions).to.eql({
|
||||
type: 'email',
|
||||
from: 'noreply@example.com',
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('handles custom verify options defined via model.settings', function(done) {
|
||||
User.settings.verifyOptions = {
|
||||
type: 'email',
|
||||
from: 'test@example.com',
|
||||
};
|
||||
const verifyOptions = User.getVerifyOptions();
|
||||
expect(verifyOptions).to.eql(User.settings.verifyOptions);
|
||||
done();
|
||||
});
|
||||
|
||||
it('can be extended by user', function(done) {
|
||||
User.getVerifyOptions = function() {
|
||||
const base = User.base.getVerifyOptions();
|
||||
return Object.assign({}, base, {
|
||||
redirect: '/redirect',
|
||||
});
|
||||
};
|
||||
const verifyOptions = User.getVerifyOptions();
|
||||
expect(verifyOptions).to.eql({
|
||||
type: 'email',
|
||||
from: 'noreply@example.com',
|
||||
redirect: '/redirect',
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies a user\'s email address', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1550,7 +1601,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Verify a user\'s email address - promise variant', function(done) {
|
||||
it('verifies a user\'s email address - promise variant', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1580,7 +1631,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Verify a user\'s email address with custom header', function(done) {
|
||||
it('verifies a user\'s email address with custom header', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1604,7 +1655,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Verify a user\'s email address with custom template function', function(done) {
|
||||
it('verifies a user\'s email address with custom template function', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1674,7 +1725,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Verify a user\'s email address with custom token generator', function(done) {
|
||||
it('verifies a user\'s email address with custom token generator', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1711,7 +1762,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Fails if custom token generator returns error', function(done) {
|
||||
it('fails if custom token generator returns error', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1742,7 +1793,7 @@ describe('User', function() {
|
|||
});
|
||||
|
||||
describe('Verification link port-squashing', function() {
|
||||
it('Do not squash non-80 ports for HTTP links', function(done) {
|
||||
it('does not squash non-80 ports for HTTP links', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1769,7 +1820,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Squash port 80 for HTTP links', function(done) {
|
||||
it('squashes port 80 for HTTP links', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1796,7 +1847,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Do not squash non-443 ports for HTTPS links', function(done) {
|
||||
it('does not squash non-443 ports for HTTPS links', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1824,7 +1875,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('Squash port 443 for HTTPS links', function(done) {
|
||||
it('squashes port 443 for HTTPS links', function(done) {
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
||||
|
@ -1853,7 +1904,7 @@ describe('User', function() {
|
|||
});
|
||||
});
|
||||
|
||||
it('should hide verification tokens from user JSON', function(done) {
|
||||
it('hides verification tokens from user JSON', function(done) {
|
||||
var user = new User({
|
||||
email: 'bar@bat.com',
|
||||
password: 'bar',
|
||||
|
@ -1865,7 +1916,7 @@ describe('User', function() {
|
|||
done();
|
||||
});
|
||||
|
||||
it('should squash "//" when restApiRoot is "/"', function(done) {
|
||||
it('squashes "//" when restApiRoot is "/"', function(done) {
|
||||
var emailBody;
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
assert(user, 'afterRemote should include result');
|
||||
|
@ -2019,6 +2070,26 @@ describe('User', function() {
|
|||
return User.create({email: 'test@example.com', password: 'pass'})
|
||||
.then(u => user = u);
|
||||
}
|
||||
|
||||
it('is called over REST method /User/:id/verify', function() {
|
||||
return User.create({email: 'bar@bat.com', password: 'bar'})
|
||||
.then(user => {
|
||||
return request(app)
|
||||
.post('/test-users/' + user.pk + '/verify')
|
||||
.expect('Content-Type', /json/)
|
||||
// we already tested before that User.verify(id) works correctly
|
||||
// having the remote method returning 204 is enough to make sure
|
||||
// User.verify() was called successfully
|
||||
.expect(204);
|
||||
});
|
||||
});
|
||||
|
||||
it('fails over REST method /User/:id/verify with invalid user id', function() {
|
||||
return request(app)
|
||||
.post('/test-users/' + 'invalid-id' + '/verify')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User.confirm(options, fn)', function() {
|
||||
|
|
Loading…
Reference in New Issue