mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-12 10:25:51 +00:00
Reduce finds on create notifications (#8352)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
parent
651c1395a8
commit
af1563f580
@ -48,6 +48,7 @@ import {
|
||||
getTextPresenter,
|
||||
removeDocInboxNotifications
|
||||
} from '@hcengineering/server-notification-resources'
|
||||
import { Person } from '@hcengineering/contact'
|
||||
|
||||
import { ReferenceTrigger } from './references'
|
||||
import { getAttrName, getCollectionAttribute, getDocUpdateAction, getTxAttributesUpdates } from './utils'
|
||||
@ -417,7 +418,7 @@ async function OnDocRemoved (txes: TxCUD<Doc>[], control: TriggerControl): Promi
|
||||
async function ReactionNotificationContentProvider (
|
||||
doc: ActivityMessage,
|
||||
originTx: TxCUD<Doc>,
|
||||
_: PersonId,
|
||||
_: Ref<Person>,
|
||||
control: TriggerControl
|
||||
): Promise<NotificationContent> {
|
||||
const tx = originTx as TxCreateDoc<Reaction>
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import activity, { ActivityMessage, ActivityReference, UserMentionInfo } from '@hcengineering/activity'
|
||||
import contact, { Employee, Person, pickPrimarySocialId } from '@hcengineering/contact'
|
||||
import contact, { Employee, Person } from '@hcengineering/contact'
|
||||
import core, {
|
||||
PersonId,
|
||||
Blob,
|
||||
@ -47,11 +47,10 @@ import {
|
||||
getNotificationContent,
|
||||
getNotificationProviderControl,
|
||||
getPushCollaboratorTx,
|
||||
isShouldNotifyTx,
|
||||
NotifyResult,
|
||||
shouldNotifyCommon,
|
||||
toReceiverInfo,
|
||||
type NotificationProviderControl
|
||||
type NotificationProviderControl,
|
||||
isShouldNotifyTx
|
||||
} from '@hcengineering/server-notification-resources'
|
||||
import { areEqualJson, extractReferences, jsonToMarkup, markupToJSON } from '@hcengineering/text-core'
|
||||
|
||||
@ -79,27 +78,31 @@ export async function getPersonNotificationTxes (
|
||||
originTx: TxCUD<Doc>,
|
||||
notificationControl: NotificationProviderControl
|
||||
): Promise<Tx[]> {
|
||||
const receiver = reference.attachedTo as Ref<Person>
|
||||
const receiverSocialIds = await control.findAll(ctx, contact.class.SocialIdentity, { attachedTo: receiver })
|
||||
const receiverSocialStrings = receiverSocialIds.map((si) => si._id) as PersonId[]
|
||||
const receiverPersonRef = reference.attachedTo as Ref<Person>
|
||||
const receiverSocialIdentity = await control.findAll(ctx, contact.class.SocialIdentity, {
|
||||
attachedTo: receiverPersonRef
|
||||
})
|
||||
const receiverSocialIds = receiverSocialIdentity.map((si) => si._id) as PersonId[]
|
||||
|
||||
if (receiverSocialStrings.includes(senderId)) {
|
||||
if (receiverSocialIds.includes(senderId)) {
|
||||
return []
|
||||
}
|
||||
|
||||
const employee = await control.findAll(
|
||||
ctx,
|
||||
contact.mixin.Employee,
|
||||
{ _id: receiver as Ref<Employee>, active: true },
|
||||
{ limit: 1 }
|
||||
)
|
||||
const account = employee[0]?.personUuid
|
||||
if (account == null) {
|
||||
const receiverEmployee = (
|
||||
await control.findAll(
|
||||
ctx,
|
||||
contact.mixin.Employee,
|
||||
{ _id: receiverPersonRef as Ref<Employee>, active: true },
|
||||
{ limit: 1 }
|
||||
)
|
||||
)[0]
|
||||
const receiverAccount = receiverEmployee?.personUuid
|
||||
if (receiverAccount == null) {
|
||||
return []
|
||||
}
|
||||
|
||||
const res: Tx[] = []
|
||||
const isAvailable = await checkSpace(account, space, control, res)
|
||||
const isAvailable = await checkSpace(receiverAccount, space, control, res)
|
||||
|
||||
if (!isAvailable) {
|
||||
return []
|
||||
@ -107,10 +110,12 @@ export async function getPersonNotificationTxes (
|
||||
|
||||
const doc = (await control.findAll(ctx, reference.srcDocClass, { _id: reference.srcDocId }))[0]
|
||||
|
||||
const receiverSpace = (await control.findAll(ctx, contact.class.PersonSpace, { person: receiver }, { limit: 1 }))[0]
|
||||
const receiverSpace = (
|
||||
await control.findAll(ctx, contact.class.PersonSpace, { person: receiverPersonRef }, { limit: 1 })
|
||||
)[0]
|
||||
if (receiverSpace === undefined) return res
|
||||
|
||||
const collaboratorsTx = await getCollaboratorsTxes(reference, control, account, doc)
|
||||
const collaboratorsTx = await getCollaboratorsTxes(reference, control, receiverAccount, doc)
|
||||
|
||||
res.push(...collaboratorsTx)
|
||||
|
||||
@ -120,7 +125,7 @@ export async function getPersonNotificationTxes (
|
||||
|
||||
const info = (
|
||||
await control.findAll<UserMentionInfo>(ctx, activity.class.UserMentionInfo, {
|
||||
user: receiver,
|
||||
user: receiverPersonRef,
|
||||
attachedTo: reference.attachedDocId
|
||||
})
|
||||
)[0]
|
||||
@ -130,7 +135,7 @@ export async function getPersonNotificationTxes (
|
||||
control.txFactory.createTxCreateDoc(activity.class.UserMentionInfo, space, {
|
||||
attachedTo: reference.attachedDocId ?? reference.srcDocId,
|
||||
attachedToClass: reference.attachedDocClass ?? reference.srcDocClass,
|
||||
user: receiver,
|
||||
user: receiverPersonRef,
|
||||
content: reference.message,
|
||||
collection: 'mentions'
|
||||
})
|
||||
@ -150,42 +155,35 @@ export async function getPersonNotificationTxes (
|
||||
mentionedInClass: reference.attachedDocClass ?? reference.srcDocClass,
|
||||
objectId: reference.srcDocId,
|
||||
objectClass: reference.srcDocClass,
|
||||
user: account,
|
||||
user: receiverAccount,
|
||||
isViewed: false,
|
||||
archived: false
|
||||
}
|
||||
|
||||
const senderPerson = await getPerson(control, senderId)
|
||||
const senderSocialIds =
|
||||
senderPerson !== undefined
|
||||
? await control.findAll(ctx, contact.class.SocialIdentity, { attachedTo: senderPerson._id })
|
||||
: []
|
||||
|
||||
const receiverSocialString = pickPrimarySocialId(receiverSocialStrings)
|
||||
const receiverInfo = toReceiverInfo(control.hierarchy, {
|
||||
_id: receiverSocialString,
|
||||
person: employee[0],
|
||||
const receiver = {
|
||||
account: receiverAccount,
|
||||
socialIds: receiverSocialIds,
|
||||
space: receiverSpace._id,
|
||||
socialStrings: receiverSocialStrings
|
||||
})
|
||||
if (receiverInfo === undefined) return res
|
||||
|
||||
const senderInfo = {
|
||||
_id: senderId,
|
||||
person: senderPerson,
|
||||
socialStrings: senderSocialIds.map((si) => si._id)
|
||||
employee: receiverEmployee._id
|
||||
}
|
||||
const sender = {
|
||||
socialId: senderId,
|
||||
person: senderPerson
|
||||
}
|
||||
|
||||
const notifyResult = await shouldNotifyCommon(
|
||||
control,
|
||||
receiverSocialStrings,
|
||||
receiverSocialIds,
|
||||
notification.ids.MentionCommonNotificationType,
|
||||
notificationControl
|
||||
)
|
||||
const messageNotifyResult = await getMessageNotifyResult(
|
||||
reference,
|
||||
account,
|
||||
receiverSocialStrings,
|
||||
receiverAccount,
|
||||
receiverEmployee,
|
||||
receiverSocialIds,
|
||||
control,
|
||||
originTx,
|
||||
doc,
|
||||
@ -204,8 +202,8 @@ export async function getPersonNotificationTxes (
|
||||
control,
|
||||
doc,
|
||||
data,
|
||||
receiverInfo,
|
||||
senderInfo,
|
||||
receiver,
|
||||
sender,
|
||||
reference.srcDocId,
|
||||
reference.srcDocClass,
|
||||
doc.space,
|
||||
@ -220,12 +218,12 @@ export async function getPersonNotificationTxes (
|
||||
await control.findAll(
|
||||
ctx,
|
||||
notification.class.DocNotifyContext,
|
||||
{ objectId: reference.srcDocId, user: account },
|
||||
{ objectId: reference.srcDocId, user: receiverAccount },
|
||||
{ projection: { _id: 1 } }
|
||||
)
|
||||
)[0]
|
||||
if (context !== undefined) {
|
||||
const content = await getNotificationContent(originTx, receiverSocialStrings, senderInfo, doc, control)
|
||||
const content = await getNotificationContent(originTx, receiverPersonRef, sender, doc, control)
|
||||
const notificationData: CommonInboxNotification = {
|
||||
...data,
|
||||
...content,
|
||||
@ -246,8 +244,8 @@ export async function getPersonNotificationTxes (
|
||||
control,
|
||||
res,
|
||||
doc,
|
||||
receiverInfo,
|
||||
senderInfo,
|
||||
receiver,
|
||||
sender,
|
||||
notification.class.MentionInboxNotification,
|
||||
msg as ActivityMessage
|
||||
)
|
||||
@ -331,6 +329,7 @@ async function getCollaboratorsTxes (
|
||||
async function getMessageNotifyResult (
|
||||
reference: Data<ActivityReference>,
|
||||
account: AccountUuid,
|
||||
person: Person,
|
||||
personIds: PersonId[],
|
||||
control: TriggerControl,
|
||||
tx: TxCUD<Doc>,
|
||||
@ -357,7 +356,7 @@ async function getMessageNotifyResult (
|
||||
return new Map()
|
||||
}
|
||||
|
||||
return await isShouldNotifyTx(control, tx, doc, personIds, false, false, notificationControl, undefined)
|
||||
return await isShouldNotifyTx(control, tx, doc, person._id, personIds, false, false, notificationControl, undefined)
|
||||
}
|
||||
|
||||
function isMarkupType (type: Ref<Class<Type<any>>>): boolean {
|
||||
|
@ -307,7 +307,7 @@ export async function ChunterTrigger (txes: TxCUD<Doc>[], control: TriggerContro
|
||||
export async function getChunterNotificationContent (
|
||||
_: Doc,
|
||||
tx: TxCUD<Doc>,
|
||||
target: PersonId,
|
||||
target: Ref<Person>,
|
||||
control: TriggerControl
|
||||
): Promise<NotificationContent> {
|
||||
let title: IntlString = notification.string.CommonNotificationTitle
|
||||
@ -494,7 +494,7 @@ async function OnUserStatus (txes: TxCUD<UserStatus>[], control: TriggerControl)
|
||||
return []
|
||||
}
|
||||
|
||||
function JoinChannelTypeMatch (originTx: Tx, _: Doc, person: Person, user: PersonId[]): boolean {
|
||||
function JoinChannelTypeMatch (originTx: Tx, _: Doc, person: Ref<Person>, user: PersonId[]): boolean {
|
||||
if (user.includes(originTx.modifiedBy)) return false
|
||||
if (originTx._class !== core.class.TxUpdateDoc) return false
|
||||
|
||||
|
@ -202,6 +202,16 @@ export async function getPrimarySocialIdsByAccounts (
|
||||
}
|
||||
|
||||
export async function getAccountBySocialId (control: TriggerControl, socialId: PersonId): Promise<AccountUuid | null> {
|
||||
const contextAccount = control.ctx.contextData.socialStringsToUsers.get(socialId)
|
||||
if (contextAccount != null) {
|
||||
return contextAccount
|
||||
}
|
||||
|
||||
const controlAccount = control.ctx.contextData.account
|
||||
if (controlAccount.socialIds.includes(socialId)) {
|
||||
return controlAccount.uuid
|
||||
}
|
||||
|
||||
const socialIdentity = await control.findAll(
|
||||
control.ctx,
|
||||
contact.class.SocialIdentity,
|
||||
|
@ -6,7 +6,6 @@ import core, {
|
||||
AccountRole,
|
||||
combineAttributes,
|
||||
DocumentQuery,
|
||||
includesAny,
|
||||
PersonId,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
@ -21,7 +20,7 @@ import core, {
|
||||
systemAccountUuid
|
||||
} from '@hcengineering/core'
|
||||
import { NotificationType } from '@hcengineering/notification'
|
||||
import { getEmployees, getSocialStrings, getSocialStringsByPersons } from '@hcengineering/server-contact'
|
||||
import { getEmployees, getSocialStrings } from '@hcengineering/server-contact'
|
||||
import { TriggerControl } from '@hcengineering/server-core'
|
||||
|
||||
import documents, {
|
||||
@ -391,7 +390,7 @@ export async function documentTextPresenter (doc: ControlledDocument): Promise<s
|
||||
async function CoAuthorsTypeMatch (
|
||||
originTx: TxCUD<ControlledDocument>,
|
||||
_doc: Doc,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
socialIds: PersonId[],
|
||||
_type: NotificationType,
|
||||
control: TriggerControl
|
||||
@ -402,15 +401,13 @@ async function CoAuthorsTypeMatch (
|
||||
const employees = Array.isArray(tx.operations.coAuthors)
|
||||
? tx.operations.coAuthors ?? []
|
||||
: (combineAttributes([tx.operations], 'coAuthors', '$push', '$each') as Ref<Employee>[])
|
||||
const employeeSocialStrings = Object.values(await getSocialStringsByPersons(control, employees)).flat()
|
||||
|
||||
return includesAny(socialIds, employeeSocialStrings)
|
||||
return employees.some((it) => it === person)
|
||||
} else if (originTx._class === core.class.TxCreateDoc) {
|
||||
const tx = originTx as TxCreateDoc<ControlledDocument>
|
||||
const employees = tx.attributes.coAuthors
|
||||
const employeeSocialStrings = Object.values(await getSocialStringsByPersons(control, employees)).flat()
|
||||
|
||||
return includesAny(socialIds, employeeSocialStrings)
|
||||
return employees.some((it) => it === person)
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -95,7 +95,7 @@ export async function OnMessageCreate (txes: Tx[], control: TriggerControl): Pro
|
||||
export function IsIncomingMessageTypeMatch (
|
||||
tx: Tx,
|
||||
doc: Doc,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
user: PersonId[],
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
|
@ -28,7 +28,6 @@ import core, {
|
||||
Data,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
generateId,
|
||||
MeasureContext,
|
||||
MixinUpdate,
|
||||
Ref,
|
||||
@ -36,7 +35,6 @@ import core, {
|
||||
SortingOrder,
|
||||
Space,
|
||||
Timestamp,
|
||||
toIdMap,
|
||||
Tx,
|
||||
TxCreateDoc,
|
||||
TxCUD,
|
||||
@ -45,12 +43,13 @@ import core, {
|
||||
TxRemoveDoc,
|
||||
TxUpdateDoc,
|
||||
AccountUuid,
|
||||
notEmpty
|
||||
notEmpty,
|
||||
generateId,
|
||||
toIdMap
|
||||
} from '@hcengineering/core'
|
||||
import notification, {
|
||||
ActivityInboxNotification,
|
||||
BaseNotificationType,
|
||||
BrowserNotification,
|
||||
ClassCollaborators,
|
||||
Collaborators,
|
||||
CommonInboxNotification,
|
||||
@ -61,13 +60,6 @@ import notification, {
|
||||
} from '@hcengineering/notification'
|
||||
import { getResource, translate } from '@hcengineering/platform'
|
||||
import { type TriggerControl } from '@hcengineering/server-core'
|
||||
import {
|
||||
getEmployeeByAcc,
|
||||
getPrimarySocialIdsByAccounts,
|
||||
getAccountBySocialId,
|
||||
getSocialIdsByAccounts,
|
||||
getEmployeesBySocialIds
|
||||
} from '@hcengineering/server-contact'
|
||||
import serverNotification, {
|
||||
NOTIFICATION_BODY_SIZE,
|
||||
ReceiverInfo,
|
||||
@ -75,6 +67,7 @@ import serverNotification, {
|
||||
} from '@hcengineering/server-notification'
|
||||
import { markupToText, stripTags } from '@hcengineering/text-core'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import { getAccountBySocialId, getEmployeesBySocialIds } from '@hcengineering/server-contact'
|
||||
|
||||
import {
|
||||
AvailableProvidersCache,
|
||||
@ -89,22 +82,21 @@ import {
|
||||
createPullCollaboratorsTx,
|
||||
createPushCollaboratorsTx,
|
||||
getHTMLPresenter,
|
||||
getNotificationContent,
|
||||
getNotificationLink,
|
||||
getNotificationProviderControl,
|
||||
getObjectSpace,
|
||||
getTextPresenter,
|
||||
getUsersInfo,
|
||||
getReceiversInfo,
|
||||
isAllowed,
|
||||
isMixinTx,
|
||||
isShouldNotifyTx,
|
||||
isUserEmployeeInFieldValueTypeMatch,
|
||||
isUserInFieldValueTypeMatch,
|
||||
messageToMarkup,
|
||||
replaceAll,
|
||||
toReceiverInfo,
|
||||
updateNotifyContextsSpace,
|
||||
type NotificationProviderControl
|
||||
type NotificationProviderControl,
|
||||
getNotificationContent,
|
||||
getSenderInfo
|
||||
} from './utils'
|
||||
import { PushNotificationsHandler } from './push'
|
||||
|
||||
@ -381,7 +373,7 @@ export async function pushInboxNotifications (
|
||||
objectClass,
|
||||
objectSpace,
|
||||
receiver,
|
||||
sender._id,
|
||||
sender.socialId,
|
||||
shouldUpdateTimestamp ? modifiedOn : undefined,
|
||||
tx
|
||||
)
|
||||
@ -517,7 +509,7 @@ export async function pushActivityInboxNotifications (
|
||||
activityMessage: ActivityMessage,
|
||||
shouldUpdateTimestamp: boolean
|
||||
): Promise<TxCreateDoc<InboxNotification> | undefined> {
|
||||
const content = await getNotificationContent(originTx, receiver.socialStrings, sender, object, control)
|
||||
const content = await getNotificationContent(originTx, receiver.employee, sender, object, control)
|
||||
const data: Partial<Data<ActivityInboxNotification>> = {
|
||||
...content,
|
||||
attachedTo: activityMessage._id,
|
||||
@ -582,7 +574,7 @@ async function createNotifyContext (
|
||||
const contextsCache: ContextsCache = control.cache.get(ContextsCacheKey) ?? {
|
||||
contexts: new Map<string, Ref<DocNotifyContext>>()
|
||||
}
|
||||
const cacheKey = `${objectId}_${receiver._id}`
|
||||
const cacheKey = `${objectId}_${receiver.account}`
|
||||
const cachedId = contextsCache.contexts.get(cacheKey)
|
||||
|
||||
if (cachedId !== undefined) {
|
||||
@ -602,18 +594,15 @@ async function createNotifyContext (
|
||||
hidden: false,
|
||||
tx: tx?._id,
|
||||
lastUpdateTimestamp: updateTimestamp,
|
||||
lastViewedTimestamp: sender === receiver._id ? updateTimestamp : undefined
|
||||
lastViewedTimestamp: receiver.socialIds.some((it) => it === sender) ? updateTimestamp : undefined
|
||||
})
|
||||
|
||||
contextsCache.contexts.set(cacheKey, createTx.objectId)
|
||||
control.cache.set(ContextsCacheKey, contextsCache)
|
||||
await ctx.with('apply', {}, () => control.apply(control.ctx, [createTx]))
|
||||
const personUuid = receiver.person?.personUuid
|
||||
if (personUuid !== undefined) {
|
||||
control.ctx.contextData.broadcast.targets['docNotifyContext' + createTx._id] = (it) => {
|
||||
if (it._id === createTx._id) {
|
||||
return [personUuid]
|
||||
}
|
||||
control.ctx.contextData.broadcast.targets['docNotifyContext' + createTx._id] = (it) => {
|
||||
if (it._id === createTx._id) {
|
||||
return [receiver.account]
|
||||
}
|
||||
}
|
||||
return createTx.objectId
|
||||
@ -631,10 +620,6 @@ export async function getNotificationTxes (
|
||||
activityMessages: ActivityMessage[],
|
||||
settings: NotificationProviderControl
|
||||
): Promise<Tx[]> {
|
||||
if (receiver.employee === undefined) {
|
||||
return []
|
||||
}
|
||||
|
||||
const res: Tx[] = []
|
||||
|
||||
for (const message of activityMessages) {
|
||||
@ -643,7 +628,8 @@ export async function getNotificationTxes (
|
||||
control,
|
||||
tx,
|
||||
object,
|
||||
receiver.socialStrings,
|
||||
receiver.employee,
|
||||
receiver.socialIds,
|
||||
params.isOwn,
|
||||
params.isSpace,
|
||||
settings,
|
||||
@ -699,7 +685,7 @@ export async function getNotificationTxes (
|
||||
message.attachedToClass,
|
||||
object.space,
|
||||
receiver,
|
||||
sender._id,
|
||||
sender.socialId,
|
||||
params.shouldUpdateTimestamp ? tx.modifiedOn : undefined,
|
||||
tx
|
||||
)
|
||||
@ -718,19 +704,15 @@ async function updateContextsTimestamp (
|
||||
): Promise<void> {
|
||||
if (contexts.length === 0) return
|
||||
const res: Tx[] = []
|
||||
const socialIdsByAccounts = await getSocialIdsByAccounts(
|
||||
control,
|
||||
contexts.map((it) => it.user)
|
||||
)
|
||||
const modifiedByAccount = await getAccountBySocialId(control, modifiedBy)
|
||||
|
||||
for (const context of contexts) {
|
||||
const isViewed =
|
||||
context.lastViewedTimestamp !== undefined && (context.lastUpdateTimestamp ?? 0) <= context.lastViewedTimestamp
|
||||
const ctxUserSocialIds = socialIdsByAccounts[context.user] ?? []
|
||||
const updateTx = control.txFactory.createTxUpdateDoc(context._class, context.space, context._id, {
|
||||
hidden: false,
|
||||
lastUpdateTimestamp: timestamp,
|
||||
...(isViewed && ctxUserSocialIds.includes(modifiedBy)
|
||||
...(isViewed && context.user === modifiedByAccount
|
||||
? {
|
||||
lastViewedTimestamp: timestamp
|
||||
}
|
||||
@ -867,29 +849,18 @@ export async function createCollabDocInfo (
|
||||
if (targets.size === 0) {
|
||||
return res
|
||||
}
|
||||
const targetPrimarySocialStringsByAccounts = await getPrimarySocialIdsByAccounts(control, Array.from(targets))
|
||||
|
||||
const usersInfo = await ctx.with('get-user-info', {}, (ctx) =>
|
||||
getUsersInfo(ctx, [...Object.values(targetPrimarySocialStringsByAccounts), tx.modifiedBy], control)
|
||||
)
|
||||
const sender: SenderInfo = usersInfo.get(tx.modifiedBy) ?? {
|
||||
_id: tx.modifiedBy,
|
||||
socialStrings: []
|
||||
}
|
||||
|
||||
const receivers = await getReceiversInfo(ctx, Array.from(targets), control)
|
||||
const sender: SenderInfo = await getSenderInfo(ctx, tx.modifiedBy, control)
|
||||
const settings = await getNotificationProviderControl(ctx, control)
|
||||
for (const target of targets) {
|
||||
const targetSocialString = targetPrimarySocialStringsByAccounts[target]
|
||||
const info: ReceiverInfo | undefined = toReceiverInfo(control.hierarchy, usersInfo.get(targetSocialString))
|
||||
|
||||
if (info === undefined) continue
|
||||
|
||||
for (const receiver of receivers) {
|
||||
const targetRes = await getNotificationTxes(
|
||||
ctx,
|
||||
control,
|
||||
object,
|
||||
tx,
|
||||
info,
|
||||
receiver,
|
||||
sender,
|
||||
params,
|
||||
notifyContexts,
|
||||
@ -897,13 +868,10 @@ export async function createCollabDocInfo (
|
||||
settings
|
||||
)
|
||||
const ids = new Set(targetRes.map((it) => it._id))
|
||||
const { personUuid } = info.person
|
||||
if (personUuid !== undefined) {
|
||||
const id = generateId() as string
|
||||
control.ctx.contextData.broadcast.targets[id] = (it) => {
|
||||
if (ids.has(it._id)) {
|
||||
return [personUuid]
|
||||
}
|
||||
const id = generateId() as string
|
||||
control.ctx.contextData.broadcast.targets[id] = (it) => {
|
||||
if (ids.has(it._id)) {
|
||||
return [receiver.account]
|
||||
}
|
||||
}
|
||||
res = res.concat(targetRes)
|
||||
@ -1141,13 +1109,15 @@ async function updateCollaboratorsMixin (
|
||||
}
|
||||
|
||||
const providers = await control.modelDb.findAll(notification.class.NotificationProvider, {})
|
||||
const modifiedByAccount = await getAccountBySocialId(control, tx.modifiedBy)
|
||||
const socialIdsByAccounts = await getSocialIdsByAccounts(control, tx.attributes.collaborators)
|
||||
const sender: SenderInfo = await getSenderInfo(ctx, tx.modifiedBy, control)
|
||||
const receivers = await getReceiversInfo(ctx, tx.attributes.collaborators, control)
|
||||
|
||||
for (const collab of tx.attributes.collaborators) {
|
||||
if (!prevCollabs.has(collab) && modifiedByAccount !== collab) {
|
||||
const info = receivers.find((it) => it.account === collab)
|
||||
if (info === undefined) continue
|
||||
if (!prevCollabs.has(collab) && sender.person?.personUuid !== collab) {
|
||||
for (const provider of providers) {
|
||||
if (isAllowed(control, socialIdsByAccounts[collab], type, provider, notificationControl)) {
|
||||
if (isAllowed(control, info.socialIds, type, provider, notificationControl)) {
|
||||
newCollabs.push(collab)
|
||||
break
|
||||
}
|
||||
@ -1167,23 +1137,17 @@ async function updateCollaboratorsMixin (
|
||||
user: { $in: newCollabs },
|
||||
objectId: tx.objectId
|
||||
})
|
||||
const newCollabsPrimarySocialStringsByAccounts = await getPrimarySocialIdsByAccounts(control, newCollabs)
|
||||
|
||||
const infos = await ctx.with('get-user-info', {}, (ctx) =>
|
||||
getUsersInfo(ctx, [...Object.values(newCollabsPrimarySocialStringsByAccounts), originTx.modifiedBy], control)
|
||||
)
|
||||
const sender: SenderInfo = infos.get(originTx.modifiedBy) ?? { _id: originTx.modifiedBy, socialStrings: [] }
|
||||
const infos = receivers.filter((it) => newCollabs.includes(it.account))
|
||||
|
||||
for (const collab of newCollabs) {
|
||||
const target = toReceiverInfo(hierarchy, infos.get(newCollabsPrimarySocialStringsByAccounts[collab]))
|
||||
if (target === undefined) continue
|
||||
const isMember = space.members.includes(collab)
|
||||
for (const target of infos) {
|
||||
const isMember = space.members.includes(target.account)
|
||||
if (space.private && !isMember) continue
|
||||
|
||||
if (!hierarchy.isDerived(space._class, core.class.SystemSpace) && !isMember) {
|
||||
res.push(
|
||||
control.txFactory.createTxUpdateDoc(space._class, space.space, space._id, {
|
||||
$push: { members: collab }
|
||||
$push: { members: target.account }
|
||||
})
|
||||
)
|
||||
}
|
||||
@ -1536,12 +1500,7 @@ export async function OnAttributeUpdate (txes: Tx[], control: TriggerControl): P
|
||||
return result
|
||||
}
|
||||
|
||||
async function applyUserTxes (
|
||||
ctx: MeasureContext,
|
||||
control: TriggerControl,
|
||||
txes: Tx[],
|
||||
cache: Map<AccountUuid, Doc> = new Map<AccountUuid, Doc>()
|
||||
): Promise<Tx[]> {
|
||||
async function applyUserTxes (ctx: MeasureContext, control: TriggerControl, txes: Tx[]): Promise<Tx[]> {
|
||||
const map: Map<AccountUuid, Tx[]> = new Map<AccountUuid, Tx[]>()
|
||||
const res: Tx[] = []
|
||||
|
||||
@ -1553,17 +1512,6 @@ async function applyUserTxes (
|
||||
) {
|
||||
const notification = TxProcessor.createDoc2Doc(ttx as TxCreateDoc<InboxNotification>)
|
||||
|
||||
if (map.has(notification.user)) {
|
||||
map.get(notification.user)?.push(tx)
|
||||
} else {
|
||||
map.set(notification.user, [tx])
|
||||
}
|
||||
} else if (
|
||||
control.hierarchy.isDerived(ttx.objectClass, notification.class.BrowserNotification) &&
|
||||
ttx._class === core.class.TxCreateDoc
|
||||
) {
|
||||
const notification = TxProcessor.createDoc2Doc(ttx as TxCreateDoc<BrowserNotification>)
|
||||
|
||||
if (map.has(notification.user)) {
|
||||
map.get(notification.user)?.push(tx)
|
||||
} else {
|
||||
@ -1575,18 +1523,11 @@ async function applyUserTxes (
|
||||
}
|
||||
|
||||
for (const [user, txs] of map.entries()) {
|
||||
const person = (cache.get(user) as Person) ?? (await getEmployeeByAcc(control, user))
|
||||
const personUuid = person?.personUuid
|
||||
|
||||
if (personUuid !== undefined) {
|
||||
cache.set(user, person)
|
||||
await control.apply(ctx, txs)
|
||||
|
||||
const m1 = toIdMap(txs)
|
||||
control.ctx.contextData.broadcast.targets.docNotifyContext = (it) => {
|
||||
if (m1.has(it._id)) {
|
||||
return [personUuid]
|
||||
}
|
||||
await control.apply(ctx, txs)
|
||||
const m1 = toIdMap(txs)
|
||||
control.ctx.contextData.broadcast.targets.docNotifyContext = (it) => {
|
||||
if (m1.has(it._id)) {
|
||||
return [user]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1640,12 +1581,9 @@ async function updateCollaborators (
|
||||
if (hierarchy.classHierarchyMixin(objectClass, activity.mixin.ActivityDoc) === undefined) return res
|
||||
|
||||
const contexts = await control.findAll(control.ctx, notification.class.DocNotifyContext, { objectId })
|
||||
const toAddPrimarySocialStringsByAccounts = await getPrimarySocialIdsByAccounts(control, toAdd)
|
||||
const addedInfo = await getUsersInfo(ctx, Object.values(toAddPrimarySocialStringsByAccounts), control)
|
||||
const addedInfo = await getReceiversInfo(ctx, toAdd, control)
|
||||
|
||||
for (const addedUser of addedInfo.values()) {
|
||||
const info = toReceiverInfo(hierarchy, addedUser)
|
||||
if (info === undefined) continue
|
||||
for (const info of addedInfo.values()) {
|
||||
const context = getDocNotifyContext(control, contexts, objectId, info.account)
|
||||
if (context !== undefined) {
|
||||
if (context.hidden) {
|
||||
@ -1884,7 +1822,6 @@ export default async () => ({
|
||||
PushNotificationsHandler
|
||||
},
|
||||
function: {
|
||||
IsUserInFieldValueTypeMatch: isUserInFieldValueTypeMatch,
|
||||
IsUserEmployeeInFieldValueTypeMatch: isUserEmployeeInFieldValueTypeMatch
|
||||
}
|
||||
})
|
||||
|
@ -15,9 +15,17 @@
|
||||
import activity, { ActivityMessage, DocUpdateMessage } from '@hcengineering/activity'
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import chunter, { ChatMessage } from '@hcengineering/chunter'
|
||||
import contact, { Employee, formatName, includesAny, Person } from '@hcengineering/contact'
|
||||
import contact, {
|
||||
Employee,
|
||||
formatName,
|
||||
includesAny,
|
||||
Person,
|
||||
PersonSpace,
|
||||
SocialIdentity,
|
||||
SocialIdentityRef
|
||||
} from '@hcengineering/contact'
|
||||
import core, {
|
||||
PersonId,
|
||||
AccountUuid,
|
||||
Class,
|
||||
concatLink,
|
||||
Doc,
|
||||
@ -26,15 +34,16 @@ import core, {
|
||||
Hierarchy,
|
||||
Markup,
|
||||
matchQuery,
|
||||
type MeasureContext,
|
||||
MixinUpdate,
|
||||
notEmpty,
|
||||
PersonId,
|
||||
Ref,
|
||||
Space,
|
||||
Tx,
|
||||
TxCUD,
|
||||
TxMixin,
|
||||
TxUpdateDoc,
|
||||
type MeasureContext,
|
||||
AccountUuid
|
||||
TxUpdateDoc
|
||||
} from '@hcengineering/core'
|
||||
import notification, {
|
||||
BaseNotificationType,
|
||||
@ -43,18 +52,12 @@ import notification, {
|
||||
NotificationContent,
|
||||
notificationId,
|
||||
NotificationProvider,
|
||||
NotificationType,
|
||||
type NotificationProviderSetting,
|
||||
NotificationType,
|
||||
type NotificationTypeSetting
|
||||
} from '@hcengineering/notification'
|
||||
import { getMetadata, getResource, IntlString, translate } from '@hcengineering/platform'
|
||||
import serverCore, { TriggerControl } from '@hcengineering/server-core'
|
||||
import {
|
||||
getPersonsBySocialIds,
|
||||
getEmployeesBySocialIds,
|
||||
getSocialStringsByPersons,
|
||||
getPerson
|
||||
} from '@hcengineering/server-contact'
|
||||
import serverNotification, {
|
||||
HTMLPresenter,
|
||||
NotificationPresenter,
|
||||
@ -74,7 +77,7 @@ import { NotifyResult } from './types'
|
||||
export function isUserEmployeeInFieldValueTypeMatch (
|
||||
_: Tx,
|
||||
doc: Doc,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
socialIds: PersonId[],
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
@ -145,13 +148,13 @@ export async function shouldNotifyCommon (
|
||||
|
||||
export function isAllowed (
|
||||
control: TriggerControl,
|
||||
receiver: PersonId[],
|
||||
receiverIds: PersonId[],
|
||||
type: BaseNotificationType,
|
||||
provider: NotificationProvider,
|
||||
notificationControl: NotificationProviderControl
|
||||
): boolean {
|
||||
const providerSettings = (notificationControl.byProvider.get(provider._id) ?? []).filter(({ createdBy }) =>
|
||||
createdBy !== undefined ? receiver.includes(createdBy) : false
|
||||
createdBy !== undefined ? receiverIds.includes(createdBy) : false
|
||||
)
|
||||
|
||||
if (providerSettings.length > 0 && providerSettings.every((s) => !s.enabled)) {
|
||||
@ -169,7 +172,7 @@ export function isAllowed (
|
||||
}
|
||||
|
||||
const setting = (notificationControl.settingsByProvider.get(provider._id) ?? []).find(
|
||||
(it) => it.type === type._id && it.createdBy !== undefined && receiver.includes(it.createdBy)
|
||||
(it) => it.type === type._id && it.createdBy !== undefined && receiverIds.includes(it.createdBy)
|
||||
)
|
||||
|
||||
if (setting !== undefined) {
|
||||
@ -189,6 +192,7 @@ export async function isShouldNotifyTx (
|
||||
control: TriggerControl,
|
||||
tx: TxCUD<Doc>,
|
||||
object: Doc,
|
||||
person: Ref<Person>,
|
||||
personIds: PersonId[],
|
||||
isOwn: boolean,
|
||||
isSpace: boolean,
|
||||
@ -213,8 +217,6 @@ export async function isShouldNotifyTx (
|
||||
const mixin = control.hierarchy.as(type, serverNotification.mixin.TypeMatch)
|
||||
if (mixin.func !== undefined) {
|
||||
const f = await getResource(mixin.func)
|
||||
const person = await getPerson(control, personIds[0])
|
||||
if (person === undefined) continue
|
||||
let res = f(tx, object, person, personIds, type, control)
|
||||
if (res instanceof Promise) {
|
||||
res = await res
|
||||
@ -324,15 +326,15 @@ export function getTextPresenter (_class: Ref<Class<Doc>>, hierarchy: Hierarchy)
|
||||
}
|
||||
|
||||
async function getSenderName (control: TriggerControl, sender: SenderInfo): Promise<string> {
|
||||
if (sender._id === core.account.System || sender._id === core.account.ConfigUser) {
|
||||
if (sender.socialId === core.account.System || sender.socialId === core.account.ConfigUser) {
|
||||
return await translate(core.string.System, {})
|
||||
}
|
||||
|
||||
const { person } = sender
|
||||
|
||||
if (person === undefined) {
|
||||
console.error('Cannot find person', { accountId: sender._id })
|
||||
Analytics.handleError(new Error(`Cannot find person ${sender._id}`))
|
||||
console.error('Cannot find person', { socialId: sender.socialId })
|
||||
Analytics.handleError(new Error(`Cannot find person ${sender.socialId}`))
|
||||
|
||||
return ''
|
||||
}
|
||||
@ -407,7 +409,7 @@ function getNotificationPresenter (_class: Ref<Class<Doc>>, hierarchy: Hierarchy
|
||||
|
||||
export async function getNotificationContent (
|
||||
originTx: TxCUD<Doc>,
|
||||
socialIds: PersonId[],
|
||||
receiver: Ref<Person>,
|
||||
sender: SenderInfo,
|
||||
object: Doc,
|
||||
control: TriggerControl
|
||||
@ -425,7 +427,7 @@ export async function getNotificationContent (
|
||||
|
||||
if (notificationPresenter !== undefined) {
|
||||
const getFuillfillmentParams = await getResource(notificationPresenter.presenter)
|
||||
const updateParams = await getFuillfillmentParams(object, originTx, socialIds[0], control)
|
||||
const updateParams = await getFuillfillmentParams(object, originTx, receiver, control)
|
||||
title = updateParams.title
|
||||
body = updateParams.body
|
||||
data = updateParams.data
|
||||
@ -455,74 +457,93 @@ export async function getNotificationContent (
|
||||
return content
|
||||
}
|
||||
|
||||
export async function getUsersInfo (
|
||||
export async function getReceiversInfo (
|
||||
ctx: MeasureContext,
|
||||
ids: PersonId[],
|
||||
accounts: AccountUuid[],
|
||||
control: TriggerControl
|
||||
): Promise<Map<PersonId, ReceiverInfo | SenderInfo>> {
|
||||
if (ids.length === 0) return new Map()
|
||||
const uniqueIds = Array.from(new Set(ids))
|
||||
): Promise<ReceiverInfo[]> {
|
||||
if (accounts.length === 0) return []
|
||||
|
||||
const employeesBySocialId = await getEmployeesBySocialIds(control, uniqueIds)
|
||||
const presentEmployeeIds = Object.values(employeesBySocialId)
|
||||
.map((it) => it?._id)
|
||||
.filter((it) => it !== undefined)
|
||||
const missingSocialIds = Object.entries(employeesBySocialId)
|
||||
.filter(([, employee]) => employee === undefined)
|
||||
.map(([id]) => id as PersonId)
|
||||
const personsBySocialId = await getPersonsBySocialIds(control, missingSocialIds)
|
||||
|
||||
const employeesIds = new Set(presentEmployeeIds)
|
||||
const spaces = (await control.findAll(ctx, contact.class.PersonSpace, {})).filter((it) =>
|
||||
employeesIds.has(it.person as Ref<Employee>)
|
||||
const employees: Pick<Employee, '_id' | 'personUuid'>[] = await control.findAll(
|
||||
ctx,
|
||||
contact.mixin.Employee,
|
||||
{ personUuid: { $in: accounts }, active: true },
|
||||
{ projection: { _id: 1, personUuid: 1 } }
|
||||
)
|
||||
const spacesByEmployee = groupByArray(spaces, (it) => it.person)
|
||||
if (employees.length === 0) return []
|
||||
|
||||
const persons = [...presentEmployeeIds, ...Object.values(personsBySocialId).map((it) => it._id)]
|
||||
const spaces: Pick<PersonSpace, '_id' | 'person'>[] = await control.queryFind(
|
||||
ctx,
|
||||
contact.class.PersonSpace,
|
||||
{},
|
||||
{ projection: { _id: 1, person: 1 } }
|
||||
)
|
||||
if (spaces.length === 0) return []
|
||||
|
||||
const socialStringsByPersons = await getSocialStringsByPersons(control, persons as Ref<Person>[])
|
||||
const socialIds: Pick<SocialIdentity, '_id' | 'attachedTo'>[] = await control.findAll(
|
||||
ctx,
|
||||
contact.class.SocialIdentity,
|
||||
{ attachedTo: { $in: employees.map((it) => it._id) } },
|
||||
{ projection: { _id: 1, attachedTo: 1 } }
|
||||
)
|
||||
|
||||
return new Map(
|
||||
uniqueIds.map((_id) => {
|
||||
const employee = employeesBySocialId[_id]
|
||||
const space = employee !== undefined ? spacesByEmployee.get(employee._id)?.[0] : undefined
|
||||
const person = employee ?? personsBySocialId[_id]
|
||||
const socialStrings = socialStringsByPersons[person?._id] ?? []
|
||||
const employeeByAccount = new Map(employees.map((it) => [it.personUuid, it]))
|
||||
const spaceByPerson = new Map(spaces.map((it) => [it.person, it]))
|
||||
const socialIdsByEmployee = groupByArray(socialIds, (it) => it.attachedTo)
|
||||
|
||||
return [
|
||||
_id,
|
||||
{
|
||||
_id,
|
||||
person,
|
||||
socialStrings,
|
||||
space: space?._id,
|
||||
account: employee?.personUuid,
|
||||
employee
|
||||
}
|
||||
]
|
||||
return accounts
|
||||
.map((account) => {
|
||||
const employee = employeeByAccount.get(account)
|
||||
if (employee === undefined) return undefined
|
||||
const space = spaceByPerson.get(employee._id)
|
||||
if (space === undefined) return undefined
|
||||
|
||||
const info: ReceiverInfo = {
|
||||
employee: employee._id,
|
||||
space: space._id,
|
||||
account,
|
||||
socialIds: socialIdsByEmployee.get(employee._id)?.map((it) => it._id) ?? []
|
||||
}
|
||||
return info
|
||||
})
|
||||
)
|
||||
.filter(notEmpty)
|
||||
}
|
||||
|
||||
export function toReceiverInfo (hierarchy: Hierarchy, info?: SenderInfo | ReceiverInfo): ReceiverInfo | undefined {
|
||||
if (info === undefined) return undefined
|
||||
if (info.person === undefined) return undefined
|
||||
if (!('space' in info)) return undefined
|
||||
if (info.space === undefined) return undefined
|
||||
export async function getSenderInfo (
|
||||
ctx: MeasureContext,
|
||||
socialId: PersonId,
|
||||
control: TriggerControl
|
||||
): Promise<SenderInfo> {
|
||||
const controlAccount = control.ctx.contextData.account
|
||||
let account: AccountUuid | undefined = control.ctx.contextData.socialStringsToUsers.get(socialId)
|
||||
|
||||
const isEmployee = hierarchy.hasMixin(info.person, contact.mixin.Employee)
|
||||
if (!isEmployee) return undefined
|
||||
if (account == null && controlAccount.socialIds.includes(socialId)) {
|
||||
account = controlAccount.uuid
|
||||
}
|
||||
|
||||
const employee = hierarchy.as(info.person, contact.mixin.Employee)
|
||||
if (!employee.active || employee.personUuid == null) return undefined
|
||||
if (account != null) {
|
||||
return {
|
||||
socialId,
|
||||
person: (await control.findAll(ctx, contact.class.Person, { personUuid: account }))[0]
|
||||
}
|
||||
}
|
||||
|
||||
const socialIdentity = (
|
||||
await control.findAll(
|
||||
control.ctx,
|
||||
contact.class.SocialIdentity,
|
||||
{ _id: socialId as SocialIdentityRef },
|
||||
{ limit: 1, projection: { _id: 1, attachedTo: 1 } }
|
||||
)
|
||||
)[0]
|
||||
|
||||
if (socialIdentity === undefined) {
|
||||
return { socialId }
|
||||
}
|
||||
|
||||
return {
|
||||
_id: info._id,
|
||||
person: employee,
|
||||
space: info.space,
|
||||
socialStrings: info.socialStrings,
|
||||
account: employee.personUuid,
|
||||
employee
|
||||
socialId,
|
||||
person: (await control.findAll(ctx, contact.class.Person, { _id: socialIdentity.attachedTo }))[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ export type TypeMatchFunc = Resource<
|
||||
(
|
||||
tx: Tx,
|
||||
doc: Doc,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
socialIds: PersonId[],
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
@ -79,7 +79,7 @@ export interface TypeMatch extends NotificationType {
|
||||
export type NotificationContentProvider = (
|
||||
doc: Doc,
|
||||
tx: TxCUD<Doc>,
|
||||
target: PersonId,
|
||||
person: Ref<Person>,
|
||||
control: TriggerControl
|
||||
) => Promise<NotificationContent>
|
||||
|
||||
@ -91,19 +91,15 @@ export interface NotificationPresenter extends Class<Doc> {
|
||||
}
|
||||
|
||||
export interface ReceiverInfo {
|
||||
_id: PersonId
|
||||
person: Person
|
||||
socialStrings: PersonId[]
|
||||
|
||||
space: Ref<PersonSpace>
|
||||
account: AccountUuid
|
||||
employee: Employee
|
||||
employee: Ref<Employee>
|
||||
socialIds: PersonId[]
|
||||
space: Ref<PersonSpace>
|
||||
}
|
||||
|
||||
export interface SenderInfo {
|
||||
_id: PersonId
|
||||
socialId: PersonId
|
||||
person?: Person
|
||||
socialStrings: PersonId[]
|
||||
}
|
||||
|
||||
export type NotificationProviderFunc = (
|
||||
@ -152,7 +148,6 @@ export default plugin(serverNotificationId, {
|
||||
PushNotificationsHandler: '' as Resource<TriggerFunc>
|
||||
},
|
||||
function: {
|
||||
IsUserInFieldValueTypeMatch: '' as TypeMatchFunc,
|
||||
IsUserEmployeeInFieldValueTypeMatch: '' as TypeMatchFunc
|
||||
}
|
||||
})
|
||||
|
@ -16,7 +16,6 @@
|
||||
import { DocUpdateMessage } from '@hcengineering/activity'
|
||||
import core, { Doc, Tx, TxCUD, TxCreateDoc, TxProcessor, TxUpdateDoc, type MeasureContext } from '@hcengineering/core'
|
||||
import notification from '@hcengineering/notification'
|
||||
import { getPrimarySocialIdsByAccounts } from '@hcengineering/server-contact'
|
||||
import { getResource, translate } from '@hcengineering/platform'
|
||||
import request, { Request, RequestStatus } from '@hcengineering/request'
|
||||
import { pushDocUpdateMessages } from '@hcengineering/server-activity-resources'
|
||||
@ -25,9 +24,9 @@ import {
|
||||
getCollaborators,
|
||||
getNotificationProviderControl,
|
||||
getNotificationTxes,
|
||||
getTextPresenter,
|
||||
getUsersInfo,
|
||||
toReceiverInfo
|
||||
getReceiversInfo,
|
||||
getSenderInfo,
|
||||
getTextPresenter
|
||||
} from '@hcengineering/server-notification-resources'
|
||||
|
||||
/**
|
||||
@ -146,35 +145,18 @@ async function getRequestNotificationTx (
|
||||
const notifyContexts = await control.findAll(control.ctx, notification.class.DocNotifyContext, {
|
||||
objectId: doc._id
|
||||
})
|
||||
const collaboratorsPrimarySocialStringsByAccounts = await getPrimarySocialIdsByAccounts(
|
||||
control,
|
||||
Array.from(collaborators)
|
||||
)
|
||||
const usersInfo = await getUsersInfo(
|
||||
control.ctx,
|
||||
[...Object.values(collaboratorsPrimarySocialStringsByAccounts), tx.modifiedBy],
|
||||
control
|
||||
)
|
||||
const senderInfo = usersInfo.get(tx.modifiedBy) ?? {
|
||||
_id: tx.modifiedBy,
|
||||
socialStrings: []
|
||||
}
|
||||
const receiverInfos = await getReceiversInfo(ctx, Array.from(collaborators), control)
|
||||
const senderInfo = await getSenderInfo(ctx, tx.modifiedBy, control)
|
||||
|
||||
const notificationControl = await getNotificationProviderControl(ctx, control)
|
||||
|
||||
for (const target of collaborators) {
|
||||
const targetInfo = toReceiverInfo(
|
||||
control.hierarchy,
|
||||
usersInfo.get(collaboratorsPrimarySocialStringsByAccounts[target])
|
||||
)
|
||||
if (targetInfo === undefined) continue
|
||||
|
||||
for (const receiver of receiverInfos) {
|
||||
const txes = await getNotificationTxes(
|
||||
ctx,
|
||||
control,
|
||||
request,
|
||||
tx,
|
||||
targetInfo,
|
||||
receiver,
|
||||
senderInfo,
|
||||
{ isOwn: true, isSpace: false, shouldUpdateTimestamp: true },
|
||||
notifyContexts,
|
||||
|
@ -100,7 +100,7 @@ export async function OnMessageCreate (txes: Tx[], control: TriggerControl): Pro
|
||||
export function IsIncomingMessageTypeMatch (
|
||||
tx: Tx,
|
||||
doc: Doc,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
user: PersonId[],
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
|
@ -14,7 +14,7 @@
|
||||
//
|
||||
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import contact, { Employee, Person, pickPrimarySocialId } from '@hcengineering/contact'
|
||||
import contact, { Employee, Person } from '@hcengineering/contact'
|
||||
|
||||
import core, {
|
||||
AttachedData,
|
||||
@ -37,13 +37,14 @@ import core, {
|
||||
import notification, { CommonInboxNotification } from '@hcengineering/notification'
|
||||
import { getResource } from '@hcengineering/platform'
|
||||
import type { TriggerControl } from '@hcengineering/server-core'
|
||||
import { getSocialStrings, getPerson, getAllSocialStringsByPersonId } from '@hcengineering/server-contact'
|
||||
import { getSocialStrings } from '@hcengineering/server-contact'
|
||||
import { ReceiverInfo, SenderInfo } from '@hcengineering/server-notification'
|
||||
import {
|
||||
getCommonNotificationTxes,
|
||||
getNotificationContent,
|
||||
getNotificationProviderControl,
|
||||
isShouldNotifyTx
|
||||
isShouldNotifyTx,
|
||||
getSenderInfo
|
||||
} from '@hcengineering/server-notification-resources'
|
||||
import serverTime, { OnToDo, ToDoFactory } from '@hcengineering/server-time'
|
||||
import task, { makeRank } from '@hcengineering/task'
|
||||
@ -295,44 +296,33 @@ export async function OnToDoCreate (txes: TxCUD<Doc>[], control: TriggerControl)
|
||||
continue
|
||||
}
|
||||
|
||||
const socialStrings = await getSocialStrings(control, employee._id)
|
||||
const primarySocialString = pickPrimarySocialId(socialStrings)
|
||||
const socialIds = await getSocialStrings(control, employee._id)
|
||||
const account = employee.personUuid
|
||||
|
||||
if (account == null) {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Select a proper account
|
||||
const receiverInfo: ReceiverInfo = {
|
||||
_id: primarySocialString,
|
||||
person: employee,
|
||||
socialStrings,
|
||||
|
||||
employee,
|
||||
account,
|
||||
space: personSpace._id
|
||||
socialIds,
|
||||
space: personSpace._id,
|
||||
employee: employee._id
|
||||
}
|
||||
|
||||
const senderPerson = await getPerson(control, tx.modifiedBy)
|
||||
const senderSocialStrings = await getAllSocialStringsByPersonId(control, [tx.modifiedBy])
|
||||
|
||||
const senderInfo: SenderInfo = {
|
||||
_id: tx.modifiedBy,
|
||||
person: senderPerson,
|
||||
socialStrings: senderSocialStrings
|
||||
}
|
||||
const senderInfo: SenderInfo = await getSenderInfo(control.ctx, tx.modifiedBy, control)
|
||||
const notificationControl = await getNotificationProviderControl(control.ctx, control)
|
||||
const notifyResult = await isShouldNotifyTx(
|
||||
control,
|
||||
createTx,
|
||||
todo,
|
||||
socialStrings,
|
||||
employee._id,
|
||||
socialIds,
|
||||
true,
|
||||
false,
|
||||
notificationControl
|
||||
)
|
||||
const content = await getNotificationContent(tx, socialStrings, senderInfo, todo, control)
|
||||
const content = await getNotificationContent(tx, employee._id, senderInfo, todo, control)
|
||||
const data: Partial<Data<CommonInboxNotification>> = {
|
||||
...content,
|
||||
header: time.string.ToDo,
|
||||
@ -361,12 +351,9 @@ export async function OnToDoCreate (txes: TxCUD<Doc>[], control: TriggerControl)
|
||||
await control.apply(control.ctx, txes)
|
||||
|
||||
const ids = txes.map((it) => it._id)
|
||||
const personUuid = receiverInfo.person?.personUuid
|
||||
if (personUuid !== undefined) {
|
||||
control.ctx.contextData.broadcast.targets.notifications = (it) => {
|
||||
if (ids.includes(it._id)) {
|
||||
return [personUuid]
|
||||
}
|
||||
control.ctx.contextData.broadcast.targets.notifications = (it) => {
|
||||
if (ids.includes(it._id)) {
|
||||
return [receiverInfo.account]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ import core, {
|
||||
concatLink,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
PersonId,
|
||||
Ref,
|
||||
Space,
|
||||
systemAccountUuid,
|
||||
@ -34,7 +33,6 @@ import core, {
|
||||
} from '@hcengineering/core'
|
||||
import { NotificationContent } from '@hcengineering/notification'
|
||||
import { getMetadata, IntlString } from '@hcengineering/platform'
|
||||
import { getSocialStrings } from '@hcengineering/server-contact'
|
||||
import serverCore, { TriggerControl } from '@hcengineering/server-core'
|
||||
import { NOTIFICATION_BODY_SIZE } from '@hcengineering/server-notification'
|
||||
import { stripTags } from '@hcengineering/text-core'
|
||||
@ -89,18 +87,13 @@ export async function issueTextPresenter (doc: Doc): Promise<string> {
|
||||
return `${issue.identifier} ${issue.title}`
|
||||
}
|
||||
|
||||
async function isSamePerson (control: TriggerControl, assignee: Ref<Person>, target: PersonId): Promise<boolean> {
|
||||
const socialStrings = await getSocialStrings(control, assignee)
|
||||
return socialStrings.includes(target)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function getIssueNotificationContent (
|
||||
doc: Doc,
|
||||
tx: TxCUD<Doc>,
|
||||
target: PersonId,
|
||||
target: Ref<Person>,
|
||||
control: TriggerControl
|
||||
): Promise<NotificationContent> {
|
||||
const issue = doc as Issue
|
||||
@ -127,7 +120,7 @@ export async function getIssueNotificationContent (
|
||||
if (
|
||||
updateTx.operations.assignee !== null &&
|
||||
updateTx.operations.assignee !== undefined &&
|
||||
(await isSamePerson(control, updateTx.operations.assignee, target))
|
||||
updateTx.operations.assignee === target
|
||||
) {
|
||||
body = tracker.string.IssueAssignedToYou
|
||||
} else {
|
||||
|
@ -24,13 +24,13 @@ import { isTxUpdateDoc } from '../utils/isTxUpdateDoc'
|
||||
export function TrainingRequestNotificationTypeMatch (
|
||||
tx: TxCUD<TrainingRequest>,
|
||||
doc: TrainingRequest,
|
||||
person: Person,
|
||||
person: Ref<Person>,
|
||||
user: PersonId[],
|
||||
type: NotificationType,
|
||||
control: TriggerControl
|
||||
): boolean {
|
||||
if (isTxCreateDoc(tx)) {
|
||||
return doc.trainees.includes(person._id as Ref<Employee>)
|
||||
return doc.trainees.includes(person as Ref<Employee>)
|
||||
}
|
||||
|
||||
if (isTxUpdateDoc(tx)) {
|
||||
@ -40,7 +40,7 @@ export function TrainingRequestNotificationTypeMatch (
|
||||
}
|
||||
|
||||
const newTrainees = typeof pushed === 'object' ? pushed.$each : [pushed]
|
||||
return newTrainees.includes(person._id as Ref<Employee>)
|
||||
return newTrainees.includes(person as Ref<Employee>)
|
||||
}
|
||||
|
||||
return false
|
||||
|
Loading…
Reference in New Issue
Block a user