UBERF-5675: fix activity and notifications for colelction update (#4819)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
Kristina 2024-02-29 10:32:17 +04:00 committed by GitHub
parent ff9e4abb7d
commit 9dab305008
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 43 deletions

View File

@ -87,6 +87,8 @@ export class TRequestPresenter extends TClass implements RequestPresenter {
export function createModel (builder: Builder): void {
builder.createModel(TRequest, TRequestDecisionComment, TRequestPresenter)
builder.mixin(request.class.Request, core.class.Class, activity.mixin.IgnoreActivity, {})
builder.mixin(request.class.Request, core.class.Class, view.mixin.ObjectEditor, {
editor: request.component.EditRequest
})

View File

@ -23,6 +23,6 @@ export { serverRequestId } from '@hcengineering/server-request'
export function createModel (builder: Builder): void {
builder.createDoc(serverCore.class.Trigger, core.space.Model, {
trigger: serverRequest.trigger.OnRequestUpdate
trigger: serverRequest.trigger.OnRequest
})
}

View File

@ -151,8 +151,8 @@ function getDocUpdateMessageTx (
)
}
async function pushDocUpdateMessages (
ctx: MeasureContext,
export async function pushDocUpdateMessages (
ctx: MeasureContext | undefined,
control: ActivityControl,
res: TxCollectionCUD<Doc, DocUpdateMessage>[],
object: Doc | undefined,
@ -295,7 +295,7 @@ export async function generateDocUpdateMessages (
case core.class.TxCollectionCUD: {
const actualTx = TxProcessor.extractTx(tx) as TxCUD<Doc>
res = await generateDocUpdateMessages(ctx, actualTx, control, res, tx, objectCache)
if ([core.class.TxCreateDoc, core.class.TxRemoveDoc, core.class.TxUpdateDoc].includes(actualTx._class)) {
if ([core.class.TxCreateDoc, core.class.TxRemoveDoc].includes(actualTx._class)) {
if (!isActivityDoc(tx.objectClass, control.hierarchy)) {
return res
}

View File

@ -540,7 +540,7 @@ export async function pushActivityInboxNotifications (
}
}
async function getNotificationTxes (
export async function getNotificationTxes (
control: TriggerControl,
object: Doc,
tx: TxCUD<Doc>,
@ -608,6 +608,12 @@ export async function createCollabDocInfo (
return res
}
const docMessages = activityMessage.filter((message) => message.attachedTo === object._id)
if (docMessages.length === 0) {
return res
}
const targets = new Set(collaborators)
// user is not collaborator of himself, but we should notify user of changes related to users account (mentions, comments etc)
@ -619,7 +625,7 @@ export async function createCollabDocInfo (
}
const notifyContexts = await control.findAll(notification.class.DocNotifyContext, {
attachedTo: { $in: activityMessage.map(({ attachedTo }) => attachedTo) }
attachedTo: object._id
})
for (const target of targets) {
@ -633,7 +639,7 @@ export async function createCollabDocInfo (
isOwn,
isSpace,
notifyContexts,
activityMessage,
docMessages,
shouldUpdateTimestamp
)
)
@ -800,15 +806,6 @@ async function collectionCollabDoc (
return res
}
const isNotificationPushed = (res as TxCUD<Doc>[]).some(
({ _class, objectClass }) =>
_class === core.class.TxCreateDoc && objectClass === notification.class.ActivityInboxNotification
)
if (isNotificationPushed) {
return res
}
const mixin = control.hierarchy.classHierarchyMixin(tx.objectClass, notification.mixin.ClassCollaborators)
if (mixin === undefined) {
@ -821,18 +818,10 @@ async function collectionCollabDoc (
return res
}
if (control.hierarchy.hasMixin(doc, notification.mixin.Collaborators)) {
const collaborators = control.hierarchy.as(doc, notification.mixin.Collaborators)
const collaborators = await getCollaborators(doc, control, tx, res)
res = res.concat(
await createCollabDocInfo(collaborators.collaborators, control, actualTx, tx, doc, activityMessages, false)
)
} else {
const collaborators = await getDocCollaborators(doc, mixin, control)
res.push(getMixinTx(tx, control, collaborators))
res = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessages, false))
}
return res
}
@ -1107,6 +1096,28 @@ async function OnActivityNotificationViewed (
)
}
export async function getCollaborators (
doc: Doc,
control: TriggerControl,
tx: TxCUD<Doc>,
res: Tx[]
): Promise<Ref<Account>[]> {
const mixin = control.hierarchy.classHierarchyMixin(doc._class, notification.mixin.ClassCollaborators)
if (mixin === undefined) {
return []
}
if (control.hierarchy.hasMixin(doc, notification.mixin.Collaborators)) {
return control.hierarchy.as(doc, notification.mixin.Collaborators).collaborators
} else {
const collaborators = await getDocCollaborators(doc, mixin, control)
res.push(getMixinTx(tx, control, collaborators))
return collaborators
}
}
export * from './types'
export * from './utils'

View File

@ -38,8 +38,11 @@
"@hcengineering/server-core": "^0.6.1",
"@hcengineering/server-request": "^0.6.0",
"@hcengineering/request": "^0.6.6",
"@hcengineering/chunter": "^0.6.12",
"@hcengineering/view": "^0.6.9",
"@hcengineering/contact": "^0.6.20"
"@hcengineering/contact": "^0.6.20",
"@hcengineering/server-activity-resources": "^0.6.0",
"@hcengineering/server-notification-resources": "^0.6.0",
"@hcengineering/notification": "^0.6.16",
"@hcengineering/activity": "^0.6.0"
}
}

View File

@ -13,18 +13,42 @@
// limitations under the License.
//
import core, { Doc, Hierarchy, Tx, TxCollectionCUD, TxUpdateDoc } from '@hcengineering/core'
import core, { Doc, Tx, TxCUD, TxCollectionCUD, TxCreateDoc, TxUpdateDoc, TxProcessor } from '@hcengineering/core'
import request, { Request, RequestStatus } from '@hcengineering/request'
import type { TriggerControl } from '@hcengineering/server-core'
import { pushDocUpdateMessages } from '@hcengineering/server-activity-resources'
import { DocUpdateMessage } from '@hcengineering/activity'
import notification from '@hcengineering/notification'
import { getNotificationTxes, getCollaborators } from '@hcengineering/server-notification-resources'
/**
* @public
*/
export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise<Tx[]> {
export async function OnRequest (tx: Tx, control: TriggerControl): Promise<Tx[]> {
if (tx._class !== core.class.TxCollectionCUD) {
return []
}
const hierarchy = control.hierarchy
const ptx = tx as TxCollectionCUD<Doc, Request>
if (!checkTx(ptx, hierarchy)) return []
const ctx = ptx.tx as TxUpdateDoc<Request>
if (!hierarchy.isDerived(ptx.tx.objectClass, request.class.Request)) {
return []
}
let res: Tx[] = []
res = res.concat(await getRequestNotificationTx(ptx, control))
if (ptx.tx._class === core.class.TxUpdateDoc) {
res = res.concat(await OnRequestUpdate(ptx, control))
}
return res
}
async function OnRequestUpdate (tx: TxCollectionCUD<Doc, Request>, control: TriggerControl): Promise<Tx[]> {
const ctx = tx.tx as TxUpdateDoc<Request>
if (ctx.operations.$push?.approved === undefined) return []
const request = (await control.findAll(ctx.objectClass, { _id: ctx.objectId }))[0]
if (request.approved.length === request.requiredApprovesCount) {
@ -33,9 +57,9 @@ export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise
})
collectionTx.space = core.space.Tx
const resTx = control.txFactory.createTxCollectionCUD(
ptx.objectClass,
ptx.objectId,
ptx.objectSpace,
tx.objectClass,
tx.objectId,
tx.objectSpace,
'requests',
collectionTx
)
@ -46,20 +70,59 @@ export async function OnRequestUpdate (tx: Tx, control: TriggerControl): Promise
return []
}
function checkTx (ptx: TxCollectionCUD<Doc, Request>, hierarchy: Hierarchy): boolean {
if (ptx._class !== core.class.TxCollectionCUD) {
return false
async function getRequest (tx: TxCUD<Request>, control: TriggerControl): Promise<Request | undefined> {
if (tx._class === core.class.TxCreateDoc) {
return TxProcessor.createDoc2Doc(tx as TxCreateDoc<Request>)
}
if (tx._class === core.class.TxRemoveDoc) {
return control.removedMap.get(tx.objectId) as Request
}
if (tx._class === core.class.TxUpdateDoc) {
return (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
}
if (ptx.tx._class !== core.class.TxUpdateDoc || !hierarchy.isDerived(ptx.tx.objectClass, request.class.Request)) {
return false
return undefined
}
return true
// We need request-specific logic to attach a activity message on request create/update to parent, but use request collaborators for notifications
async function getRequestNotificationTx (tx: TxCollectionCUD<Doc, Request>, control: TriggerControl): Promise<Tx[]> {
const request = await getRequest(tx.tx, control)
if (request === undefined) return []
const doc = (await control.findAll(tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0]
if (doc === undefined) return []
const res: Tx[] = []
const messagesTxes = await pushDocUpdateMessages(undefined, control, [], doc, tx)
if (messagesTxes.length === 0) return []
res.push(...messagesTxes)
const messages = messagesTxes.map((messageTx) =>
TxProcessor.createDoc2Doc(messageTx.tx as TxCreateDoc<DocUpdateMessage>)
)
const collaborators = await getCollaborators(request, control, tx.tx, res)
if (collaborators.length === 0) return res
const notifyContexts = await control.findAll(notification.class.DocNotifyContext, {
attachedTo: doc._id
})
for (const target of collaborators) {
const txes = await getNotificationTxes(control, request, tx.tx, tx, target, true, false, notifyContexts, messages)
res.push(...txes)
}
return res
}
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnRequestUpdate
OnRequest
}
})

View File

@ -26,6 +26,6 @@ export const serverRequestId = 'server-request' as Plugin
*/
export default plugin(serverRequestId, {
trigger: {
OnRequestUpdate: '' as Resource<TriggerFunc>
OnRequest: '' as Resource<TriggerFunc>
}
})