mirror of
https://github.com/moparisthebest/mail
synced 2024-11-22 17:02: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'),
|
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
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'),
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
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/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();
|
||||||
|
@ -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;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
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