You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-26 22:41:17 +02:00
Desktop,Mobile: Resolves #10073, #10080: Fix conflicts notebook doesn't work with the trash feature (#10104)
This commit is contained in:
2
packages/lib/models/utils/getConflictFolderId.ts
Normal file
2
packages/lib/models/utils/getConflictFolderId.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
export default () => 'c04f1c7c04f1c7c04f1c7c04f1c7c04f';
|
||||
67
packages/lib/models/utils/readOnly.test.ts
Normal file
67
packages/lib/models/utils/readOnly.test.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { ModelType } from '../../BaseModel';
|
||||
import Folder from '../Folder';
|
||||
import ItemChange from '../ItemChange';
|
||||
import Note from '../Note';
|
||||
import { defaultState as defaultShareState, State as ShareState } from '../../services/share/reducer';
|
||||
import { ItemSlice, itemIsReadOnlySync } from './readOnly';
|
||||
import Resource from '../Resource';
|
||||
import shim from '../../shim';
|
||||
import { setupDatabaseAndSynchronizer, simulateReadOnlyShareEnv, switchClient, tempFilePath } from '../../testing/test-utils';
|
||||
import BaseItem from '../BaseItem';
|
||||
|
||||
|
||||
const checkReadOnly = (itemType: ModelType, item: ItemSlice, shareData: ShareState = defaultShareState) => {
|
||||
const syncUserId = '';
|
||||
return itemIsReadOnlySync(itemType, ItemChange.SOURCE_UNSPECIFIED, item, syncUserId, shareData);
|
||||
};
|
||||
|
||||
const createTestResource = async () => {
|
||||
const tempFile = tempFilePath('txt');
|
||||
await shim.fsDriver().writeFile(tempFile, 'Test', 'utf8');
|
||||
const note1 = await Note.save({ title: 'note' });
|
||||
await shim.attachFileToNote(note1, tempFile);
|
||||
};
|
||||
|
||||
describe('readOnly', () => {
|
||||
beforeEach(async () => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
});
|
||||
|
||||
test('trashed items should be marked as read-only', async () => {
|
||||
let folder = await Folder.save({ title: 'Test' });
|
||||
let note = await Note.save({ parent_id: folder.id, title: 'Test note' });
|
||||
|
||||
expect(checkReadOnly(ModelType.Note, note as ItemSlice)).toBe(false);
|
||||
expect(checkReadOnly(ModelType.Folder, folder as ItemSlice)).toBe(false);
|
||||
|
||||
await Folder.delete(folder.id, { toTrash: true });
|
||||
|
||||
// Should be deleted
|
||||
note = await Note.load(note.id);
|
||||
expect(note.deleted_time).not.toBe(0);
|
||||
folder = await Folder.load(folder.id);
|
||||
expect(folder.deleted_time).not.toBe(0);
|
||||
|
||||
expect(checkReadOnly(ModelType.Note, note as ItemSlice)).toBe(true);
|
||||
expect(checkReadOnly(ModelType.Folder, folder as ItemSlice)).toBe(true);
|
||||
});
|
||||
|
||||
test('should support checking if resources are not read-only', async () => {
|
||||
await createTestResource();
|
||||
const resource = (await Resource.all())[0];
|
||||
expect(checkReadOnly(ModelType.Resource, resource)).toBe(false);
|
||||
});
|
||||
|
||||
test('should support checking that resources are read-only due to a share', async () => {
|
||||
await createTestResource();
|
||||
|
||||
const share_id = '123456';
|
||||
let resource = (await Resource.all())[0];
|
||||
resource = await Resource.save({ ...resource, share_id });
|
||||
|
||||
const cleanup = simulateReadOnlyShareEnv(share_id);
|
||||
expect(checkReadOnly(ModelType.Resource, resource, BaseItem.syncShareCache)).toBe(true);
|
||||
cleanup();
|
||||
});
|
||||
});
|
||||
@@ -6,6 +6,7 @@ import { State as ShareState } from '../../services/share/reducer';
|
||||
import ItemChange from '../ItemChange';
|
||||
import Setting from '../Setting';
|
||||
import { checkObjectHasProperties } from '@joplin/utils/object';
|
||||
import isTrashableItem from '../../services/trash/isTrashableItem';
|
||||
|
||||
const logger = Logger.create('models/utils/readOnly');
|
||||
|
||||
@@ -75,13 +76,17 @@ export const checkIfItemCanBeAddedToFolder = async (itemType: ModelType, Folder:
|
||||
// extra `sharePermissionCheckOnly` boolean to do the check for one case or the other. A bit of a
|
||||
// hack but good enough for now.
|
||||
export const itemIsReadOnlySync = (itemType: ModelType, changeSource: number, item: ItemSlice, userId: string, shareState: ShareState, sharePermissionCheckOnly = false): boolean => {
|
||||
checkObjectHasProperties(item, sharePermissionCheckOnly ? ['share_id'] : ['share_id', 'deleted_time']);
|
||||
if (!sharePermissionCheckOnly && isTrashableItem(itemType, item)) {
|
||||
checkObjectHasProperties(item, ['deleted_time']);
|
||||
}
|
||||
|
||||
// Item is in trash
|
||||
if (!sharePermissionCheckOnly && item.deleted_time) return true;
|
||||
|
||||
if (!needsShareReadOnlyChecks(itemType, changeSource, shareState)) return false;
|
||||
|
||||
checkObjectHasProperties(item, ['share_id']);
|
||||
|
||||
// Item is not shared
|
||||
if (!item.share_id) return false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user