Update linked attachment base directory code
- Replace nsIFile and persistent descriptors with OS.File and string paths - Add tests for base dir settings
This commit is contained in:
parent
9e356a7e63
commit
88627adcdb
3 changed files with 217 additions and 78 deletions
|
@ -323,69 +323,77 @@ Zotero_Preferences.Advanced = {
|
|||
|
||||
|
||||
Zotero_Preferences.Attachment_Base_Directory = {
|
||||
choosePath: function () {
|
||||
// Get existing base directory
|
||||
var oldBasePath = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (oldBasePath) {
|
||||
var oldBasePathFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
getPath: function () {
|
||||
var oldPath = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (oldPath) {
|
||||
try {
|
||||
oldBasePathFile.persistentDescriptor = oldBasePath;
|
||||
return OS.Path.normalize(oldPath);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
Components.utils.reportError(e);
|
||||
oldBasePathFile = null;
|
||||
Zotero.logError(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
choosePath: Zotero.Promise.coroutine(function* () {
|
||||
var oldPath = this.getPath();
|
||||
|
||||
//Prompt user to choose new base path
|
||||
if (oldPath) {
|
||||
var oldPathFile = Zotero.File.pathToFile(oldPath);
|
||||
}
|
||||
var nsIFilePicker = Components.interfaces.nsIFilePicker;
|
||||
var fp = Components.classes["@mozilla.org/filepicker;1"]
|
||||
.createInstance(nsIFilePicker);
|
||||
if (oldBasePathFile) {
|
||||
fp.displayDirectory = oldBasePathFile;
|
||||
if (oldPathFile) {
|
||||
fp.displayDirectory = oldPathFile;
|
||||
}
|
||||
fp.init(window, Zotero.getString('attachmentBasePath.selectDir'), nsIFilePicker.modeGetFolder);
|
||||
fp.appendFilters(nsIFilePicker.filterAll);
|
||||
if (fp.show() != nsIFilePicker.returnOK) {
|
||||
return false;
|
||||
}
|
||||
var newBasePathFile = fp.file;
|
||||
var newPath = OS.Path.normalize(fp.file.path);
|
||||
|
||||
if (oldBasePathFile && oldBasePathFile.equals(newBasePathFile)) {
|
||||
if (oldPath && oldPath == newPath) {
|
||||
Zotero.debug("Base directory hasn't changed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return changePath(newPath);
|
||||
}),
|
||||
|
||||
|
||||
changePath: Zotero.Promise.coroutine(function* (basePath) {
|
||||
// Find all current attachments with relative attachment paths
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '"
|
||||
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
|
||||
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var oldRelativeAttachmentIDs = Zotero.DB.columnQuery(sql, params) || [];
|
||||
var oldRelativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
|
||||
|
||||
//Find all attachments on the new base path
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=?";
|
||||
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var allAttachments = Zotero.DB.columnQuery(sql,params);
|
||||
var allAttachments = yield Zotero.DB.columnQueryAsync(sql, params);
|
||||
var newAttachmentPaths = {};
|
||||
var numNewAttachments = 0;
|
||||
var numOldAttachments = 0;
|
||||
var attachmentFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
for (let i=0; i<allAttachments.length; i++) {
|
||||
let attachmentID = allAttachments[i];
|
||||
let attachmentPath;
|
||||
let relPath = false
|
||||
|
||||
try {
|
||||
let attachment = Zotero.Items.get(attachmentID);
|
||||
let attachment = yield Zotero.Items.getAsync(attachmentID);
|
||||
// This will return FALSE for relative paths if base directory
|
||||
// isn't currently set
|
||||
attachmentFile = attachment.getFile(false, true);
|
||||
attachmentPath = attachment.getFilePath();
|
||||
// Get existing relative path
|
||||
let path = attachment.attachmentPath;
|
||||
if (path.indexOf(Zotero.Attachments.BASE_PATH_PLACEHOLDER) == 0) {
|
||||
relPath = path.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
|
||||
let storedPath = attachment.attachmentPath;
|
||||
if (storedPath.startsWith(Zotero.Attachments.BASE_PATH_PLACEHOLDER)) {
|
||||
relPath = storedPath.substr(Zotero.Attachments.BASE_PATH_PLACEHOLDER.length);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -397,10 +405,7 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
// If a file with the same relative path exists within the new base directory,
|
||||
// don't touch the attachment, since it will continue to work
|
||||
if (relPath) {
|
||||
let relFile = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
relFile.setRelativeDescriptor(newBasePathFile, relPath);
|
||||
if (relFile.exists()) {
|
||||
if (yield OS.File.exists(OS.Path.join(basePath, relPath))) {
|
||||
numNewAttachments++;
|
||||
continue;
|
||||
}
|
||||
|
@ -409,15 +414,14 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
// Files within the new base directory need to be updated to use
|
||||
// relative paths (or, if the new base directory is an ancestor or
|
||||
// descendant of the old one, new relative paths)
|
||||
if (attachmentFile && Zotero.File.directoryContains(newBasePathFile, attachmentFile)) {
|
||||
newAttachmentPaths[attachmentID] = relPath
|
||||
? attachmentFile.persistentDescriptor : null;
|
||||
if (attachmentPath && Zotero.File.directoryContains(basePath, attachmentPath)) {
|
||||
newAttachmentPaths[attachmentID] = relPath ? attachmentPath : null;
|
||||
numNewAttachments++;
|
||||
}
|
||||
// Existing relative attachments not within the new base directory
|
||||
// will be converted to absolute paths
|
||||
else if (relPath && oldBasePathFile) {
|
||||
newAttachmentPaths[attachmentID] = attachmentFile.persistentDescriptor;
|
||||
else if (relPath && this.getPath()) {
|
||||
newAttachmentPaths[attachmentID] = attachmentPath;
|
||||
numOldAttachments++;
|
||||
}
|
||||
}
|
||||
|
@ -475,50 +479,41 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
|
||||
// Set new data directory
|
||||
Zotero.debug("Setting new base directory");
|
||||
Zotero.Prefs.set('baseAttachmentPath', newBasePathFile.persistentDescriptor);
|
||||
Zotero.Prefs.set('baseAttachmentPath', basePath);
|
||||
Zotero.Prefs.set('saveRelativeAttachmentPath', true);
|
||||
// Resave all attachments on base path (so that their paths become relative)
|
||||
// and all other relative attachments (so that their paths become absolute)
|
||||
for (let id in newAttachmentPaths) {
|
||||
let attachment = Zotero.Items.get(id);
|
||||
if (newAttachmentPaths[id]) {
|
||||
attachment.attachmentPath = newAttachmentPaths[id];
|
||||
attachment.save({
|
||||
skipDateModifiedUpdate: true
|
||||
});
|
||||
yield Zotero.Utilities.Internal.forEachChunkAsync(
|
||||
Object.keys(newAttachmentPaths),
|
||||
100,
|
||||
function (chunk) {
|
||||
return Zotero.DB.executeTransaction(function* () {
|
||||
for (let id of chunk) {
|
||||
let attachment = Zotero.Items.get(id);
|
||||
if (newAttachmentPaths[id]) {
|
||||
attachment.attachmentPath = newAttachmentPaths[id];
|
||||
}
|
||||
else {
|
||||
attachment.attachmentPath = attachment.getFilePath();
|
||||
}
|
||||
yield attachment.save({
|
||||
skipDateModifiedUpdate: true
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
attachment.updateAttachmentPath();
|
||||
}
|
||||
}
|
||||
return newBasePathFile.persistentDescriptor;
|
||||
},
|
||||
|
||||
|
||||
getPath: function (asFile) {
|
||||
var desc = Zotero.Prefs.get('baseAttachmentPath');
|
||||
if (desc == '') {
|
||||
return asFile ? null : '';
|
||||
}
|
||||
);
|
||||
|
||||
var file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
try {
|
||||
file.persistentDescriptor = desc;
|
||||
}
|
||||
catch (e) {
|
||||
return asFile ? null : '';
|
||||
}
|
||||
return asFile ? file : file.path;
|
||||
},
|
||||
return true;
|
||||
}),
|
||||
|
||||
|
||||
clearPath: function () {
|
||||
clearPath: Zotero.Promise.coroutine(function* () {
|
||||
// Find all current attachments with relative paths
|
||||
var sql = "SELECT itemID FROM itemAttachments WHERE linkMode=? AND path LIKE '"
|
||||
+ Zotero.Attachments.BASE_PATH_PLACEHOLDER + "%'";
|
||||
var params = [Zotero.Attachments.LINK_MODE_LINKED_FILE];
|
||||
var relativeAttachmentIDs = Zotero.DB.columnQuery(sql, params) || [];
|
||||
var relativeAttachmentIDs = yield Zotero.DB.columnQueryAsync(sql, params);
|
||||
|
||||
// Prompt for confirmation
|
||||
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||
|
@ -562,26 +557,40 @@ Zotero_Preferences.Attachment_Base_Directory = {
|
|||
// attachments so that their absolute paths are stored
|
||||
Zotero.debug('Clearing base directory');
|
||||
Zotero.Prefs.set('saveRelativeAttachmentPath', false);
|
||||
for (var i=0; i<relativeAttachmentIDs.length; i++) {
|
||||
Zotero.Items.get(relativeAttachmentIDs[i]).updateAttachmentPath();
|
||||
}
|
||||
|
||||
yield Zotero.Utilities.Internal.forEachChunkAsync(
|
||||
relativeAttachmentIDs,
|
||||
100,
|
||||
function (chunk) {
|
||||
return Zotero.DB.executeTransaction(function* () {
|
||||
for (let id of chunk) {
|
||||
let attachment = yield Zotero.Items.getAsync(id);
|
||||
attachment.attachmentPath = attachment.getFilePath();
|
||||
yield attachment.save({
|
||||
skipDateModifiedUpdate: true
|
||||
});
|
||||
}
|
||||
}.bind(this));
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
Zotero.Prefs.set('baseAttachmentPath', '');
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
updateUI: function () {
|
||||
updateUI: Zotero.Promise.coroutine(function* () {
|
||||
var filefield = document.getElementById('baseAttachmentPath');
|
||||
var file = this.getPath(true);
|
||||
filefield.file = file;
|
||||
if (file) {
|
||||
filefield.label = file.path;
|
||||
var path = Zotero.Prefs.get('baseAttachmentPath');
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
if (yield OS.File.exists(path)) {
|
||||
filefield.file = Zotero.File.pathToFile(path);
|
||||
filefield.label = path;
|
||||
}
|
||||
else {
|
||||
filefield.label = '';
|
||||
}
|
||||
|
||||
document.getElementById('resetBasePath').disabled = !Zotero.Prefs.get('baseAttachmentPath');
|
||||
}
|
||||
document.getElementById('resetBasePath').disabled = !path;
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -154,7 +154,8 @@
|
|||
readonly="true"
|
||||
flex="1"
|
||||
tabindex="-1"/>
|
||||
<button label="&zotero.preferences.attachmentBaseDir.selectBasePath;"
|
||||
<button id="baseAttachmentPathButton"
|
||||
label="&zotero.preferences.attachmentBaseDir.selectBasePath;"
|
||||
oncommand="Zotero_Preferences.Attachment_Base_Directory.choosePath()"/>
|
||||
</hbox>
|
||||
|
||||
|
|
129
test/tests/preferences_advancedTest.js
Normal file
129
test/tests/preferences_advancedTest.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
describe("Advanced Preferences", function () {
|
||||
describe("Files & Folders", function () {
|
||||
describe("Linked Attachment Base Directory", function () {
|
||||
var setBaseDirectory = Zotero.Promise.coroutine(function* (basePath) {
|
||||
var win = yield loadWindow("chrome://zotero/content/preferences/preferences.xul", {
|
||||
pane: 'zotero-prefpane-advanced',
|
||||
tabIndex: 1
|
||||
});
|
||||
|
||||
// Wait for tab to load
|
||||
var doc = win.document;
|
||||
var prefwindow = doc.documentElement;
|
||||
var defer = Zotero.Promise.defer();
|
||||
var pane = doc.getElementById('zotero-prefpane-advanced');
|
||||
if (!pane.loaded) {
|
||||
pane.addEventListener('paneload', function () {
|
||||
defer.resolve();
|
||||
})
|
||||
yield defer.promise;
|
||||
}
|
||||
|
||||
var promise = waitForDialog();
|
||||
yield win.Zotero_Preferences.Attachment_Base_Directory.changePath(basePath);
|
||||
yield promise;
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
var clearBaseDirectory = Zotero.Promise.coroutine(function* (basePath) {
|
||||
var win = yield loadWindow("chrome://zotero/content/preferences/preferences.xul", {
|
||||
pane: 'zotero-prefpane-advanced',
|
||||
tabIndex: 1
|
||||
});
|
||||
|
||||
// Wait for tab to load
|
||||
var doc = win.document;
|
||||
var prefwindow = doc.documentElement;
|
||||
var defer = Zotero.Promise.defer();
|
||||
var pane = doc.getElementById('zotero-prefpane-advanced');
|
||||
if (!pane.loaded) {
|
||||
pane.addEventListener('paneload', function () {
|
||||
defer.resolve();
|
||||
})
|
||||
yield defer.promise;
|
||||
}
|
||||
|
||||
var promise = waitForDialog();
|
||||
yield win.Zotero_Preferences.Attachment_Base_Directory.clearPath();
|
||||
yield promise;
|
||||
|
||||
win.close();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
Zotero.Prefs.clear('baseAttachmentPath');
|
||||
Zotero.Prefs.clear('saveRelativeAttachmentPath');
|
||||
});
|
||||
|
||||
it("should set new base directory", function* () {
|
||||
var basePath = getTestDataDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
assert.equal(Zotero.Prefs.get('baseAttachmentPath'), basePath);
|
||||
assert.isTrue(Zotero.Prefs.get('saveRelativeAttachmentPath'));
|
||||
})
|
||||
|
||||
it("should clear base directory", function* () {
|
||||
var basePath = getTestDataDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
yield clearBaseDirectory();
|
||||
|
||||
assert.equal(Zotero.Prefs.get('baseAttachmentPath'), '');
|
||||
assert.isFalse(Zotero.Prefs.get('saveRelativeAttachmentPath'));
|
||||
})
|
||||
|
||||
it("should change absolute path of linked attachment under new base dir to prefixed path", function* () {
|
||||
var file = getTestDataDirectory();
|
||||
file.append('test.png');
|
||||
var attachment = yield Zotero.Attachments.linkFromFile({ file });
|
||||
assert.equal(attachment.attachmentPath, file.path);
|
||||
|
||||
var basePath = getTestDataDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
|
||||
assert.equal(
|
||||
attachment.attachmentPath,
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
|
||||
);
|
||||
})
|
||||
|
||||
it("should change prefixed path to absolute when changing base directory", function* () {
|
||||
var basePath = getTestDataDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
|
||||
var file = getTestDataDirectory();
|
||||
file.append('test.png');
|
||||
var attachment = yield Zotero.Attachments.linkFromFile({ file });
|
||||
assert.equal(
|
||||
attachment.attachmentPath,
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
|
||||
);
|
||||
|
||||
var basePath = Zotero.getTempDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
|
||||
assert.equal(attachment.attachmentPath, file.path);
|
||||
})
|
||||
|
||||
it("should change prefixed path to absolute when clearing base directory", function* () {
|
||||
var basePath = getTestDataDirectory().path;
|
||||
yield setBaseDirectory(basePath);
|
||||
|
||||
var file = getTestDataDirectory();
|
||||
file.append('test.png');
|
||||
var attachment = yield Zotero.Attachments.linkFromFile({ file });
|
||||
assert.equal(
|
||||
attachment.attachmentPath,
|
||||
Zotero.Attachments.BASE_PATH_PLACEHOLDER + 'test.png'
|
||||
);
|
||||
|
||||
yield clearBaseDirectory();
|
||||
|
||||
assert.equal(Zotero.Prefs.get('baseAttachmentPath'), '');
|
||||
assert.isFalse(Zotero.Prefs.get('saveRelativeAttachmentPath'));
|
||||
|
||||
assert.equal(attachment.attachmentPath, file.path);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue