UBERF-6802: Improve create chat message performance (#5530)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-05-07 10:49:36 +04:00 committed by GitHub
parent 0c4ff22173
commit 9d47b22a17
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 198 additions and 213 deletions

View File

@ -20,7 +20,6 @@ import chunter from '@hcengineering/chunter'
import serverNotification from '@hcengineering/server-notification'
import serverCore, { type ObjectDDParticipant } from '@hcengineering/server-core'
import serverChunter from '@hcengineering/server-chunter'
import notification from '@hcengineering/notification'
export { serverChunterId } from '@hcengineering/server-chunter'
@ -78,25 +77,12 @@ export function createModel (builder: Builder): void {
}
})
builder.mixin(chunter.ids.DMNotification, notification.class.NotificationType, serverNotification.mixin.TypeMatch, {
func: serverChunter.function.IsDirectMessage
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverChunter.trigger.OnChatMessageCreate,
txMatch: {
_class: core.class.TxCollectionCUD,
'tx._class': core.class.TxCreateDoc,
'tx.objectClass': chunter.class.ChatMessage
}
})
builder.mixin(
chunter.ids.ThreadNotification,
notification.class.NotificationType,
serverNotification.mixin.TypeMatch,
{
func: serverChunter.function.IsThreadMessage
}
)
builder.mixin(
chunter.ids.ChannelNotification,
notification.class.NotificationType,
serverNotification.mixin.TypeMatch,
{
func: serverChunter.function.IsChannelMessage
}
)
}

View File

