mirror of
https://github.com/hcengineering/platform.git
synced 2025-03-15 02:23:12 +00:00
QFIX: Fix REST API + few minors (#8108)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
5bb36d6eee
commit
e0ec8d4206
@ -5,5 +5,7 @@
|
|||||||
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
|
{ "src": "/icon-192.png", "type": "image/png", "sizes": "192x192" },
|
||||||
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" },
|
{ "src": "/icon-512.png", "type": "image/png", "sizes": "512x512" },
|
||||||
{ "src": "/icon-1024.png", "type": "image/png", "sizes": "1024x1024" }
|
{ "src": "/icon-1024.png", "type": "image/png", "sizes": "1024x1024" }
|
||||||
]
|
],
|
||||||
|
"start_url": "/",
|
||||||
|
"scope": "/"
|
||||||
}
|
}
|
@ -3,7 +3,6 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { type AnalyticProvider, Analytics } from "@hcengineering/analytics"
|
import { type AnalyticProvider, Analytics } from "@hcengineering/analytics"
|
||||||
import { AnalyticsCollectorProvider } from './analytics/analyticsCollector'
|
|
||||||
import { PosthogAnalyticProvider } from "./analytics/posthog"
|
import { PosthogAnalyticProvider } from "./analytics/posthog"
|
||||||
import { SentryAnalyticProvider } from "./analytics/sentry"
|
import { SentryAnalyticProvider } from "./analytics/sentry"
|
||||||
import { type Config } from "./platform"
|
import { type Config } from "./platform"
|
||||||
@ -11,8 +10,7 @@ import { type Config } from "./platform"
|
|||||||
export function configureAnalytics (config: Config) {
|
export function configureAnalytics (config: Config) {
|
||||||
const providers: AnalyticProvider[] = [
|
const providers: AnalyticProvider[] = [
|
||||||
new SentryAnalyticProvider,
|
new SentryAnalyticProvider,
|
||||||
new PosthogAnalyticProvider,
|
new PosthogAnalyticProvider
|
||||||
new AnalyticsCollectorProvider
|
|
||||||
]
|
]
|
||||||
for (const provider of providers) {
|
for (const provider of providers) {
|
||||||
Analytics.init(provider, config)
|
Analytics.init(provider, config)
|
||||||
|
@ -39,7 +39,7 @@ import { PlatformError, unknownError } from '@hcengineering/platform'
|
|||||||
import type { RestClient } from './types'
|
import type { RestClient } from './types'
|
||||||
import { extractJson, withRetry } from './utils'
|
import { extractJson, withRetry } from './utils'
|
||||||
|
|
||||||
export async function createRestClient (endpoint: string, workspaceId: string, token: string): Promise<RestClient> {
|
export function createRestClient (endpoint: string, workspaceId: string, token: string): RestClient {
|
||||||
return new RestClientImpl(endpoint, workspaceId, token)
|
return new RestClientImpl(endpoint, workspaceId, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,8 @@ import {
|
|||||||
import { buildStorageFromConfig, storageConfigFromEnv } from '@hcengineering/server-storage'
|
import { buildStorageFromConfig, storageConfigFromEnv } from '@hcengineering/server-storage'
|
||||||
import { createWorkspace, upgradeWorkspace } from './ws-operations'
|
import { createWorkspace, upgradeWorkspace } from './ws-operations'
|
||||||
|
|
||||||
|
const dbCleanTreshold = 256 // Cleanup workspaces if less 256mb
|
||||||
|
|
||||||
export interface WorkspaceOptions {
|
export interface WorkspaceOptions {
|
||||||
errorHandler: (workspace: BaseWorkspaceInfo, error: any) => Promise<void>
|
errorHandler: (workspace: BaseWorkspaceInfo, error: any) => Promise<void>
|
||||||
force: boolean
|
force: boolean
|
||||||
@ -372,15 +374,19 @@ export class WorkspaceWorker {
|
|||||||
/**
|
/**
|
||||||
* If onlyDrop is true, will drop workspace from database, overwize remove only indexes and do full reindex.
|
* If onlyDrop is true, will drop workspace from database, overwize remove only indexes and do full reindex.
|
||||||
*/
|
*/
|
||||||
async doCleanup (ctx: MeasureContext, workspace: BaseWorkspaceInfo, onlyDrop: boolean): Promise<void> {
|
async doCleanup (ctx: MeasureContext, workspace: BaseWorkspaceInfo, cleanIndexes: boolean): Promise<void> {
|
||||||
const { dbUrl } = prepareTools([])
|
const { dbUrl } = prepareTools([])
|
||||||
const adapter = getWorkspaceDestroyAdapter(dbUrl)
|
const adapter = getWorkspaceDestroyAdapter(dbUrl)
|
||||||
await adapter.deleteWorkspace(ctx, sharedPipelineContextVars, { name: workspace.workspace, uuid: workspace.uuid })
|
await adapter.deleteWorkspace(ctx, sharedPipelineContextVars, { name: workspace.workspace, uuid: workspace.uuid })
|
||||||
|
|
||||||
await this.doReindexFulltext(ctx, workspace, onlyDrop)
|
await this.doReindexFulltext(ctx, workspace, cleanIndexes)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async doReindexFulltext (ctx: MeasureContext, workspace: BaseWorkspaceInfo, onlyDrop: boolean): Promise<void> {
|
private async doReindexFulltext (
|
||||||
|
ctx: MeasureContext,
|
||||||
|
workspace: BaseWorkspaceInfo,
|
||||||
|
clearIndexes: boolean
|
||||||
|
): Promise<void> {
|
||||||
if (this.fulltextUrl !== undefined) {
|
if (this.fulltextUrl !== undefined) {
|
||||||
const token = generateToken(systemAccountEmail, { name: workspace.workspace }, { service: 'workspace' })
|
const token = generateToken(systemAccountEmail, { name: workspace.workspace }, { service: 'workspace' })
|
||||||
|
|
||||||
@ -390,7 +396,7 @@ export class WorkspaceWorker {
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ token, onlyDrop })
|
body: JSON.stringify({ token, onlyDrop: clearIndexes })
|
||||||
})
|
})
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(`HTTP Error ${res.status} ${res.statusText}`)
|
throw new Error(`HTTP Error ${res.status} ${res.statusText}`)
|
||||||
@ -491,12 +497,16 @@ export class WorkspaceWorker {
|
|||||||
// We should remove DB, not storages.
|
// We should remove DB, not storages.
|
||||||
await sendEvent('migrate-clean-started', 0)
|
await sendEvent('migrate-clean-started', 0)
|
||||||
await this.sendTransactorMaitenance(token, { name: workspace.workspace })
|
await this.sendTransactorMaitenance(token, { name: workspace.workspace })
|
||||||
|
|
||||||
|
const sz = workspace.backupInfo?.backupSize ?? 0
|
||||||
|
if (sz <= dbCleanTreshold) {
|
||||||
try {
|
try {
|
||||||
await this.doCleanup(ctx, workspace, false)
|
await this.doCleanup(ctx, workspace, false)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
Analytics.handleError(err)
|
Analytics.handleError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
await sendEvent('migrate-clean-done', 0)
|
await sendEvent('migrate-clean-done', 0)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -149,9 +149,9 @@ describe('rest-server', () => {
|
|||||||
await shutdown()
|
await shutdown()
|
||||||
})
|
})
|
||||||
|
|
||||||
async function connect (): Promise<RestClient> {
|
function connect (): RestClient {
|
||||||
const token: string = generateToken('user1@site.com', getWorkspaceId('test-ws'))
|
const token: string = generateToken('user1@site.com', getWorkspaceId('test-ws'))
|
||||||
return await createRestClient(`http://localhost:${port}`, 'test-ws', token)
|
return createRestClient(`http://localhost:${port}`, 'test-ws', token)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function connectTx (): Promise<TxOperations> {
|
async function connectTx (): Promise<TxOperations> {
|
||||||
@ -160,7 +160,7 @@ describe('rest-server', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('get account', async () => {
|
it('get account', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const account = await conn.getAccount()
|
const account = await conn.getAccount()
|
||||||
|
|
||||||
expect(account.email).toBe('user1@site.com')
|
expect(account.email).toBe('user1@site.com')
|
||||||
@ -175,7 +175,7 @@ describe('rest-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('find spaces', async () => {
|
it('find spaces', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const spaces = await conn.findAll(core.class.Space, {})
|
const spaces = await conn.findAll(core.class.Space, {})
|
||||||
expect(spaces.length).toBe(2)
|
expect(spaces.length).toBe(2)
|
||||||
expect(spaces[0].name).toBe('Sp1')
|
expect(spaces[0].name).toBe('Sp1')
|
||||||
@ -183,7 +183,7 @@ describe('rest-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('find avg', async () => {
|
it('find avg', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
let ops = 0
|
let ops = 0
|
||||||
let total = 0
|
let total = 0
|
||||||
const attempts = 1000
|
const attempts = 1000
|
||||||
@ -204,7 +204,7 @@ describe('rest-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('add space', async () => {
|
it('add space', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const account = await conn.getAccount()
|
const account = await conn.getAccount()
|
||||||
const tx: TxCreateDoc<Space> = {
|
const tx: TxCreateDoc<Space> = {
|
||||||
_class: core.class.TxCreateDoc,
|
_class: core.class.TxCreateDoc,
|
||||||
|
@ -44,9 +44,9 @@ describe('rest-api-server', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
async function connect (ws?: WorkspaceToken): Promise<RestClient> {
|
function connect (ws?: WorkspaceToken): RestClient {
|
||||||
const tok = ws ?? apiWorkspace1
|
const tok = ws ?? apiWorkspace1
|
||||||
return await createRestClient(tok.endpoint, tok.workspaceId, tok.token)
|
return createRestClient(tok.endpoint, tok.workspaceId, tok.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function connectTx (ws?: WorkspaceToken): Promise<TxOperations> {
|
async function connectTx (ws?: WorkspaceToken): Promise<TxOperations> {
|
||||||
@ -55,7 +55,7 @@ describe('rest-api-server', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('get account', async () => {
|
it('get account', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const account = await conn.getAccount()
|
const account = await conn.getAccount()
|
||||||
|
|
||||||
expect(account.email).toBe('user1')
|
expect(account.email).toBe('user1')
|
||||||
@ -69,7 +69,7 @@ describe('rest-api-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('find spaces', async () => {
|
it('find spaces', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const spaces = await conn.findAll(core.class.Space, {})
|
const spaces = await conn.findAll(core.class.Space, {})
|
||||||
expect(spaces.length).toBeGreaterThanOrEqual(20)
|
expect(spaces.length).toBeGreaterThanOrEqual(20)
|
||||||
const personSpace = spaces.find((it) => it.name === 'Pesonal space' && it.private)
|
const personSpace = spaces.find((it) => it.name === 'Pesonal space' && it.private)
|
||||||
@ -77,12 +77,12 @@ describe('rest-api-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('find spaces limit', async () => {
|
it('find spaces limit', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const spaces = await conn.findAll(core.class.Space, {}, { limit: 5 })
|
const spaces = await conn.findAll(core.class.Space, {}, { limit: 5 })
|
||||||
expect(spaces.length).toBe(5)
|
expect(spaces.length).toBe(5)
|
||||||
})
|
})
|
||||||
it('find spaces by-name', async () => {
|
it('find spaces by-name', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const spaces = await conn.findAll(
|
const spaces = await conn.findAll(
|
||||||
contact.class.PersonSpace,
|
contact.class.PersonSpace,
|
||||||
{ name: 'Personal space' },
|
{ name: 'Personal space' },
|
||||||
@ -98,24 +98,24 @@ describe('rest-api-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('find channels', async () => {
|
it('find channels', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const spaces = await conn.findAll(chunter.class.Channel, {})
|
const spaces = await conn.findAll(chunter.class.Channel, {})
|
||||||
expect(spaces.length).toBeGreaterThanOrEqual(2)
|
expect(spaces.length).toBeGreaterThanOrEqual(2)
|
||||||
expect(spaces.find((it) => it._id === 'chunter:space:General')).not.toBeNull()
|
expect(spaces.find((it) => it._id === 'chunter:space:General')).not.toBeNull()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('find avg', async () => {
|
it('find avg', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
await checkFindPerformance(conn) // 5ms max per operation
|
await checkFindPerformance(conn) // 5ms max per operation
|
||||||
})
|
})
|
||||||
|
|
||||||
it('find avg-europe', async () => {
|
it('find avg-europe', async () => {
|
||||||
const conn = await connect(apiWorkspace2)
|
const conn = connect(apiWorkspace2)
|
||||||
await checkFindPerformance(conn) // 5ms max per operation
|
await checkFindPerformance(conn) // 5ms max per operation
|
||||||
})
|
})
|
||||||
|
|
||||||
it('add space', async () => {
|
it('add space', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const account = await conn.getAccount()
|
const account = await conn.getAccount()
|
||||||
const spaceName = generateId()
|
const spaceName = generateId()
|
||||||
const tx: TxCreateDoc<Space> = {
|
const tx: TxCreateDoc<Space> = {
|
||||||
@ -142,7 +142,7 @@ describe('rest-api-server', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('get-model', async () => {
|
it('get-model', async () => {
|
||||||
const conn = await connect()
|
const conn = connect()
|
||||||
const { hierarchy, model } = await conn.getModel()
|
const { hierarchy, model } = await conn.getModel()
|
||||||
|
|
||||||
const dsc = hierarchy.getDescendants(core.class.Space)
|
const dsc = hierarchy.getDescendants(core.class.Space)
|
||||||
|
Loading…
Reference in New Issue
Block a user