list and store only encrypted emails in local db

This commit is contained in:
Tankred Hase 2013-09-28 19:04:15 +02:00
parent 7eb885c679
commit 267e889872
8 changed files with 178 additions and 35 deletions

View File

@ -52,6 +52,7 @@ define(function(require) {
// development
createDummyMails(function(emails) {
updateStatus('Last update: ', new Date());
$scope.emails = emails;
$scope.select($scope.emails[0]);
});

View File

@ -30,7 +30,6 @@ define(function(require) {
callback();
return;
}
// validate type
if (!type) {
callback({
@ -41,16 +40,7 @@ define(function(require) {
// format items for batch storing in dao
list.forEach(function(i) {
// put uid in key if available... for easy querying
if (i.uid) {
key = type + '_' + i.uid;
} else if (i.sentDate && i.id) {
key = type + '_' + i.sentDate + '_' + i.id;
} else if (i.id) {
key = type + '_' + i.id;
} else {
key = type;
}
key = createKey(i, type);
items.push({
key: key,
@ -63,6 +53,23 @@ define(function(require) {
});
};
/**
* Deletes items of a certain type from storage
*/
DeviceStorageDAO.prototype.removeList = function(type, callback) {
// validate type
if (!type) {
callback({
errMsg: 'Type is not set!'
});
return;
}
jsonDao.removeList(type, function() {
callback();
});
};
/**
* List stored items of a given type
* @param type [String] The type of item e.g. 'email'
@ -70,10 +77,18 @@ define(function(require) {
* @param num [Number] The number of items to fetch (null means fetch all)
*/
DeviceStorageDAO.prototype.listItems = function(type, offset, num, callback) {
// fetch all items of a certain type from the data-store
jsonDao.list(type, offset, num, function(encryptedList) {
callback(null, encryptedList);
// validate type
if (!type || typeof offset === 'undefined' || typeof num === 'undefined') {
callback({
errMsg: 'Args not is not set!'
});
return;
}
// fetch all items of a certain type from the data-store
jsonDao.list(type, offset, num, function(matchingList) {
callback(null, matchingList);
});
};
@ -84,5 +99,26 @@ define(function(require) {
jsonDao.clear(callback);
};
//
// helper functions
//
function createKey(i, type) {
var key;
// put uid in key if available... for easy querying
if (i.uid) {
key = type + '_' + i.uid;
} else if (i.sentDate && i.id) {
key = type + '_' + i.sentDate + '_' + i.id;
} else if (i.id) {
key = type + '_' + i.id;
} else {
key = type;
}
return key;
}
return DeviceStorageDAO;
});

View File

@ -400,7 +400,8 @@ define(function(require) {
* High level sync operation for the delta from the user's IMAP inbox
*/
EmailDAO.prototype.imapSync = function(options, callback) {
var self = this;
var self = this,
dbType = 'email_' + options.folder;
// validate options
if (!options.folder || typeof options.offset === 'undefined' || typeof options.num === 'undefined') {
@ -411,13 +412,22 @@ define(function(require) {
}
fetchList(options, function(emails) {
// persist encrypted list in device storage
self._devicestorage.storeList(emails, 'email_' + options.folder, function() {
callback();
// delete old items from db
self._devicestorage.removeList(dbType, function(err) {
if (err) {
callback(err);
return;
}
// persist encrypted list in device storage
self._devicestorage.storeList(emails, dbType, function(err) {
callback(err);
});
});
});
function fetchList(folder, callback) {
var encryptedList = [];
// fetch imap folder's message list
self.imapListMessages({
folder: options.folder,
@ -429,8 +439,15 @@ define(function(require) {
return;
}
// find encrypted messages by subject
emails.forEach(function(i) {
if (i.subject === str.subject) {
encryptedList.push(i);
}
});
// fetch message bodies
fetchBodies(emails, folder, function(messages) {
fetchBodies(encryptedList, folder, function(messages) {
callback(messages);
});
});
@ -439,6 +456,11 @@ define(function(require) {
function fetchBodies(messageList, folder, callback) {
var emails = [];
if (messageList.length < 1) {
callback(emails);
return;
}
var after = _.after(messageList.length, function() {
callback(emails);
});

View File

@ -1,7 +1,7 @@
/**
* Handles generic caching of JSON objects in a lawnchair adapter
*/
define(['lawnchair', 'lawnchairSQL', 'lawnchairIDB'], function(Lawnchair) {
define(['underscore', 'lawnchair', 'lawnchairSQL', 'lawnchairIDB'], function(_, Lawnchair) {
'use strict';
var self = {},
@ -118,6 +118,35 @@ define(['lawnchair', 'lawnchairSQL', 'lawnchairIDB'], function(Lawnchair) {
db.remove(key, callback);
};
/**
* Removes an object liter from local storage by its key (delete)
*/
self.removeList = function(type, callback) {
var matchingKeys = [],
after;
// get all keys
db.keys(function(keys) {
// check if key begins with type
keys.forEach(function(key) {
if (key.indexOf(type) === 0) {
matchingKeys.push(key);
}
});
if (matchingKeys.length < 1) {
callback();
return;
}
// remove all matching keys
after = _.after(matchingKeys.length, callback);
_.each(matchingKeys, function(key) {
db.remove(key, after);
});
});
};
/**
* Clears the whole local storage cache
*/

View File

@ -35,8 +35,8 @@
}
ul {
padding: 0 $padding-horizontal;
max-height: 100%;
padding: 0 $padding-horizontal 90px $padding-horizontal;
height: 100%;
overflow-y: scroll;
}

View File

@ -367,7 +367,7 @@ define(function(require) {
});
describe('IMAP: sync messages to local storage', function() {
it('should work', function(done) {
it('should not list unencrypted messages', function(done) {
imapClientStub.listMessages.yields(null, [{
uid: 413,
}, {
@ -376,6 +376,35 @@ define(function(require) {
imapClientStub.getMessage.yields(null, {
body: 'asdf'
});
devicestorageStub.removeList.yields();
devicestorageStub.storeList.yields();
emailDao.imapSync({
folder: 'INBOX',
offset: 0,
num: 2
}, function(err) {
expect(err).to.not.exist;
expect(imapClientStub.listMessages.calledOnce).to.be.true;
expect(imapClientStub.getMessage.called).to.be.false;
expect(devicestorageStub.removeList.calledOnce).to.be.true;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});
});
it('should work', function(done) {
imapClientStub.listMessages.yields(null, [{
uid: 413,
subject: app.string.subject
}, {
uid: 414,
subject: app.string.subject
}]);
imapClientStub.getMessage.yields(null, {
body: 'asdf'
});
devicestorageStub.removeList.yields();
devicestorageStub.storeList.yields();
emailDao.imapSync({
@ -386,6 +415,7 @@ define(function(require) {
expect(err).to.not.exist;
expect(imapClientStub.listMessages.calledOnce).to.be.true;
expect(imapClientStub.getMessage.calledTwice).to.be.true;
expect(devicestorageStub.removeList.calledOnce).to.be.true;
expect(devicestorageStub.storeList.calledOnce).to.be.true;
done();
});

View File

@ -71,7 +71,6 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/devicestorag
});
asyncTest("List items", 4, function() {
var senderPubkeys = [devicestorageTest.generatedKeypair.publicKey];
var offset = 2,
@ -94,4 +93,13 @@ define(['underscore', 'cryptoLib/util', 'js/crypto/crypto', 'js/dao/devicestorag
});
});
asyncTest("Delete List items", 1, function() {
// list encrypted items from storage
storage.removeList('email_inbox', function(err) {
ok(!err);
start();
});
});
});

View File

@ -21,12 +21,18 @@ define(['js/dao/lawnchair-dao'], function(jsonDao) {
});
});
asyncTest("CRUD object literal", 4, function() {
asyncTest("CRUD object literal", 5, function() {
var key = 'type_asdf';
var key = 'type_1';
var data = {
name: 'testName',
type: 'testType'
name: 'testName1',
type: 'testType1'
};
var key2 = 'type_2';
var data2 = {
name: 'testName2',
type: 'testType2'
};
// create
@ -49,17 +55,28 @@ define(['js/dao/lawnchair-dao'], function(jsonDao) {
jsonDao.read(key, function(updated) {
equal(updated.name, newName, 'Update');
// delete
jsonDao.remove(key, function() {
// persist 2nd type
jsonDao.persist(key2, data2, function() {
// should read empty
jsonDao.read(key, function(lastRead) {
equal(lastRead, undefined, 'Delete');
// delete all items of 2nd type
jsonDao.removeList(key2, function() {
start();
jsonDao.list('type', 0, null, function(newList) {
ok(newList.length === 1, 'List');
// delete
jsonDao.remove(key, function() {
// should read empty
jsonDao.read(key, function(lastRead) {
equal(lastRead, undefined, 'Delete');
start();
});
});
});
});
});
});
});
});