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