mirror of
https://github.com/moparisthebest/mail
synced 2024-11-26 02:42:17 -05:00
refactor outbox code into business object
This commit is contained in:
parent
525fb94e05
commit
e71ee471f6
@ -13,6 +13,8 @@ define(function(require) {
|
||||
LawnchairDAO = require('js/dao/lawnchair-dao'),
|
||||
KeychainDAO = require('js/dao/keychain-dao'),
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
InvitationDAO = require('js/dao/invitation-dao'),
|
||||
OutboxBO = require('js/bo/outbox'),
|
||||
PGP = require('js/crypto/pgp'),
|
||||
config = require('js/app-config').config;
|
||||
require('cordova');
|
||||
@ -153,7 +155,7 @@ define(function(require) {
|
||||
*/
|
||||
self.init = function(userId, token, callback) {
|
||||
var auth, imapOptions, smtpOptions, certificate,
|
||||
lawnchairDao, restDao, pubkeyDao,
|
||||
lawnchairDao, restDao, pubkeyDao, invitationDao,
|
||||
keychain, imapClient, smtpClient, pgp, userStorage, xhr;
|
||||
|
||||
// fetch pinned local ssl certificate
|
||||
@ -211,6 +213,9 @@ define(function(require) {
|
||||
userStorage = new DeviceStorageDAO(lawnchairDao);
|
||||
self._emailDao = new EmailDAO(keychain, imapClient, smtpClient, pgp, userStorage);
|
||||
|
||||
invitationDao = new InvitationDAO(restDao);
|
||||
self._outboxBo = new OutboxBO(self._emailDao, invitationDao);
|
||||
|
||||
// init email dao
|
||||
var account = {
|
||||
emailAddress: userId,
|
||||
|
100
src/js/bo/outbox.js
Normal file
100
src/js/bo/outbox.js
Normal 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;
|
||||
});
|
@ -5,9 +5,7 @@ define(function(require) {
|
||||
appController = require('js/app-controller'),
|
||||
errorUtil = require('js/util/error'),
|
||||
_ = require('underscore'),
|
||||
config = require('js/app-config').config,
|
||||
emailDao, senderIntervalId,
|
||||
outboxBusy = false;
|
||||
emailDao, outboxBo;
|
||||
|
||||
//
|
||||
// Controller
|
||||
@ -20,6 +18,7 @@ define(function(require) {
|
||||
errorUtil.attachHandler($scope);
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
outboxBo = appController._outboxBo;
|
||||
|
||||
//
|
||||
// scope functions
|
||||
@ -37,86 +36,6 @@ define(function(require) {
|
||||
$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
|
||||
//
|
||||
@ -145,7 +64,7 @@ define(function(require) {
|
||||
});
|
||||
|
||||
// start checking outbox periodically
|
||||
startOutboxSender();
|
||||
outboxBo.startChecking(onOutboxUpdate);
|
||||
|
||||
callback(folders);
|
||||
$scope.$apply();
|
||||
@ -176,10 +95,21 @@ define(function(require) {
|
||||
}]);
|
||||
}
|
||||
|
||||
function startOutboxSender() {
|
||||
// start periodic checking of outbox
|
||||
senderIntervalId = setInterval($scope.emptyOutbox, config.checkOutboxInterval);
|
||||
// update outbox count
|
||||
|
||||
function onOutboxUpdate(err, count) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var outbox = _.findWhere($scope.folders, {
|
||||
type: 'Outbox'
|
||||
});
|
||||
outbox.count = count;
|
||||
$scope.$apply();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
9
src/js/dao/invitation-dao.js
Normal file
9
src/js/dao/invitation-dao.js
Normal file
@ -0,0 +1,9 @@
|
||||
define(function() {
|
||||
'use strict';
|
||||
|
||||
var InvitationDAO = function(restDao) {
|
||||
this._restDao = restDao;
|
||||
};
|
||||
|
||||
return InvitationDAO;
|
||||
});
|
@ -47,7 +47,8 @@ function startTests() {
|
||||
'test/new-unit/read-ctrl-test',
|
||||
'test/new-unit/navigation-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() {
|
||||
//Tests loaded, run tests
|
||||
mocha.run();
|
||||
|
@ -6,25 +6,31 @@ define(function(require) {
|
||||
mocks = require('angularMocks'),
|
||||
NavigationCtrl = require('js/controller/navigation'),
|
||||
EmailDAO = require('js/dao/email-dao'),
|
||||
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
OutboxBO = require('js/bo/outbox'),
|
||||
appController = require('js/app-controller');
|
||||
|
||||
describe('Navigation Controller unit test', function() {
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, deviceStorageMock, tempChrome;
|
||||
var scope, ctrl, origEmailDao, emailDaoMock, outboxBoMock, hasIdentity, outboxFolder;
|
||||
|
||||
beforeEach(function() {
|
||||
if (window.chrome.identity) {
|
||||
tempChrome = window.chrome.identity;
|
||||
delete window.chrome.identity;
|
||||
hasIdentity = !! window.chrome.identity;
|
||||
if (!hasIdentity) {
|
||||
window.chrome.identity = {};
|
||||
}
|
||||
// remember original module to restore later
|
||||
origEmailDao = appController._emailDao;
|
||||
|
||||
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||
appController._emailDao = emailDaoMock;
|
||||
outboxBoMock = sinon.createStubInstance(OutboxBO);
|
||||
appController._outboxBo = outboxBoMock;
|
||||
|
||||
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
|
||||
appController._emailDao._devicestorage = deviceStorageMock;
|
||||
// for outbox checking
|
||||
outboxFolder = {
|
||||
type: 'Outbox'
|
||||
};
|
||||
emailDaoMock.imapListFolders.yields(null, [outboxFolder]);
|
||||
outboxBoMock.startChecking.returns();
|
||||
|
||||
angular.module('navigationtest', []);
|
||||
mocks.module('navigationtest');
|
||||
@ -40,8 +46,8 @@ define(function(require) {
|
||||
afterEach(function() {
|
||||
// restore the module
|
||||
appController._emailDao = origEmailDao;
|
||||
if (tempChrome) {
|
||||
window.chrome.identity = tempChrome;
|
||||
if (hasIdentity) {
|
||||
delete window.chrome.identity;
|
||||
}
|
||||
});
|
||||
|
||||
@ -53,7 +59,6 @@ define(function(require) {
|
||||
|
||||
expect(scope.onError).to.exist;
|
||||
expect(scope.openFolder).to.exist;
|
||||
expect(scope.emptyOutbox).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
@ -79,41 +84,17 @@ define(function(require) {
|
||||
|
||||
describe('empty outbox', function() {
|
||||
it('should work', function() {
|
||||
deviceStorageMock.listItems.yields(null, [{
|
||||
id: 1
|
||||
}, {
|
||||
id: 2
|
||||
}, {
|
||||
id: 3
|
||||
}]);
|
||||
emailDaoMock.smtpSend.yields();
|
||||
deviceStorageMock.removeList.yields();
|
||||
var callback;
|
||||
|
||||
scope.emptyOutbox();
|
||||
expect(emailDaoMock.imapListFolders.callCount).to.equal(1);
|
||||
expect(outboxBoMock.startChecking.callCount).to.equal(1);
|
||||
|
||||
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
|
||||
expect(emailDaoMock.smtpSend.calledThrice).to.be.true;
|
||||
expect(deviceStorageMock.removeList.calledThrice).to.be.true;
|
||||
});
|
||||
outboxBoMock.startChecking.calledWith(sinon.match(function(cb) {
|
||||
callback = cb;
|
||||
}));
|
||||
|
||||
it('should not work when device storage errors', function() {
|
||||
deviceStorageMock.listItems.yields({errMsg: 'error'});
|
||||
|
||||
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;
|
||||
callback(null, 5);
|
||||
expect(outboxFolder.count).to.equal(5);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
67
test/new-unit/outbox-bo-test.js
Normal file
67
test/new-unit/outbox-bo-test.js
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user