Skip to content

Commit 1e0e6bf

Browse files
committed
support blobs
Signed-off-by: Anna Khismatullina <[email protected]>
1 parent 4558068 commit 1e0e6bf

File tree

5 files changed

+87
-33
lines changed

5 files changed

+87
-33
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
class: card:types:File
3+
title: File with blob
4+
blobs:
5+
- ./files/screenshot.png
6+
---
7+
8+
*DESCR)*
9+
[](./files/screenshot.png)

dev/import-tool/docs/huly/example-workspace/SlaveCard/Frodo.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ color: pink
99
x: from familiar
1010
y: from minion
1111
multy-enum: [Beta]
12-
attachments:
13-
- ../../CARDS_INSTRUCTIONS.md
12+
# attachments:
13+
# - ../../CARDS_INSTRUCTIONS.md
14+
blobs:
1415
- ../files/screenshot.png
15-
# blobs:
1616
# - ../README.md
1717
---
1818

packages/importer/src/huly/metadata.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Tag } from '@hcengineering/card'
2-
import { Association, Attribute, Doc, generateId, Ref } from '@hcengineering/core'
2+
import { Association, Attribute, Doc, generateId, Ref, Blob as PlatformBlob } from '@hcengineering/core'
33
import path from 'path'
4-
import { UnifiedDoc } from '../types'
4+
import { UnifiedDoc, UnifiedFile } from '../types'
55

