1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-10 22:11:50 +02:00

Server: Fix notebooks remain shared after being permanently deleted by the share owner (#12583)

This commit is contained in:
Henry Heino
2025-08-06 02:37:38 -07:00
committed by GitHub
parent 3f75d770f7
commit 2a216f1e61
2 changed files with 52 additions and 3 deletions

View File

@@ -916,11 +916,11 @@ export default class ItemModel extends BaseModel<Item> {
const userShare = await this.models().shareUser().byShareAndUserId(share.id, userId); const userShare = await this.models().shareUser().byShareAndUserId(share.id, userId);
if (userShare) { if (userShare) {
// Leave the share // Leave the share, but keep the notebook for the owner
await this.models().shareUser().delete(userShare.id); await this.models().shareUser().delete(userShare.id);
} else if (share.owner_id === userId) { } else if (share.owner_id === userId) {
// Delete the share // Delete the share for everyone
await this.models().share().delete(share.id); await this.delete(item.id);
} }
} else { } else {
await this.delete(item.id); await this.delete(item.id);

View File

@@ -502,6 +502,55 @@ describe('shares.folder', () => {
// Test deleting the share, but not the root folder // Test deleting the share, but not the root folder
}); });
test.each([
{
label: 'not delete a shared root folder when deleted by the recipient',
deleteFromOwner: false,
},
{
label: 'delete a shared root folder when deleted by the owner',
deleteFromOwner: true,
},
])('should $label', async ({ deleteFromOwner }) => {
const { user: owner, session: session1 } = await createUserAndSession(1);
const { user: recipient, session: session2 } = await createUserAndSession(2);
await shareFolderWithUser(session1.id, session2.id, '0000000TEST0FOLDER01000000000000', {
'0000000TEST0FOLDER01000000000000': { },
});
const folderItem = await models().item().loadByJopId(owner.id, '0000000TEST0FOLDER01000000000000');
const itemIdsForUser = async (userId: string) => {
return (await models().item().children(userId)).items.map(item => item.id);
};
if (deleteFromOwner) {
await models().item().deleteForUser(owner.id, folderItem);
// Deleting from the owner should delete the folder for both clients
expect(await itemIdsForUser(owner.id)).toHaveLength(0);
expect(await itemIdsForUser(recipient.id)).toHaveLength(0);
// Share should be removed
expect(await models().share().all()).toHaveLength(0);
} else {
// Delete from the recipient account
await models().item().deleteForUser(recipient.id, folderItem);
// Deleting from the recipient should delete the folder for just the recipient
expect(await itemIdsForUser(owner.id)).toContain(folderItem.id);
expect(await itemIdsForUser(recipient.id)).toHaveLength(0);
// The share should still exist since the owner hasn't cancelled the
// share.
expect(await models().share().all()).toHaveLength(1);
}
// The notebook should no longer be shared with anyone.
expect(await models().shareUser().all()).toHaveLength(0);
});
test('should unshare when the share object is deleted', async () => { test('should unshare when the share object is deleted', async () => {
const { user: user1, session: session1 } = await createUserAndSession(1); const { user: user1, session: session1 } = await createUserAndSession(1);
const { user: user2, session: session2 } = await createUserAndSession(2); const { user: user2, session: session2 } = await createUserAndSession(2);