@ -30,7 +30,6 @@ import serverNotification, {
type TypeMatch,
type NotificationContentProvider
} from '@hcengineering/server-notification'
import chunter from '@hcengineering/model-chunter'
export { serverNotificationId } from '@hcengineering/server-notification'
@ -67,15 +66,6 @@ export function createModel (builder: Builder): void {
}
})
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverNotification.trigger.OnChatMessageCreate,
txMatch: {
_class: core.class.TxCollectionCUD,
'tx._class': core.class.TxCreateDoc,
'tx.objectClass': chunter.class.ChatMessage
}
})
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverNotification.trigger.OnAttributeCreate,
txMatch: {

View File

@ -125,7 +125,16 @@ export async function createReactionNotifications (
const docUpdateMessage = TxProcessor.createDoc2Doc(messageTx.tx as TxCreateDoc<DocUpdateMessage>)
res = res.concat(
await createCollabDocInfo([user], control, tx.tx, tx, parentMessage, [docUpdateMessage], true, false, false)
await createCollabDocInfo(
[user],
control,
tx.tx,
tx,
parentMessage,
[docUpdateMessage],
{ isOwn: true, isSpace: false, shouldUpdateTimestamp: false },
new Map()
)
)
return res

View File

@ -41,20 +41,20 @@ import core, {
TxRemoveDoc,
TxUpdateDoc
} from '@hcengineering/core'
import notification, { Collaborators, NotificationContent } from '@hcengineering/notification'
import notification, { ClassCollaborators, Collaborators, NotificationContent } from '@hcengineering/notification'
import { getMetadata, IntlString } from '@hcengineering/platform'
import serverCore, { TriggerControl } from '@hcengineering/server-core'
import {
getDocCollaborators,
getMixinTx,
pushActivityInboxNotifications
pushActivityInboxNotifications,
createCollaboratorNotifications
} from '@hcengineering/server-notification-resources'
import { workbenchId } from '@hcengineering/workbench'
import { stripTags } from '@hcengineering/text'
import { Person, PersonAccount } from '@hcengineering/contact'
import activity, { ActivityMessage, ActivityReference } from '@hcengineering/activity'
import { IsChannelMessage, IsDirectMessage, IsThreadMessage } from './utils'
import { NOTIFICATION_BODY_SIZE } from '@hcengineering/server-notification'
/**
@ -143,37 +143,21 @@ async function OnThreadMessageCreated (tx: Tx, control: TriggerControl): Promise
return [lastReplyTx, employeeTx]
}
async function OnChatMessageCreated (tx: TxCUD<Doc>, control: TriggerControl): Promise<Tx[]> {
async function updateCollaborators (
targetDoc: Doc | undefined,
tx: TxCUD<Doc>,
control: TriggerControl,
message: ChatMessage,
mixin?: ClassCollaborators
): Promise<Tx[]> {
if (targetDoc === undefined || mixin === undefined) return []
const hierarchy = control.hierarchy
const actualTx = TxProcessor.extractTx(tx) as TxCreateDoc<ChatMessage>
if (
actualTx._class !== core.class.TxCreateDoc ||
!hierarchy.isDerived(actualTx.objectClass, chunter.class.ChatMessage)
) {
return []
}
const chatMessage = TxProcessor.createDoc2Doc(actualTx)
const mixin = hierarchy.classHierarchyMixin(chatMessage.attachedToClass, notification.mixin.ClassCollaborators)
if (mixin === undefined) {
return []
}
const targetDoc = (
await control.findAll(chatMessage.attachedToClass, { _id: chatMessage.attachedTo }, { limit: 1 })
)[0]
if (targetDoc === undefined) {
return []
}
const res: Tx[] = []
const isChannel = hierarchy.isDerived(targetDoc._class, chunter.class.Channel)
const res: Tx[] = []
if (hierarchy.hasMixin(targetDoc, notification.mixin.Collaborators)) {
const collaboratorsMixin = hierarchy.as(targetDoc, notification.mixin.Collaborators)
if (!collaboratorsMixin.collaborators.includes(chatMessage.modifiedBy)) {
if (!collaboratorsMixin.collaborators.includes(message.modifiedBy)) {
res.push(
control.txFactory.createTxMixin(
targetDoc._id,
@ -182,7 +166,7 @@ async function OnChatMessageCreated (tx: TxCUD<Doc>, control: TriggerControl): P
notification.mixin.Collaborators,
{
$push: {
collaborators: chatMessage.modifiedBy
collaborators: message.modifiedBy
}
}
)
@ -190,19 +174,50 @@ async function OnChatMessageCreated (tx: TxCUD<Doc>, control: TriggerControl): P
}
} else {
const collaborators = await getDocCollaborators(targetDoc, mixin, control)
if (!collaborators.includes(chatMessage.modifiedBy)) {
collaborators.push(chatMessage.modifiedBy)
if (!collaborators.includes(message.modifiedBy)) {
collaborators.push(message.modifiedBy)
}
res.push(getMixinTx(tx, control, collaborators))
}
if (isChannel && !(targetDoc as Channel).members.includes(chatMessage.modifiedBy)) {
res.push(...joinChannel(control, targetDoc as Channel, chatMessage.modifiedBy))
if (isChannel && !(targetDoc as Channel).members.includes(message.modifiedBy)) {
res.push(...joinChannel(control, targetDoc as Channel, message.modifiedBy))
}
return res
}
async function OnChatMessageCreate (tx: TxCUD<Doc>, control: TriggerControl): Promise<Tx[]> {
const hierarchy = control.hierarchy
const actualTx = TxProcessor.extractTx(tx) as TxCreateDoc<ChatMessage>
if (actualTx._class !== core.class.TxCreateDoc) {
return []
}
const chatMessage = TxProcessor.createDoc2Doc(actualTx)
const cache = new Map<Ref<Doc>, Doc>()
const mixin = hierarchy.classHierarchyMixin(chatMessage.attachedToClass, notification.mixin.ClassCollaborators)
let targetDoc: Doc | undefined
if (mixin !== undefined) {
targetDoc = (await control.findAll(chatMessage.attachedToClass, { _id: chatMessage.attachedTo }, { limit: 1 }))[0]
}
if (targetDoc !== undefined) {
cache.set(targetDoc._id, targetDoc)
}
const res = await Promise.all([
createCollaboratorNotifications(control.ctx, tx, control, [chatMessage], undefined, cache),
updateCollaborators(targetDoc, tx, control, chatMessage, mixin)
])
return res.flat()
}
function joinChannel (control: TriggerControl, channel: Channel, user: Ref<Account>): Tx[] {
if (channel.members.includes(user)) {
return []
@ -260,7 +275,6 @@ export async function ChunterTrigger (tx: Tx, control: TriggerControl): Promise<
const res = await Promise.all([
OnThreadMessageCreated(tx, control),
OnThreadMessageDeleted(tx, control),
OnChatMessageCreated(tx as TxCUD<Doc>, control),
OnCollaboratorsChanged(tx as TxMixin<Doc, Collaborators>, control)
])
return res.flat()
@ -516,15 +530,13 @@ export default async () => ({
ChunterTrigger,
OnDirectMessageSent,
OnChatMessageRemoved,
OnChannelMembersChanged
OnChannelMembersChanged,
OnChatMessageCreate
},
function: {
CommentRemove,
ChannelHTMLPresenter: channelHTMLPresenter,
ChannelTextPresenter: channelTextPresenter,
ChunterNotificationContentProvider: getChunterNotificationContent,
IsDirectMessage,
IsThreadMessage,
IsChannelMessage
ChunterNotificationContentProvider: getChunterNotificationContent
}
})

View File

@ -1,60 +0,0 @@
//
// Copyright © 2023 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//
import { Account, Doc, Ref, Tx, TxCreateDoc } from '@hcengineering/core'
import { NotificationType } from '@hcengineering/notification'
import { TriggerControl } from '@hcengineering/server-core'
import chunter, { DirectMessage } from '@hcengineering/chunter'
import activity from '@hcengineering/activity'
/**
* @public
*/
export async function IsChannelMessage (
tx: Tx,
doc: Doc,
user: Ref<Account>,
type: NotificationType,
control: TriggerControl
): Promise<boolean> {
const hierarchy = control.hierarchy
const isDirect = await IsDirectMessage(tx, doc, user, type, control)
if (isDirect) {
return false
}
return hierarchy.isDerived(doc._class, chunter.class.Channel) || hierarchy.hasMixin(doc, activity.mixin.ActivityDoc)
}
/**
* @public
*/
export async function IsThreadMessage (tx: TxCreateDoc<Doc>): Promise<boolean> {
return tx.objectClass === chunter.class.ThreadMessage
}
/**
* @public
*/
export async function IsDirectMessage (
tx: Tx,
doc: Doc,
user: Ref<Account>,
type: NotificationType,
control: TriggerControl
): Promise<boolean> {
const dm = (await control.findAll(chunter.class.DirectMessage, { _id: doc._id as Ref<DirectMessage> }))[0]
return dm !== undefined
}

View File

@ -16,7 +16,7 @@
import type { Plugin, Resource } from '@hcengineering/platform'
import { plugin } from '@hcengineering/platform'
import { ObjectDDParticipantFunc, TriggerFunc } from '@hcengineering/server-core'
import { NotificationContentProvider, Presenter, TypeMatchFunc } from '@hcengineering/server-notification'
import { NotificationContentProvider, Presenter } from '@hcengineering/server-notification'
/**
* @public
@ -31,15 +31,13 @@ export default plugin(serverChunterId, {
ChunterTrigger: '' as Resource<TriggerFunc>,
OnDirectMessageSent: '' as Resource<TriggerFunc>,
OnChatMessageRemoved: '' as Resource<TriggerFunc>,
OnChannelMembersChanged: '' as Resource<TriggerFunc>
OnChannelMembersChanged: '' as Resource<TriggerFunc>,
OnChatMessageCreate: '' as Resource<TriggerFunc>
},
function: {
CommentRemove: '' as Resource<ObjectDDParticipantFunc>,
ChannelHTMLPresenter: '' as Resource<Presenter>,
ChannelTextPresenter: '' as Resource<Presenter>,
IsDirectMessage: '' as TypeMatchFunc,
IsChannelMessage: '' as TypeMatchFunc,
IsThreadMessage: '' as TypeMatchFunc,
ChunterNotificationContentProvider: '' as Resource<NotificationContentProvider>
}
})

View File

@ -78,7 +78,7 @@ import serverNotification, {
import { stripTags } from '@hcengineering/text'
import { workbenchId } from '@hcengineering/workbench'
import webpush, { WebPushError } from 'web-push'
import { Content, NotifyResult } from './types'
import { Content, NotifyResult, NotifyParams } from './types'
import {
getHTMLPresenter,
getNotificationContent,
@ -386,7 +386,8 @@ export async function pushInboxNotifications (
modifiedOn: Timestamp,
senderId: Ref<PersonAccount>,
shouldPush: boolean,
shouldUpdateTimestamp = true
shouldUpdateTimestamp = true,
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
): Promise<void> {
const context = getDocNotifyContext(contexts, targetUser, attachedTo, res)
@ -434,7 +435,8 @@ export async function pushInboxNotifications (
notificationData,
_class,
senderId,
notificationTx.objectId
notificationTx.objectId,
cache
)
console.log('Push takes', Date.now() - now, 'ms')
if (pushTx !== undefined) {
@ -528,7 +530,8 @@ export async function createPushFromInbox (
data: Data<InboxNotification>,
_class: Ref<Class<InboxNotification>>,
senderId: Ref<PersonAccount>,
_id: Ref<Doc>
_id: Ref<Doc>,
cache: Map<Ref<Doc>, Doc>
): Promise<Tx | undefined> {
let title: string = ''
let body: string = ''
@ -547,8 +550,14 @@ export async function createPushFromInbox (
let senderPerson: Person | undefined
if (sender !== undefined) {
senderPerson = (await control.findAll(contact.class.Person, { _id: sender.person }))[0]
senderPerson =
(cache.get(sender.person) as Person) ?? (await control.findAll(contact.class.Person, { _id: sender.person }))[0]
}
if (senderPerson !== undefined) {
cache.set(senderPerson._id, senderPerson)
}
const path = [
workbenchId,
control.workspace.workspaceUrl,
@ -650,19 +659,11 @@ export async function pushActivityInboxNotifications (
docNotifyContexts: DocNotifyContext[],
activityMessages: ActivityMessage[],
shouldUpdateTimestamp: boolean,
shouldPush: boolean
shouldPush: boolean,
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
): Promise<void> {
for (const activityMessage of activityMessages) {
const existNotifications = await control.findAll(notification.class.ActivityInboxNotification, {
user: targetUser,
attachedTo: activityMessage._id
})
if (existNotifications.length > 0) {
return
}
const content = await getNotificationContent(originTx, targetUser, object, control)
const content = await getNotificationContent(originTx, targetUser, object, control, cache)
const data: Partial<Data<ActivityInboxNotification>> = {
...content,
attachedTo: activityMessage._id,
@ -682,7 +683,8 @@ export async function pushActivityInboxNotifications (
activityMessage.modifiedOn,
originTx.modifiedBy as Ref<PersonAccount>,
shouldPush,
shouldUpdateTimestamp
shouldUpdateTimestamp,
cache
)
}
}
@ -693,14 +695,13 @@ export async function getNotificationTxes (
tx: TxCUD<Doc>,
originTx: TxCUD<Doc>,
target: Ref<Account>,
isOwn: boolean,
isSpace: boolean,
params: NotifyParams,
docNotifyContexts: DocNotifyContext[],
activityMessages: ActivityMessage[],
shouldUpdateTimestamp = true
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
const res: Tx[] = []
const notifyResult = await isShouldNotifyTx(control, tx, originTx, object, target, isOwn, isSpace)
const notifyResult = await isShouldNotifyTx(control, tx, originTx, object, target, params.isOwn, params.isSpace)
if (notifyResult.allowed) {
await pushActivityInboxNotifications(
@ -711,8 +712,9 @@ export async function getNotificationTxes (
object,
docNotifyContexts,
activityMessages,
shouldUpdateTimestamp,
notifyResult.push
params.shouldUpdateTimestamp,
notifyResult.push,
cache
)
}
@ -745,18 +747,17 @@ export async function createCollabDocInfo (
tx: TxCUD<Doc>,
originTx: TxCUD<Doc>,
object: Doc,
activityMessage: ActivityMessage[],
isOwn: boolean,
isSpace: boolean = false,
shouldUpdateTimestamp = true
activityMessages: ActivityMessage[],
params: NotifyParams,
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
let res: Tx[] = []
if (originTx.space === core.space.DerivedTx) {
if (originTx.space === core.space.DerivedTx || collaborators.length === 0) {
return res
}
const docMessages = activityMessage.filter((message) => message.attachedTo === object._id)
const docMessages = activityMessages.filter((message) => message.attachedTo === object._id)
if (docMessages.length === 0) {
return res
@ -778,18 +779,7 @@ export async function createCollabDocInfo (
for (const target of targets) {
res = res.concat(
await getNotificationTxes(
control,
object,
tx,
originTx,
target,
isOwn,
isSpace,
notifyContexts,
docMessages,
shouldUpdateTimestamp
)
await getNotificationTxes(control, object, tx, originTx, target, params, notifyContexts, docMessages, cache)
)
}
return res
@ -819,8 +809,13 @@ async function getSpaceCollabTxes (
doc: Doc,
tx: TxCUD<Doc>,
originTx: TxCUD<Doc>,
activityMessages: ActivityMessage[]
activityMessages: ActivityMessage[],
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
if (doc.space === core.space.Space) {
return []
}
const space = (await control.findAll(core.class.Space, { _id: doc.space }))[0]
if (space === undefined) return []
const mixin = control.hierarchy.classHierarchyMixin<Doc, ClassCollaborators>(
@ -830,7 +825,16 @@ async function getSpaceCollabTxes (
if (mixin !== undefined) {
const collabs = control.hierarchy.as<Doc, Collaborators>(space, notification.mixin.Collaborators)
if (collabs.collaborators !== undefined) {
return await createCollabDocInfo(collabs.collaborators, control, tx, originTx, doc, activityMessages, false, true)
return await createCollabDocInfo(
collabs.collaborators,
control,
tx,
originTx,
doc,
activityMessages,
{ isSpace: true, isOwn: false, shouldUpdateTimestamp: true },
cache
)
}
}
return []
@ -840,7 +844,8 @@ async function createCollaboratorDoc (
tx: TxCreateDoc<Doc>,
control: TriggerControl,
activityMessage: ActivityMessage[],
originTx: TxCUD<Doc>
originTx: TxCUD<Doc>,
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
const res: Tx[] = []
const hierarchy = control.hierarchy
@ -854,11 +859,20 @@ async function createCollaboratorDoc (
const collaborators = await getDocCollaborators(doc, mixin, control)
const mixinTx = getMixinTx(tx, control, collaborators)
const notificationTxes = await createCollabDocInfo(collaborators, control, tx, originTx, doc, activityMessage, true)
const notificationTxes = await createCollabDocInfo(
collaborators,
control,
tx,
originTx,
doc,
activityMessage,
{ isOwn: true, isSpace: false, shouldUpdateTimestamp: true },
cache
)
res.push(mixinTx)
res.push(...notificationTxes)
res.push(...(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessage)))
res.push(...(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessage, cache)))
return res
}
@ -867,7 +881,8 @@ async function updateCollaboratorsMixin (
tx: TxMixin<Doc, Collaborators>,
control: TriggerControl,
activityMessages: ActivityMessage[],
originTx: TxCUD<Doc>
originTx: TxCUD<Doc>,
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
const { hierarchy } = control
@ -936,7 +951,8 @@ async function updateCollaboratorsMixin (
docNotifyContexts,
activityMessages,
true,
true
true,
cache
)
}
}
@ -947,10 +963,11 @@ async function updateCollaboratorsMixin (
async function collectionCollabDoc (
tx: TxCollectionCUD<Doc, AttachedDoc>,
control: TriggerControl,
activityMessages: ActivityMessage[]
activityMessages: ActivityMessage[],
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
const actualTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
let res = await createCollaboratorNotifications(control.ctx, actualTx, control, activityMessages, tx)
let res = await createCollaboratorNotifications(control.ctx, actualTx, control, activityMessages, tx, cache)
if (![core.class.TxCreateDoc, core.class.TxRemoveDoc, core.class.TxUpdateDoc].includes(actualTx._class)) {
return res
@ -962,15 +979,28 @@ async function collectionCollabDoc (
return res
}
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
const doc = cache.get(tx.objectId) ?? (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
if (doc === undefined) {
return res
}
cache.set(doc._id, doc)
const collaborators = await getCollaborators(doc, control, tx, res)
res = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessages, false))
res = res.concat(
await createCollabDocInfo(
collaborators,
control,
actualTx,
tx,
doc,
activityMessages,
{ isOwn: false, isSpace: false, shouldUpdateTimestamp: true },
cache
)
)
return res
}
@ -1068,7 +1098,8 @@ async function updateCollaboratorDoc (
tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>,
control: TriggerControl,
originTx: TxCUD<Doc>,
activityMessages: ActivityMessage[]
activityMessages: ActivityMessage[],
cache: Map<Ref<Doc>, Doc>
): Promise<Tx[]> {
const hierarchy = control.hierarchy
let res: Tx[] = []
@ -1076,6 +1107,7 @@ async function updateCollaboratorDoc (
if (mixin === undefined) return []
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
if (doc === undefined) return []
const params: NotifyParams = { isOwn: true, isSpace: false, shouldUpdateTimestamp: true }
if (hierarchy.hasMixin(doc, notification.mixin.Collaborators)) {
// we should handle change field and subscribe new collaborators
const collabMixin = hierarchy.as(doc, notification.mixin.Collaborators)
@ -1103,19 +1135,19 @@ async function updateCollaboratorDoc (
originTx,
doc,
activityMessages,
true,
false
params,
cache
)
)
} else {
const collaborators = await getDocCollaborators(doc, mixin, control)
res.push(getMixinTx(tx, control, collaborators))
res = res.concat(
await createCollabDocInfo(collaborators, control, tx, originTx, doc, activityMessages, true, false)
await createCollabDocInfo(collaborators, control, tx, originTx, doc, activityMessages, params, cache)
)
}
res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessages))
res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx, activityMessages, cache))
res = res.concat(await updateNotifyContextsSpace(control, tx))
return res
@ -1176,7 +1208,8 @@ export async function createCollaboratorNotifications (
tx: TxCUD<Doc>,
control: TriggerControl,
activityMessages: ActivityMessage[],
originTx?: TxCUD<Doc>
originTx?: TxCUD<Doc>,
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
): Promise<Tx[]> {
if (tx.space === core.space.DerivedTx) {
return []
@ -1188,29 +1221,28 @@ export async function createCollaboratorNotifications (
switch (tx._class) {
case core.class.TxCreateDoc:
return await createCollaboratorDoc(tx as TxCreateDoc<Doc>, control, activityMessages, originTx ?? tx)
return await createCollaboratorDoc(tx as TxCreateDoc<Doc>, control, activityMessages, originTx ?? tx, cache)
case core.class.TxUpdateDoc:
case core.class.TxMixin: {
let res = await updateCollaboratorDoc(tx as TxUpdateDoc<Doc>, control, originTx ?? tx, activityMessages)
let res = await updateCollaboratorDoc(tx as TxUpdateDoc<Doc>, control, originTx ?? tx, activityMessages, cache)
res = res.concat(
await updateCollaboratorsMixin(tx as TxMixin<Doc, Collaborators>, control, activityMessages, originTx ?? tx)
await updateCollaboratorsMixin(
tx as TxMixin<Doc, Collaborators>,
control,
activityMessages,
originTx ?? tx,
cache
)
)
return res
}
case core.class.TxCollectionCUD:
return await collectionCollabDoc(tx as TxCollectionCUD<Doc, AttachedDoc>, control, activityMessages)
return await collectionCollabDoc(tx as TxCollectionCUD<Doc, AttachedDoc>, control, activityMessages, cache)
}
return []
}
async function OnChatMessageCreate (tx: TxCollectionCUD<Doc, ChatMessage>, control: TriggerControl): Promise<Tx[]> {
const createTx = TxProcessor.extractTx(tx) as TxCreateDoc<ChatMessage>
const message = (await control.findAll(chunter.class.ChatMessage, { _id: createTx.objectId }))[0]
return await createCollaboratorNotifications(control.ctx, tx, control, [message])
}
/**
* @public
*/
@ -1314,7 +1346,6 @@ export * from './utils'
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnChatMessageCreate,
OnAttributeCreate,
OnAttributeUpdate,
OnActivityNotificationViewed,

View File

@ -31,3 +31,9 @@ export interface NotifyResult {
push: boolean
emails: BaseNotificationType[]
}
export interface NotifyParams {
isOwn: boolean
isSpace: boolean
shouldUpdateTimestamp: boolean
}

View File

@ -309,7 +309,8 @@ export function getTextPresenter (_class: Ref<Class<Doc>>, hierarchy: Hierarchy)
async function getFallbackNotificationFullfillment (
object: Doc,
originTx: TxCUD<Doc>,
control: TriggerControl
control: TriggerControl,
cache: Map<Ref<Doc>, Doc>
): Promise<NotificationContent> {
const title: IntlString = notification.string.CommonNotificationTitle
let body: IntlString = notification.string.CommonNotificationBody
@ -324,9 +325,10 @@ async function getFallbackNotificationFullfillment (
const account = control.modelDb.getObject(originTx.modifiedBy) as PersonAccount
if (account !== undefined) {
const senderPerson = await findPersonForAccount(control, account.person)
const senderPerson = (cache.get(account.person) as Person) ?? (await findPersonForAccount(control, account.person))
if (senderPerson !== undefined) {
intlParams.senderName = formatName(senderPerson.name)
cache.set(senderPerson._id, senderPerson)
}
}
@ -364,12 +366,14 @@ export async function getNotificationContent (
originTx: TxCUD<Doc>,
targetUser: Ref<Account>,
object: Doc,
control: TriggerControl
control: TriggerControl,
cache: Map<Ref<Doc>, Doc> = new Map<Ref<Doc>, Doc>()
): Promise<NotificationContent> {
let { title, body, intlParams, intlParamsNotLocalized } = await getFallbackNotificationFullfillment(
object,
originTx,
control
control,
cache
)
const actualTx = TxProcessor.extractTx(originTx)

View File

@ -150,7 +150,6 @@ export default plugin(serverNotificationId, {
OnAttributeCreate: '' as Resource<TriggerFunc>,
OnAttributeUpdate: '' as Resource<TriggerFunc>,
OnReactionChanged: '' as Resource<TriggerFunc>,
OnChatMessageCreate: '' as Resource<TriggerFunc>,
OnActivityNotificationViewed: '' as Resource<TriggerFunc>,
OnDocRemove: '' as Resource<TriggerFunc>
},

View File

@ -113,7 +113,17 @@ async function getRequestNotificationTx (tx: TxCollectionCUD<Doc, Request>, cont
})
for (const target of collaborators) {
const txes = await getNotificationTxes(control, request, tx.tx, tx, target, true, false, notifyContexts, messages)
const txes = await getNotificationTxes(
control,
request,
tx.tx,
tx,
target,
{ isOwn: true, isSpace: false, shouldUpdateTimestamp: true },
notifyContexts,
messages,
new Map()
)
res.push(...txes)
}