diff --git a/server-plugins/activity-resources/src/utils.ts b/server-plugins/activity-resources/src/utils.ts index 31c2e67920..b24b77b5d0 100644 --- a/server-plugins/activity-resources/src/utils.ts +++ b/server-plugins/activity-resources/src/utils.ts @@ -1,4 +1,5 @@ import { + Account, AttachedDoc, Class, Doc, @@ -16,6 +17,9 @@ import { import core from '@hcengineering/core/lib/component' import { DocAttributeUpdates, DocUpdateAction } from '@hcengineering/activity' import { ActivityControl, DocObjectCache, getAllObjectTransactions } from '@hcengineering/server-activity' +import { getDocCollaborators } from '@hcengineering/server-notification-resources' +import notification from '@hcengineering/notification' +import { TriggerControl } from '@hcengineering/server-core' function getAvailableAttributesKeys (tx: TxCUD, hierarchy: Hierarchy): string[] { if (hierarchy.isDerived(tx._class, core.class.TxUpdateDoc)) { @@ -143,17 +147,54 @@ export async function getDocDiff ( return { doc, prevDoc } } -export function getAttributeDiff ( - hierarchy: Hierarchy, +interface AttributeDiff { + added: DocAttributeUpdates['added'] + removed: DocAttributeUpdates['removed'] +} + +async function getCollaboratorsDiff ( + control: ActivityControl, + doc: Doc, + prevDoc: Doc | undefined +): Promise { + const { hierarchy } = control + const value = hierarchy.as(doc, notification.mixin.Collaborators).collaborators ?? [] + + let prevValue: Ref[] = [] + + if (prevDoc !== undefined && hierarchy.hasMixin(prevDoc, notification.mixin.Collaborators)) { + prevValue = hierarchy.as(prevDoc, notification.mixin.Collaborators).collaborators ?? [] + } else if (prevDoc !== undefined) { + const mixin = hierarchy.classHierarchyMixin(prevDoc._class, notification.mixin.ClassCollaborators) + prevValue = mixin !== undefined ? await getDocCollaborators(prevDoc, mixin, control as TriggerControl) : [] + } + + const added = value.filter((item) => !prevValue.includes(item)) as DocAttributeUpdates['added'] + const removed = prevValue.filter((item) => !value.includes(item)) as DocAttributeUpdates['removed'] + + return { + added, + removed + } +} + +export async function getAttributeDiff ( + control: ActivityControl, doc: Doc, prevDoc: Doc | undefined, attrKey: string, attrClass: Ref>, isMixin: boolean -): { added: DocAttributeUpdates['added'], removed: DocAttributeUpdates['removed'] } { +): Promise { + const { hierarchy } = control + let actualDoc: Doc | undefined = doc let actualPrevDoc: Doc | undefined = prevDoc + if (isMixin && hierarchy.isDerived(attrClass, notification.mixin.Collaborators)) { + return await getCollaboratorsDiff(control, doc, prevDoc) + } + if (isMixin) { actualDoc = hierarchy.as(doc, attrClass) actualPrevDoc = prevDoc === undefined ? undefined : hierarchy.as(prevDoc, attrClass) @@ -247,7 +288,7 @@ export async function getTxAttributesUpdates ( } if (Array.isArray(attrValue) && doc != null) { - const diff = getAttributeDiff(hierarchy, doc, prevDoc, key, attrClass, isMixin) + const diff = await getAttributeDiff(control, doc, prevDoc, key, attrClass, isMixin) added.push(...diff.added) removed.push(...diff.removed) attrValue = [] diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts index cf9ddb8c23..9d41c6ccb1 100644 --- a/server-plugins/notification-resources/src/index.ts +++ b/server-plugins/notification-resources/src/index.ts @@ -681,12 +681,16 @@ async function updateCollaboratorsMixin ( activityMessages: ActivityMessage[], originTx: TxCUD ): Promise { + const { hierarchy } = control + if (tx._class !== core.class.TxMixin) return [] if (originTx.space === core.space.DerivedTx) return [] - if (!control.hierarchy.isDerived(tx.mixin, notification.mixin.Collaborators)) return [] + if (!hierarchy.isDerived(tx.mixin, notification.mixin.Collaborators)) return [] + const res: Tx[] = [] + if (tx.attributes.collaborators !== undefined) { - const createTx = control.hierarchy.isDerived(tx.objectClass, core.class.AttachedDoc) + const createTx = hierarchy.isDerived(tx.objectClass, core.class.AttachedDoc) ? ( await control.findAll(core.class.TxCollectionCUD, { 'tx.objectId': tx.objectId, @@ -701,12 +705,21 @@ async function updateCollaboratorsMixin ( const mixinTxes = await control.findAll(core.class.TxMixin, { objectId: tx.objectId }) - const prevDoc = TxProcessor.buildDoc2Doc([createTx, ...mixinTxes].filter((t) => t._id !== tx._id)) as Collaborators - const prevDocMixin = control.hierarchy.as(prevDoc, notification.mixin.Collaborators) - const set = new Set(prevDocMixin?.collaborators ?? []) + const prevDoc = TxProcessor.buildDoc2Doc([createTx, ...mixinTxes].filter((t) => t._id !== tx._id)) as Doc const newCollabs: Ref[] = [] + + let prevCollabs: Set> + + if (hierarchy.hasMixin(prevDoc, notification.mixin.Collaborators)) { + const prevDocMixin = control.hierarchy.as(prevDoc, notification.mixin.Collaborators) + prevCollabs = new Set(prevDocMixin.collaborators ?? []) + } else { + const mixin = hierarchy.classHierarchyMixin(prevDoc._class, notification.mixin.ClassCollaborators) + prevCollabs = mixin !== undefined ? new Set(await getDocCollaborators(prevDoc, mixin, control)) : new Set() + } + for (const collab of tx.attributes.collaborators) { - if (!set.has(collab)) { + if (!prevCollabs.has(collab) && tx.modifiedBy !== collab) { if ( await isAllowed( control, diff --git a/server-plugins/notification-resources/src/utils.ts b/server-plugins/notification-resources/src/utils.ts index 7f19f41461..c840e5fc02 100644 --- a/server-plugins/notification-resources/src/utils.ts +++ b/server-plugins/notification-resources/src/utils.ts @@ -117,9 +117,9 @@ export async function isShouldNotify ( ) const personAccount = await getPersonAccountById(user, control) + const modifiedAccount = await getPersonAccountById(tx.modifiedBy, control) for (const type of types) { - const modifiedAccount = await getPersonAccountById(tx.modifiedBy, control) if ( type.allowedForAuthor !== true && (tx.modifiedBy === user ||