From 074dee811d471fa94f5108daf9a11024ffc3cd61 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Tue, 31 Oct 2023 22:37:31 +0700 Subject: [PATCH] UBERF-4132: Fix unexpected delete of documents in query (#3921) Signed-off-by: Andrey Sobolev --- models/tracker/src/migration.ts | 45 ++++++++++++++++++- packages/query/src/index.ts | 5 ++- .../src/components/CreateIssue.svelte | 11 +++-- plugins/tracker/src/index.ts | 1 + server-plugins/tracker-resources/src/index.ts | 14 ++++-- 5 files changed, 65 insertions(+), 11 deletions(-) diff --git a/models/tracker/src/migration.ts b/models/tracker/src/migration.ts index 1812b4316b..ed5b47d434 100644 --- a/models/tracker/src/migration.ts +++ b/models/tracker/src/migration.ts @@ -16,12 +16,14 @@ import core, { DOMAIN_TX, Data, + Ref, SortingOrder, Status, TxCollectionCUD, TxCreateDoc, TxOperations, - TxUpdateDoc + TxUpdateDoc, + toIdMap } from '@hcengineering/core' import { MigrateOperation, @@ -227,6 +229,43 @@ async function fixRemainingTime (client: MigrationClient): Promise { ) } +async function fixParentsSpace (client: MigrationClient): Promise { + while (true) { + const issues = await client.find( + DOMAIN_TASK, + { _class: tracker.class.Issue, 'parents.space': { $exists: false }, parents: { $exists: true, $ne: [] } }, + { limit: 1000 } + ) + + const parentIds: Set> = new Set() + for (const i of issues) { + for (const p of i.parents ?? []) { + parentIds.add(p.parentId) + } + } + + const parentIssues = toIdMap( + await client.find(DOMAIN_TASK, { _class: tracker.class.Issue, _id: { $in: Array.from(parentIds) } }) + ) + + for (const issue of issues) { + await client.update( + DOMAIN_TASK, + { _id: issue._id }, + { parents: issue.parents.map((it) => ({ ...it, space: parentIssues.get(it.parentId)?.space ?? it.space })) } + ) + } + if (issues.length === 0) { + break + } + } + await client.update( + DOMAIN_TASK, + { _class: { $ne: tracker.class.Issue }, remainingTime: { $exists: true } }, + { $unset: { remainingTime: '' } } + ) +} + async function moveIssues (client: MigrationClient): Promise { const docs = await client.find(DOMAIN_TRACKER, { _class: tracker.class.Issue }) if (docs.length > 0) { @@ -252,6 +291,10 @@ export const trackerOperation: MigrateOperation = { { state: 'fixRemainingTime', func: fixRemainingTime + }, + { + state: 'fixParentsSpace', + func: fixParentsSpace } ]) }, diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index e30b48a080..f47f938dd8 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -897,17 +897,18 @@ export class LiveQuery extends TxProcessor implements Client { } private async handleDocRemove (q: Query, tx: TxRemoveDoc): Promise { + const h = this.client.getHierarchy() if (q.result instanceof Promise) { q.result = await q.result } if ( q.options?.limit !== undefined && q.options.limit === q.result.length && - this.client.getHierarchy().isDerived(q._class, tx.objectClass) + h.isDerived(q._class, tx.objectClass) ) { return await this.refresh(q) } - const index = q.result.findIndex((p) => p._id === tx.objectId) + const index = q.result.findIndex((p) => p._id === tx.objectId && h.isDerived(p._class, tx.objectClass)) if (index > -1) { q.result.splice(index, 1) if (q.options?.total === true) { diff --git a/plugins/tracker-resources/src/components/CreateIssue.svelte b/plugins/tracker-resources/src/components/CreateIssue.svelte index 8e4bb0580d..977657a444 100644 --- a/plugins/tracker-resources/src/components/CreateIssue.svelte +++ b/plugins/tracker-resources/src/components/CreateIssue.svelte @@ -377,7 +377,10 @@ subIssues: 0, dueDate: object.dueDate, parents: parentIssue - ? [{ parentId: parentIssue._id, parentTitle: parentIssue.title }, ...parentIssue.parents] + ? [ + { parentId: parentIssue._id, parentTitle: parentIssue.title, space: parentIssue.space }, + ...parentIssue.parents + ] : [], reportedTime: 0, remainingTime: 0, @@ -422,11 +425,11 @@ } const parents = parentIssue ? [ - { parentId: _id, parentTitle: value.title }, - { parentId: parentIssue._id, parentTitle: parentIssue.title }, + { parentId: _id, parentTitle: value.title, space: parentIssue.space }, + { parentId: parentIssue._id, parentTitle: parentIssue.title, space: parentIssue.space }, ...parentIssue.parents ] - : [{ parentId: _id, parentTitle: value.title }] + : [{ parentId: _id, parentTitle: value.title, space: _space }] await subIssuesComponent.save(parents, _id) addNotification( await translate(tracker.string.IssueCreated, {}, $themeStore.language), diff --git a/plugins/tracker/src/index.ts b/plugins/tracker/src/index.ts index 1f3e1e5441..948bec8cda 100644 --- a/plugins/tracker/src/index.ts +++ b/plugins/tracker/src/index.ts @@ -290,6 +290,7 @@ export interface TimeSpendReport extends AttachedDoc { export interface IssueParentInfo { parentId: Ref parentTitle: string + space: Ref } /** diff --git a/server-plugins/tracker-resources/src/index.ts b/server-plugins/tracker-resources/src/index.ts index 92944111fe..b8cd7242fc 100644 --- a/server-plugins/tracker-resources/src/index.ts +++ b/server-plugins/tracker-resources/src/index.ts @@ -226,7 +226,11 @@ export async function OnIssueUpdate (tx: Tx, control: TriggerControl): Promise ({ parentId: it._id, parentTitle: it.title })) + const parents: IssueParentInfo[] = parentIssue.map((it) => ({ + parentId: it._id, + parentTitle: it.title, + space: it.space + })) await updateIssueParentEstimations( { _id: removeTx.objectId, @@ -354,7 +358,9 @@ async function doIssueUpdate ( ) const updatedParents = - newParent !== undefined ? [{ parentId: newParent._id, parentTitle: newParent.title }, ...newParent.parents] : [] + newParent !== undefined + ? [{ parentId: newParent._id, parentTitle: newParent.title, space: newParent.space }, ...newParent.parents] + : [] function update (issue: Issue): DocumentUpdate { const parentInfoIndex = issue.parents.findIndex(({ parentId }) => parentId === updateTx.objectId) @@ -431,7 +437,7 @@ function updateIssueParentEstimations ( ): void { for (const pinfo of sourceParents) { res.push( - control.txFactory.createTxUpdateDoc(tracker.class.Issue, issue.space, pinfo.parentId, { + control.txFactory.createTxUpdateDoc(tracker.class.Issue, pinfo.space, pinfo.parentId, { $pull: { childInfo: { childId: issue._id } } @@ -440,7 +446,7 @@ function updateIssueParentEstimations ( } for (const pinfo of targetParents) { res.push( - control.txFactory.createTxUpdateDoc(tracker.class.Issue, issue.space, pinfo.parentId, { + control.txFactory.createTxUpdateDoc(tracker.class.Issue, pinfo.space, pinfo.parentId, { $push: { childInfo: { childId: issue._id,