Download remotely updated files in "as needed" file sync mode

Previously, files updated remotely wouldn't be downloaded in "as needed"
mode if a copy of the file already existed locally and could only be
re-downloaded by deleting the file via Show File.

This causes remotely modified files that exist locally to be downloaded
at sync time, even in "as needed" mode, by marking them as
"force_download". While this might not be ideal for people who use "as
needed" to limit data transfer, it's better for people who use it simply
to limit local storage, and ending up with an outdated file while
offline seems worse than a little bit of extra data transfer.

In the future, we'll likely also provide ways to explicitly download and
remove files, so keeping chosen files in sync makes sense.

Files modified remotely before this change (which were marked as
"to_download" instead of "force_download") won't be downloaded as sync
time in "as needed" mode, but they'll now be re-downloaded on open.

Fixes #1322
This commit is contained in:
Dan Stillman 2020-03-07 02:25:44 -05:00
parent 76a1535a60
commit d389a71280
5 changed files with 171 additions and 44 deletions

View file

@ -745,7 +745,7 @@ describe("Zotero.Sync.Data.Local", function() {
assert.isTrue(library.storageDownloadNeeded);
})
it("should mark updated attachment items for download", function* () {
it("should mark remotely updated attachment item for forced download", function* () {
var library = Zotero.Libraries.userLibrary;
var libraryID = library.id;
Zotero.Sync.Storage.Local.setModeForLibrary(libraryID, 'zfs');
@ -771,10 +771,43 @@ describe("Zotero.Sync.Data.Local", function() {
'item', libraryID, [json], { stopOnError: true }
);
assert.equal(item.attachmentSyncState, Zotero.Sync.Storage.Local.SYNC_STATE_TO_DOWNLOAD);
assert.equal(item.attachmentSyncState, Zotero.Sync.Storage.Local.SYNC_STATE_FORCE_DOWNLOAD);
assert.isTrue(library.storageDownloadNeeded);
})
it("should mark remotely updated attachment item with missing file for download", async function () {
var library = Zotero.Libraries.userLibrary;
var libraryID = library.id;
Zotero.Sync.Storage.Local.setModeForLibrary(libraryID, 'zfs');
var item = await importFileAttachment('test.png');
item.version = 5;
item.synced = true;
await item.saveTx();
// Set file as synced
item.attachmentSyncedModificationTime = await item.attachmentModificationTime;
item.attachmentSyncedHash = await item.attachmentHash;
item.attachmentSyncState = "in_sync";
await item.saveTx({ skipAll: true });
// Delete file
await OS.File.remove(item.getFilePath());
// Simulate download of version with updated attachment
var json = item.toResponseJSON();
json.version = 10;
json.data.version = 10;
json.data.md5 = '57f8a4fda823187b91e1191487b87fe6';
json.data.mtime = new Date().getTime() + 10000;
await Zotero.Sync.Data.Local.processObjectsFromJSON(
'item', libraryID, [json], { stopOnError: true }
);
assert.equal(item.attachmentSyncState, Zotero.Sync.Storage.Local.SYNC_STATE_TO_DOWNLOAD);
assert.isTrue(library.storageDownloadNeeded);
});
it("should ignore attachment metadata when resolving metadata conflict", function* () {
var libraryID = Zotero.Libraries.userLibraryID;
Zotero.Sync.Storage.Local.setModeForLibrary(libraryID, 'zfs');
@ -806,7 +839,7 @@ describe("Zotero.Sync.Data.Local", function() {
);
assert.equal(item.getField('title'), newTitle);
assert.equal(item.attachmentSyncState, Zotero.Sync.Storage.Local.SYNC_STATE_TO_DOWNLOAD);
assert.equal(item.attachmentSyncState, Zotero.Sync.Storage.Local.SYNC_STATE_FORCE_DOWNLOAD);
})
it("should roll back partial object changes on error", function* () {