mirror of
https://github.com/laurent22/joplin.git
synced 2024-11-27 08:21:03 +02:00
Handle sync when resource has been edited
This commit is contained in:
parent
0e5a0fdbe5
commit
1852d9291d
@ -3,7 +3,7 @@
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { setupDatabase, allSyncTargetItemsEncrypted, kvStore, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, checkThrowAsync, asyncTest } = require('test-utils.js');
|
||||
const { setupDatabase, allSyncTargetItemsEncrypted, resourceFetcher, kvStore, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, checkThrowAsync, asyncTest } = require('test-utils.js');
|
||||
const { shim } = require('lib/shim.js');
|
||||
const fs = require('fs-extra');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
@ -991,6 +991,42 @@ describe('synchronizer', function() {
|
||||
expect(fileContentEqual(resourcePath1, resourcePath1_2)).toBe(true);
|
||||
}));
|
||||
|
||||
it('should sync resource blob changes', asyncTest(async () => {
|
||||
const tempFile = `${__dirname}/tmp/test.txt`;
|
||||
await shim.fsDriver().writeFile(tempFile, '1234', 'utf8');
|
||||
const folder1 = await Folder.save({ title: 'folder1' });
|
||||
const note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||
await shim.attachFileToNote(note1, tempFile);
|
||||
await synchronizer().start();
|
||||
|
||||
await switchClient(2);
|
||||
|
||||
await synchronizer().start();
|
||||
await resourceFetcher().start();
|
||||
await resourceFetcher().waitForAllFinished();
|
||||
let resource1_2 = (await Resource.all())[0];
|
||||
const modFile = `${__dirname}/tmp/test_mod.txt`;
|
||||
await shim.fsDriver().writeFile(modFile, '1234 MOD', 'utf8');
|
||||
await shim.updateResourceBlob(resource1_2.id, modFile);
|
||||
const originalSize = resource1_2.size;
|
||||
resource1_2 = (await Resource.all())[0];
|
||||
const newSize = resource1_2.size;
|
||||
expect(originalSize).toBe(4);
|
||||
expect(newSize).toBe(8);
|
||||
await synchronizer().start();
|
||||
|
||||
await switchClient(1);
|
||||
|
||||
await synchronizer().start();
|
||||
await resourceFetcher().start();
|
||||
await resourceFetcher().waitForAllFinished();
|
||||
const resource1_1 = (await Resource.all())[0];
|
||||
expect(resource1_1.size).toBe(newSize);
|
||||
const resource1_1Path = Resource.fullPath(resource1_1);
|
||||
const newContent = await shim.fsDriver().readFile(resource1_1Path, 'utf8');
|
||||
expect(newContent).toBe('1234 MOD');
|
||||
}));
|
||||
|
||||
it('should upload decrypted items to sync target after encryption disabled', asyncTest(async () => {
|
||||
Setting.setValue('encryption.enabled', true);
|
||||
const masterKey = await loadEncryptionMasterKey();
|
||||
|
@ -37,6 +37,7 @@ const EncryptionService = require('lib/services/EncryptionService.js');
|
||||
const DecryptionWorker = require('lib/services/DecryptionWorker.js');
|
||||
const ResourceService = require('lib/services/ResourceService.js');
|
||||
const RevisionService = require('lib/services/RevisionService.js');
|
||||
const ResourceFetcher = require('lib/services/ResourceFetcher.js');
|
||||
const KvStore = require('lib/services/KvStore.js');
|
||||
const WebDavApi = require('lib/WebDavApi');
|
||||
const DropboxApi = require('lib/DropboxApi');
|
||||
@ -47,6 +48,7 @@ const encryptionServices_ = [];
|
||||
const revisionServices_ = [];
|
||||
const decryptionWorkers_ = [];
|
||||
const resourceServices_ = [];
|
||||
const resourceFetchers_ = [];
|
||||
const kvStores_ = [];
|
||||
let fileApi_ = null;
|
||||
let currentClient_ = 1;
|
||||
@ -250,6 +252,7 @@ async function setupDatabaseAndSynchronizer(id = null) {
|
||||
decryptionWorkers_[id] = new DecryptionWorker();
|
||||
decryptionWorkers_[id].setEncryptionService(encryptionServices_[id]);
|
||||
resourceServices_[id] = new ResourceService();
|
||||
resourceFetchers_[id] = new ResourceFetcher(() => { return synchronizers_[id].api(); });
|
||||
kvStores_[id] = new KvStore();
|
||||
|
||||
await fileApi().clearRoot();
|
||||
@ -294,6 +297,11 @@ function resourceService(id = null) {
|
||||
return resourceServices_[id];
|
||||
}
|
||||
|
||||
function resourceFetcher(id = null) {
|
||||
if (id === null) id = currentClient_;
|
||||
return resourceFetchers_[id];
|
||||
}
|
||||
|
||||
async function loadEncryptionMasterKey(id = null, useExisting = false) {
|
||||
const service = encryptionService(id);
|
||||
|
||||
@ -546,4 +554,4 @@ class TestApp extends BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { kvStore, resourceService, allSyncTargetItemsEncrypted, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, TestApp };
|
||||
module.exports = { kvStore, resourceService, resourceFetcher, allSyncTargetItemsEncrypted, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync, encryptionService, loadEncryptionMasterKey, fileContentEqual, decryptionWorker, asyncTest, currentClientId, id, ids, sortedIds, at, createNTestNotes, createNTestFolders, createNTestTags, TestApp };
|
||||
|
@ -521,7 +521,7 @@ class BaseApplication {
|
||||
DecryptionWorker.instance().scheduleStart();
|
||||
}
|
||||
|
||||
if (this.hasGui() && action.type === 'SYNC_CREATED_RESOURCE') {
|
||||
if (this.hasGui() && action.type === 'SYNC_CREATED_OR_UPDATED_RESOURCE') {
|
||||
ResourceFetcher.instance().autoAddResources();
|
||||
}
|
||||
|
||||
|
@ -110,8 +110,16 @@ class Resource extends BaseItem {
|
||||
}
|
||||
|
||||
static async isReady(resource) {
|
||||
const r = await this.readyStatus(resource);
|
||||
return r === 'ok';
|
||||
}
|
||||
|
||||
static async readyStatus(resource) {
|
||||
const ls = await this.localState(resource);
|
||||
return resource && ls.fetch_status === Resource.FETCH_STATUS_DONE && !resource.encryption_blob_encrypted;
|
||||
if (!resource) return 'notFound';
|
||||
if (ls.fetch_status !== Resource.FETCH_STATUS_DONE) return 'notDownloaded';
|
||||
if (resource.encryption_blob_encrypted) return 'encrypted';
|
||||
return 'ok';
|
||||
}
|
||||
|
||||
// For resources, we need to decrypt the item (metadata) and the resource binary blob.
|
||||
|
@ -207,6 +207,9 @@ function shimInit() {
|
||||
|
||||
shim.updateResourceBlob = async function(resourceId, newBlobFilePath) {
|
||||
const resource = await Resource.load(resourceId);
|
||||
const readyStatus = await Resource.readyStatus(resourceId);
|
||||
if (readyStatus !== 'ok') throw new Error(`Cannot set resource blob because resource is not ready. Status: ${readyStatus}`);
|
||||
|
||||
const fileStat = await shim.fsDriver().stat(newBlobFilePath);
|
||||
await shim.fsDriver().copy(newBlobFilePath, Resource.fullPath(resource));
|
||||
|
||||
|
@ -718,9 +718,9 @@ class Synchronizer {
|
||||
if (action == 'createLocal') options.isNew = true;
|
||||
if (action == 'updateLocal') options.oldItem = local;
|
||||
|
||||
const creatingNewResource = content.type_ == BaseModel.TYPE_RESOURCE && action == 'createLocal';
|
||||
const creatingOrUpdatingResource = content.type_ == BaseModel.TYPE_RESOURCE && (action == 'createLocal' || action == 'updateLocal');
|
||||
|
||||
if (creatingNewResource) {
|
||||
if (creatingOrUpdatingResource) {
|
||||
if (content.size >= this.maxResourceSize()) {
|
||||
await handleCannotSyncItem(ItemClass, syncTargetId, content, `File "${content.title}" is larger than allowed ${this.maxResourceSize()} bytes. Beyond this limit, the mobile app would crash.`, BaseItem.SYNC_ITEM_LOCATION_REMOTE);
|
||||
continue;
|
||||
@ -731,7 +731,7 @@ class Synchronizer {
|
||||
|
||||
await ItemClass.save(content, options);
|
||||
|
||||
if (creatingNewResource) this.dispatch({ type: 'SYNC_CREATED_RESOURCE', id: content.id });
|
||||
if (creatingOrUpdatingResource) this.dispatch({ type: 'SYNC_CREATED_OR_UPDATED_RESOURCE', id: content.id });
|
||||
|
||||
if (!hasAutoEnabledEncryption && content.type_ === BaseModel.TYPE_MASTER_KEY && !masterKeysBefore) {
|
||||
hasAutoEnabledEncryption = true;
|
||||
|
@ -151,7 +151,7 @@ const generalMiddleware = store => next => async (action) => {
|
||||
DecryptionWorker.instance().scheduleStart();
|
||||
}
|
||||
|
||||
if (action.type === 'SYNC_CREATED_RESOURCE') {
|
||||
if (action.type === 'SYNC_CREATED_OR_UPDATED_RESOURCE') {
|
||||
ResourceFetcher.instance().autoAddResources();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user