diff --git a/models/server-notification/src/index.ts b/models/server-notification/src/index.ts index 2da67e62a9..dc62f67dd7 100644 --- a/models/server-notification/src/index.ts +++ b/models/server-notification/src/index.ts @@ -31,7 +31,6 @@ import serverNotification, { type NotificationContentProvider } from '@hcengineering/server-notification' import chunter from '@hcengineering/model-chunter' -import activity from '@hcengineering/activity' export { serverNotificationId } from '@hcengineering/server-notification' @@ -60,15 +59,6 @@ export class TTypeMatch extends TNotificationType implements TypeMatch { export function createModel (builder: Builder): void { builder.createModel(THTMLPresenter, TTextPresenter, TTypeMatch, TNotificationPresenter) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { - trigger: serverNotification.trigger.ActivityNotificationsHandler, - txMatch: { - _class: core.class.TxCollectionCUD, - 'tx._class': core.class.TxCreateDoc, - 'tx.objectClass': activity.class.DocUpdateMessage - } - }) - builder.createDoc(serverCore.class.Trigger, core.space.Model, { trigger: serverNotification.trigger.OnActivityNotificationViewed, txMatch: { diff --git a/server-plugins/activity-resources/src/index.ts b/server-plugins/activity-resources/src/index.ts index cb08b2082b..7c77b31bd5 100644 --- a/server-plugins/activity-resources/src/index.ts +++ b/server-plugins/activity-resources/src/index.ts @@ -29,7 +29,11 @@ import core, { import { ActivityControl, DocObjectCache } from '@hcengineering/server-activity' import type { TriggerControl } from '@hcengineering/server-core' import activity, { ActivityMessage, DocUpdateMessage, Reaction } from '@hcengineering/activity' -import { createCollabDocInfo, removeDocInboxNotifications } from '@hcengineering/server-notification-resources' +import { + createCollabDocInfo, + createCollaboratorNotifications, + removeDocInboxNotifications +} from '@hcengineering/server-notification-resources' import { getDocUpdateAction, getTxAttributesUpdates } from './utils' @@ -98,7 +102,7 @@ export async function createReactionNotifications ( const docUpdateMessage = TxProcessor.createDoc2Doc(messageTx.tx as TxCreateDoc) res = res.concat( - await createCollabDocInfo([user], control, tx.tx, tx, parentMessage, docUpdateMessage, true, false, false) + await createCollabDocInfo([user], control, tx.tx, tx, parentMessage, [docUpdateMessage], true, false, false) ) return res @@ -271,7 +275,12 @@ async function ActivityMessagesHandler (tx: TxCUD, control: TriggerControl) return [] } - return await generateDocUpdateMessages(tx, control) + const txes = await generateDocUpdateMessages(tx, control) + const messages = txes.map((messageTx) => TxProcessor.createDoc2Doc(messageTx.tx as TxCreateDoc)) + + const notificationTxes = await createCollaboratorNotifications(tx, control, messages) + + return [...txes, ...notificationTxes] } async function OnDocRemoved (originTx: TxCUD, control: TriggerControl): Promise { diff --git a/server-plugins/chunter-resources/src/index.ts b/server-plugins/chunter-resources/src/index.ts index 3416547e9c..cd8654f26f 100644 --- a/server-plugins/chunter-resources/src/index.ts +++ b/server-plugins/chunter-resources/src/index.ts @@ -445,15 +445,9 @@ export async function OnDirectMessageSent (originTx: Tx, control: TriggerControl if (anotherPerson == null) return [] - await pushActivityInboxNotifications( - dmCreationTx, - control, - res, - anotherPerson, - directChannel, - notifyContexts, + await pushActivityInboxNotifications(dmCreationTx, control, res, anotherPerson, directChannel, notifyContexts, [ message - ) + ]) } else if (notifyContext.hidden) { res.push( control.txFactory.createTxUpdateDoc(notifyContext._class, notifyContext.space, notifyContext._id, { diff --git a/server-plugins/notification-resources/src/index.ts b/server-plugins/notification-resources/src/index.ts index ec39578980..439b990cc8 100644 --- a/server-plugins/notification-resources/src/index.ts +++ b/server-plugins/notification-resources/src/index.ts @@ -60,7 +60,7 @@ import serverNotification, { HTMLPresenter, TextPresenter } from '@hcengineering/server-notification' -import activity, { ActivityMessage, DocUpdateMessage } from '@hcengineering/activity' +import activity, { ActivityMessage } from '@hcengineering/activity' import { Content } from './types' import { @@ -149,7 +149,7 @@ export async function OnBacklinkCreate ( )[0] res = res.concat( - await createCollabDocInfo([receiver._id], control, messageTx.tx, messageTx, doc, message as ActivityMessage, true) + await createCollabDocInfo([receiver._id], control, messageTx.tx, messageTx, doc, [message as ActivityMessage], true) ) return res @@ -386,6 +386,35 @@ export async function getDocCollaborators ( return Array.from(collaborators.values()) } +function getDocNotifyContext ( + docNotifyContexts: DocNotifyContext[], + targetUser: Ref, + attachedTo: Ref, + res: Tx[] +): DocNotifyContext | undefined { + const context = docNotifyContexts.find((context) => context.user === targetUser && context.attachedTo === attachedTo) + + if (context !== undefined) { + return context + } + + const contextTx = (res as TxCUD[]).find((tx) => { + if (tx._class === core.class.TxCreateDoc && tx.objectClass === notification.class.DocNotifyContext) { + const createTx = tx as TxCreateDoc + + return createTx.attributes.attachedTo === attachedTo && createTx.attributes.user === targetUser + } + + return false + }) as TxCreateDoc | undefined + + if (contextTx !== undefined) { + return TxProcessor.createDoc2Doc(contextTx) + } + + return undefined +} + export async function pushInboxNotifications ( control: TriggerControl, res: Tx[], @@ -393,20 +422,20 @@ export async function pushInboxNotifications ( attachedTo: Ref, attachedToClass: Ref>, space: Ref, - docNotifyContexts: DocNotifyContext[], + contexts: DocNotifyContext[], data: Partial>, _class: Ref>, modifiedOn: Timestamp, shouldUpdateTimestamp = true ): Promise { - const docNotifyContext = docNotifyContexts.find(({ user }) => user === targetUser) + const context = getDocNotifyContext(contexts, targetUser, attachedTo, res) // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - const isHidden = !!docNotifyContext?.hidden + const isHidden = !!context?.hidden let docNotifyContextId: Ref - if (docNotifyContext === undefined) { + if (context === undefined) { const createContextTx = control.txFactory.createTxCreateDoc(notification.class.DocNotifyContext, space, { user: targetUser, attachedTo, @@ -419,12 +448,12 @@ export async function pushInboxNotifications ( } else { if (shouldUpdateTimestamp) { res.push( - control.txFactory.createTxUpdateDoc(docNotifyContext._class, docNotifyContext.space, docNotifyContext._id, { + control.txFactory.createTxUpdateDoc(context._class, context.space, context._id, { lastUpdateTimestamp: modifiedOn }) ) } - docNotifyContextId = docNotifyContext._id + docNotifyContextId = context._id } if (!isHidden) { @@ -449,38 +478,40 @@ export async function pushActivityInboxNotifications ( targetUser: Ref, object: Doc, docNotifyContexts: DocNotifyContext[], - activityMessage: ActivityMessage, + activityMessages: ActivityMessage[], shouldUpdateTimestamp = true ): Promise { - const existNotifications = await control.findAll(notification.class.ActivityInboxNotification, { - user: targetUser, - attachedTo: activityMessage._id - }) + for (const activityMessage of activityMessages) { + const existNotifications = await control.findAll(notification.class.ActivityInboxNotification, { + user: targetUser, + attachedTo: activityMessage._id + }) - if (existNotifications.length > 0) { - return + if (existNotifications.length > 0) { + return + } + + const content = await getNotificationContent(originTx, targetUser, object, control) + const data: Partial> = { + ...content, + attachedTo: activityMessage._id, + attachedToClass: activityMessage._class + } + + await pushInboxNotifications( + control, + res, + targetUser, + activityMessage.attachedTo, + activityMessage.attachedToClass, + activityMessage.space, + docNotifyContexts, + data, + notification.class.ActivityInboxNotification, + activityMessage.modifiedOn, + shouldUpdateTimestamp + ) } - - const content = await getNotificationContent(originTx, targetUser, object, control) - const data: Partial> = { - ...content, - attachedTo: activityMessage._id, - attachedToClass: activityMessage._class - } - - await pushInboxNotifications( - control, - res, - targetUser, - activityMessage.attachedTo, - activityMessage.attachedToClass, - activityMessage.space, - docNotifyContexts, - data, - notification.class.ActivityInboxNotification, - activityMessage.modifiedOn, - shouldUpdateTimestamp - ) } async function getNotificationTxes ( @@ -492,7 +523,7 @@ async function getNotificationTxes ( isOwn: boolean, isSpace: boolean, docNotifyContexts: DocNotifyContext[], - activityMessage: ActivityMessage, + activityMessages: ActivityMessage[], shouldUpdateTimestamp = true ): Promise { const res: Tx[] = [] @@ -506,7 +537,7 @@ async function getNotificationTxes ( target, object, docNotifyContexts, - activityMessage, + activityMessages, shouldUpdateTimestamp ) } @@ -540,7 +571,7 @@ export async function createCollabDocInfo ( tx: TxCUD, originTx: TxCUD, object: Doc, - activityMessage: ActivityMessage, + activityMessage: ActivityMessage[], isOwn: boolean, isSpace: boolean = false, shouldUpdateTimestamp = true @@ -553,7 +584,7 @@ export async function createCollabDocInfo ( const targets = new Set(collaborators) const notifyContexts = await control.findAll(notification.class.DocNotifyContext, { - attachedTo: activityMessage.attachedTo + attachedTo: { $in: activityMessage.map(({ attachedTo }) => attachedTo) } }) for (const target of targets) { @@ -599,7 +630,7 @@ async function getSpaceCollabTxes ( doc: Doc, tx: TxCUD, originTx: TxCUD, - activityMessage: ActivityMessage + activityMessages: ActivityMessage[] ): Promise { const space = (await control.findAll(core.class.Space, { _id: doc.space }))[0] if (space === undefined) return [] @@ -610,7 +641,7 @@ async function getSpaceCollabTxes ( if (mixin !== undefined) { const collabs = control.hierarchy.as(space, notification.mixin.Collaborators) if (collabs.collaborators !== undefined) { - return await createCollabDocInfo(collabs.collaborators, control, tx, originTx, doc, activityMessage, false, true) + return await createCollabDocInfo(collabs.collaborators, control, tx, originTx, doc, activityMessages, false, true) } } return [] @@ -619,7 +650,7 @@ async function getSpaceCollabTxes ( async function createCollaboratorDoc ( tx: TxCreateDoc, control: TriggerControl, - activityMessage: ActivityMessage, + activityMessage: ActivityMessage[], originTx: TxCUD ): Promise { const res: Tx[] = [] @@ -646,7 +677,7 @@ async function createCollaboratorDoc ( async function updateCollaboratorsMixin ( tx: TxMixin, control: TriggerControl, - activityMessage: ActivityMessage, + activityMessages: ActivityMessage[], originTx: TxCUD ): Promise { if (tx._class !== core.class.TxMixin) return [] @@ -701,7 +732,7 @@ async function updateCollaboratorsMixin ( collab, prevDoc, docNotifyContexts, - activityMessage + activityMessages ) } } @@ -712,21 +743,19 @@ async function updateCollaboratorsMixin ( async function collectionCollabDoc ( tx: TxCollectionCUD, control: TriggerControl, - activityMessage: ActivityMessage + activityMessages: ActivityMessage[] ): Promise { const actualTx = TxProcessor.extractTx(tx) as TxCUD - let res = await collaboratorDocHandler(actualTx, control, activityMessage, tx) + let res = await createCollaboratorNotifications(actualTx, control, activityMessages, tx) if (![core.class.TxCreateDoc, core.class.TxRemoveDoc].includes(actualTx._class)) { return res } - const isNotificationPushed = (res as TxCUD[]) - .filter( - (ctx: TxCUD): ctx is TxCreateDoc => - ctx._class === core.class.TxCreateDoc && ctx.objectClass === notification.class.ActivityInboxNotification - ) - .some(({ attributes }) => attributes.attachedTo === activityMessage._id) + const isNotificationPushed = (res as TxCUD[]).some( + ({ _class, objectClass }) => + _class === core.class.TxCreateDoc && objectClass === notification.class.ActivityInboxNotification + ) if (isNotificationPushed) { return res @@ -748,13 +777,13 @@ async function collectionCollabDoc ( const collaborators = control.hierarchy.as(doc, notification.mixin.Collaborators) res = res.concat( - await createCollabDocInfo(collaborators.collaborators, control, actualTx, tx, doc, activityMessage, false) + await createCollabDocInfo(collaborators.collaborators, control, actualTx, tx, doc, activityMessages, false) ) } else { const collaborators = await getDocCollaborators(doc, mixin, control) res.push(getMixinTx(tx, control, collaborators)) - res = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessage, false)) + res = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessages, false)) } return res } @@ -826,7 +855,7 @@ async function updateCollaboratorDoc ( tx: TxUpdateDoc | TxMixin, control: TriggerControl, originTx: TxCUD, - activityMessage: ActivityMessage + activityMessages: ActivityMessage[] ): Promise { const hierarchy = control.hierarchy let res: Tx[] = [] @@ -860,7 +889,7 @@ async function updateCollaboratorDoc ( tx, originTx, doc, - activityMessage, + activityMessages, true, false ) @@ -868,10 +897,12 @@ async function updateCollaboratorDoc ( } else { const collaborators = await getDocCollaborators(doc, mixin, control) res.push(getMixinTx(tx, control, collaborators)) - res = res.concat(await createCollabDocInfo(collaborators, control, tx, originTx, doc, activityMessage, true, false)) + res = res.concat( + await createCollabDocInfo(collaborators, control, tx, originTx, doc, activityMessages, true, false) + ) } - res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessage)) + res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessages)) res = res.concat(await updateNotifyContextsSpace(control, tx)) return res @@ -927,10 +958,10 @@ export async function OnAttributeUpdate (tx: Tx, control: TriggerControl): Promi return [res] } -async function collaboratorDocHandler ( +export async function createCollaboratorNotifications ( tx: TxCUD, control: TriggerControl, - activityMessage: ActivityMessage, + activityMessages: ActivityMessage[], originTx?: TxCUD ): Promise { if (tx.space === core.space.DerivedTx) { @@ -939,41 +970,29 @@ async function collaboratorDocHandler ( switch (tx._class) { case core.class.TxCreateDoc: - return await createCollaboratorDoc(tx as TxCreateDoc, control, activityMessage, originTx ?? tx) + return await createCollaboratorDoc(tx as TxCreateDoc, control, activityMessages, originTx ?? tx) case core.class.TxUpdateDoc: case core.class.TxMixin: { - let res = await updateCollaboratorDoc(tx as TxUpdateDoc, control, originTx ?? tx, activityMessage) + let res = await updateCollaboratorDoc(tx as TxUpdateDoc, control, originTx ?? tx, activityMessages) res = res.concat( - await updateCollaboratorsMixin(tx as TxMixin, control, activityMessage, originTx ?? tx) + await updateCollaboratorsMixin(tx as TxMixin, control, activityMessages, originTx ?? tx) ) return res } case core.class.TxRemoveDoc: return await removeCollaboratorDoc(tx as TxRemoveDoc, control) case core.class.TxCollectionCUD: - return await collectionCollabDoc(tx as TxCollectionCUD, control, activityMessage) + return await collectionCollabDoc(tx as TxCollectionCUD, control, activityMessages) } return [] } -async function ActivityNotificationsHandler ( - tx: TxCollectionCUD, - control: TriggerControl -): Promise { - const createTx = TxProcessor.extractTx(tx) as TxCreateDoc - const { txId } = createTx.attributes - const originTx = (await control.findAll(core.class.TxCUD, { _id: txId }, { limit: 1 }))[0] - const message = (await control.findAll(activity.class.DocUpdateMessage, { _id: createTx.objectId }))[0] - - return await collaboratorDocHandler(originTx, control, message) -} - async function OnChatMessageCreate (tx: TxCollectionCUD, control: TriggerControl): Promise { const createTx = TxProcessor.extractTx(tx) as TxCreateDoc const message = (await control.findAll(chunter.class.ChatMessage, { _id: createTx.objectId }))[0] - return await collaboratorDocHandler(tx, control, message) + return await createCollaboratorNotifications(tx, control, [message]) } /** @@ -1038,7 +1057,6 @@ export * from './utils' export default async () => ({ trigger: { OnChatMessageCreate, - ActivityNotificationsHandler, OnAttributeCreate, OnAttributeUpdate, OnBacklinkCreate, diff --git a/server-plugins/notification/src/index.ts b/server-plugins/notification/src/index.ts index f65e4ed208..094e1524ca 100644 --- a/server-plugins/notification/src/index.ts +++ b/server-plugins/notification/src/index.ts @@ -144,7 +144,6 @@ export default plugin(serverNotificationId, { }, trigger: { OnBacklinkCreate: '' as Resource, - ActivityNotificationsHandler: '' as Resource, OnAttributeCreate: '' as Resource, OnAttributeUpdate: '' as Resource, OnReactionChanged: '' as Resource,