mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-25 19:58:30 +03:00
UBERF-6802: Improve create chat message performance (#5530)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
0c4ff22173
commit
9d47b22a17
@ -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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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: {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
})
|
||||
|
@ -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
|
||||
}
|
@ -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>
|
||||
}
|
||||
})
|
||||
|
@ -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,
|
||||
|
@ -31,3 +31,9 @@ export interface NotifyResult {
|
||||
push: boolean
|
||||
emails: BaseNotificationType[]
|
||||
}
|
||||
|
||||
export interface NotifyParams {
|
||||
isOwn: boolean
|
||||
isSpace: boolean
|
||||
shouldUpdateTimestamp: boolean
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user