checkpoint

Signed-off-by: Andrey Platov <andrey@hardcoreeng.com>
This commit is contained in:
Andrey Platov 2021-09-14 13:24:58 +02:00
parent 6d743c92e9
commit 736ee30dca
No known key found for this signature in database
GPG Key ID: C8787EFEB4B64AF0
9 changed files with 36 additions and 38 deletions

View File

@ -40,10 +40,11 @@
const client = getClient() const client = getClient()
async function createAttachment(file: File) { async function createAttachment(file: File) {
console.log('CREATE ATTACHMENT')
loading = true loading = true
try { try {
const id = generateId<Attachment>() const id = generateId<Attachment>()
const uuid = await uploadFile(id, object.space, file) const uuid = await uploadFile(id, object.space, file, object._id)
console.log('uploaded file uuid', uuid) console.log('uploaded file uuid', uuid)
client.createDoc(chunter.class.Attachment, object.space, { client.createDoc(chunter.class.Attachment, object.space, {
attachedTo: object._id, attachedTo: object._id,

View File

@ -15,7 +15,7 @@
<script lang="ts"> <script lang="ts">
import { createEventDispatcher } from 'svelte' import { createEventDispatcher } from 'svelte'
import type { Ref, Space, Doc } from '@anticrm/core' import type { Ref, Space } from '@anticrm/core'
import { generateId } from '@anticrm/core' import { generateId } from '@anticrm/core'
import { getClient, Card, Channels } from '@anticrm/presentation' import { getClient, Card, Channels } from '@anticrm/presentation'
@ -58,16 +58,17 @@
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const client = getClient() const client = getClient()
const candidateId = generateId<Candidate>()
async function createCandidate() { async function createCandidate() {
console.log(_space) console.log(_space)
// create candidate // create candidate
const candidateId = await client.createDoc(recruit.class.Candidate, _space, { await client.createDoc(recruit.class.Candidate, _space, {
firstName: object.firstName, firstName: object.firstName,
lastName: object.lastName, lastName: object.lastName,
city: object.city, city: object.city,
channels: object.channels, channels: object.channels,
}) }, candidateId)
console.log('resume name', resume.name) console.log('resume name', resume.name)
@ -98,7 +99,7 @@
loading = true loading = true
try { try {
const id = generateId<Attachment>() const id = generateId<Attachment>()
resume.uuid = await uploadFile(id, space, file) resume.uuid = await uploadFile(id, space, file, candidateId)
resume.id = id resume.id = id
resume.name = file.name resume.name = file.name
resume.size = file.size resume.size = file.size

View File

@ -19,14 +19,14 @@ import { getMetadata } from '@anticrm/platform'
import login from '@anticrm/login' import login from '@anticrm/login'
export async function uploadFile(id: Ref<Doc>, space: Ref<Space>, file: File): Promise<string> { export async function uploadFile(id: Ref<Doc>, space: Ref<Space>, file: File, attachedTo: Ref<Doc>): Promise<string> {
console.log(file) console.log(file)
const uploadUrl = getMetadata(login.metadata.UploadUrl) const uploadUrl = getMetadata(login.metadata.UploadUrl)
const data = new FormData() const data = new FormData()
data.append('file', file) data.append('file', file)
const url = `${uploadUrl}?id=${id}&space=${space}` const url = `${uploadUrl}?id=${id}&space=${space}&attachedTo=${attachedTo}`
const resp = await fetch(url, { const resp = await fetch(url, {
method: 'POST', method: 'POST',
headers: { headers: {

View File

@ -15,8 +15,9 @@
// //
import { TxCreateDoc, Doc, Ref, Class, Obj, Hierarchy, AnyAttribute, Storage, DocumentQuery, FindOptions, FindResult, TxProcessor, IndexKind } from '@anticrm/core' import { TxCreateDoc, Doc, Ref, Class, Obj, Hierarchy, AnyAttribute, Storage, DocumentQuery, FindOptions, FindResult, TxProcessor, IndexKind } from '@anticrm/core'
import type { AttachedDoc } from '@anticrm/core'
import type { IndexedContent, FullTextAdapter, WithFind } from './types' import type { IndexedDoc, FullTextAdapter, WithFind } from './types'
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const NO_INDEX = {} as AnyAttribute const NO_INDEX = {} as AnyAttribute
@ -35,8 +36,9 @@ export class FullTextIndex extends TxProcessor implements Storage {
async findAll<T extends Doc> (_class: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<FindResult<T>> { async findAll<T extends Doc> (_class: Ref<Class<T>>, query: DocumentQuery<T>, options?: FindOptions<T>): Promise<FindResult<T>> {
console.log('search', query) console.log('search', query)
const docs = await this.adapter.search(query) const docs = await this.adapter.search(query)
const ids = docs.map(doc => doc.id as Ref<T>) console.log(docs)
return this.dbStorage.findAll(_class, { _id: { $in: ids as any } }, options) const ids = docs.map(doc => (doc.attachedTo ?? doc.id) as Ref<T>)
return this.dbStorage.findAll(_class, { _id: { $in: ids as any } }, options) // TODO: remove `as any`
} }
private findFullTextAttribute (clazz: Ref<Class<Obj>>): AnyAttribute | undefined { private findFullTextAttribute (clazz: Ref<Class<Obj>>): AnyAttribute | undefined {
@ -60,12 +62,13 @@ export class FullTextIndex extends TxProcessor implements Storage {
if (attribute === undefined) return if (attribute === undefined) return
const doc = TxProcessor.createDoc2Doc(tx) const doc = TxProcessor.createDoc2Doc(tx)
const content = (doc as any)[attribute.name] const content = (doc as any)[attribute.name]
const indexedDoc: IndexedContent = { const indexedDoc: IndexedDoc = {
id: doc._id, id: doc._id,
_class: doc._class, _class: doc._class,
modifiedBy: doc.modifiedBy, modifiedBy: doc.modifiedBy,
modifiedOn: doc.modifiedOn, modifiedOn: doc.modifiedOn,
space: doc.space, space: doc.space,
attachedTo: (doc as AttachedDoc).attachedTo,
content content
} }
return await this.adapter.index(indexedDoc) return await this.adapter.index(indexedDoc)

View File

@ -39,26 +39,15 @@ export interface IndexedDoc {
space: Ref<Space> space: Ref<Space>
modifiedOn: Timestamp modifiedOn: Timestamp
modifiedBy: Ref<Account> modifiedBy: Ref<Account>
attachedTo?: Ref<Doc>
content?: string
data?: string
} }
/** /**
* @public * @public
*/ */
export interface IndexedContent extends IndexedDoc { export type SearchQuery = any // TODO: replace with DocumentQuery
content: string
}
/**
* @public
*/
export interface IndexedAttachment extends IndexedDoc {
data: string
}
/**
* @public
*/
export type SearchQuery = any
/** /**
* @public * @public

View File

@ -16,12 +16,12 @@
import type { Ref, Doc, Class, Obj, Account, Space } from '@anticrm/core' import type { Ref, Doc, Class, Obj, Account, Space } from '@anticrm/core'
import { createElasticAdapter } from '../adapter' import { createElasticAdapter } from '../adapter'
import type { IndexedContent } from '@anticrm/server-core' import type { IndexedDoc } from '@anticrm/server-core'
describe('client', () => { describe('client', () => {
it('should create document', async () => { it('should create document', async () => {
const adapter = await createElasticAdapter('http://localhost:9200/', 'ws1') const adapter = await createElasticAdapter('http://localhost:9200/', 'ws1')
const doc: IndexedContent = { const doc: IndexedDoc = {
id: 'doc1' as Ref<Doc>, id: 'doc1' as Ref<Doc>,
_class: 'class1' as Ref<Class<Obj>>, _class: 'class1' as Ref<Class<Obj>>,
modifiedBy: 'andrey' as Ref<Account>, modifiedBy: 'andrey' as Ref<Account>,

View File

@ -14,7 +14,7 @@
// limitations under the License. // limitations under the License.
// //
import type { FullTextAdapter, IndexedAttachment, IndexedDoc, SearchQuery } from '@anticrm/server-core' import type { FullTextAdapter, IndexedDoc, SearchQuery } from '@anticrm/server-core'
import { Client } from '@elastic/elasticsearch' import { Client } from '@elastic/elasticsearch'
@ -32,9 +32,9 @@ class ElasticAdapter implements FullTextAdapter {
index: this.db, index: this.db,
body: { body: {
query: { query: {
match: { multi_match: {
content: query.$search query: query.$search,
// 'attachment.content': query.$search fields: ['content', 'attachment.content']
} }
} }
} }
@ -46,13 +46,14 @@ class ElasticAdapter implements FullTextAdapter {
async index (doc: IndexedDoc): Promise<void> { async index (doc: IndexedDoc): Promise<void> {
console.log('eastic: index', doc) console.log('eastic: index', doc)
if ((doc as IndexedAttachment).data === undefined) { if (doc.data === undefined) {
const resp = await this.client.index({ const resp = await this.client.index({
index: this.db, index: this.db,
type: '_doc', type: '_doc',
body: doc body: doc
}) })
console.log(resp) console.log('resp', resp)
console.log('error', (resp.meta as any)?.body?.error)
} else { } else {
console.log('attachment pipeline') console.log('attachment pipeline')
const resp = await this.client.index({ const resp = await this.client.index({
@ -61,7 +62,8 @@ class ElasticAdapter implements FullTextAdapter {
pipeline: 'attachment', pipeline: 'attachment',
body: doc body: doc
}) })
console.log(resp) console.log('resp', resp)
console.log('error', (resp.meta as any)?.body?.error)
} }
} }
} }

View File

@ -8,7 +8,7 @@
"start": "ts-node src/__start.ts", "start": "ts-node src/__start.ts",
"build": "heft build", "build": "heft build",
"lint:fix": "eslint --fix src", "lint:fix": "eslint --fix src",
"bundle": "esbuild src/__start.ts --bundle --minify --platform=node > bundle.js", "bundle": "esbuild src/__start.ts --bundle --platform=node > bundle.js",
"docker:build": "docker build -t anticrm/upload .", "docker:build": "docker build -t anticrm/upload .",
"docker:push": "docker push anticrm/upload" "docker:push": "docker push anticrm/upload"
}, },

View File

@ -22,7 +22,7 @@ import { decode } from 'jwt-simple'
import type { Space, Ref, Doc, Account } from '@anticrm/core' import type { Space, Ref, Doc, Account } from '@anticrm/core'
// import { TxFactory } from '@anticrm/core' // import { TxFactory } from '@anticrm/core'
import type { Token, IndexedAttachment } from '@anticrm/server-core' import type { Token, IndexedDoc } from '@anticrm/server-core'
import { createElasticAdapter } from '@anticrm/elastic' import { createElasticAdapter } from '@anticrm/elastic'
import chunter from '@anticrm/chunter' import chunter from '@anticrm/chunter'
// import { createContributingClient } from '@anticrm/contrib' // import { createContributingClient } from '@anticrm/contrib'
@ -133,6 +133,7 @@ export function start (transactorEndpoint: string, elasticUrl: string, minio: Cl
const id = req.query.id as Ref<Doc> const id = req.query.id as Ref<Doc>
const space = req.query.space as Ref<Space> const space = req.query.space as Ref<Space>
const attachedTo = req.query.attachedTo as Ref<Doc>
// const name = req.query.name as string // const name = req.query.name as string
// await createAttachment( // await createAttachment(
@ -148,12 +149,13 @@ export function start (transactorEndpoint: string, elasticUrl: string, minio: Cl
const elastic = await createElasticAdapter(elasticUrl, payload.workspace) const elastic = await createElasticAdapter(elasticUrl, payload.workspace)
const indexedDoc: IndexedAttachment = { const indexedDoc: IndexedDoc = {
id, id,
_class: chunter.class.Attachment, _class: chunter.class.Attachment,
space, space,
modifiedOn: Date.now(), modifiedOn: Date.now(),
modifiedBy: 'core:account:System' as Ref<Account>, modifiedBy: 'core:account:System' as Ref<Account>,
attachedTo,
data: file.data.toString('base64') data: file.data.toString('base64')
} }