UBERF-7583: Fix workspace upgrade (#6062)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-07-12 20:10:33 +07:00 committed by GitHub
parent e4192b27fc
commit c94076087d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 54 additions and 24 deletions

View File

@ -453,7 +453,7 @@ export class ApplyOperations extends TxOperations {
findAll: (_class, query, options?) => ops.client.findAll(_class, query, options), findAll: (_class, query, options?) => ops.client.findAll(_class, query, options),
searchFulltext: (query, options) => ops.client.searchFulltext(query, options), searchFulltext: (query, options) => ops.client.searchFulltext(query, options),
tx: async (tx): Promise<TxResult> => { tx: async (tx): Promise<TxResult> => {
if (ops.getHierarchy().isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
this.txes.push(tx as TxCUD<Doc>) this.txes.push(tx as TxCUD<Doc>)
} }
return {} return {}
@ -518,7 +518,7 @@ export class TxBuilder extends TxOperations {
findAll: async (_class, query, options?) => toFindResult([]), findAll: async (_class, query, options?) => toFindResult([]),
searchFulltext: async (query, options) => ({ docs: [] }), searchFulltext: async (query, options) => ({ docs: [] }),
tx: async (tx): Promise<TxResult> => { tx: async (tx): Promise<TxResult> => {
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
this.txes.push(tx as TxCUD<Doc>) this.txes.push(tx as TxCUD<Doc>)
} }
return {} return {}

View File

@ -438,6 +438,16 @@ export abstract class TxProcessor implements WithTx {
return doc as D return doc as D
} }
static isExtendsCUD (_class: Ref<Class<Doc>>): boolean {
return (
_class === core.class.TxCreateDoc ||
_class === core.class.TxUpdateDoc ||
_class === core.class.TxRemoveDoc ||
_class === core.class.TxCollectionCUD ||
_class === core.class.TxMixin
)
}
static extractTx (tx: Tx): Tx { static extractTx (tx: Tx): Tx {
if (tx._class === core.class.TxCollectionCUD) { if (tx._class === core.class.TxCollectionCUD) {
const ctx = tx as TxCollectionCUD<Doc, AttachedDoc> const ctx = tx as TxCollectionCUD<Doc, AttachedDoc>

View File

@ -200,7 +200,7 @@ class UIClient extends TxOperations implements Client, OptimisticTxes {
return return
} }
if (!this.getHierarchy().isDerived(tx._class, core.class.TxCUD)) { if (!TxProcessor.isExtendsCUD(tx._class)) {
return return
} }

View File

@ -303,7 +303,7 @@ export class AnalyticsMiddleware extends BasePresentationMiddleware implements P
const applyIf = etx as TxApplyIf const applyIf = etx as TxApplyIf
void this.handleTx(...applyIf.txes) void this.handleTx(...applyIf.txes)
} }
if (this.client.getHierarchy().isDerived(etx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(etx._class)) {
const cud = etx as TxCUD<Doc> const cud = etx as TxCUD<Doc>
const _class = this.client.getHierarchy().getClass(cud.objectClass) const _class = this.client.getHierarchy().getClass(cud.objectClass)
if (_class.label !== undefined) { if (_class.label !== undefined) {

View File

@ -115,7 +115,7 @@ async function performCompletion (
export async function AsyncOnGPTRequest (tx: Tx, tc: TriggerControl): Promise<Tx[]> { export async function AsyncOnGPTRequest (tx: Tx, tc: TriggerControl): Promise<Tx[]> {
const actualTx = TxProcessor.extractTx(tx) const actualTx = TxProcessor.extractTx(tx)
if (tc.hierarchy.isDerived(actualTx._class, core.class.TxCUD) && actualTx.modifiedBy !== openai.account.GPT) { if (TxProcessor.isExtendsCUD(actualTx._class) && actualTx.modifiedBy !== openai.account.GPT) {
const cud: TxCUD<Doc> = actualTx as TxCUD<Doc> const cud: TxCUD<Doc> = actualTx as TxCUD<Doc>
// //
if (tc.hierarchy.isDerived(cud.objectClass, chunter.class.ChatMessage)) { if (tc.hierarchy.isDerived(cud.objectClass, chunter.class.ChatMessage)) {

View File

@ -33,6 +33,7 @@ import core, {
type TxCUD, type TxCUD,
type TxCollectionCUD, type TxCollectionCUD,
TxFactory, TxFactory,
TxProcessor,
type TxResult, type TxResult,
type WorkspaceId, type WorkspaceId,
docKey, docKey,
@ -84,7 +85,7 @@ export class FullTextIndex implements WithFind {
attachedToClass = txcol.objectClass attachedToClass = txcol.objectClass
tx = txcol.tx tx = txcol.tx
} }
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const cud = tx as TxCUD<Doc> const cud = tx as TxCUD<Doc>
if (!isClassIndexable(this.hierarchy, cud.objectClass)) { if (!isClassIndexable(this.hierarchy, cud.objectClass)) {

View File

@ -255,7 +255,7 @@ export class TServerStorage implements ServerStorage {
for (const tx of txes) { for (const tx of txes) {
const txCUD = TxProcessor.extractTx(tx) as TxCUD<Doc> const txCUD = TxProcessor.extractTx(tx) as TxCUD<Doc>
if (!this.hierarchy.isDerived(txCUD._class, core.class.TxCUD)) { if (!TxProcessor.isExtendsCUD(txCUD._class)) {
// Skip unsupported tx // Skip unsupported tx
ctx.error('Unsupported transaction', tx) ctx.error('Unsupported transaction', tx)
continue continue
@ -444,6 +444,9 @@ export class TServerStorage implements ServerStorage {
if (query?.$search !== undefined) { if (query?.$search !== undefined) {
return await ctx.with(p + '-fulltext-find-all', {}, (ctx) => this.fulltext.findAll(ctx, clazz, query, options)) return await ctx.with(p + '-fulltext-find-all', {}, (ctx) => this.fulltext.findAll(ctx, clazz, query, options))
} }
if (domain === DOMAIN_MODEL) {
return this.modelDb.findAllSync(clazz, query, options)
}
const st = Date.now() const st = Date.now()
const result = await ctx.with( const result = await ctx.with(
p + '-find-all', p + '-find-all',
@ -656,11 +659,11 @@ export class TServerStorage implements ServerStorage {
): Promise<void> => { ): Promise<void> => {
const classes = new Set<Ref<Class<Doc>>>() const classes = new Set<Ref<Class<Doc>>>()
for (const dtx of derived) { for (const dtx of derived) {
if (this.hierarchy.isDerived(dtx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(dtx._class)) {
classes.add((dtx as TxCUD<Doc>).objectClass) classes.add((dtx as TxCUD<Doc>).objectClass)
} }
const etx = TxProcessor.extractTx(dtx) const etx = TxProcessor.extractTx(dtx)
if (this.hierarchy.isDerived(etx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(etx._class)) {
classes.add((etx as TxCUD<Doc>).objectClass) classes.add((etx as TxCUD<Doc>).objectClass)
} }
} }
@ -876,7 +879,7 @@ export class TServerStorage implements ServerStorage {
for (const tx of txes) { for (const tx of txes) {
if (!this.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) { if (!this.hierarchy.isDerived(tx._class, core.class.TxApplyIf)) {
if (tx.space !== core.space.DerivedTx) { if (tx.space !== core.space.DerivedTx) {
if (this.hierarchy.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const objectClass = (tx as TxCUD<Doc>).objectClass const objectClass = (tx as TxCUD<Doc>).objectClass
if ( if (
objectClass !== core.class.BenchmarkDoc && objectClass !== core.class.BenchmarkDoc &&

View File

@ -25,7 +25,8 @@ import core, {
MeasureContext, MeasureContext,
Ref, Ref,
Tx, Tx,
TxCUD TxCUD,
TxProcessor
} from '@hcengineering/core' } from '@hcengineering/core'
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform' import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
import { Middleware, SessionContext, TxMiddlewareResult, type ServerStorage } from '@hcengineering/server-core' import { Middleware, SessionContext, TxMiddlewareResult, type ServerStorage } from '@hcengineering/server-core'
@ -51,7 +52,7 @@ export class ConfigurationMiddleware extends BaseMiddleware implements Middlewar
} }
async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> { async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> {
if (this.storage.hierarchy.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const txCUD = tx as TxCUD<Doc> const txCUD = tx as TxCUD<Doc>
const domain = this.storage.hierarchy.getDomain(txCUD.objectClass) const domain = this.storage.hierarchy.getDomain(txCUD.objectClass)
if (this.targetDomains.includes(domain)) { if (this.targetDomains.includes(domain)) {

View File

@ -26,6 +26,7 @@ import core, {
Ref, Ref,
Tx, Tx,
TxCUD, TxCUD,
TxProcessor,
systemAccountEmail systemAccountEmail
} from '@hcengineering/core' } from '@hcengineering/core'
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform' import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
@ -50,7 +51,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> { async tx (ctx: SessionContext, tx: Tx): Promise<TxMiddlewareResult> {
let target: string[] | undefined let target: string[] | undefined
if (this.storage.hierarchy.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const txCUD = tx as TxCUD<Doc> const txCUD = tx as TxCUD<Doc>
const domain = this.storage.hierarchy.getDomain(txCUD.objectClass) const domain = this.storage.hierarchy.getDomain(txCUD.objectClass)
if (this.targetDomains.includes(domain)) { if (this.targetDomains.includes(domain)) {
@ -98,7 +99,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
) )
;(findResult as FindResult<Doc> as FindResult<Tx>).filter( ;(findResult as FindResult<Doc> as FindResult<Tx>).filter(
(p) => (p) =>
!hierarchy.isDerived(p._class, core.class.TxCUD) || !TxProcessor.isExtendsCUD(p._class) ||
!targetClasses.has((p as TxCUD<Doc>).objectClass) || !targetClasses.has((p as TxCUD<Doc>).objectClass) ||
p.createdBy === account._id p.createdBy === account._id
) )

View File

@ -250,9 +250,8 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle
return return
} }
const h = this.storage.hierarchy
const actualTx = TxProcessor.extractTx(tx) const actualTx = TxProcessor.extractTx(tx)
if (!h.isDerived(actualTx._class, core.class.TxCUD)) { if (!TxProcessor.isExtendsCUD(actualTx._class)) {
return return
} }
@ -322,8 +321,7 @@ export class SpacePermissionsMiddleware extends BaseMiddleware implements Middle
} }
private async processPermissionsUpdatesFromTx (ctx: SessionContext, tx: Tx): Promise<void> { private async processPermissionsUpdatesFromTx (ctx: SessionContext, tx: Tx): Promise<void> {
const h = this.storage.hierarchy if (!TxProcessor.isExtendsCUD(tx._class)) {
if (!h.isDerived(tx._class, core.class.TxCUD)) {
return return
} }

View File

@ -328,7 +328,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
const h = this.storage.hierarchy const h = this.storage.hierarchy
let targets: string[] | undefined let targets: string[] | undefined
if (h.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const account = await getUser(this.storage, ctx) const account = await getUser(this.storage, ctx)
if (tx.objectSpace === (account._id as string)) { if (tx.objectSpace === (account._id as string)) {
targets = [account.email, systemAccountEmail] targets = [account.email, systemAccountEmail]
@ -384,7 +384,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
private async processTx (ctx: SessionContext, tx: Tx): Promise<void> { private async processTx (ctx: SessionContext, tx: Tx): Promise<void> {
const h = this.storage.hierarchy const h = this.storage.hierarchy
if (h.isDerived(tx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(tx._class)) {
const cudTx = tx as TxCUD<Doc> const cudTx = tx as TxCUD<Doc>
const isSpace = h.isDerived(cudTx.objectClass, core.class.Space) const isSpace = h.isDerived(cudTx.objectClass, core.class.Space)
if (isSpace) { if (isSpace) {
@ -429,8 +429,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
exclude?: string[] | undefined exclude?: string[] | undefined
): Promise<void> { ): Promise<void> {
for (const tx of txes) { for (const tx of txes) {
const h = this.storage.hierarchy if (TxProcessor.isExtendsCUD(tx._class)) {
if (h.isDerived(tx._class, core.class.TxCUD)) {
// TODO: Do we need security check here? // TODO: Do we need security check here?
const cudTx = tx as TxCUD<Doc> const cudTx = tx as TxCUD<Doc>
await this.processTxSpaceDomain(cudTx) await this.processTxSpaceDomain(cudTx)

View File

@ -28,6 +28,8 @@ import core, {
MeasureContext, MeasureContext,
MigrationState, MigrationState,
ModelDb, ModelDb,
systemAccountEmail,
toWorkspaceString,
Tx, Tx,
WorkspaceId, WorkspaceId,
type Doc, type Doc,
@ -44,6 +46,7 @@ import toolPlugin from './plugin'
import { MigrateClientImpl } from './upgrade' import { MigrateClientImpl } from './upgrade'
import { getMetadata } from '@hcengineering/platform' import { getMetadata } from '@hcengineering/platform'
import { generateToken } from '@hcengineering/server-token'
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
@ -411,6 +414,20 @@ export async function upgradeModel (
i++ i++
} }
}) })
if (connection === undefined) {
// We need to send reboot for workspace
console.info('send force close')
const serverEndpoint = transactorUrl.replaceAll('wss://', 'https://').replace('ws://', 'http://')
const token = generateToken(systemAccountEmail, workspaceId, { admin: 'true' })
await fetch(
serverEndpoint +
`/api/v1/manage?token=${token}&operation=force-close&wsId=${toWorkspaceString(workspaceId, '@')}`,
{
method: 'PUT'
}
)
}
} finally { } finally {
await connection?.sendForceClose() await connection?.sendForceClose()
await connection?.close() await connection?.close()

View File

@ -305,11 +305,11 @@ export class ClientSession implements Session {
): Promise<void> { ): Promise<void> {
const classes = new Set<Ref<Class<Doc>>>() const classes = new Set<Ref<Class<Doc>>>()
for (const dtx of derived) { for (const dtx of derived) {
if (this._pipeline.storage.hierarchy.isDerived(dtx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(dtx._class)) {
classes.add((dtx as TxCUD<Doc>).objectClass) classes.add((dtx as TxCUD<Doc>).objectClass)
} }
const etx = TxProcessor.extractTx(dtx) const etx = TxProcessor.extractTx(dtx)
if (this._pipeline.storage.hierarchy.isDerived(etx._class, core.class.TxCUD)) { if (TxProcessor.isExtendsCUD(etx._class)) {
classes.add((etx as TxCUD<Doc>).objectClass) classes.add((etx as TxCUD<Doc>).objectClass)
} }
} }