Skip to content

Commit

Permalink
UBERF-5675: fix activity and notifications for colelction update (hce…
Browse files Browse the repository at this point in the history
…ngineering#4819)

Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
Signed-off-by: Tiago Cruz <tcruz@netic.io>
  • Loading branch information
kristina-fefelova authored and tjaoc committed Mar 5, 2024
1 parent 0a74937 commit 0f03efe
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 43 deletions.
2 changes: 2 additions & 0 deletions models/request/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down
2 changes: 1 addition & 1 deletion models/server-request/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
}
6 changes: 3 additions & 3 deletions server-plugins/activity-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down
55 changes: 33 additions & 22 deletions server-plugins/notification-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ export async function pushActivityInboxNotifications (
}
}

async function getNotificationTxes (
export async function getNotificationTxes (
control: TriggerControl,
object: Doc,
tx: TxCUD<Doc>,
Expand Down Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -633,7 +639,7 @@ export async function createCollabDocInfo (
isOwn,
isSpace,
notifyContexts,
activityMessage,
docMessages,
shouldUpdateTimestamp
)
)
Expand Down Expand Up @@ -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) {
Expand All @@ -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 = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessages, false))

res.push(getMixinTx(tx, control, collaborators))
res = res.concat(await createCollabDocInfo(collaborators, control, actualTx, tx, doc, activityMessages, false))
}
return res
}

Expand Down Expand Up @@ -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'

Expand Down
7 changes: 5 additions & 2 deletions server-plugins/request-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
91 changes: 77 additions & 14 deletions server-plugins/request-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
)
Expand All @@ -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
}

// 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 true

return res
}

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export default async () => ({
trigger: {
OnRequestUpdate
OnRequest
}
})
2 changes: 1 addition & 1 deletion server-plugins/request/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ export const serverRequestId = 'server-request' as Plugin
*/
export default plugin(serverRequestId, {
trigger: {
OnRequestUpdate: '' as Resource<TriggerFunc>
OnRequest: '' as Resource<TriggerFunc>
}
})

0 comments on commit 0f03efe

Please sign in to comment.