Uberf 5986 (#4969)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-03-15 00:12:37 +07:00 committed by GitHub
parent e3373f9278
commit 4efece2074
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 136 additions and 99 deletions

View File

@ -13,32 +13,32 @@
// limitations under the License.
//
import activity, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/activity'
import core, {
DOMAIN_TX,
TxOperations,
TxProcessor,
generateId,
type AttachedDoc,
type Doc,
type Domain,
DOMAIN_TX,
generateId,
type Ref,
type TxCollectionCUD,
type TxCUD,
TxOperations,
TxProcessor
type TxCollectionCUD
} from '@hcengineering/core'
import {
tryMigrate,
type MigrateOperation,
type MigrationClient,
type MigrationUpgradeClient,
tryMigrate
type MigrationUpgradeClient
} from '@hcengineering/model'
import notification, {
notificationId,
type ActivityInboxNotification,
type DocNotifyContext,
type DocUpdates,
type DocUpdateTx,
notificationId
type DocUpdates
} from '@hcengineering/notification'
import activity, { type ActivityMessage, type DocUpdateMessage } from '@hcengineering/activity'
import { DOMAIN_NOTIFICATION } from './index'
@ -72,120 +72,157 @@ async function createSpace (client: MigrationUpgradeClient): Promise<void> {
async function getActivityMessages (
client: MigrationClient,
tx: DocUpdateTx,
context: DocNotifyContext
): Promise<ActivityMessage[]> {
contexts: {
context: DocNotifyContext
txes: DocUpdateTx[]
}[]
): Promise<ActivityInboxNotification[]> {
const result: ActivityInboxNotification[] = []
const txes = contexts.flatMap((it) => it.txes)
const docUpdateMessages = await client.find<DocUpdateMessage>(DOMAIN_ACTIVITY, {
_class: activity.class.DocUpdateMessage,
txId: tx._id,
attachedTo: context.attachedTo
txId: { $in: txes.map((it) => it._id) },
attachedTo: { $in: contexts.map((it) => it.context.attachedTo) }
})
if (docUpdateMessages.length > 0) {
return docUpdateMessages
}
const originTx = (await client.find<TxCUD<Doc>>(DOMAIN_TX, { _id: tx._id }))[0]
if (originTx === undefined) {
return []
}
const innerTx = TxProcessor.extractTx(originTx as TxCollectionCUD<Doc, AttachedDoc>) as TxCUD<Doc>
return (
await client.find<ActivityMessage>(DOMAIN_ACTIVITY, {
_id: innerTx.objectId as Ref<ActivityMessage>,
attachedTo: context.attachedTo
docUpdateMessages.forEach((message) => {
const ctx = contexts.find((it) => it.context.attachedTo === message.attachedTo)
if (ctx === undefined) {
return
}
const tx = ctx.txes.find((it) => it._id === (message.txId as any))
if (tx == null) {
return
}
result.push({
_id: generateId(),
_class: notification.class.ActivityInboxNotification,
space: ctx.context.space,
user: ctx.context.user,
isViewed: !tx.isNew,
attachedTo: message._id,
attachedToClass: message._class,
docNotifyContext: ctx.context._id,
title: tx.title,
body: tx.body,
intlParams: tx.intlParams,
intlParamsNotLocalized: tx.intlParamsNotLocalized,
modifiedOn: tx.modifiedOn,
modifiedBy: tx.modifiedBy,
createdOn: tx.modifiedOn,
createdBy: tx.modifiedBy
})
})
).filter(({ _class }) => client.hierarchy.isDerived(_class, activity.class.ActivityMessage))
}
const originTx: TxCUD<Doc>[] = await client.find<TxCUD<Doc>>(DOMAIN_TX, { _id: { $in: txes.map((it) => it._id) } })
if (originTx.length === 0) {
return result
}
const innerTx = originTx.map((it) => TxProcessor.extractTx(it as TxCollectionCUD<Doc, AttachedDoc>) as TxCUD<Doc>)
;(
await client.find<ActivityMessage>(DOMAIN_ACTIVITY, {
_id: { $in: innerTx.map((it) => it.objectId as Ref<ActivityMessage>) }
})
)
.filter(({ _class }) => client.hierarchy.isDerived(_class, activity.class.ActivityMessage))
.forEach((message) => {
const tx = originTx.find((q) => (TxProcessor.extractTx(q) as TxCUD<Doc>).objectId === message._id)
if (tx == null) {
return
}
const ctx = contexts.find((it) => it.context.attachedTo === message.attachedTo)
if (ctx === undefined) {
return
}
const docTx = ctx.txes.find((it) => it._id === tx._id)
if (docTx == null) {
return
}
result.push({
_id: generateId(),
_class: notification.class.ActivityInboxNotification,
space: ctx.context.space,
user: ctx.context.user,
isViewed: !docTx.isNew,
attachedTo: message._id,
attachedToClass: message._class,
docNotifyContext: ctx.context._id,
title: docTx.title,
body: docTx.body,
intlParams: docTx.intlParams,
intlParamsNotLocalized: docTx.intlParamsNotLocalized,
modifiedOn: docTx.modifiedOn,
modifiedBy: docTx.modifiedBy,
createdOn: docTx.modifiedOn,
createdBy: docTx.modifiedBy
})
})
return result
}
async function getInboxNotifications (
client: MigrationClient,
tx: DocUpdateTx,
context: DocNotifyContext
): Promise<ActivityInboxNotification[]> {
const messages = await getActivityMessages(client, tx, context)
async function getInboxData (client: MigrationClient, docUpdates: DocUpdates[]): Promise<InboxData[]> {
const toProcess = docUpdates.filter((it) => !it.hidden && client.hierarchy.hasClass(it.attachedToClass))
if (messages.length === 0) {
return []
}
const contexts = toProcess.map((docUpdate) => {
const newTxIndex = docUpdate.txes.findIndex(({ isNew }) => isNew)
return messages.map((message) => ({
_id: generateId(),
_class: notification.class.ActivityInboxNotification,
space: context.space,
user: context.user,
isViewed: !tx.isNew,
attachedTo: message._id,
attachedToClass: message._class,
docNotifyContext: context._id,
title: tx.title,
body: tx.body,
intlParams: tx.intlParams,
intlParamsNotLocalized: tx.intlParamsNotLocalized,
modifiedOn: tx.modifiedOn,
modifiedBy: tx.modifiedBy,
createdOn: tx.modifiedOn,
createdBy: tx.modifiedBy
const context: DocNotifyContext = {
_id: docUpdate._id,
_class: notification.class.DocNotifyContext,
space: docUpdate.space,
user: docUpdate.user,
attachedTo: docUpdate.attachedTo,
attachedToClass: docUpdate.attachedToClass,
hidden: docUpdate.hidden,
lastViewedTimestamp: newTxIndex !== -1 ? docUpdate.txes[newTxIndex - 1]?.modifiedOn : docUpdate.lastTxTime,
lastUpdateTimestamp: docUpdate.lastTxTime,
modifiedBy: docUpdate.modifiedBy,
modifiedOn: docUpdate.modifiedOn,
createdBy: docUpdate.createdBy,
createdOn: docUpdate.createdOn
}
return {
context,
txes: docUpdate.txes
}
})
const notifications = await getActivityMessages(client, contexts)
return contexts.map((it) => ({
context: it.context,
notifications: notifications.filter((nit) => nit.docNotifyContext === it.context._id)
}))
}
async function getInboxData (client: MigrationClient, docUpdate: DocUpdates): Promise<InboxData | undefined> {
if (docUpdate.hidden) {
return
}
if (!client.hierarchy.hasClass(docUpdate.attachedToClass)) {
console.log('cannot find class: ', docUpdate.attachedToClass)
return
}
const { txes } = docUpdate
const newTxIndex = txes.findIndex(({ isNew }) => isNew)
const context: DocNotifyContext = {
_id: docUpdate._id,
_class: notification.class.DocNotifyContext,
space: docUpdate.space,
user: docUpdate.user,
attachedTo: docUpdate.attachedTo,
attachedToClass: docUpdate.attachedToClass,
hidden: docUpdate.hidden,
lastViewedTimestamp: newTxIndex !== -1 ? txes[newTxIndex - 1]?.modifiedOn : docUpdate.lastTxTime,
lastUpdateTimestamp: docUpdate.lastTxTime,
modifiedBy: docUpdate.modifiedBy,
modifiedOn: docUpdate.modifiedOn,
createdBy: docUpdate.createdBy,
createdOn: docUpdate.createdOn
}
const notifications = (await Promise.all(txes.map((tx) => getInboxNotifications(client, tx, context)))).flat()
return {
context,
notifications
}
}
async function migrateInboxNotifications (client: MigrationClient): Promise<void> {
let processing = 0
while (true) {
const docUpdates = await client.find<DocUpdates>(
DOMAIN_NOTIFICATION,
{
_class: notification.class.DocUpdates
},
{ limit: 500 }
{ limit: 1000 }
)
console.log('notifications processing:', processing)
if (docUpdates.length === 0) {
return
}
const data: InboxData[] = (
await Promise.all(docUpdates.map((docUpdate) => getInboxData(client, docUpdate)))
).filter((data): data is InboxData => data !== undefined)
processing += docUpdates.length
const data: InboxData[] = (await getInboxData(client, docUpdates)).filter(
(data): data is InboxData => data !== undefined
)
await client.deleteMany(DOMAIN_NOTIFICATION, { _id: { $in: docUpdates.map(({ _id }) => _id) } })
await client.create(

View File

@ -113,7 +113,7 @@ async function createDocUpdateMessages (client: MigrationClient): Promise<void>
async function generateFor (_class: Ref<Class<Doc>>, documents: MigrationIterator<Doc>): Promise<void> {
const classNotFound = new Set<string>()
while (true) {
const docs = await documents.next(50)
const docs = await documents.next(100)
if (docs == null || docs.length === 0) {
break