1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 10:52:17 -05:00

refactor outbox code into business object

This commit is contained in:
Tankred Hase 2013-11-19 16:14:48 +01:00
parent 525fb94e05
commit e71ee471f6
7 changed files with 224 additions and 131 deletions

View File

@ -13,6 +13,8 @@ define(function(require) {
LawnchairDAO = require('js/dao/lawnchair-dao'), LawnchairDAO = require('js/dao/lawnchair-dao'),
KeychainDAO = require('js/dao/keychain-dao'), KeychainDAO = require('js/dao/keychain-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'), DeviceStorageDAO = require('js/dao/devicestorage-dao'),
InvitationDAO = require('js/dao/invitation-dao'),
OutboxBO = require('js/bo/outbox'),
PGP = require('js/crypto/pgp'), PGP = require('js/crypto/pgp'),
config = require('js/app-config').config; config = require('js/app-config').config;
require('cordova'); require('cordova');
@ -153,7 +155,7 @@ define(function(require) {
*/ */
self.init = function(userId, token, callback) { self.init = function(userId, token, callback) {
var auth, imapOptions, smtpOptions, certificate, var auth, imapOptions, smtpOptions, certificate,
lawnchairDao, restDao, pubkeyDao, lawnchairDao, restDao, pubkeyDao, invitationDao,
keychain, imapClient, smtpClient, pgp, userStorage, xhr; keychain, imapClient, smtpClient, pgp, userStorage, xhr;
// fetch pinned local ssl certificate // fetch pinned local ssl certificate
@ -211,6 +213,9 @@ define(function(require) {
userStorage = new DeviceStorageDAO(lawnchairDao); userStorage = new DeviceStorageDAO(lawnchairDao);
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, pgp, userStorage); self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, pgp, userStorage);
invitationDao = new InvitationDAO(restDao);
self._outboxBo = new OutboxBO(self._emailDao, invitationDao);
// init email dao // init email dao
var account = { var account = {
emailAddress: userId, emailAddress: userId,

100
src/js/bo/outbox.js Normal file
View File

@ -0,0 +1,100 @@
define(function(require) {
'use strict';
var config = require('js/app-config').config,
dbType = 'email_OUTBOX';
var OutboxBO = function(emailDao, invitationDao) {
this._emailDao = emailDao;
this._invitationDao = invitationDao;
this._outboxBusy = false;
};
OutboxBO.prototype.startChecking = function(callback) {
// start periodic checking of outbox
this._intervalId = setInterval(this._emptyOutbox.bind(this, callback), config.checkOutboxInterval);
};
OutboxBO.prototype.stopChecking = function() {
if (!this._intervalId) {
return;
}
clearInterval(this._intervalId);
delete this._intervalId;
};
OutboxBO.prototype._emptyOutbox = function(callback) {
var self = this,
emails;
if (self._outboxBusy) {
return;
}
checkStorage();
function checkStorage() {
self._outboxBusy = true;
// get last item from outbox
self._emailDao._devicestorage.listItems(dbType, 0, null, function(err, pending) {
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
// update outbox folder count
emails = pending;
// sending pending mails
send();
});
}
function send() {
callback(null, emails.length);
if (emails.length === 0) {
self._outboxBusy = false;
return;
}
var email = emails.shift();
self._emailDao.smtpSend(email, function(err) {
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
removeFromStorage(email.id);
});
}
function removeFromStorage(id) {
if (!id) {
self._outboxBusy = false;
callback({
errMsg: 'Cannot remove email from storage without a valid id!'
});
return;
}
// delete email from local storage
var key = dbType + '_' + id;
self._emailDao._devicestorage.removeList(key, function(err) {
if (err) {
self._outboxBusy = false;
callback(err);
return;
}
send();
});
}
};
return OutboxBO;
});

View File

@ -5,9 +5,7 @@ define(function(require) {
appController = require('js/app-controller'), appController = require('js/app-controller'),
errorUtil = require('js/util/error'), errorUtil = require('js/util/error'),
_ = require('underscore'), _ = require('underscore'),
config = require('js/app-config').config, emailDao, outboxBo;
emailDao, senderIntervalId,
outboxBusy = false;
// //
// Controller // Controller
@ -20,6 +18,7 @@ define(function(require) {
errorUtil.attachHandler($scope); errorUtil.attachHandler($scope);
emailDao = appController._emailDao; emailDao = appController._emailDao;
outboxBo = appController._outboxBo;
// //
// scope functions // scope functions
@ -37,86 +36,6 @@ define(function(require) {
$scope.state.nav.toggle(false); $scope.state.nav.toggle(false);
}; };
//
// Outbox checker
//
$scope.emptyOutbox = function() {
var dbType = 'email_OUTBOX',
outbox = _.findWhere($scope.folders, {
type: 'Outbox'
});
checkStorage();
function checkStorage() {
if (outboxBusy) {
return;
}
outboxBusy = true;
// get last item from outbox
emailDao._devicestorage.listItems(dbType, 0, null, function(err, pending) {
if (err) {
outboxBusy = false;
$scope.onError(err);
return;
}
// update outbox folder count
outbox.count = pending.length;
$scope.$apply();
// sending pending mails
send(pending);
});
}
function send(emails) {
if (emails.length === 0) {
outboxBusy = false;
return;
}
var email = emails.shift();
emailDao.smtpSend(email, function(err) {
if (err) {
outboxBusy = false;
$scope.onError(err);
return;
}
removeFromStorage(email.id);
send(emails);
});
}
function removeFromStorage(id) {
if (!id) {
outboxBusy = false;
$scope.onError({
errMsg: 'Cannot remove email from storage without a valid id!'
});
return;
}
// delete email from local storage
var key = dbType + '_' + id;
emailDao._devicestorage.removeList(key, function(err) {
if (err) {
outboxBusy = false;
$scope.onError(err);
return;
}
outbox.count = (outbox.count > 0) ? outbox.count - 1 : outbox.count;
$scope.$apply();
outboxBusy = false;
});
}
};
// //
// Start // Start
// //
@ -145,7 +64,7 @@ define(function(require) {
}); });
// start checking outbox periodically // start checking outbox periodically
startOutboxSender(); outboxBo.startChecking(onOutboxUpdate);
callback(folders); callback(folders);
$scope.$apply(); $scope.$apply();
@ -176,10 +95,21 @@ define(function(require) {
}]); }]);
} }
function startOutboxSender() { // update outbox count
// start periodic checking of outbox
senderIntervalId = setInterval($scope.emptyOutbox, config.checkOutboxInterval); function onOutboxUpdate(err, count) {
if (err) {
$scope.onError(err);
return;
} }
var outbox = _.findWhere($scope.folders, {
type: 'Outbox'
});
outbox.count = count;
$scope.$apply();
}
}; };
// //

View File

@ -0,0 +1,9 @@
define(function() {
'use strict';
var InvitationDAO = function(restDao) {
this._restDao = restDao;
};
return InvitationDAO;
});

View File

@ -47,7 +47,8 @@ function startTests() {
'test/new-unit/read-ctrl-test', 'test/new-unit/read-ctrl-test',
'test/new-unit/navigation-ctrl-test', 'test/new-unit/navigation-ctrl-test',
'test/new-unit/mail-list-ctrl-test', 'test/new-unit/mail-list-ctrl-test',
'test/new-unit/write-ctrl-test' 'test/new-unit/write-ctrl-test',
'test/new-unit/outbox-bo-test'
], function() { ], function() {
//Tests loaded, run tests //Tests loaded, run tests
mocha.run(); mocha.run();

View File

@ -6,25 +6,31 @@ define(function(require) {
mocks = require('angularMocks'), mocks = require('angularMocks'),
NavigationCtrl = require('js/controller/navigation'), NavigationCtrl = require('js/controller/navigation'),
EmailDAO = require('js/dao/email-dao'), EmailDAO = require('js/dao/email-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'), OutboxBO = require('js/bo/outbox'),
appController = require('js/app-controller'); appController = require('js/app-controller');
describe('Navigation Controller unit test', function() { describe('Navigation Controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, deviceStorageMock, tempChrome; var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, hasIdentity, outboxFolder;
beforeEach(function() { beforeEach(function() {
if (window.chrome.identity) { hasIdentity = !! window.chrome.identity;
tempChrome = window.chrome.identity; if (!hasIdentity) {
delete window.chrome.identity; window.chrome.identity = {};
} }
// remember original module to restore later // remember original module to restore later
origEmailDao = appController._emailDao; origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO); emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock; appController._emailDao = emailDaoMock;
outboxBoMock = sinon.createStubInstance(OutboxBO);
appController._outboxBo = outboxBoMock;
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO); // for outbox checking
appController._emailDao._devicestorage = deviceStorageMock; outboxFolder = {
type: 'Outbox'
};
emailDaoMock.imapListFolders.yields(null, [outboxFolder]);
outboxBoMock.startChecking.returns();
angular.module('navigationtest', []); angular.module('navigationtest', []);
mocks.module('navigationtest'); mocks.module('navigationtest');
@ -40,8 +46,8 @@ define(function(require) {
afterEach(function() { afterEach(function() {
// restore the module // restore the module
appController._emailDao = origEmailDao; appController._emailDao = origEmailDao;
if (tempChrome) { if (hasIdentity) {
window.chrome.identity = tempChrome; delete window.chrome.identity;
} }
}); });
@ -53,7 +59,6 @@ define(function(require) {
expect(scope.onError).to.exist; expect(scope.onError).to.exist;
expect(scope.openFolder).to.exist; expect(scope.openFolder).to.exist;
expect(scope.emptyOutbox).to.exist;
}); });
}); });
@ -79,41 +84,17 @@ define(function(require) {
describe('empty outbox', function() { describe('empty outbox', function() {
it('should work', function() { it('should work', function() {
deviceStorageMock.listItems.yields(null, [{ var callback;
id: 1
}, {
id: 2
}, {
id: 3
}]);
emailDaoMock.smtpSend.yields();
deviceStorageMock.removeList.yields();
scope.emptyOutbox(); expect(emailDaoMock.imapListFolders.callCount).to.equal(1);
expect(outboxBoMock.startChecking.callCount).to.equal(1);
expect(deviceStorageMock.listItems.calledOnce).to.be.true; outboxBoMock.startChecking.calledWith(sinon.match(function(cb) {
expect(emailDaoMock.smtpSend.calledThrice).to.be.true; callback = cb;
expect(deviceStorageMock.removeList.calledThrice).to.be.true; }));
});
it('should not work when device storage errors', function() { callback(null, 5);
deviceStorageMock.listItems.yields({errMsg: 'error'}); expect(outboxFolder.count).to.equal(5);
scope.emptyOutbox();
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
});
it('should not work when smtp send fails', function() {
deviceStorageMock.listItems.yields(null, [{
id: 1
}]);
emailDaoMock.smtpSend.yields({errMsg: 'error'});
scope.emptyOutbox();
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
expect(emailDaoMock.smtpSend.calledOnce).to.be.true;
}); });
}); });
}); });

View File

@ -0,0 +1,67 @@
define(function(require) {
'use strict';
var expect = chai.expect,
OutboxBO = require('js/bo/outbox'),
EmailDAO = require('js/dao/email-dao'),
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
InvitationDAO = require('js/dao/invitation-dao');
describe('Outbox Business Object unit test', function() {
var outbox, emailDaoStub, devicestorageStub, invitationDaoStub;
beforeEach(function() {
emailDaoStub = sinon.createStubInstance(EmailDAO);
emailDaoStub._devicestorage = devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
invitationDaoStub = sinon.createStubInstance(InvitationDAO);
outbox = new OutboxBO(emailDaoStub, invitationDaoStub);
});
afterEach(function() {});
describe('init', function() {
it('should work', function() {
expect(outbox).to.exist;
expect(outbox._emailDao).to.equal(emailDaoStub);
expect(outbox._invitationDao).to.equal(invitationDaoStub);
expect(outbox._outboxBusy).to.be.false;
});
});
describe('start/stop checking', function() {
it('should work', function() {
function onOutboxUpdate(err) {
expect(err).to.not.exist;
}
outbox.startChecking(onOutboxUpdate);
expect(outbox._intervalId).to.exist;
outbox.stopChecking();
expect(outbox._intervalId).to.not.exist;
});
});
describe('empty outbox', function() {
it('should work', function(done) {
devicestorageStub.listItems.yields(null, [{
id: '12345'
}]);
emailDaoStub.smtpSend.yields();
devicestorageStub.removeList.yields();
function onOutboxUpdate(err, count) {
expect(err).to.not.exist;
if (count === 0) {
expect(devicestorageStub.listItems.callCount).to.equal(1);
expect(emailDaoStub.smtpSend.callCount).to.equal(1);
expect(devicestorageStub.removeList.callCount).to.equal(1);
done();
}
}
outbox._emptyOutbox(onOutboxUpdate);
});
});
});
});