Fix notifications (#3723)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2023-09-20 22:57:15 +06:00 committed by GitHub
parent 450cdec288
commit d9d47846cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 29 deletions

View File

@ -25,6 +25,7 @@ import chunter, {
import contact, { Employee, PersonAccount } from '@hcengineering/contact' import contact, { Employee, PersonAccount } from '@hcengineering/contact'
import core, { import core, {
Account, Account,
AttachedDoc,
Class, Class,
concatLink, concatLink,
Doc, Doc,
@ -49,11 +50,15 @@ import { getDocCollaborators, getMixinTx, pushNotification } from '@hcengineerin
import { workbenchId } from '@hcengineering/workbench' import { workbenchId } from '@hcengineering/workbench'
import { getBacklinks } from './backlinks' import { getBacklinks } from './backlinks'
function getCreateBacklinksTxes (control: TriggerControl, txFactory: TxFactory, doc: Doc): Tx[] { function getCreateBacklinksTxes (
control: TriggerControl,
txFactory: TxFactory,
doc: Doc,
backlinkId: Ref<Doc>,
backlinkClass: Ref<Class<Doc>>
): Tx[] {
const txes: Tx[] = [] const txes: Tx[] = []
const backlinkId = doc._id
const backlinkClass = doc._class
const attachedDocId = doc._id const attachedDocId = doc._id
const attributes = control.hierarchy.getAllAttributes(doc._class) const attributes = control.hierarchy.getAllAttributes(doc._class)
@ -334,8 +339,9 @@ async function BacklinksCreate (tx: Tx, control: TriggerControl): Promise<Tx[]>
const txFactory = new TxFactory(control.txFactory.account) const txFactory = new TxFactory(control.txFactory.account)
const doc = TxProcessor.createDoc2Doc(ctx) const doc = TxProcessor.createDoc2Doc(ctx)
const collTx = tx as TxCollectionCUD<Doc, AttachedDoc>
const txes: Tx[] = getCreateBacklinksTxes(control, txFactory, doc) const txes: Tx[] = getCreateBacklinksTxes(control, txFactory, doc, collTx.objectId, collTx.objectClass)
if (txes.length !== 0) { if (txes.length !== 0) {
await control.apply(txes, true) await control.apply(txes, true)
} }

View File

@ -94,7 +94,8 @@ export async function OnBacklinkCreate (tx: Tx, control: TriggerControl): Promis
) )
res.push(collabTx) res.push(collabTx)
} }
res = res.concat(await createCollabDocInfo([receiver._id], control, tx as TxCUD<Doc>, doc)) const actualTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
res = res.concat(await createCollabDocInfo([receiver._id], control, actualTx, tx as TxCUD<Doc>, doc))
} }
return res return res
} }
@ -359,29 +360,26 @@ function fieldUpdated (field: string, ops: DocumentUpdate<Doc> | MixinUpdate<Doc
return false return false
} }
function isTypeMatched ( function isTypeMatched (control: TriggerControl, type: NotificationType, tx: TxCUD<Doc>, originTx: TxCUD<Doc>): boolean {
control: TriggerControl,
type: NotificationType,
tx: TxCUD<Doc>,
extractedTx: TxCUD<Doc>
): boolean {
const h = control.hierarchy const h = control.hierarchy
const targetClass = h.getBaseClass(type.objectClass) const targetClass = h.getBaseClass(type.objectClass)
if (!type.txClasses.includes(tx._class)) return false if (!type.txClasses.includes(tx._class)) return false
if (!control.hierarchy.isDerived(h.getBaseClass(extractedTx.objectClass), targetClass)) return false if (!control.hierarchy.isDerived(h.getBaseClass(tx.objectClass), targetClass)) return false
if (tx._class === core.class.TxCollectionCUD && type.attachedToClass !== undefined) { if (originTx._class === core.class.TxCollectionCUD && type.attachedToClass !== undefined) {
if (!control.hierarchy.isDerived(h.getBaseClass(tx.objectClass), h.getBaseClass(type.attachedToClass))) return false if (!control.hierarchy.isDerived(h.getBaseClass(originTx.objectClass), h.getBaseClass(type.attachedToClass))) {
return false
}
} }
if (type.field !== undefined) { if (type.field !== undefined) {
if (extractedTx._class === core.class.TxUpdateDoc) { if (tx._class === core.class.TxUpdateDoc) {
if (!fieldUpdated(type.field, (extractedTx as TxUpdateDoc<Doc>).operations)) return false if (!fieldUpdated(type.field, (tx as TxUpdateDoc<Doc>).operations)) return false
} }
if (extractedTx._class === core.class.TxMixin) { if (tx._class === core.class.TxMixin) {
if (!fieldUpdated(type.field, (extractedTx as TxMixin<Doc, Doc>).attributes)) return false if (!fieldUpdated(type.field, (tx as TxMixin<Doc, Doc>).attributes)) return false
} }
} }
if (type.txMatch !== undefined) { if (type.txMatch !== undefined) {
const res = matchQuery([extractedTx], type.txMatch, extractedTx._class, control.hierarchy, true) const res = matchQuery([tx], type.txMatch, tx._class, control.hierarchy, true)
if (res.length === 0) return false if (res.length === 0) return false
} }
return true return true
@ -390,15 +388,15 @@ function isTypeMatched (
async function getMatchedTypes ( async function getMatchedTypes (
control: TriggerControl, control: TriggerControl,
tx: TxCUD<Doc>, tx: TxCUD<Doc>,
originTx: TxCUD<Doc>,
isSpace: boolean = false isSpace: boolean = false
): Promise<NotificationType[]> { ): Promise<NotificationType[]> {
const allTypes = (await control.modelDb.findAll(notification.class.NotificationType, {})).filter((p) => const allTypes = (await control.modelDb.findAll(notification.class.NotificationType, {})).filter((p) =>
isSpace ? p.spaceSubscribe === true : p.spaceSubscribe !== true isSpace ? p.spaceSubscribe === true : p.spaceSubscribe !== true
) )
const extractedTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
const filtered: NotificationType[] = [] const filtered: NotificationType[] = []
for (const type of allTypes) { for (const type of allTypes) {
if (isTypeMatched(control, type, tx, extractedTx)) { if (isTypeMatched(control, type, tx, originTx)) {
filtered.push(type) filtered.push(type)
} }
} }
@ -413,13 +411,14 @@ interface NotifyResult {
async function isShouldNotify ( async function isShouldNotify (
control: TriggerControl, control: TriggerControl,
tx: TxCUD<Doc>, tx: TxCUD<Doc>,
originTx: TxCUD<Doc>,
object: Doc, object: Doc,
user: Ref<Account>, user: Ref<Account>,
isSpace: boolean isSpace: boolean
): Promise<NotifyResult> { ): Promise<NotifyResult> {
let allowed = false let allowed = false
const emailTypes: NotificationType[] = [] const emailTypes: NotificationType[] = []
const types = await getMatchedTypes(control, tx, isSpace) const types = await getMatchedTypes(control, tx, originTx, isSpace)
for (const type of types) { for (const type of types) {
if (type.allowedForAuthor !== true && tx.modifiedBy === user) continue if (type.allowedForAuthor !== true && tx.modifiedBy === user) continue
if (control.hierarchy.hasMixin(type, serverNotification.mixin.TypeMatch)) { if (control.hierarchy.hasMixin(type, serverNotification.mixin.TypeMatch)) {
@ -499,13 +498,14 @@ export function pushNotification (
async function getNotificationTxes ( async function getNotificationTxes (
control: TriggerControl, control: TriggerControl,
object: Doc, object: Doc,
tx: TxCUD<Doc>,
originTx: TxCUD<Doc>, originTx: TxCUD<Doc>,
target: Ref<Account>, target: Ref<Account>,
docUpdates: DocUpdates[], docUpdates: DocUpdates[],
isSpace: boolean isSpace: boolean
): Promise<Tx[]> { ): Promise<Tx[]> {
const res: Tx[] = [] const res: Tx[] = []
const allowed = await isShouldNotify(control, originTx, object, target, isSpace) const allowed = await isShouldNotify(control, tx, originTx, object, target, isSpace)
if (allowed.allowed) { if (allowed.allowed) {
pushNotification(control, res, target, object, originTx, docUpdates) pushNotification(control, res, target, object, originTx, docUpdates)
} }
@ -534,6 +534,7 @@ async function getNotificationTxes (
async function createCollabDocInfo ( async function createCollabDocInfo (
collaborators: Ref<Account>[], collaborators: Ref<Account>[],
control: TriggerControl, control: TriggerControl,
tx: TxCUD<Doc>,
originTx: TxCUD<Doc>, originTx: TxCUD<Doc>,
object: Doc, object: Doc,
isSpace: boolean = false isSpace: boolean = false
@ -543,7 +544,7 @@ async function createCollabDocInfo (
const targets = new Set(collaborators) const targets = new Set(collaborators)
const docUpdates = await control.findAll(notification.class.DocUpdates, { attachedTo: object._id }) const docUpdates = await control.findAll(notification.class.DocUpdates, { attachedTo: object._id })
for (const target of targets) { for (const target of targets) {
res = res.concat(await getNotificationTxes(control, object, originTx, target, docUpdates, isSpace)) res = res.concat(await getNotificationTxes(control, object, tx, originTx, target, docUpdates, isSpace))
} }
return res return res
} }
@ -583,7 +584,7 @@ async function getSpaceCollabTxes (
if (mixin !== undefined) { if (mixin !== undefined) {
const collabs = control.hierarchy.as<Doc, Collaborators>(space, notification.mixin.Collaborators) const collabs = control.hierarchy.as<Doc, Collaborators>(space, notification.mixin.Collaborators)
if (collabs.collaborators !== undefined) { if (collabs.collaborators !== undefined) {
return await createCollabDocInfo(collabs.collaborators, control, originTx, doc, true) return await createCollabDocInfo(collabs.collaborators, control, tx, originTx, doc, true)
} }
} }
return [] return []
@ -605,7 +606,7 @@ export async function createCollaboratorDoc (
const collaborators = await getDocCollaborators(doc, mixin, control) const collaborators = await getDocCollaborators(doc, mixin, control)
const mixinTx = getMixinTx(tx, control, collaborators) const mixinTx = getMixinTx(tx, control, collaborators)
const notificationTxes = await createCollabDocInfo(collaborators, control, originTx, doc) const notificationTxes = await createCollabDocInfo(collaborators, control, tx, originTx, doc)
res.push(mixinTx) res.push(mixinTx)
res.push(...notificationTxes) res.push(...notificationTxes)
} }
@ -703,7 +704,7 @@ async function collectionCollabDoc (tx: TxCollectionCUD<Doc, AttachedDoc>, contr
if (doc !== undefined) { if (doc !== undefined) {
if (control.hierarchy.hasMixin(doc, notification.mixin.Collaborators)) { if (control.hierarchy.hasMixin(doc, notification.mixin.Collaborators)) {
const collabMixin = control.hierarchy.as(doc, notification.mixin.Collaborators) const collabMixin = control.hierarchy.as(doc, notification.mixin.Collaborators)
res = res.concat(await createCollabDocInfo(collabMixin.collaborators, control, tx, doc)) res = res.concat(await createCollabDocInfo(collabMixin.collaborators, control, tx, tx, doc))
} }
} }
} }
@ -807,12 +808,12 @@ async function updateCollaboratorDoc (
) )
} }
res = res.concat( res = res.concat(
await createCollabDocInfo([...collabMixin.collaborators, ...newCollaborators], control, originTx, doc) await createCollabDocInfo([...collabMixin.collaborators, ...newCollaborators], control, tx, originTx, doc)
) )
} else { } else {
const collaborators = await getDocCollaborators(doc, mixin, control) const collaborators = await getDocCollaborators(doc, mixin, control)
res.push(getMixinTx(tx, control, collaborators)) res.push(getMixinTx(tx, control, collaborators))
res = res.concat(await createCollabDocInfo(collaborators, control, originTx, doc)) res = res.concat(await createCollabDocInfo(collaborators, control, tx, originTx, doc))
} }
res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx)) res = res.concat(await getSpaceCollabTxes(control, doc, tx, originTx))