diff --git a/chrome/content/zotero/xpcom/data/library.js b/chrome/content/zotero/xpcom/data/library.js index 60edb9b85..335c632bc 100644 --- a/chrome/content/zotero/xpcom/data/library.js +++ b/chrome/content/zotero/xpcom/data/library.js @@ -34,8 +34,18 @@ Zotero.Library = function(params = {}) { this._hasCollections = null; this._hasSearches = null; - Zotero.Utilities.assignProps(this, params, ['libraryType', 'editable', - 'filesEditable', 'libraryVersion', 'lastSync']); + Zotero.Utilities.assignProps( + this, + params, + [ + 'libraryType', + 'editable', + 'filesEditable', + 'libraryVersion', + 'lastSync', + 'lastStorageSync' + ] + ); // Return a proxy so that we can disable the object once it's deleted return new Proxy(this, { @@ -53,7 +63,9 @@ Zotero.Library = function(params = {}) { */ // DB columns Zotero.defineProperty(Zotero.Library, '_dbColumns', { - value: Object.freeze(['type', 'editable', 'filesEditable', 'version', 'lastSync']) + value: Object.freeze([ + 'type', 'editable', 'filesEditable', 'version', 'lastSync', 'lastStorageSync' + ]) }); // Converts DB column name to (internal) object property @@ -139,6 +151,12 @@ Zotero.defineProperty(Zotero.Library.prototype, 'lastSync', { get: function() this._get('_libraryLastSync') }); +Zotero.defineProperty(Zotero.Library.prototype, 'lastStorageSync', { + get: function () this._get('_libraryLastStorageSync'), + set: function (v) this._set('_libraryLastStorageSync', v) +}); + + Zotero.defineProperty(Zotero.Library.prototype, 'name', { get: function() { if (this._libraryType == 'user') { @@ -233,6 +251,7 @@ Zotero.Library.prototype._set = function(prop, val) { if (val != -1 && val < this._libraryVersion) throw new Error(prop + ' cannot decrease'); break; + case '_libraryLastSync': if (!val) { val = false; @@ -243,6 +262,18 @@ Zotero.Library.prototype._set = function(prop, val) { val = new Date(Math.floor(val.getTime()/1000) * 1000); } break; + + case '_libraryLastStorageSync': + if (parseInt(val) != val) { + Zotero.debug(val); + throw new Error("timestamp must be an integer"); + } + if (val > 9999999999) { + Zotero.debug(val); + throw new Error("timestamp must be in seconds"); + } + val = parseInt(val); + break; } if (this[prop] == val) return; // Unchanged @@ -267,7 +298,8 @@ Zotero.Library.prototype._loadDataFromRow = function(row) { this._libraryEditable = !!row._libraryEditable; this._libraryFilesEditable = !!row._libraryFilesEditable; this._libraryVersion = row._libraryVersion; - this._libraryLastSync = row._libraryLastSync != 0 ? new Date(row._libraryLastSync * 1000) : false; + this._libraryLastSync = row._libraryLastSync !== 0 ? new Date(row._libraryLastSync * 1000) : false; + this._libraryLastStorageSync = row._libraryLastStorageSync || false; this._hasCollections = !!row.hasCollections; this._hasSearches = !!row.hasSearches; @@ -391,8 +423,7 @@ Zotero.Library.prototype._saveData = Zotero.Promise.coroutine(function* (env) { // convert to integer val = val ? Math.floor(val.getTime() / 1000) : 0; } - - if (typeof val == 'boolean') { + else if (typeof val == 'boolean') { val = val ? 1 : 0; } diff --git a/chrome/content/zotero/xpcom/schema.js b/chrome/content/zotero/xpcom/schema.js index 54cf5b2a2..59f39f621 100644 --- a/chrome/content/zotero/xpcom/schema.js +++ b/chrome/content/zotero/xpcom/schema.js @@ -1943,10 +1943,10 @@ Zotero.Schema = new function(){ yield _updateDBVersion('compatibility', 1); yield Zotero.DB.queryAsync("ALTER TABLE libraries RENAME TO librariesOld"); - yield Zotero.DB.queryAsync("CREATE TABLE libraries (\n libraryID INTEGER PRIMARY KEY,\n type TEXT NOT NULL,\n editable INT NOT NULL,\n filesEditable INT NOT NULL,\n version INT NOT NULL DEFAULT 0,\n lastsync INT NOT NULL DEFAULT 0\n)"); + yield Zotero.DB.queryAsync("CREATE TABLE libraries (\n libraryID INTEGER PRIMARY KEY,\n type TEXT NOT NULL,\n editable INT NOT NULL,\n filesEditable INT NOT NULL,\n version INT NOT NULL DEFAULT 0,\n lastSync INT NOT NULL DEFAULT 0,\n lastStorageSync INT NOT NULL DEFAULT 0\n)"); yield Zotero.DB.queryAsync("INSERT INTO libraries (libraryID, type, editable, filesEditable) VALUES (1, 'user', 1, 1)"); yield Zotero.DB.queryAsync("INSERT INTO libraries (libraryID, type, editable, filesEditable) VALUES (4, 'publications', 1, 1)"); - yield Zotero.DB.queryAsync("INSERT INTO libraries SELECT libraryID, libraryType, editable, filesEditable, 0, 0 FROM librariesOld JOIN groups USING (libraryID)"); + yield Zotero.DB.queryAsync("INSERT INTO libraries SELECT libraryID, libraryType, editable, filesEditable, 0, 0, 0 FROM librariesOld JOIN groups USING (libraryID)"); yield Zotero.DB.queryAsync("INSERT OR IGNORE INTO syncObjectTypes VALUES (7, 'setting')"); yield Zotero.DB.queryAsync("DELETE FROM version WHERE schema IN ('userdata2', 'userdata3')"); diff --git a/resource/schema/userdata.sql b/resource/schema/userdata.sql index 8263741e1..3a47ac67d 100644 --- a/resource/schema/userdata.sql +++ b/resource/schema/userdata.sql @@ -261,7 +261,8 @@ CREATE TABLE libraries ( editable INT NOT NULL, filesEditable INT NOT NULL, version INT NOT NULL DEFAULT 0, - lastSync INT NOT NULL DEFAULT 0 + lastSync INT NOT NULL DEFAULT 0, + lastStorageSync INT NOT NULL DEFAULT 0 ); CREATE TABLE users ( diff --git a/test/tests/libraryTest.js b/test/tests/libraryTest.js index 548e69ad0..1b4882ec4 100644 --- a/test/tests/libraryTest.js +++ b/test/tests/libraryTest.js @@ -63,6 +63,26 @@ describe("Zotero.Library", function() { }); }); + describe("#lastStorageSync", function () { + it("should set and get a time in seconds", function* () { + var library = yield createGroup(); + var time = Math.round(new Date().getTime() / 1000); + library.lastStorageSync = time; + yield library.saveTx(); + + var dbTime = yield Zotero.DB.valueQueryAsync( + "SELECT lastStorageSync FROM libraries WHERE libraryID=?", library.libraryID + ); + assert.equal(dbTime, time); + assert.equal(library.lastStorageSync, time); + }); + + it("should throw if setting time in milliseconds", function* () { + var library = Zotero.Libraries.userLibrary; + assert.throws(() => library.lastStorageSync = new Date().getTime(), "timestamp must be in seconds"); + }) + }) + describe("#editable", function() { it("should return editable status", function() { let library = Zotero.Libraries.get(Zotero.Libraries.userLibraryID);