From f297105c25206e8aaa8c048674eead258a594e8f Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Fri, 9 Aug 2024 22:31:30 +0300 Subject: [PATCH] server: Fix duplicating notes with relationships (closes #308) --- integration-tests/auth.setup.ts | 4 ++-- integration-tests/duplicate.spec.ts | 9 +++++++++ src/becca/entities/abstract_becca_entity.ts | 4 ++-- src/services/notes.ts | 4 +--- 4 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 integration-tests/duplicate.spec.ts diff --git a/integration-tests/auth.setup.ts b/integration-tests/auth.setup.ts index ba2670006..ed27ca648 100644 --- a/integration-tests/auth.setup.ts +++ b/integration-tests/auth.setup.ts @@ -2,8 +2,8 @@ import { test as setup, expect } from '@playwright/test'; const authFile = 'playwright/.auth/user.json'; -const ROOT_URL = "http://localhost:8080"; -const LOGIN_PASSWORD = "eliandoran"; +const ROOT_URL = "http://localhost:8082"; +const LOGIN_PASSWORD = "demo1234"; // Reference: https://playwright.dev/docs/auth#basic-shared-account-in-all-tests diff --git a/integration-tests/duplicate.spec.ts b/integration-tests/duplicate.spec.ts new file mode 100644 index 000000000..7decbd7f0 --- /dev/null +++ b/integration-tests/duplicate.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from '@playwright/test'; + +test("Can duplicate note with broken links", async ({ page }) => { + await page.goto(`http://localhost:8082/#2VammGGdG6Ie`); + await page.locator('.tree-wrapper .fancytree-active').getByText('Note map').click({ button: 'right' }); + await page.getByText('Duplicate subtree').click(); + await expect(page.locator(".toast-body")).toBeHidden(); + await expect(page.locator('.tree-wrapper').getByText('Note map (dup)')).toBeVisible(); +}); \ No newline at end of file diff --git a/src/becca/entities/abstract_becca_entity.ts b/src/becca/entities/abstract_becca_entity.ts index 0016b2a07..45bb2b77d 100644 --- a/src/becca/entities/abstract_becca_entity.ts +++ b/src/becca/entities/abstract_becca_entity.ts @@ -34,7 +34,7 @@ abstract class AbstractBeccaEntity> { isSynced?: boolean; blobId?: string; - protected beforeSaving() { + protected beforeSaving(opts?: {}) { const constructorData = (this.constructor as unknown as ConstructorData); if (!(this as any)[constructorData.primaryKeyName]) { (this as any)[constructorData.primaryKeyName] = utils.newEntityId(); @@ -109,7 +109,7 @@ abstract class AbstractBeccaEntity> { const isNewEntity = !(this as any)[primaryKeyName]; - this.beforeSaving(); + this.beforeSaving(opts); const pojo = this.getPojoToSave(); diff --git a/src/services/notes.ts b/src/services/notes.ts index cee8a8f91..59031b8d9 100644 --- a/src/services/notes.ts +++ b/src/services/notes.ts @@ -817,7 +817,6 @@ function undeleteBranch(branchId: string, deleteId: string, taskContext: TaskCon for (const attributeRow of attributeRows) { // relation might point to a note which hasn't been undeleted yet and would thus throw up - // TODO: skipValidation is not used. new BAttribute(attributeRow).save({skipValidation: true}); } @@ -997,8 +996,7 @@ function duplicateSubtreeInner(origNote: BNote, origBranch: BBranch, newParentNo } // the relation targets may not be created yet, the mapping is pre-generated - // TODO: This used to be `attr.save({skipValidation: true});`, but skipValidation is in beforeSaving. - attr.save(); + attr.save({skipValidation: true}); } for (const childBranch of origNote.getChildBranches()) {