Add SMS validation

This commit is contained in:
Tankred Hase 2014-09-19 18:59:13 +02:00
parent 7c7d650cf2
commit d1308aa14c
6 changed files with 198 additions and 17 deletions

View File

@ -29,12 +29,38 @@ define(function(require) {
appCtrl._adminDao.createUser({
emailAddress: $scope.emailAddress,
password: $scope.pass,
//phone: $scope.phone,
//betaCode: $scope.betaCode
phone: $scope.phone,
betaCode: $scope.betaCode.toUpperCase()
}, function(err) {
$scope.busy = false;
if (err) {
$scope.errMsg = err.errMsg || err.message;
$scope.$apply();
return;
}
$scope.goTo(3);
$scope.$apply();
});
};
$scope.validateUser = function() {
if ($scope.formValidate.$invalid) {
return;
}
$scope.busyValidate = true;
$scope.errMsgValidate = undefined; // reset error msg
// verify user to REST api
appCtrl._adminDao.validateUser({
emailAddress: $scope.emailAddress,
token: $scope.token.toUpperCase()
}, function(err) {
if (err) {
$scope.busy = false;
$scope.errMsg = err.errMsg || err.message;
$scope.busyValidate = false;
$scope.errMsgValidate = err.errMsg || err.message;
$scope.$apply();
return;
}

View File

@ -15,7 +15,7 @@ define(function() {
AdminDAO.prototype.createUser = function(options, callback) {
var uri;
if (!options.emailAddress || !options.password /* || !options.phone*/ ) {
if (!options.emailAddress || !options.password || !options.phone) {
callback(new Error('Incomplete arguments!'));
return;
}
@ -34,5 +34,30 @@ define(function() {
});
};
/**
* Verify a user's phone number by confirming a token to the server.
* @param {String} options.emailAddress The desired email address
* @param {String} options.token The validation token.
* @param {Function} callback(error)
*/
AdminDAO.prototype.validateUser = function(options, callback) {
var uri;
if (!options.emailAddress || !options.token) {
callback(new Error('Incomplete arguments!'));
return;
}
uri = '/user/validate';
this._restDao.post(options, uri, function(err) {
if (!err || (err && err.code === 202)) {
// success
callback();
} else {
callback(new Error('Validation failed!'));
}
});
};
return AdminDAO;
});

View File

@ -78,6 +78,10 @@
width: 100%;
}
input.token {
width: auto;
}
input[type=file] {
width: 100%;
background-color: white;
@ -142,10 +146,6 @@
margin-top: 20px;
}
input.token {
width: auto;
}
.code {
max-width: 240px;
margin: 0 auto;

View File

@ -13,7 +13,7 @@
<hr>
<div class="choice">
<p><b>Login to IMAP account.</b> Connect Whiteout Mail to any existing email account via IMAP.</p>
<button class="btn btn-alt" wo-touch="goTo(3)">Login to existing</button>
<button class="btn btn-alt" wo-touch="goTo(4)">Login to existing</button>
</div>
</div>
</div>
@ -29,7 +29,7 @@
<label class="input-error-message" ng-show="errMsg">{{errMsg}}</label>
<label class="input-error-message" ng-show="form.$invalid">Please fill out all required fields!</label>
<div class="flex">
<input class="input-text wmail" ng-model="user" required type="text" pattern='^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))' placeholder="User name">
<input class="input-text wmail" ng-model="user" required type="text" pattern='^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))' placeholder="User name" focus-me="step === 2">
<span class="domain">@wmail.io</span>
</div>
<input class="input-text" type="text" ng-model="realname" placeholder="Full name (optional)"></input>
@ -51,7 +51,30 @@
</div>
</div>
<div class="providers" ng-show="step === 3">
<div ng-show="step === 3">
<div class="logo">
<img src="img/whiteout_logo.svg" alt="whiteout.io">
</div><!--/logo-->
<div class="content">
<p><b>Validate phone number.</b> We have sent you a validation code via SMS. Please enter this code to confirm your phone number.</p>
<form name="formValidate">
<label class="input-error-message" ng-show="errMsgValidate">{{errMsgValidate}}</label>
<br>
<input type="text" class="input-text token" size="6" maxlength="6" ng-model="token" placeholder="Code" focus-me="step === 3" required pattern="([a-zA-Z0-9]*)">
<div class="working" ng-show="busyValidate">
<span class="spinner"></span>
</div>
<div>
<button class="btn" type="submit" ng-click="validateUser()">Confirm code</button>
</div>
</form>
</div>
</div>
<div class="providers" ng-show="step === 4">
<h1>Select account</h1>
<ul>

View File

@ -25,6 +25,7 @@ define(function(require) {
scope = $rootScope.$new();
scope.state = {};
scope.form = {};
scope.formValidate = {};
sinon.stub(location, 'path').returns(location);
sinon.stub(location, 'search').returns(location);
@ -58,6 +59,7 @@ define(function(require) {
it('should fail to error creating user', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
adminStub.createUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
@ -73,11 +75,13 @@ define(function(require) {
it('should work', function(done) {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
adminStub.createUser.yieldsAsync();
scope.login = function() {
expect(scope.busy).to.be.true;
scope.$apply = function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.be.undefined;
expect(scope.step).to.equal(3);
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
@ -87,6 +91,46 @@ define(function(require) {
});
});
describe('validateUser', function() {
it('should return early for invalid form', function() {
scope.formValidate.$invalid = true;
scope.validateUser();
expect(adminStub.validateUser.called).to.be.false;
});
it('should fail to error creating user', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync(new Error('asdf'));
scope.$apply = function() {
expect(scope.busyValidate).to.be.false;
expect(scope.errMsgValidate).to.equal('asdf');
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
it('should work', function(done) {
scope.formValidate.$invalid = false;
scope.token = 'asfd';
adminStub.validateUser.yieldsAsync();
scope.login = function() {
expect(scope.busyValidate).to.be.true;
expect(scope.errMsgValidate).to.be.undefined;
expect(adminStub.validateUser.calledOnce).to.be.true;
done();
};
scope.validateUser();
expect(scope.busyValidate).to.be.true;
});
});
describe('login', function() {
it('should work', function() {
scope.form.$invalid = false;

View File

@ -33,7 +33,8 @@ define(function(require) {
it('should fail if user already exists', function(done) {
var opt = {
emailAddress: emailAddress,
password: password
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields({
@ -50,7 +51,8 @@ define(function(require) {
it('should fail due to unknown error', function(done) {
var opt = {
emailAddress: emailAddress,
password: password
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields(new Error());
@ -65,7 +67,8 @@ define(function(require) {
it('should work', function(done) {
var opt = {
emailAddress: emailAddress,
password: password
password: password,
phone: '12345'
};
restDaoStub.post.withArgs(opt, '/user').yields();
@ -78,6 +81,66 @@ define(function(require) {
});
});
describe('validateUser', function() {
it('should fail due to incomplete args', function(done) {
var opt = {
emailAddress: emailAddress
};
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
done();
});
});
it('should fail due to error in rest api', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields(new Error());
adminDao.validateUser(opt, function(err) {
expect(err).to.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with no error object', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields();
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
it('should work with 202', function(done) {
var opt = {
emailAddress: emailAddress,
token: 'H45Z6D'
};
restDaoStub.post.withArgs(opt, '/user/validate').yields({
code: 202
});
adminDao.validateUser(opt, function(err) {
expect(err).to.not.exist;
expect(restDaoStub.post.calledOnce).to.be.true;
done();
});
});
});
});
});