www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit cbf4876173974398ee921a4739210e4159d092ab
parent 06867d886ee65ae47a8b8714de3878a580286ff2
Author: Dan Stillman <dstillman@zotero.org>
Date:   Fri,  7 Aug 2015 15:36:46 -0400

Fix attachment renaming

Fixes #822

Diffstat:
Mchrome/content/zotero/bindings/attachmentbox.xml | 30+++++++++++++++++++++++++++++-
Mchrome/content/zotero/xpcom/data/item.js | 23+++++++++++------------
Mchrome/content/zotero/xpcom/storage.js | 37+++++++++++++++++--------------------
Mchrome/content/zotero/zoteroPane.js | 2+-
Mtest/tests/itemPaneTest.js | 16++++++++++++++++
Mtest/tests/itemTest.js | 22++++++++++++++++++++++
6 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/chrome/content/zotero/bindings/attachmentbox.xml b/chrome/content/zotero/bindings/attachmentbox.xml @@ -135,7 +135,35 @@ </property> - <!-- Private properties --> + <!-- Methods --> + + <constructor> + <![CDATA[ + this._notifierID = Zotero.Notifier.registerObserver(this, ['item'], 'attachmentbox'); + ]]> + </constructor> + + <destructor> + <![CDATA[ + Zotero.Notifier.unregisterObserver(this._notifierID); + ]]> + </destructor> + + <method name="notify"> + <parameter name="event"/> + <parameter name="type"/> + <parameter name="ids"/> + <body><![CDATA[ + if (event != 'modify' || !this.item || !this.item.id) return; + for (let i = 0; i < ids.length; i++) { + if (ids[i] != this.item.id) { + continue; + } + this.refresh(); + break; + } + ]]></body> + </method> <method name="refresh"> <body><![CDATA[ diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js @@ -2434,7 +2434,7 @@ Zotero.Item.prototype.fileExistsCached = function () { * false Attachment file not found */ Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function* (newName, overwrite) { - var origPath = yield this.getFilePath(); + var origPath = yield this.getFilePathAsync(); if (!origPath) { Zotero.debug("Attachment file not found in renameAttachmentFile()", 2); return false; @@ -2442,20 +2442,19 @@ Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function* try { var origName = OS.Path.basename(origPath); - var origModDate = yield OS.File.stat(origPath).lastModificationDate; + var origModDate = (yield OS.File.stat(origPath)).lastModificationDate; newName = Zotero.File.getValidFileName(newName); - var destPath = OS.Path.join(OS.Path.dirname(origPath), newName); - var destName = OS.Path.basename(destPath); - // Ignore if no change - // - // Note: Just comparing origName to newName isn't reliable - if (origFileName === destName) { + if (origName === newName) { + Zotero.debug("Filename has not changed"); return true; } + var destPath = OS.Path.join(OS.Path.dirname(origPath), newName); + var destName = OS.Path.basename(destPath); + // Update mod time and clear hash so the file syncs // TODO: use an integer counter instead of mod time for change detection // Update mod time first, because it may fail for read-only files on Windows @@ -2475,8 +2474,8 @@ Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function* yield this.relinkAttachmentFile(destPath); yield Zotero.DB.executeTransaction(function* () { - Zotero.Sync.Storage.setSyncedHash(this.id, null, false); - Zotero.Sync.Storage.setSyncState(this.id, Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD); + yield Zotero.Sync.Storage.setSyncedHash(this.id, null, false); + yield Zotero.Sync.Storage.setSyncState(this.id, Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD); }.bind(this)); return true; @@ -2529,7 +2528,7 @@ Zotero.Item.prototype.relinkAttachmentFile = Zotero.Promise.coroutine(function* try { // If selected file isn't in the attachment's storage directory, // copy it in and use that one instead - var storageDir = Zotero.Attachments.getStorageDirectory(this.id).path; + var storageDir = Zotero.Attachments.getStorageDirectory(this).path; if (this.isImportedAttachment() && OS.Path.dirname(path) != storageDir) { // If file with same name already exists in the storage directory, // move it out of the way @@ -2560,7 +2559,7 @@ Zotero.Item.prototype.relinkAttachmentFile = Zotero.Promise.coroutine(function* this.attachmentPath = Zotero.Attachments.getPath(Zotero.File.pathToFile(newPath), linkMode); - yield this.save({ + yield this.saveTx({ skipDateModifiedUpdate: true, skipClientDateModifiedUpdate: skipItemUpdate }); diff --git a/chrome/content/zotero/xpcom/storage.js b/chrome/content/zotero/xpcom/storage.js @@ -499,7 +499,7 @@ Zotero.Sync.Storage = new function () { */ this.getSyncState = function (itemID) { var sql = "SELECT syncState FROM itemAttachments WHERE itemID=?"; - return Zotero.DB.valueQuery(sql, itemID); + return Zotero.DB.valueQueryAsync(sql, itemID); } @@ -507,7 +507,7 @@ Zotero.Sync.Storage = new function () { * @param {Integer} itemID * @param {Integer} syncState Constant from Zotero.Sync.Storage */ - this.setSyncState = function (itemID, syncState) { + this.setSyncState = Zotero.Promise.method(function (itemID, syncState) { switch (syncState) { case this.SYNC_STATE_TO_UPLOAD: case this.SYNC_STATE_TO_DOWNLOAD: @@ -517,13 +517,12 @@ Zotero.Sync.Storage = new function () { break; default: - throw "Invalid sync state '" + syncState - + "' in Zotero.Sync.Storage.setSyncState()" + throw new Error("Invalid sync state '" + syncState); } var sql = "UPDATE itemAttachments SET syncState=? WHERE itemID=?"; - return Zotero.DB.valueQuery(sql, [syncState, itemID]); - } + return Zotero.DB.valueQueryAsync(sql, [syncState, itemID]); + }); /** @@ -572,18 +571,18 @@ Zotero.Sync.Storage = new function () { /** - * @param {Integer} itemID - * @return {String|NULL} File hash, or NULL if never synced + * @param {Integer} itemID + * @return {Promise<String|null|false>} - File hash, null if never synced, if false if + * file doesn't exist */ - this.getSyncedHash = function (itemID) { + this.getSyncedHash = Zotero.Promise.coroutine(function* (itemID) { var sql = "SELECT storageHash FROM itemAttachments WHERE itemID=?"; - var hash = Zotero.DB.valueQuery(sql, itemID); + var hash = yield Zotero.DB.valueQueryAsync(sql, itemID); if (hash === false) { - throw "Item " + itemID + " not found in " - + "Zotero.Sync.Storage.getSyncedHash()"; + throw new Error("Item " + itemID + " not found"); } return hash; - } + }) /** @@ -592,24 +591,22 @@ Zotero.Sync.Storage = new function () { * @param {Boolean} [updateItem=FALSE] Update dateModified field of * attachment item */ - this.setSyncedHash = function (itemID, hash, updateItem) { + this.setSyncedHash = Zotero.Promise.coroutine(function* (itemID, hash, updateItem) { if (hash !== null && hash.length != 32) { throw ("Invalid file hash '" + hash + "' in Zotero.Storage.setSyncedHash()"); } - Zotero.DB.beginTransaction(); + Zotero.DB.requireTransaction(); var sql = "UPDATE itemAttachments SET storageHash=? WHERE itemID=?"; - Zotero.DB.valueQuery(sql, [hash, itemID]); + yield Zotero.DB.queryAsync(sql, [hash, itemID]); if (updateItem) { // Update item date modified so the new mod time will be synced var sql = "UPDATE items SET clientDateModified=? WHERE itemID=?"; - Zotero.DB.query(sql, [Zotero.DB.transactionDateTime, itemID]); + yield Zotero.DB.queryAsync(sql, [Zotero.DB.transactionDateTime, itemID]); } - - Zotero.DB.commitTransaction(); - } + }); /** diff --git a/chrome/content/zotero/zoteroPane.js b/chrome/content/zotero/zoteroPane.js @@ -4104,7 +4104,7 @@ var ZoteroPane = new function() newName = newName + ext; } - var renamed = item.renameAttachmentFile(newName); + var renamed = yield item.renameAttachmentFile(newName); if (renamed !== true) { Zotero.debug("Could not rename file (" + renamed + ")"); continue; diff --git a/test/tests/itemPaneTest.js b/test/tests/itemPaneTest.js @@ -29,6 +29,22 @@ describe("Item pane", function () { }) }) + describe("Attachment pane", function () { + it("should refresh on file rename", function* () { + var file = getTestDataDirectory(); + file.append('test.png'); + var item = yield Zotero.Attachments.importFromFile({ + file: file + }); + var newName = 'test2.png'; + yield item.renameAttachmentFile(newName); + + var itemBox = doc.getElementById('zotero-attachment-box'); + var label = itemBox._id('fileName'); + assert.equal(label.value, newName); + }) + }) + describe("Note pane", function () { it("should refresh on note update", function* () { var item = new Zotero.Item('note'); diff --git a/test/tests/itemTest.js b/test/tests/itemTest.js @@ -539,6 +539,28 @@ describe("Zotero.Item", function () { }); }) + describe("#renameAttachmentFile()", function () { + it("should rename an attached file", function* () { + var file = getTestDataDirectory(); + file.append('test.png'); + var item = yield Zotero.Attachments.importFromFile({ + file: file + }); + var newName = 'test2.png'; + yield item.renameAttachmentFile(newName); + assert.equal(item.attachmentFilename, newName); + var path = yield item.getFilePathAsync(); + assert.equal(OS.Path.basename(path), newName) + yield OS.File.exists(path); + + assert.equal( + (yield Zotero.Sync.Storage.getSyncState(item.id)), + Zotero.Sync.Storage.SYNC_STATE_TO_UPLOAD + ); + assert.isNull(yield Zotero.Sync.Storage.getSyncedHash(item.id)); + }) + }) + describe("#setTags", function () { it("should save an array of tags in API JSON format", function* () { var tags = [