Fix "Rename File from Parent Metadata" if target filename exists
Add a unique numeric suffix to the filename, before any extension
This commit is contained in:
parent
c784db88a8
commit
0f743e55c7
|
@ -2416,14 +2416,18 @@ Zotero.Item.prototype.fileExistsCached = function () {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Rename file associated with an attachment
|
* Rename file associated with an attachment
|
||||||
*
|
*
|
||||||
* -1 Destination file exists -- use _force_ to overwrite
|
* @param {String} newName
|
||||||
* -2 Error renaming
|
* @param {Boolean} [overwrite=false] - Overwrite file if one exists
|
||||||
* false Attachment file not found
|
* @param {Boolean} [unique=false] - Add suffix to create unique filename if necessary
|
||||||
|
* @return {Number|false} -- true - Rename successful
|
||||||
|
* -1 - Destination file exists; use _force_ to overwrite
|
||||||
|
* -2 - Error renaming
|
||||||
|
* false - Attachment file not found
|
||||||
*/
|
*/
|
||||||
Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function* (newName, overwrite) {
|
Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function* (newName, overwrite=false, unique=false) {
|
||||||
var origPath = yield this.getFilePathAsync();
|
var origPath = yield this.getFilePathAsync();
|
||||||
if (!origPath) {
|
if (!origPath) {
|
||||||
Zotero.debug("Attachment file not found in renameAttachmentFile()", 2);
|
Zotero.debug("Attachment file not found in renameAttachmentFile()", 2);
|
||||||
|
@ -2442,21 +2446,57 @@ Zotero.Item.prototype.renameAttachmentFile = Zotero.Promise.coroutine(function*
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var destPath = OS.Path.join(OS.Path.dirname(origPath), newName);
|
var parentDir = OS.Path.dirname(origPath);
|
||||||
|
var destPath = OS.Path.join(parentDir, newName);
|
||||||
var destName = OS.Path.basename(destPath);
|
var destName = OS.Path.basename(destPath);
|
||||||
|
// Get root + extension, if there is one
|
||||||
|
var pos = destName.lastIndexOf('.');
|
||||||
|
if (pos > 0) {
|
||||||
|
var root = destName.substr(0, pos);
|
||||||
|
var ext = destName.substr(pos + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var root = destName;
|
||||||
|
}
|
||||||
|
|
||||||
// Update mod time and clear hash so the file syncs
|
// Update mod time and clear hash so the file syncs
|
||||||
// TODO: use an integer counter instead of mod time for change detection
|
// 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
|
// Update mod time first, because it may fail for read-only files on Windows
|
||||||
yield OS.File.setDates(origPath, null, null);
|
yield OS.File.setDates(origPath, null, null);
|
||||||
var result = yield OS.File.move(origPath, destPath, { noOverwrite: !overwrite })
|
var result;
|
||||||
// If no overwriting and file exists, return -1
|
var incr = 0;
|
||||||
.catch(OS.File.Error, function (e) {
|
while (true) {
|
||||||
if (e.becauseExists) {
|
// If filename already exists, add a numeric suffix to the end of the root, before
|
||||||
return -1;
|
// the extension if there is one
|
||||||
|
if (incr) {
|
||||||
|
if (ext) {
|
||||||
|
destName = root + ' ' + (incr + 1) + '.' + ext;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
destName = root + ' ' + (incr + 1);
|
||||||
|
}
|
||||||
|
destPath = OS.Path.join(parentDir, destName);
|
||||||
}
|
}
|
||||||
throw e;
|
|
||||||
});
|
try {
|
||||||
|
result = yield OS.File.move(origPath, destPath, { noOverwrite: !overwrite })
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof OS.File.Error) {
|
||||||
|
if (e.becauseExists) {
|
||||||
|
// Increment number to create unique suffix
|
||||||
|
if (unique) {
|
||||||
|
incr++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If no overwriting or making unique and file exists, return -1
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4541,7 +4541,7 @@ var ZoteroPane = new function()
|
||||||
newName = newName + ext;
|
newName = newName + ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
var renamed = yield item.renameAttachmentFile(newName);
|
var renamed = yield item.renameAttachmentFile(newName, false, true);
|
||||||
if (renamed !== true) {
|
if (renamed !== true) {
|
||||||
Zotero.debug("Could not rename file (" + renamed + ")");
|
Zotero.debug("Could not rename file (" + renamed + ")");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -244,6 +244,93 @@ describe("ZoteroPane", function() {
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe("#renameSelectedAttachmentsFromParents()", function () {
|
||||||
|
it("should rename a linked file", async function () {
|
||||||
|
var oldFilename = 'old.png';
|
||||||
|
var newFilename = 'Test.png';
|
||||||
|
var file = getTestDataDirectory();
|
||||||
|
file.append('test.png');
|
||||||
|
var tmpDir = await getTempDirectory();
|
||||||
|
var oldFile = OS.Path.join(tmpDir, oldFilename);
|
||||||
|
await OS.File.copy(file.path, oldFile);
|
||||||
|
|
||||||
|
var item = createUnsavedDataObject('item');
|
||||||
|
item.setField('title', 'Test');
|
||||||
|
await item.saveTx();
|
||||||
|
|
||||||
|
var attachment = await Zotero.Attachments.linkFromFile({
|
||||||
|
file: oldFile,
|
||||||
|
parentItemID: item.id
|
||||||
|
});
|
||||||
|
await zp.selectItem(attachment.id);
|
||||||
|
|
||||||
|
await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents());
|
||||||
|
assert.equal(attachment.attachmentFilename, newFilename);
|
||||||
|
var path = await attachment.getFilePathAsync();
|
||||||
|
assert.equal(OS.Path.basename(path), newFilename)
|
||||||
|
await OS.File.exists(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use unique name for linked file if target name is taken", async function () {
|
||||||
|
var oldFilename = 'old.png';
|
||||||
|
var newFilename = 'Test.png';
|
||||||
|
var uniqueFilename = 'Test 2.png';
|
||||||
|
var file = getTestDataDirectory();
|
||||||
|
file.append('test.png');
|
||||||
|
var tmpDir = await getTempDirectory();
|
||||||
|
var oldFile = OS.Path.join(tmpDir, oldFilename);
|
||||||
|
await OS.File.copy(file.path, oldFile);
|
||||||
|
// Create file with target filename
|
||||||
|
await Zotero.File.putContentsAsync(OS.Path.join(tmpDir, newFilename), '');
|
||||||
|
|
||||||
|
var item = createUnsavedDataObject('item');
|
||||||
|
item.setField('title', 'Test');
|
||||||
|
await item.saveTx();
|
||||||
|
|
||||||
|
var attachment = await Zotero.Attachments.linkFromFile({
|
||||||
|
file: oldFile,
|
||||||
|
parentItemID: item.id
|
||||||
|
});
|
||||||
|
await zp.selectItem(attachment.id);
|
||||||
|
|
||||||
|
await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents());
|
||||||
|
assert.equal(attachment.attachmentFilename, uniqueFilename);
|
||||||
|
var path = await attachment.getFilePathAsync();
|
||||||
|
assert.equal(OS.Path.basename(path), uniqueFilename)
|
||||||
|
await OS.File.exists(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should use unique name for linked file without extension if target name is taken", async function () {
|
||||||
|
var oldFilename = 'old';
|
||||||
|
var newFilename = 'Test';
|
||||||
|
var uniqueFilename = 'Test 2';
|
||||||
|
var file = getTestDataDirectory();
|
||||||
|
file.append('test.png');
|
||||||
|
var tmpDir = await getTempDirectory();
|
||||||
|
var oldFile = OS.Path.join(tmpDir, oldFilename);
|
||||||
|
await OS.File.copy(file.path, oldFile);
|
||||||
|
// Create file with target filename
|
||||||
|
await Zotero.File.putContentsAsync(OS.Path.join(tmpDir, newFilename), '');
|
||||||
|
|
||||||
|
var item = createUnsavedDataObject('item');
|
||||||
|
item.setField('title', 'Test');
|
||||||
|
await item.saveTx();
|
||||||
|
|
||||||
|
var attachment = await Zotero.Attachments.linkFromFile({
|
||||||
|
file: oldFile,
|
||||||
|
parentItemID: item.id
|
||||||
|
});
|
||||||
|
await zp.selectItem(attachment.id);
|
||||||
|
|
||||||
|
await assert.eventually.isTrue(zp.renameSelectedAttachmentsFromParents());
|
||||||
|
assert.equal(attachment.attachmentFilename, uniqueFilename);
|
||||||
|
var path = await attachment.getFilePathAsync();
|
||||||
|
assert.equal(OS.Path.basename(path), uniqueFilename)
|
||||||
|
await OS.File.exists(path);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("#duplicateSelectedItem()", function () {
|
describe("#duplicateSelectedItem()", function () {
|
||||||
it("should add reverse relations", async function () {
|
it("should add reverse relations", async function () {
|
||||||
await selectLibrary(win);
|
await selectLibrary(win);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user