mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-07 00:12:50 +00:00
Merge remote-tracking branch 'origin/develop' into staging
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
commit
17df8e193b
3
.vscode/launch.json
vendored
3
.vscode/launch.json
vendored
@ -441,7 +441,6 @@
|
|||||||
"CLIENT_SECRET": "${env:POD_GITHUB_CLIENT_SECRET}",
|
"CLIENT_SECRET": "${env:POD_GITHUB_CLIENT_SECRET}",
|
||||||
"PRIVATE_KEY": "${env:POD_GITHUB_PRIVATE_KEY}",
|
"PRIVATE_KEY": "${env:POD_GITHUB_PRIVATE_KEY}",
|
||||||
"COLLABORATOR_URL": "ws://localhost:3078",
|
"COLLABORATOR_URL": "ws://localhost:3078",
|
||||||
"SYSTEM_EMAIL": "anticrm@hc.engineering",
|
|
||||||
"MINIO_ENDPOINT": "localhost",
|
"MINIO_ENDPOINT": "localhost",
|
||||||
"MINIO_ACCESS_KEY": "minioadmin",
|
"MINIO_ACCESS_KEY": "minioadmin",
|
||||||
"MINIO_SECRET_KEY": "minioadmin",
|
"MINIO_SECRET_KEY": "minioadmin",
|
||||||
@ -463,7 +462,6 @@
|
|||||||
"args": ["src/index.ts"],
|
"args": ["src/index.ts"],
|
||||||
"env": {
|
"env": {
|
||||||
"ACCOUNTS_URL": "http://localhost:3000",
|
"ACCOUNTS_URL": "http://localhost:3000",
|
||||||
"SYSTEM_EMAIL": "anticrm@hc.engineering",
|
|
||||||
"SECRET": "secret",
|
"SECRET": "secret",
|
||||||
"DOCS_RELEASE_INTERVAL": "10000",
|
"DOCS_RELEASE_INTERVAL": "10000",
|
||||||
"DOCS_IN_REVIEW_CHECK_INTERVAL": "10000",
|
"DOCS_IN_REVIEW_CHECK_INTERVAL": "10000",
|
||||||
@ -523,7 +521,6 @@
|
|||||||
"MINIO_ACCESS_KEY": "minioadmin",
|
"MINIO_ACCESS_KEY": "minioadmin",
|
||||||
"MINIO_SECRET_KEY": "minioadmin",
|
"MINIO_SECRET_KEY": "minioadmin",
|
||||||
"SERVICE_ID": "sign-service",
|
"SERVICE_ID": "sign-service",
|
||||||
"SYSTEM_EMAIL": "",
|
|
||||||
"ACCOUNTS_URL": "http://localhost:3000",
|
"ACCOUNTS_URL": "http://localhost:3000",
|
||||||
"BRANDING_PATH": "${workspaceRoot}/services/sign/pod-sign/debug/branding.json"
|
"BRANDING_PATH": "${workspaceRoot}/services/sign/pod-sign/debug/branding.json"
|
||||||
},
|
},
|
||||||
|
@ -81,7 +81,7 @@ async function moveWorkspace (
|
|||||||
tables = tables.filter((t) => include.has(t))
|
tables = tables.filter((t) => include.has(t))
|
||||||
}
|
}
|
||||||
|
|
||||||
await createTables(new MeasureMetricsContext('', {}), pgClient, tables)
|
await createTables(new MeasureMetricsContext('', {}), pgClient, '', tables)
|
||||||
const token = generateToken(systemAccountEmail, wsId)
|
const token = generateToken(systemAccountEmail, wsId)
|
||||||
const endpoint = await getTransactorEndpoint(token, 'external')
|
const endpoint = await getTransactorEndpoint(token, 'external')
|
||||||
const connection = (await connect(endpoint, wsId, undefined, {
|
const connection = (await connect(endpoint, wsId, undefined, {
|
||||||
|
@ -361,7 +361,8 @@ export function createModel (builder: Builder): void {
|
|||||||
viewOptions: {
|
viewOptions: {
|
||||||
groupBy: [],
|
groupBy: [],
|
||||||
orderBy: [],
|
orderBy: [],
|
||||||
other: [vacancyHideArchivedOption]
|
other: [vacancyHideArchivedOption],
|
||||||
|
storageKey: 'vacancyViewOptions'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recruit.viewlet.TableVacancy
|
recruit.viewlet.TableVacancy
|
||||||
@ -502,7 +503,8 @@ export function createModel (builder: Builder): void {
|
|||||||
viewOptions: {
|
viewOptions: {
|
||||||
groupBy: [],
|
groupBy: [],
|
||||||
orderBy: [],
|
orderBy: [],
|
||||||
other: [applicationDoneOption, hideApplicantsFromArchivedVacanciesOption]
|
other: [applicationDoneOption, hideApplicantsFromArchivedVacanciesOption],
|
||||||
|
storageKey: 'applicantViewOptions'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recruit.viewlet.ApplicantTable
|
recruit.viewlet.ApplicantTable
|
||||||
@ -559,7 +561,8 @@ export function createModel (builder: Builder): void {
|
|||||||
action: view.function.ShowEmptyGroups,
|
action: view.function.ShowEmptyGroups,
|
||||||
label: view.string.ShowEmptyGroups
|
label: view.string.ShowEmptyGroups
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
storageKey: 'applicantViewOptions'
|
||||||
}
|
}
|
||||||
if (colors) {
|
if (colors) {
|
||||||
model.other.push(showColorsViewOption)
|
model.other.push(showColorsViewOption)
|
||||||
@ -784,7 +787,8 @@ export function createModel (builder: Builder): void {
|
|||||||
['modifiedOn', SortingOrder.Descending],
|
['modifiedOn', SortingOrder.Descending],
|
||||||
['createdOn', SortingOrder.Descending]
|
['createdOn', SortingOrder.Descending]
|
||||||
],
|
],
|
||||||
other: [vacancyHideArchivedOption]
|
other: [vacancyHideArchivedOption],
|
||||||
|
storageKey: 'vacancyViewOptions'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
recruit.viewlet.ListVacancy
|
recruit.viewlet.ListVacancy
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Attachment } from '@hcengineering/attachment'
|
import { Attachment } from '@hcengineering/attachment'
|
||||||
import { Account, Class, Doc, IdMap, Markup, Ref, Space, generateId, toIdMap } from '@hcengineering/core'
|
import { RateLimiter, Account, Class, Doc, IdMap, Markup, Ref, Space, generateId, toIdMap } from '@hcengineering/core'
|
||||||
import { Asset, IntlString, setPlatformStatus, unknownError } from '@hcengineering/platform'
|
import { Asset, IntlString, setPlatformStatus, unknownError } from '@hcengineering/platform'
|
||||||
import {
|
import {
|
||||||
DraftController,
|
DraftController,
|
||||||
@ -183,12 +183,14 @@
|
|||||||
await tick()
|
await tick()
|
||||||
const list = inputFile.files
|
const list = inputFile.files
|
||||||
if (list === null || list.length === 0) return
|
if (list === null || list.length === 0) return
|
||||||
|
const limiter = new RateLimiter(10)
|
||||||
for (let index = 0; index < list.length; index++) {
|
for (let index = 0; index < list.length; index++) {
|
||||||
const file = list.item(index)
|
const file = list.item(index)
|
||||||
if (file !== null) {
|
if (file !== null) {
|
||||||
await createAttachment(file)
|
await limiter.add(() => createAttachment(file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await limiter.waitProcessing()
|
||||||
inputFile.value = ''
|
inputFile.value = ''
|
||||||
progress = false
|
progress = false
|
||||||
}
|
}
|
||||||
@ -196,13 +198,16 @@
|
|||||||
async function fileDrop (e: DragEvent): Promise<void> {
|
async function fileDrop (e: DragEvent): Promise<void> {
|
||||||
progress = true
|
progress = true
|
||||||
const list = e.dataTransfer?.files
|
const list = e.dataTransfer?.files
|
||||||
|
const limiter = new RateLimiter(10)
|
||||||
|
|
||||||
if (list === undefined || list.length === 0) return
|
if (list === undefined || list.length === 0) return
|
||||||
for (let index = 0; index < list.length; index++) {
|
for (let index = 0; index < list.length; index++) {
|
||||||
const file = list.item(index)
|
const file = list.item(index)
|
||||||
if (file !== null) {
|
if (file !== null) {
|
||||||
await createAttachment(file)
|
await limiter.add(() => createAttachment(file))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await limiter.waitProcessing()
|
||||||
progress = false
|
progress = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,17 +262,17 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
saved = true
|
saved = true
|
||||||
const promises: Promise<any>[] = []
|
const limiter = new RateLimiter(10)
|
||||||
newAttachments.forEach((p) => {
|
newAttachments.forEach((p) => {
|
||||||
const attachment = attachments.get(p)
|
const attachment = attachments.get(p)
|
||||||
if (attachment !== undefined) {
|
if (attachment !== undefined) {
|
||||||
promises.push(saveAttachment(attachment))
|
void limiter.add(() => saveAttachment(attachment))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
removedAttachments.forEach((p) => {
|
removedAttachments.forEach((p) => {
|
||||||
promises.push(deleteAttachment(p))
|
void limiter.add(() => deleteAttachment(p))
|
||||||
})
|
})
|
||||||
await Promise.all(promises)
|
await limiter.waitProcessing()
|
||||||
newAttachments.clear()
|
newAttachments.clear()
|
||||||
removedAttachments.clear()
|
removedAttachments.clear()
|
||||||
saveDraft()
|
saveDraft()
|
||||||
|
@ -125,7 +125,7 @@ export function adjustSelectionIndent (
|
|||||||
let insertionOffset = 0
|
let insertionOffset = 0
|
||||||
|
|
||||||
for (const range of ranges) {
|
for (const range of ranges) {
|
||||||
if (direction > 0 ? range.text === '' : range.indent === 0) {
|
if (direction > 0 ? range.text === '' && ranges.length > 1 : range.indent === 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const indentOffset = indentLevelOffset(range.indent, direction)
|
const indentOffset = indentLevelOffset(range.indent, direction)
|
||||||
|
@ -117,7 +117,8 @@ export const MermaidExtension = CodeBlockLowlight.extend<MermaidOptions>({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addProseMirrorPlugins () {
|
addProseMirrorPlugins () {
|
||||||
return [...(this.parent?.() ?? []), MermaidDecorator(this.options)]
|
const parent = (this.parent?.() ?? []).filter((p) => p.props.handlePaste === undefined)
|
||||||
|
return [...parent, MermaidDecorator(this.options)]
|
||||||
},
|
},
|
||||||
|
|
||||||
addNodeView () {
|
addNodeView () {
|
||||||
|
@ -31,8 +31,11 @@ export function isDropdownType (viewOption: ViewOptionModel): viewOption is Drop
|
|||||||
return viewOption.type === 'dropdown'
|
return viewOption.type === 'dropdown'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeViewOptionsKey (viewlet: Ref<Viewlet>, variant?: string): string {
|
function makeViewOptionsKey (viewlet: Viewlet, variant?: string, ignoreViewletKey = false): string {
|
||||||
const prefix = viewlet + (variant !== undefined ? `-${variant}` : '')
|
const prefix =
|
||||||
|
viewlet.viewOptions?.storageKey !== undefined && !ignoreViewletKey
|
||||||
|
? viewlet.viewOptions.storageKey
|
||||||
|
: viewlet._id + (variant !== undefined ? `-${variant}` : '')
|
||||||
const loc = getCurrentResolvedLocation()
|
const loc = getCurrentResolvedLocation()
|
||||||
loc.fragment = undefined
|
loc.fragment = undefined
|
||||||
loc.query = undefined
|
loc.query = undefined
|
||||||
@ -40,7 +43,7 @@ export function makeViewOptionsKey (viewlet: Ref<Viewlet>, variant?: string): st
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setViewOptions (viewlet: Viewlet, options: ViewOptions): void {
|
export function setViewOptions (viewlet: Viewlet, options: ViewOptions): void {
|
||||||
const key = makeViewOptionsKey(viewlet._id, viewlet.variant)
|
const key = makeViewOptionsKey(viewlet, viewlet.variant)
|
||||||
localStorage.setItem(key, JSON.stringify(options))
|
localStorage.setItem(key, JSON.stringify(options))
|
||||||
setStore(key, options)
|
setStore(key, options)
|
||||||
}
|
}
|
||||||
@ -52,13 +55,19 @@ function setStore (key: string, options: ViewOptions): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _getViewOptions (viewlet: Viewlet, viewOptionStore: Map<string, ViewOptions>): ViewOptions | null {
|
function _getViewOptions (viewlet: Viewlet, viewOptionStore: Map<string, ViewOptions>): ViewOptions | null {
|
||||||
const key = makeViewOptionsKey(viewlet._id, viewlet.variant)
|
const key = makeViewOptionsKey(viewlet, viewlet.variant)
|
||||||
const store = viewOptionStore.get(key)
|
const store = viewOptionStore.get(key)
|
||||||
if (store !== undefined) {
|
if (store !== undefined) {
|
||||||
return store
|
return store
|
||||||
}
|
}
|
||||||
const options = localStorage.getItem(key)
|
let options = localStorage.getItem(key)
|
||||||
if (options === null) return null
|
if (options === null) {
|
||||||
|
const key = makeViewOptionsKey(viewlet, viewlet.variant, true)
|
||||||
|
options = localStorage.getItem(key)
|
||||||
|
if (options === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
const res = JSON.parse(options)
|
const res = JSON.parse(options)
|
||||||
setStore(key, res)
|
setStore(key, res)
|
||||||
return res
|
return res
|
||||||
|
@ -794,6 +794,7 @@ export interface ViewOptionsModel {
|
|||||||
orderBy: OrderOption[]
|
orderBy: OrderOption[]
|
||||||
other: ViewOptionModel[]
|
other: ViewOptionModel[]
|
||||||
groupDepth?: number
|
groupDepth?: number
|
||||||
|
storageKey?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,11 +173,10 @@ export async function OnUserStatus (txes: Tx[], control: TriggerControl): Promis
|
|||||||
async function roomJoinHandler (info: ParticipantInfo, control: TriggerControl): Promise<Tx[]> {
|
async function roomJoinHandler (info: ParticipantInfo, control: TriggerControl): Promise<Tx[]> {
|
||||||
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
||||||
const roomInfo = roomInfos.find((ri) => ri.room === info.room)
|
const roomInfo = roomInfos.find((ri) => ri.room === info.room)
|
||||||
if (roomInfo !== undefined) {
|
if (roomInfo !== undefined && !roomInfo.persons.includes(info.person)) {
|
||||||
roomInfo.persons.push(info.person)
|
|
||||||
return [
|
return [
|
||||||
control.txFactory.createTxUpdateDoc(love.class.RoomInfo, core.space.Workspace, roomInfo._id, {
|
control.txFactory.createTxUpdateDoc(love.class.RoomInfo, core.space.Workspace, roomInfo._id, {
|
||||||
persons: Array.from(new Set([...roomInfo.persons, info.person]))
|
$push: { persons: info.person }
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
@ -221,7 +220,6 @@ async function setDefaultRoomAccess (info: ParticipantInfo, control: TriggerCont
|
|||||||
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
||||||
const oldRoomInfo = roomInfos.find((ri) => ri.persons.includes(info.person))
|
const oldRoomInfo = roomInfos.find((ri) => ri.persons.includes(info.person))
|
||||||
if (oldRoomInfo !== undefined) {
|
if (oldRoomInfo !== undefined) {
|
||||||
oldRoomInfo.persons = oldRoomInfo.persons.filter((p) => p !== info.person)
|
|
||||||
if (oldRoomInfo.persons.length === 0) {
|
if (oldRoomInfo.persons.length === 0) {
|
||||||
res.push(control.txFactory.createTxRemoveDoc(oldRoomInfo._class, oldRoomInfo.space, oldRoomInfo._id))
|
res.push(control.txFactory.createTxRemoveDoc(oldRoomInfo._class, oldRoomInfo.space, oldRoomInfo._id))
|
||||||
|
|
||||||
@ -237,7 +235,7 @@ async function setDefaultRoomAccess (info: ParticipantInfo, control: TriggerCont
|
|||||||
} else {
|
} else {
|
||||||
res.push(
|
res.push(
|
||||||
control.txFactory.createTxUpdateDoc(love.class.RoomInfo, core.space.Workspace, oldRoomInfo._id, {
|
control.txFactory.createTxUpdateDoc(love.class.RoomInfo, core.space.Workspace, oldRoomInfo._id, {
|
||||||
persons: oldRoomInfo.persons
|
$pull: { persons: info.person }
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -433,23 +431,44 @@ async function isRoomEmpty (
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function combineAttributes (attributes: any[], key: string, operator: string, arrayKey: string): any[] {
|
||||||
|
return Array.from(
|
||||||
|
new Set(
|
||||||
|
attributes.flatMap((attr) =>
|
||||||
|
Array.isArray(attr[operator]?.[key]?.[arrayKey]) ? attr[operator]?.[key]?.[arrayKey] : attr[operator]?.[key]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).filter((v) => v != null)
|
||||||
|
}
|
||||||
|
|
||||||
async function OnRoomInfo (txes: TxCUD<RoomInfo>[], control: TriggerControl): Promise<Tx[]> {
|
async function OnRoomInfo (txes: TxCUD<RoomInfo>[], control: TriggerControl): Promise<Tx[]> {
|
||||||
const result: Tx[] = []
|
const result: Tx[] = []
|
||||||
|
const personsByRoom = new Map<Ref<RoomInfo>, Ref<Person>[]>()
|
||||||
for (const tx of txes) {
|
for (const tx of txes) {
|
||||||
if (tx._class === core.class.TxRemoveDoc) {
|
if (tx._class === core.class.TxRemoveDoc) {
|
||||||
const roomInfo = control.removedMap.get(tx.objectId) as RoomInfo
|
const roomInfo = control.removedMap.get(tx.objectId) as RoomInfo
|
||||||
if (roomInfo === undefined) continue
|
if (roomInfo === undefined) continue
|
||||||
if (roomInfo.room === love.ids.Reception) continue
|
if (roomInfo.room === love.ids.Reception) continue
|
||||||
|
personsByRoom.delete(tx.objectId)
|
||||||
result.push(...(await finishRoomMeetings(roomInfo.room, tx.modifiedOn, control)))
|
result.push(...(await finishRoomMeetings(roomInfo.room, tx.modifiedOn, control)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (tx._class === core.class.TxUpdateDoc) {
|
if (tx._class === core.class.TxUpdateDoc) {
|
||||||
const newPersons = (tx as TxUpdateDoc<RoomInfo>).operations.persons
|
const updateTx = tx as TxUpdateDoc<RoomInfo>
|
||||||
if (newPersons === undefined) continue
|
const pulled = combineAttributes([updateTx.operations], 'persons', '$pull', '$in')
|
||||||
|
const pushed = combineAttributes([updateTx.operations], 'persons', '$push', '$each')
|
||||||
|
|
||||||
|
if (pulled.length === 0 && pushed.length === 0) continue
|
||||||
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
const roomInfos = await control.queryFind(control.ctx, love.class.RoomInfo, {})
|
||||||
const roomInfo = roomInfos.find((r) => r._id === tx.objectId)
|
const roomInfo = roomInfos.find((r) => r._id === tx.objectId)
|
||||||
if (roomInfo === undefined) continue
|
if (roomInfo === undefined) continue
|
||||||
if (roomInfo.room === love.ids.Reception) continue
|
if (roomInfo.room === love.ids.Reception) continue
|
||||||
|
|
||||||
|
const currentPersons = personsByRoom.get(tx.objectId) ?? roomInfo.persons
|
||||||
|
const newPersons = currentPersons.filter((p) => !pulled.includes(p)).concat(pushed)
|
||||||
|
|
||||||
|
personsByRoom.set(tx.objectId, newPersons)
|
||||||
|
|
||||||
if (await isRoomEmpty(roomInfo.room, roomInfo.isOffice, newPersons, control)) {
|
if (await isRoomEmpty(roomInfo.room, roomInfo.isOffice, newPersons, control)) {
|
||||||
result.push(...(await finishRoomMeetings(roomInfo.room, tx.modifiedOn, control)))
|
result.push(...(await finishRoomMeetings(roomInfo.room, tx.modifiedOn, control)))
|
||||||
}
|
}
|
||||||
|
@ -761,8 +761,7 @@ export async function createAcc (
|
|||||||
const salt = randomBytes(32)
|
const salt = randomBytes(32)
|
||||||
const hash = password !== null ? hashWithSalt(password, salt) : null
|
const hash = password !== null ? hashWithSalt(password, salt) : null
|
||||||
|
|
||||||
const systemEmails = [systemAccountEmail]
|
if (systemAccountEmail === email) {
|
||||||
if (systemEmails.includes(email)) {
|
|
||||||
ctx.error('system email used for account', { email })
|
ctx.error('system email used for account', { email })
|
||||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountAlreadyExists, { account: email }))
|
throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountAlreadyExists, { account: email }))
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import core, {
|
|||||||
type ModelDb,
|
type ModelDb,
|
||||||
type ObjQueryType,
|
type ObjQueryType,
|
||||||
type Projection,
|
type Projection,
|
||||||
|
RateLimiter,
|
||||||
type Ref,
|
type Ref,
|
||||||
type ReverseLookups,
|
type ReverseLookups,
|
||||||
type SessionData,
|
type SessionData,
|
||||||
@ -1506,13 +1507,18 @@ interface OperationBulk {
|
|||||||
mixins: TxMixin<Doc, Doc>[]
|
mixins: TxMixin<Doc, Doc>[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initRateLimit = new RateLimiter(1)
|
||||||
|
|
||||||
class PostgresAdapter extends PostgresAdapterBase {
|
class PostgresAdapter extends PostgresAdapterBase {
|
||||||
async init (ctx: MeasureContext, domains?: string[], excludeDomains?: string[]): Promise<void> {
|
async init (ctx: MeasureContext, domains?: string[], excludeDomains?: string[]): Promise<void> {
|
||||||
let resultDomains = domains ?? this.hierarchy.domains()
|
let resultDomains = domains ?? this.hierarchy.domains()
|
||||||
if (excludeDomains !== undefined) {
|
if (excludeDomains !== undefined) {
|
||||||
resultDomains = resultDomains.filter((it) => !excludeDomains.includes(it))
|
resultDomains = resultDomains.filter((it) => !excludeDomains.includes(it))
|
||||||
}
|
}
|
||||||
await createTables(ctx, this.client, resultDomains)
|
const url = this.refClient.url()
|
||||||
|
await initRateLimit.exec(async () => {
|
||||||
|
await createTables(ctx, this.client, url, resultDomains)
|
||||||
|
})
|
||||||
this._helper.domains = new Set(resultDomains as Domain[])
|
this._helper.domains = new Set(resultDomains as Domain[])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1789,7 +1795,10 @@ class PostgresAdapter extends PostgresAdapterBase {
|
|||||||
class PostgresTxAdapter extends PostgresAdapterBase implements TxAdapter {
|
class PostgresTxAdapter extends PostgresAdapterBase implements TxAdapter {
|
||||||
async init (ctx: MeasureContext, domains?: string[], excludeDomains?: string[]): Promise<void> {
|
async init (ctx: MeasureContext, domains?: string[], excludeDomains?: string[]): Promise<void> {
|
||||||
const resultDomains = domains ?? [DOMAIN_TX, DOMAIN_MODEL_TX]
|
const resultDomains = domains ?? [DOMAIN_TX, DOMAIN_MODEL_TX]
|
||||||
await createTables(ctx, this.client, resultDomains)
|
await initRateLimit.exec(async () => {
|
||||||
|
const url = this.refClient.url()
|
||||||
|
await createTables(ctx, this.client, url, resultDomains)
|
||||||
|
})
|
||||||
this._helper.domains = new Set(resultDomains as Domain[])
|
this._helper.domains = new Set(resultDomains as Domain[])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,8 +72,13 @@ export const NumericTypes = [
|
|||||||
core.class.Collection
|
core.class.Collection
|
||||||
]
|
]
|
||||||
|
|
||||||
export async function createTables (ctx: MeasureContext, client: postgres.Sql, domains: string[]): Promise<void> {
|
export async function createTables (
|
||||||
const filtered = domains.filter((d) => !loadedDomains.has(d))
|
ctx: MeasureContext,
|
||||||
|
client: postgres.Sql,
|
||||||
|
url: string,
|
||||||
|
domains: string[]
|
||||||
|
): Promise<void> {
|
||||||
|
const filtered = domains.filter((d) => !loadedDomains.has(url + translateDomain(d)))
|
||||||
if (filtered.length === 0) {
|
if (filtered.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -90,17 +95,15 @@ export async function createTables (ctx: MeasureContext, client: postgres.Sql, d
|
|||||||
const exists = new Set(tables.map((it) => it.table_name))
|
const exists = new Set(tables.map((it) => it.table_name))
|
||||||
|
|
||||||
await retryTxn(client, async (client) => {
|
await retryTxn(client, async (client) => {
|
||||||
await ctx.with('load-schemas', {}, () =>
|
const domainsToLoad = mapped.filter((it) => exists.has(it))
|
||||||
getTableSchema(
|
if (domainsToLoad.length > 0) {
|
||||||
client,
|
await ctx.with('load-schemas', {}, () => getTableSchema(client, domainsToLoad))
|
||||||
mapped.filter((it) => exists.has(it))
|
}
|
||||||
)
|
|
||||||
)
|
|
||||||
for (const domain of mapped) {
|
for (const domain of mapped) {
|
||||||
if (!exists.has(domain)) {
|
if (!exists.has(domain)) {
|
||||||
await ctx.with('create-table', {}, () => createTable(client, domain))
|
await ctx.with('create-table', {}, () => createTable(client, domain))
|
||||||
}
|
}
|
||||||
loadedDomains.add(domain)
|
loadedDomains.add(url + domain)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -188,6 +191,8 @@ export async function shutdown (): Promise<void> {
|
|||||||
export interface PostgresClientReference {
|
export interface PostgresClientReference {
|
||||||
getClient: () => Promise<postgres.Sql>
|
getClient: () => Promise<postgres.Sql>
|
||||||
close: () => void
|
close: () => void
|
||||||
|
|
||||||
|
url: () => string
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostgresClientReferenceImpl {
|
class PostgresClientReferenceImpl {
|
||||||
@ -195,6 +200,7 @@ class PostgresClientReferenceImpl {
|
|||||||
client: postgres.Sql | Promise<postgres.Sql>
|
client: postgres.Sql | Promise<postgres.Sql>
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
readonly connectionString: string,
|
||||||
client: postgres.Sql | Promise<postgres.Sql>,
|
client: postgres.Sql | Promise<postgres.Sql>,
|
||||||
readonly onclose: () => void
|
readonly onclose: () => void
|
||||||
) {
|
) {
|
||||||
@ -202,6 +208,10 @@ class PostgresClientReferenceImpl {
|
|||||||
this.client = client
|
this.client = client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url (): string {
|
||||||
|
return this.connectionString
|
||||||
|
}
|
||||||
|
|
||||||
async getClient (): Promise<postgres.Sql> {
|
async getClient (): Promise<postgres.Sql> {
|
||||||
if (this.client instanceof Promise) {
|
if (this.client instanceof Promise) {
|
||||||
this.client = await this.client
|
this.client = await this.client
|
||||||
@ -233,6 +243,10 @@ export class ClientRef implements PostgresClientReference {
|
|||||||
clientRefs.set(this.id, this)
|
clientRefs.set(this.id, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
url (): string {
|
||||||
|
return this.client.url()
|
||||||
|
}
|
||||||
|
|
||||||
closed = false
|
closed = false
|
||||||
async getClient (): Promise<postgres.Sql> {
|
async getClient (): Promise<postgres.Sql> {
|
||||||
if (!this.closed) {
|
if (!this.closed) {
|
||||||
@ -274,7 +288,7 @@ export function getDBClient (connectionString: string, database?: string): Postg
|
|||||||
...extraOptions
|
...extraOptions
|
||||||
})
|
})
|
||||||
|
|
||||||
existing = new PostgresClientReferenceImpl(sql, () => {
|
existing = new PostgresClientReferenceImpl(connectionString, sql, () => {
|
||||||
connections.delete(key)
|
connections.delete(key)
|
||||||
})
|
})
|
||||||
connections.set(key, existing)
|
connections.set(key, existing)
|
||||||
|
@ -23,7 +23,6 @@ interface Config {
|
|||||||
Secret: string
|
Secret: string
|
||||||
Credentials: string
|
Credentials: string
|
||||||
WATCH_URL: string
|
WATCH_URL: string
|
||||||
SystemEmail: string
|
|
||||||
InitLimit: number
|
InitLimit: number
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
ServiceID: 'SERVICE_ID',
|
ServiceID: 'SERVICE_ID',
|
||||||
Secret: 'SECRET',
|
Secret: 'SECRET',
|
||||||
Credentials: 'Credentials',
|
Credentials: 'Credentials',
|
||||||
SystemEmail: 'SYSTEM_EMAIL',
|
|
||||||
WATCH_URL: 'WATCH_URL',
|
WATCH_URL: 'WATCH_URL',
|
||||||
InitLimit: 'INIT_LIMIT'
|
InitLimit: 'INIT_LIMIT'
|
||||||
}
|
}
|
||||||
@ -52,7 +50,6 @@ const config: Config = (() => {
|
|||||||
AccountsURL: process.env[envMap.AccountsURL],
|
AccountsURL: process.env[envMap.AccountsURL],
|
||||||
ServiceID: process.env[envMap.ServiceID] ?? 'calendar-service',
|
ServiceID: process.env[envMap.ServiceID] ?? 'calendar-service',
|
||||||
Secret: process.env[envMap.Secret],
|
Secret: process.env[envMap.Secret],
|
||||||
SystemEmail: process.env[envMap.SystemEmail] ?? 'anticrm@hc.engineering',
|
|
||||||
Credentials: process.env[envMap.Credentials],
|
Credentials: process.env[envMap.Credentials],
|
||||||
InitLimit: parseNumber(process.env[envMap.InitLimit]) ?? 50,
|
InitLimit: parseNumber(process.env[envMap.InitLimit]) ?? 50,
|
||||||
WATCH_URL: process.env[envMap.WATCH_URL]
|
WATCH_URL: process.env[envMap.WATCH_URL]
|
||||||
|
@ -18,6 +18,7 @@ import contact, { Channel, Contact, type Employee, type PersonAccount } from '@h
|
|||||||
import core, {
|
import core, {
|
||||||
TxOperations,
|
TxOperations,
|
||||||
TxProcessor,
|
TxProcessor,
|
||||||
|
systemAccountEmail,
|
||||||
toIdMap,
|
toIdMap,
|
||||||
type Account,
|
type Account,
|
||||||
type Client,
|
type Client,
|
||||||
@ -34,7 +35,6 @@ import { Collection, type Db } from 'mongodb'
|
|||||||
import { CalendarClient } from './calendar'
|
import { CalendarClient } from './calendar'
|
||||||
import { CalendarController } from './calendarController'
|
import { CalendarController } from './calendarController'
|
||||||
import { getClient } from './client'
|
import { getClient } from './client'
|
||||||
import config from './config'
|
|
||||||
import { SyncHistory, type ProjectCredentials, type User } from './types'
|
import { SyncHistory, type ProjectCredentials, type User } from './types'
|
||||||
|
|
||||||
export class WorkspaceClient {
|
export class WorkspaceClient {
|
||||||
@ -159,7 +159,7 @@ export class WorkspaceClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initClient (workspace: string): Promise<Client> {
|
private async initClient (workspace: string): Promise<Client> {
|
||||||
const token = generateToken(config.SystemEmail, { name: workspace })
|
const token = generateToken(systemAccountEmail, { name: workspace })
|
||||||
const client = await getClient(token)
|
const client = await getClient(token)
|
||||||
client.notify = (...tx: Tx[]) => {
|
client.notify = (...tx: Tx[]) => {
|
||||||
void this.txHandler(...tx)
|
void this.txHandler(...tx)
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import client, { ClientSocket } from '@hcengineering/client'
|
import client, { ClientSocket } from '@hcengineering/client'
|
||||||
import clientResources from '@hcengineering/client-resources'
|
import clientResources from '@hcengineering/client-resources'
|
||||||
import { Client, ClientConnectEvent } from '@hcengineering/core'
|
import { Client, ClientConnectEvent, systemAccountEmail } from '@hcengineering/core'
|
||||||
import { setMetadata } from '@hcengineering/platform'
|
import { setMetadata } from '@hcengineering/platform'
|
||||||
import { getTransactorEndpoint } from '@hcengineering/server-client'
|
import { getTransactorEndpoint } from '@hcengineering/server-client'
|
||||||
import serverToken, { generateToken } from '@hcengineering/server-token'
|
import serverToken, { generateToken } from '@hcengineering/server-token'
|
||||||
@ -30,7 +30,7 @@ export async function createPlatformClient (
|
|||||||
|
|
||||||
setMetadata(serverToken.metadata.Secret, config.ServerSecret)
|
setMetadata(serverToken.metadata.Secret, config.ServerSecret)
|
||||||
const token = generateToken(
|
const token = generateToken(
|
||||||
config.SystemEmail,
|
systemAccountEmail,
|
||||||
{
|
{
|
||||||
name: workspace
|
name: workspace
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import { CollaboratorClient, getClient as getCollaboratorClient } from '@hcengineering/collaborator-client'
|
import { CollaboratorClient, getClient as getCollaboratorClient } from '@hcengineering/collaborator-client'
|
||||||
import { WorkspaceId } from '@hcengineering/core'
|
import { systemAccountEmail, WorkspaceId } from '@hcengineering/core'
|
||||||
import { generateToken } from '@hcengineering/server-token'
|
import { generateToken } from '@hcengineering/server-token'
|
||||||
import config from './config'
|
import config from './config'
|
||||||
|
|
||||||
@ -12,6 +12,6 @@ import config from './config'
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
export function createCollaboratorClient (workspaceId: WorkspaceId): CollaboratorClient {
|
export function createCollaboratorClient (workspaceId: WorkspaceId): CollaboratorClient {
|
||||||
const token = generateToken(config.SystemEmail, workspaceId, { mode: 'github' })
|
const token = generateToken(systemAccountEmail, workspaceId, { mode: 'github' })
|
||||||
return getCollaboratorClient(workspaceId, token, config.CollaboratorURL)
|
return getCollaboratorClient(workspaceId, token, config.CollaboratorURL)
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,10 @@
|
|||||||
// Copyright © 2023 Hardcore Engineering Inc.
|
// Copyright © 2023 Hardcore Engineering Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { systemAccountEmail } from '@hcengineering/core'
|
|
||||||
|
|
||||||
interface Config {
|
interface Config {
|
||||||
AccountsURL: string
|
AccountsURL: string
|
||||||
ServiceID: string
|
ServiceID: string
|
||||||
ServerSecret: string
|
ServerSecret: string
|
||||||
SystemEmail: string
|
|
||||||
FrontURL: string
|
FrontURL: string
|
||||||
|
|
||||||
// '*' means all workspaces
|
// '*' means all workspaces
|
||||||
@ -36,7 +33,6 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
AccountsURL: 'ACCOUNTS_URL',
|
AccountsURL: 'ACCOUNTS_URL',
|
||||||
ServiceID: 'SERVICE_ID',
|
ServiceID: 'SERVICE_ID',
|
||||||
ServerSecret: 'SERVER_SECRET',
|
ServerSecret: 'SERVER_SECRET',
|
||||||
SystemEmail: 'SYSTEM_EMAIL',
|
|
||||||
FrontURL: 'FRONT_URL',
|
FrontURL: 'FRONT_URL',
|
||||||
|
|
||||||
AppID: 'APP_ID',
|
AppID: 'APP_ID',
|
||||||
@ -62,7 +58,6 @@ const required: Array<keyof Config> = [
|
|||||||
'AccountsURL',
|
'AccountsURL',
|
||||||
'ServerSecret',
|
'ServerSecret',
|
||||||
'ServiceID',
|
'ServiceID',
|
||||||
'SystemEmail',
|
|
||||||
'FrontURL',
|
'FrontURL',
|
||||||
'AppID',
|
'AppID',
|
||||||
'ClientID',
|
'ClientID',
|
||||||
@ -82,7 +77,6 @@ const config: Config = (() => {
|
|||||||
AccountsURL: process.env[envMap.AccountsURL],
|
AccountsURL: process.env[envMap.AccountsURL],
|
||||||
ServerSecret: process.env[envMap.ServerSecret],
|
ServerSecret: process.env[envMap.ServerSecret],
|
||||||
ServiceID: process.env[envMap.ServiceID] ?? 'github-service',
|
ServiceID: process.env[envMap.ServiceID] ?? 'github-service',
|
||||||
SystemEmail: process.env[envMap.SystemEmail] ?? systemAccountEmail,
|
|
||||||
AllowedWorkspaces: process.env[envMap.AllowedWorkspaces]?.split(',') ?? ['*'],
|
AllowedWorkspaces: process.env[envMap.AllowedWorkspaces]?.split(',') ?? ['*'],
|
||||||
FrontURL: process.env[envMap.FrontURL] ?? '',
|
FrontURL: process.env[envMap.FrontURL] ?? '',
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import core, {
|
|||||||
MeasureContext,
|
MeasureContext,
|
||||||
RateLimiter,
|
RateLimiter,
|
||||||
Ref,
|
Ref,
|
||||||
|
systemAccountEmail,
|
||||||
TxOperations
|
TxOperations
|
||||||
} from '@hcengineering/core'
|
} from '@hcengineering/core'
|
||||||
import github, { GithubAuthentication, makeQuery, type GithubIntegration } from '@hcengineering/github'
|
import github, { GithubAuthentication, makeQuery, type GithubIntegration } from '@hcengineering/github'
|
||||||
@ -730,7 +731,7 @@ export class PlatformWorker {
|
|||||||
}
|
}
|
||||||
await rateLimiter.add(async () => {
|
await rateLimiter.add(async () => {
|
||||||
const token = generateToken(
|
const token = generateToken(
|
||||||
config.SystemEmail,
|
systemAccountEmail,
|
||||||
{
|
{
|
||||||
name: workspace
|
name: workspace
|
||||||
},
|
},
|
||||||
|
@ -24,7 +24,6 @@ interface Config {
|
|||||||
Secret: string
|
Secret: string
|
||||||
Credentials: string
|
Credentials: string
|
||||||
WATCH_TOPIC_NAME: string
|
WATCH_TOPIC_NAME: string
|
||||||
SystemEmail: string
|
|
||||||
FooterMessage: string
|
FooterMessage: string
|
||||||
InitLimit: number
|
InitLimit: number
|
||||||
}
|
}
|
||||||
@ -39,7 +38,6 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
ServiceID: 'SERVICE_ID',
|
ServiceID: 'SERVICE_ID',
|
||||||
Secret: 'SECRET',
|
Secret: 'SECRET',
|
||||||
Credentials: 'Credentials',
|
Credentials: 'Credentials',
|
||||||
SystemEmail: 'SYSTEM_EMAIL',
|
|
||||||
WATCH_TOPIC_NAME: 'WATCH_TOPIC_NAME',
|
WATCH_TOPIC_NAME: 'WATCH_TOPIC_NAME',
|
||||||
FooterMessage: 'FOOTER_MESSAGE',
|
FooterMessage: 'FOOTER_MESSAGE',
|
||||||
InitLimit: 'INIT_LIMIT'
|
InitLimit: 'INIT_LIMIT'
|
||||||
@ -55,7 +53,6 @@ const config: Config = (() => {
|
|||||||
AccountsURL: process.env[envMap.AccountsURL],
|
AccountsURL: process.env[envMap.AccountsURL],
|
||||||
ServiceID: process.env[envMap.ServiceID] ?? 'gmail-service',
|
ServiceID: process.env[envMap.ServiceID] ?? 'gmail-service',
|
||||||
Secret: process.env[envMap.Secret],
|
Secret: process.env[envMap.Secret],
|
||||||
SystemEmail: process.env[envMap.SystemEmail] ?? 'anticrm@hc.engineering',
|
|
||||||
Credentials: process.env[envMap.Credentials],
|
Credentials: process.env[envMap.Credentials],
|
||||||
WATCH_TOPIC_NAME: process.env[envMap.WATCH_TOPIC_NAME],
|
WATCH_TOPIC_NAME: process.env[envMap.WATCH_TOPIC_NAME],
|
||||||
InitLimit: parseNumber(process.env[envMap.InitLimit]) ?? 50,
|
InitLimit: parseNumber(process.env[envMap.InitLimit]) ?? 50,
|
||||||
|
@ -20,6 +20,7 @@ import core, {
|
|||||||
type Doc,
|
type Doc,
|
||||||
MeasureContext,
|
MeasureContext,
|
||||||
type Ref,
|
type Ref,
|
||||||
|
systemAccountEmail,
|
||||||
type Tx,
|
type Tx,
|
||||||
type TxCreateDoc,
|
type TxCreateDoc,
|
||||||
TxProcessor,
|
TxProcessor,
|
||||||
@ -31,7 +32,6 @@ import type { StorageAdapter } from '@hcengineering/server-core'
|
|||||||
import { generateToken } from '@hcengineering/server-token'
|
import { generateToken } from '@hcengineering/server-token'
|
||||||
import { type Db } from 'mongodb'
|
import { type Db } from 'mongodb'
|
||||||
import { getClient } from './client'
|
import { getClient } from './client'
|
||||||
import config from './config'
|
|
||||||
import { GmailClient } from './gmail'
|
import { GmailClient } from './gmail'
|
||||||
import { type Channel, type ProjectCredentials, type User } from './types'
|
import { type Channel, type ProjectCredentials, type User } from './types'
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ export class WorkspaceClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initClient (workspace: string): Promise<Client> {
|
private async initClient (workspace: string): Promise<Client> {
|
||||||
const token = generateToken(config.SystemEmail, { name: workspace })
|
const token = generateToken(systemAccountEmail, { name: workspace })
|
||||||
console.log('token', token, workspace)
|
console.log('token', token, workspace)
|
||||||
const client = await getClient(token)
|
const client = await getClient(token)
|
||||||
client.notify = (...tx: Tx[]) => {
|
client.notify = (...tx: Tx[]) => {
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
interface Config {
|
interface Config {
|
||||||
AccountsURL: string
|
AccountsURL: string
|
||||||
Port: number
|
Port: number
|
||||||
SystemEmail: string
|
|
||||||
ServiceID: string
|
ServiceID: string
|
||||||
|
|
||||||
LiveKitHost: string
|
LiveKitHost: string
|
||||||
@ -42,7 +41,6 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
StorageProviderName: 'STORAGE_PROVIDER_NAME',
|
StorageProviderName: 'STORAGE_PROVIDER_NAME',
|
||||||
Secret: 'SECRET',
|
Secret: 'SECRET',
|
||||||
ServiceID: 'SERVICE_ID',
|
ServiceID: 'SERVICE_ID',
|
||||||
SystemEmail: 'SYSTEM_EMAIL',
|
|
||||||
MongoUrl: 'MONGO_URL'
|
MongoUrl: 'MONGO_URL'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +57,6 @@ const config: Config = (() => {
|
|||||||
StorageProviderName: process.env[envMap.StorageProviderName] ?? 's3',
|
StorageProviderName: process.env[envMap.StorageProviderName] ?? 's3',
|
||||||
Secret: process.env[envMap.Secret],
|
Secret: process.env[envMap.Secret],
|
||||||
ServiceID: process.env[envMap.ServiceID] ?? 'love-service',
|
ServiceID: process.env[envMap.ServiceID] ?? 'love-service',
|
||||||
SystemEmail: process.env[envMap.SystemEmail] ?? 'anticrm@hc.engineering',
|
|
||||||
MongoUrl: process.env[envMap.MongoUrl]
|
MongoUrl: process.env[envMap.MongoUrl]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,13 +12,20 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import core, { Client, Ref, TxOperations, type Blob, Data, MeasureContext } from '@hcengineering/core'
|
import attachment, { Attachment } from '@hcengineering/attachment'
|
||||||
|
import core, {
|
||||||
|
Client,
|
||||||
|
Data,
|
||||||
|
MeasureContext,
|
||||||
|
Ref,
|
||||||
|
systemAccountEmail,
|
||||||
|
TxOperations,
|
||||||
|
type Blob
|
||||||
|
} from '@hcengineering/core'
|
||||||
import drive, { createFile } from '@hcengineering/drive'
|
import drive, { createFile } from '@hcengineering/drive'
|
||||||
import love, { MeetingMinutes } from '@hcengineering/love'
|
import love, { MeetingMinutes } from '@hcengineering/love'
|
||||||
import { generateToken } from '@hcengineering/server-token'
|
import { generateToken } from '@hcengineering/server-token'
|
||||||
import attachment, { Attachment } from '@hcengineering/attachment'
|
|
||||||
import { getClient } from './client'
|
import { getClient } from './client'
|
||||||
import config from './config'
|
|
||||||
|
|
||||||
export class WorkspaceClient {
|
export class WorkspaceClient {
|
||||||
private client!: TxOperations
|
private client!: TxOperations
|
||||||
@ -39,7 +46,7 @@ export class WorkspaceClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async initClient (workspace: string): Promise<Client> {
|
private async initClient (workspace: string): Promise<Client> {
|
||||||
const token = generateToken(config.SystemEmail, { name: workspace })
|
const token = generateToken(systemAccountEmail, { name: workspace })
|
||||||
const client = await getClient(token)
|
const client = await getClient(token)
|
||||||
this.client = new TxOperations(client, core.account.System)
|
this.client = new TxOperations(client, core.account.System)
|
||||||
return this.client
|
return this.client
|
||||||
|
@ -11,7 +11,6 @@ export interface Config {
|
|||||||
Port: number
|
Port: number
|
||||||
Secret: string
|
Secret: string
|
||||||
ServiceID: string
|
ServiceID: string
|
||||||
SystemEmail: string
|
|
||||||
BrandingPath: string
|
BrandingPath: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +24,6 @@ const config: Config = (() => {
|
|||||||
Port: parseNumber(process.env.PORT) ?? 4006,
|
Port: parseNumber(process.env.PORT) ?? 4006,
|
||||||
Secret: process.env.SECRET,
|
Secret: process.env.SECRET,
|
||||||
ServiceID: process.env.SERVICE_ID,
|
ServiceID: process.env.SERVICE_ID,
|
||||||
SystemEmail: process.env.SYSTEM_EMAIL ?? 'anticrm@hc.engineering',
|
|
||||||
BrandingPath: process.env.BRANDING_PATH ?? ''
|
BrandingPath: process.env.BRANDING_PATH ?? ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { P12Signer } from '@signpdf/signer-p12'
|
|||||||
import signpdf from '@signpdf/signpdf'
|
import signpdf from '@signpdf/signpdf'
|
||||||
import { PDFDocument, StandardFonts, degrees, degreesToRadians, rgb } from 'pdf-lib'
|
import { PDFDocument, StandardFonts, degrees, degreesToRadians, rgb } from 'pdf-lib'
|
||||||
|
|
||||||
import config from './config'
|
import { systemAccountEmail } from '@hcengineering/core'
|
||||||
|
|
||||||
interface Rect {
|
interface Rect {
|
||||||
x: number
|
x: number
|
||||||
@ -50,7 +50,7 @@ export async function signPDF (file: Buffer, certp12: Buffer, pwd: string, ctx:
|
|||||||
// Make it configurable when will be needed to allow signing for different reasons.
|
// Make it configurable when will be needed to allow signing for different reasons.
|
||||||
const options: Options = {
|
const options: Options = {
|
||||||
name: ctx.title,
|
name: ctx.title,
|
||||||
contactInfo: config.SystemEmail,
|
contactInfo: systemAccountEmail,
|
||||||
appName: ctx.title,
|
appName: ctx.title,
|
||||||
reason: 'Export from the system',
|
reason: 'Export from the system',
|
||||||
location: 'N/A'
|
location: 'N/A'
|
||||||
|
@ -13,11 +13,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
import { type Client } from '@hcengineering/core'
|
import { systemAccountEmail, type Client } from '@hcengineering/core'
|
||||||
import { generateToken, type Token } from '@hcengineering/server-token'
|
import { generateToken, type Token } from '@hcengineering/server-token'
|
||||||
|
|
||||||
import { createClient, getTransactorEndpoint } from '@hcengineering/server-client'
|
import { createClient, getTransactorEndpoint } from '@hcengineering/server-client'
|
||||||
import config from './config'
|
|
||||||
|
|
||||||
export class SignController {
|
export class SignController {
|
||||||
private readonly clients: Map<string, Client> = new Map<string, Client>()
|
private readonly clients: Map<string, Client> = new Map<string, Client>()
|
||||||
@ -50,7 +49,7 @@ export class SignController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async createPlatformClient (workspace: string): Promise<Client> {
|
private async createPlatformClient (workspace: string): Promise<Client> {
|
||||||
const token = generateToken(config.SystemEmail, {
|
const token = generateToken(systemAccountEmail, {
|
||||||
name: workspace
|
name: workspace
|
||||||
})
|
})
|
||||||
const endpoint = await getTransactorEndpoint(token)
|
const endpoint = await getTransactorEndpoint(token)
|
||||||
|
@ -12,7 +12,6 @@ interface Config {
|
|||||||
AccountsURL: string
|
AccountsURL: string
|
||||||
ServiceID: string
|
ServiceID: string
|
||||||
Secret: string
|
Secret: string
|
||||||
SystemEmail: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const envMap: { [key in keyof Config]: string } = {
|
const envMap: { [key in keyof Config]: string } = {
|
||||||
@ -28,8 +27,7 @@ const envMap: { [key in keyof Config]: string } = {
|
|||||||
|
|
||||||
AccountsURL: 'ACCOUNTS_URL',
|
AccountsURL: 'ACCOUNTS_URL',
|
||||||
ServiceID: 'SERVICE_ID',
|
ServiceID: 'SERVICE_ID',
|
||||||
Secret: 'SECRET',
|
Secret: 'SECRET'
|
||||||
SystemEmail: 'SYSTEM_EMAIL'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaults: Partial<Config> = {
|
const defaults: Partial<Config> = {
|
||||||
@ -45,7 +43,6 @@ const defaults: Partial<Config> = {
|
|||||||
|
|
||||||
AccountsURL: undefined,
|
AccountsURL: undefined,
|
||||||
ServiceID: 'telegram-service',
|
ServiceID: 'telegram-service',
|
||||||
SystemEmail: 'anticrm@hc.engineering',
|
|
||||||
|
|
||||||
Secret: undefined
|
Secret: undefined
|
||||||
}
|
}
|
||||||
@ -76,7 +73,6 @@ const config = (() => {
|
|||||||
MongoURI: process.env[envMap.MongoURI],
|
MongoURI: process.env[envMap.MongoURI],
|
||||||
AccountsURL: process.env[envMap.AccountsURL],
|
AccountsURL: process.env[envMap.AccountsURL],
|
||||||
ServiceID: process.env[envMap.ServiceID],
|
ServiceID: process.env[envMap.ServiceID],
|
||||||
SystemEmail: process.env[envMap.SystemEmail],
|
|
||||||
Secret: process.env[envMap.Secret]
|
Secret: process.env[envMap.Secret]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import core, {
|
|||||||
Hierarchy,
|
Hierarchy,
|
||||||
MeasureContext,
|
MeasureContext,
|
||||||
Ref,
|
Ref,
|
||||||
|
systemAccountEmail,
|
||||||
Tx,
|
Tx,
|
||||||
TxCreateDoc,
|
TxCreateDoc,
|
||||||
TxCUD,
|
TxCUD,
|
||||||
@ -31,7 +32,6 @@ import telegramP, { NewTelegramMessage } from '@hcengineering/telegram'
|
|||||||
import type { Collection } from 'mongodb'
|
import type { Collection } from 'mongodb'
|
||||||
import { Api } from 'telegram'
|
import { Api } from 'telegram'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import config from './config'
|
|
||||||
import { platformToTelegram, telegramToPlatform } from './markup'
|
import { platformToTelegram, telegramToPlatform } from './markup'
|
||||||
import { MsgQueue } from './queue'
|
import { MsgQueue } from './queue'
|
||||||
import type { TelegramConnectionInterface } from './telegram'
|
import type { TelegramConnectionInterface } from './telegram'
|
||||||
@ -151,7 +151,7 @@ export class WorkspaceWorker {
|
|||||||
lastMsgStorage: Collection<LastMsgRecord>,
|
lastMsgStorage: Collection<LastMsgRecord>,
|
||||||
channelsStorage: Collection<WorkspaceChannel>
|
channelsStorage: Collection<WorkspaceChannel>
|
||||||
): Promise<WorkspaceWorker> {
|
): Promise<WorkspaceWorker> {
|
||||||
const token = generateToken(config.SystemEmail, { name: workspace })
|
const token = generateToken(systemAccountEmail, { name: workspace })
|
||||||
const client = await createPlatformClient(token)
|
const client = await createPlatformClient(token)
|
||||||
|
|
||||||
const worker = new WorkspaceWorker(
|
const worker = new WorkspaceWorker(
|
||||||
|
Loading…
Reference in New Issue
Block a user