diff --git a/src/js/app-router.js b/src/js/app-router.js index 090d554..545ea2f 100644 --- a/src/js/app-router.js +++ b/src/js/app-router.js @@ -19,7 +19,7 @@ var AppRouter = Backbone.Router.extend({ var jsonDao = new app.dao.LawnchairDAO(window); var crypto = new app.crypto.Crypto(window, util); var cloudstorage = new app.dao.CloudStorage(window, $); - var devicestorage = new app.dao.DeviceStorage(crypto, jsonDao, null); + var devicestorage = new app.dao.DeviceStorage(util, crypto, jsonDao, null); this.emailDao = new app.dao.EmailDAO(_, crypto, devicestorage, cloudstorage); var loginView = new app.view.LoginView({dao: this.emailDao}); diff --git a/src/js/crypto/util.js b/src/js/crypto/util.js index a5b8660..5edd0dc 100644 --- a/src/js/crypto/util.js +++ b/src/js/crypto/util.js @@ -66,6 +66,14 @@ app.crypto.Util = function(window, uuid) { return outList; }; + /** + * Parse a date string with the following format "1900-01-31 18:17:53" + */ + this.parseDate = function(str) { + var parts = str.match(/(\d+)/g); + return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]); + }; + /** * Converts a binary String (e.g. from the FileReader Api) to an ArrayBuffer * @param str [String] a binary string with integer values (0..255) per character diff --git a/src/js/dao/devicestorage.js b/src/js/dao/devicestorage.js index 32d6f07..3b131af 100644 --- a/src/js/dao/devicestorage.js +++ b/src/js/dao/devicestorage.js @@ -6,7 +6,7 @@ * through transparent encryption. If not, the crypto API is * used to encrypt data on the fly before persisting via a JSON store. */ -app.dao.DeviceStorage = function(crypto, jsonDao, sqlcipherDao) { +app.dao.DeviceStorage = function(util, crypto, jsonDao, sqlcipherDao) { /** * Stores a list of encrypted items in the object store @@ -14,11 +14,20 @@ app.dao.DeviceStorage = function(crypto, jsonDao, sqlcipherDao) { * @param type [String] The type of item to be persisted e.g. 'email' */ this.storeEcryptedList = function(list, type, callback) { - var i, items = []; + var i, date, key, items = []; // format items for batch storing in dao for (i = 0; i < list.length; i++) { - items.push({ key:crypto.emailAddress + '_' + type + '_' + list[i].id, object:list[i] }); + + // put date in key if available... for easy querying + if (list[i].sentDate) { + date = util.parseDate(list[i].sentDate); + key = crypto.emailAddress + '_' + type + '_' + date.getTime() + '_' + list[i].id; + } else { + key = crypto.emailAddress + '_' + type + '_' + list[i].id; + } + + items.push({ key:key, object:list[i] }); } jsonDao.batch(items, function() { diff --git a/src/js/dao/lawnchair-dao.js b/src/js/dao/lawnchair-dao.js index 96d7e8c..23ca52c 100644 --- a/src/js/dao/lawnchair-dao.js +++ b/src/js/dao/lawnchair-dao.js @@ -45,7 +45,7 @@ app.dao.LawnchairDAO = function(window) { * @param num [Number] The number of items to fetch (null means fetch all) */ this.list = function(type, offset, num, callback) { - var i, list = [], matchingKeys =[], parts, date; + var i, list = [], matchingKeys = [], parts, timeStr, time; Lawnchair(function() { var self = this; @@ -58,7 +58,27 @@ app.dao.LawnchairDAO = function(window) { if (keys[i].indexOf(type) === 0) { matchingKeys.push(keys[i]); } - } + } + + // sort keys by type and date + matchingKeys = _.sortBy(matchingKeys, function(key) { + parts = key.split('_'); + timeStr = parts[parts.length-2]; + time = parseInt(timeStr, 10); + return time; + }); + + // if num is null, list all items + num = (num !== null) ? num : matchingKeys.length; + + // set window of items to fetch + if (offset + num < matchingKeys.length) { + matchingKeys = matchingKeys.splice(matchingKeys.length - offset - num, num); + } else if (offset + num >= matchingKeys.length && offset < matchingKeys.length) { + matchingKeys = matchingKeys.splice(0, matchingKeys.length - offset); + } else { + matchingKeys = []; + } // return if there are no matching keys if (matchingKeys.length === 0) { @@ -70,27 +90,6 @@ app.dao.LawnchairDAO = function(window) { self.get(matchingKeys, function(matchingList) { for (i = 0; i < matchingList.length; i++) { list.push(matchingList[i].object); - } - - // sort items by date - if (list[0].sentDate) { - list = _.sortBy(list, function(item) { - parts = item.sentDate.match(/(\d+)/g); - date = new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]); - return date.getTime(); - }); - } - - // if num is null, list all items - num = (num !== null) ? num : list.length; - - // set window of items to fetch - if (offset + num < list.length) { - list = list.splice(list.length - offset - num, num); - } else if (offset + num >= list.length && offset < list.length) { - list = list.splice(0, list.length - offset); - } else { - list = []; } // return only the interval between offset and num diff --git a/test/test-data.js b/test/test-data.js index 0325382..5548025 100644 --- a/test/test-data.js +++ b/test/test-data.js @@ -13,7 +13,7 @@ var TestData = function() { from:'john@from.com', to:['jack@to.com'], subject: 'Important stuff ' + i, - sentDate: (1900 + i) + '-03-13 18:17:53', + sentDate: (1971 + i) + '-03-13 18:17:53', body: bigAssString }); diff --git a/test/unit/devicestorage-test.js b/test/unit/devicestorage-test.js index 557a209..0feb0d3 100644 --- a/test/unit/devicestorage-test.js +++ b/test/unit/devicestorage-test.js @@ -12,7 +12,7 @@ asyncTest("Init", 3, function() { devicestorage_test.util = new app.crypto.Util(window, uuid); devicestorage_test.jsonDao = new app.dao.LawnchairDAO(window); devicestorage_test.crypto = new app.crypto.Crypto(window, devicestorage_test.util); - devicestorage_test.storage = new app.dao.DeviceStorage(devicestorage_test.crypto, devicestorage_test.jsonDao, null); + devicestorage_test.storage = new app.dao.DeviceStorage(devicestorage_test.util, devicestorage_test.crypto, devicestorage_test.jsonDao, null); ok(devicestorage_test.storage, 'DeviceStorageDAO'); // generate test data diff --git a/test/unit/email-dao-test.js b/test/unit/email-dao-test.js index da48457..d5d360b 100644 --- a/test/unit/email-dao-test.js +++ b/test/unit/email-dao-test.js @@ -12,7 +12,7 @@ asyncTest("Init", 2, function() { var util = new app.crypto.Util(window, uuid); var jsonDao = new app.dao.LawnchairDAO(window); emaildao_test.crypto = new app.crypto.Crypto(window, util); - emaildao_test.storage = new app.dao.DeviceStorage(emaildao_test.crypto, jsonDao, null); + emaildao_test.storage = new app.dao.DeviceStorage(util, emaildao_test.crypto, jsonDao, null); // cloud storage stub var cloudstorageStub = { getUserSecretKey: function(emailAdress, callback) { callback(); } diff --git a/test/unit/util-test.js b/test/unit/util-test.js index 7f5654a..d01f738 100644 --- a/test/unit/util-test.js +++ b/test/unit/util-test.js @@ -26,6 +26,12 @@ test("random", 3, function() { ok(str.length === 16, "Random length"); }); +test("Parse Date", 1, function() { + var util = new app.crypto.Util(window, uuid); + var date = util.parseDate('1900-01-31 18:17:53'); + ok(date, "Date: " + date); +}); + test("String -> ArrayBuffer -> String", 3, function() { var util = new app.crypto.Util(window);