66
export interface RelationMetadata { // todo: rename
77
association: Ref<Association>
@@ -10,6 +10,7 @@ export interface RelationMetadata { // todo: rename
1010
}
1111
export type MapAttributeToUnifiedDoc = Map<string, UnifiedDoc<Attribute<Tag>>>
1212
export type MapNameToIsMany = Map<string, RelationMetadata> // todo: rename
13+
1314
export interface TagMetadata {
1415
_id: string
1516
attributes: MapAttributeToUnifiedDoc // title -> attribute id
@@ -19,6 +20,7 @@ export interface TagMetadata {
1920
export class MetadataStorage {
2021
private readonly pathToRef = new Map<string, Ref<Doc>>() // todo: attachments to a separate map?
2122
private readonly pathToMetadata = new Map<string, TagMetadata>()
23+
private readonly pathToBlobUuid = new Map<string, Ref<PlatformBlob>>() // todo: blobs to a separate map?
2224

2325
public getIdByAbsolutePath (path: string): Ref<Doc> {
2426
let id = this.pathToRef.get(path)
@@ -29,11 +31,6 @@ export class MetadataStorage {
2931
return id
3032
}
3133

32-
public getIdByRelativePath (currentPath: string, relativePath: string): Ref<Doc> {
33-
const fullPath = path.resolve(currentPath, relativePath)
34-
return this.getIdByAbsolutePath(fullPath)
35-
}
36-
3734
public hasMetadata (path: string): boolean {
3835
return this.pathToMetadata.has(path)
3936
}

packages/importer/src/huly/unified.ts

Lines changed: 69 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import card, { Card, MasterTag, Tag } from '@hcengineering/card'
44
import core, {
55
Association,
66
Attribute,
7+
BlobType,
78
Class,
89
Doc,
910
Enum,
@@ -29,7 +30,6 @@ export interface UnifiedDocProcessResult {
2930

3031
export class UnifiedDocProcessor {
3132
private readonly metadataStorage = new MetadataStorage()
32-
3333
async importFromDirectory (directoryPath: string): Promise<UnifiedDocProcessResult> {
3434
const result: UnifiedDocProcessResult = {
3535
docs: new Map(),
@@ -173,7 +173,11 @@ export class UnifiedDocProcessor {
173173
masterTagAttrs: Map<string, UnifiedDoc<Attribute<MasterTag>>>,
174174
parentCardId?: Ref<Card>
175175
): Promise<void> {
176-
const cardWithRelations = await this.createCardWithRelations(cardProps, cardPath, masterTagId, masterTagRelations, masterTagAttrs, parentCardId, blobs)
176+
if (cardProps.blobs !== undefined) {
177+
await this.createBlobs(cardProps.blobs, cardPath, result)
178+
}
179+
180+
const cardWithRelations = await this.createCardWithRelations(cardProps, cardPath, masterTagId, masterTagRelations, masterTagAttrs, result.files, parentCardId)
177181

178182
if (cardWithRelations.length > 0) {
179183
const docs = result.docs.get(cardPath) ?? []
@@ -184,7 +188,7 @@ export class UnifiedDocProcessor {
184188
await this.applyTags(card, cardProps, cardPath, result)
185189

186190
if (cardProps.attachments !== undefined) {
187-
await this.processAttachments(cardProps.attachments, cardPath, card, result)
191+
await this.createAttachments(cardProps.attachments, cardPath, card, result)
188192
}
189193

190194
const cardDir = path.join(path.dirname(cardPath), path.basename(cardPath, '.md'))
@@ -387,10 +391,12 @@ export class UnifiedDocProcessor {
387391
masterTagId: Ref<MasterTag>,
388392
masterTagRelations: Map<string, RelationMetadata>, // todo: rename to masterTagsAssociations
389393
masterTagAttrs: Map<string, UnifiedDoc<Attribute<MasterTag>>>,
394+
blobFiles: Map<string, UnifiedFile>,
390395
parentCardId?: Ref<Card>
391396
): Promise<UnifiedDoc<Doc>[]> {
392-
const { _class, title, tags: rawTags, ...customProperties } = cardHeader
397+
const { _class, title, blobs: rawBlobs, tags: rawTags, ...customProperties } = cardHeader
393398
const tags = rawTags !== undefined ? (Array.isArray(rawTags) ? rawTags : [rawTags]) : []
399+
const blobs = rawBlobs !== undefined ? (Array.isArray(rawBlobs) ? rawBlobs : [rawBlobs]) : []
394400

395401
const cardId = this.metadataStorage.getIdByAbsolutePath(cardPath) as Ref<Card>
396402
const cardProps: Record<string, any> = {
@@ -400,6 +406,24 @@ export class UnifiedDocProcessor {
400406
parent: parentCardId
401407
}
402408

409+
if (blobs.length > 0) {
410+
const blobProps: Record<string, BlobType> = {}
411+
for (const blob of blobs) {
412+
const blobPath = path.resolve(path.dirname(cardPath), blob)
413+
const blobFile = blobFiles.get(blobPath)
414+
if (blobFile === undefined) {
415+
throw new Error('Blob file not found: ' + blobPath + ' from:' + cardPath)
416+
}
417+
blobProps[blobFile._id] = {
418+
file: blobFile._id,
419+
type: blobFile.type,
420+
name: blobFile.name,
421+
metadata: {} // todo: blobFile.metadata
422+
}
423+
}
424+
cardProps.blobs = blobProps
425+
}
426+
403427
const tagAssociations = new Map<string, RelationMetadata>()
404428
for (const tag of tags) {
405429
const tagPath = path.resolve(path.dirname(cardPath), tag)
@@ -510,28 +534,15 @@ export class UnifiedDocProcessor {
510534
}
511535
}
512536

513-
private async processAttachments (
537+
private async createAttachments (
514538
attachments: string[],
515539
cardPath: string,
516540
card: UnifiedDoc<Card>,
517541
result: UnifiedDocProcessResult
518542
): Promise<void> {
519543
for (const attachment of attachments) {
520544
const attachmentPath = path.resolve(path.dirname(cardPath), attachment)
521-
const attachmentName = path.basename(attachmentPath)
522-
const fileId = this.metadataStorage.getIdByAbsolutePath(attachmentPath) as Ref<PlatformBlob>
523-
const type = contentType(attachmentPath)
524-
const size = fs.statSync(attachmentPath).size
525-
526-
const file: UnifiedFile = {
527-
_id: fileId, // id for datastore
528-
name: attachmentName,
529-
blobProvider: async () => {
530-
const data = fs.readFileSync(attachmentPath)
531-
const props = type !== false ? { type } : undefined
532-
return new Blob([data], props)
533-
}
534-
}
545+
const file = await this.createFile(attachmentPath)
535546
result.files.set(attachmentPath, file)
536547

537548
const attachmentId = this.metadataStorage.getIdByAbsolutePath(attachmentPath) as Ref<Attachment>
@@ -542,18 +553,53 @@ export class UnifiedDocProcessor {
542553
space: core.space.Workspace,
543554
attachedTo: card.props._id as Ref<Card>,
544555
attachedToClass: card._class,
545-
file: fileId,
546-
name: attachmentName,
556+
file: file._id,
557+
name: file.name,
547558
collection: 'attachments',
548559
lastModified: Date.now(),
549-
type: type !== false ? type : 'application/octet-stream',
550-
size
560+
type: file.type,
561+
size: file.size
551562
}
552563
}
553564
result.docs.set(attachmentPath, [attachmentDoc])
554565
}
555566
}
556567

568+
private async createBlobs (
569+
blobs: string[],
570+
cardPath: string,
571+
result: UnifiedDocProcessResult
572+
): Promise<void> {
573+
for (const blob of blobs) {
574+
const blobPath = path.resolve(path.dirname(cardPath), blob)
575+
const file = await this.createFile(blobPath)
576+
result.files.set(blobPath, file)
577+
}
578+
}
579+
580+
private async createFile (
581+
fileAbsPath: string
582+
): Promise<UnifiedFile> {
583+
// const fileAbsPath = path.resolve(path.dirname(currentPath), filePath)
584+
const fileName = path.basename(fileAbsPath)
585+
const fileId = this.metadataStorage.getIdByAbsolutePath(fileAbsPath) as Ref<PlatformBlob>
586+
const type = contentType(fileName)
587+
const size = fs.statSync(fileAbsPath).size
588+
589+
const file: UnifiedFile = {
590+
_id: fileId, // id for datastore
591+
name: fileName,
592+
type: type !== false ? type : 'application/octet-stream',
593+
size, // todo: make sure this one is needed
594+
blobProvider: async () => {
595+
const data = fs.readFileSync(fileAbsPath)
596+
const props = type !== false ? { type } : undefined
597+
return new Blob([data], props)
598+
}
599+
}
600+
return file
601+
}
602+
557603
private async createAssociation (
558604
yamlPath: string,
559605
yamlConfig: Record<string, any>

packages/importer/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ export interface UnifiedMixin<T extends Doc, M extends Doc> { // todo: extends T
1717
export interface UnifiedFile {
1818
_id: Ref<PlatformBlob>
1919
name: string
20+
type: string
21+
size: number
2022
blobProvider: blobProvider
2123
}
2224

0 commit comments

Comments
 (0)