diff --git a/packages/lib/services/interop/InteropService.test.ts b/packages/lib/services/interop/InteropService.test.ts index 99a20d2ab5..b393ceb008 100644 --- a/packages/lib/services/interop/InteropService.test.ts +++ b/packages/lib/services/interop/InteropService.test.ts @@ -1,13 +1,14 @@ import InteropService from '../../services/interop/InteropService'; import { CustomExportContext, CustomImportContext, Module, ModuleType } from '../../services/interop/types'; import shim from '../../shim'; - -const { fileContentEqual, setupDatabaseAndSynchronizer, switchClient, checkThrowAsync, exportDir, supportDir } = require('../../testing/test-utils.js'); +import { fileContentEqual, setupDatabaseAndSynchronizer, switchClient, checkThrowAsync, exportDir, supportDir } from '../../testing/test-utils'; import Folder from '../../models/Folder'; import Note from '../../models/Note'; import Tag from '../../models/Tag'; import Resource from '../../models/Resource'; -const fs = require('fs-extra'); +import * as fs from 'fs-extra'; +import { NoteEntity, ResourceEntity } from '../database/types'; +import { ModelType } from '../../BaseModel'; const ArrayUtils = require('../../ArrayUtils'); async function recreateExportDir() { @@ -23,6 +24,62 @@ function fieldsEqual(model1: any, model2: any, fieldNames: string[]) { } } +function memoryExportModule() { + interface Item { + type: number; + object: any; + } + + interface Resource { + filePath: string; + object: ResourceEntity; + } + + interface Result { + destPath: string; + items: Item[]; + resources: Resource[]; + } + + const result: Result = { + destPath: '', + items: [], + resources: [], + }; + + const module: Module = { + type: ModuleType.Exporter, + description: 'Memory Export Module', + format: 'memory', + fileExtensions: ['memory'], + isCustom: true, + + onInit: async (context: CustomExportContext) => { + result.destPath = context.destPath; + }, + + onProcessItem: async (_context: CustomExportContext, itemType: number, item: any) => { + result.items.push({ + type: itemType, + object: item, + }); + }, + + onProcessResource: async (_context: CustomExportContext, resource: any, filePath: string) => { + result.resources.push({ + filePath: filePath, + object: resource, + }); + }, + + onClose: async (_context: CustomExportContext) => { + // nothing + }, + }; + + return { result, module }; +} + describe('services_InteropService', function() { beforeEach(async (done) => { @@ -462,6 +519,23 @@ describe('services_InteropService', function() { expect(result.warnings.length).toBe(0); })); + it('should not export certain note properties', (async () => { + const folder = await Folder.save({ title: 'folder' }); + await Note.save({ title: 'note', is_shared: 1, share_id: 'someid', parent_id: folder.id }); + + const service = InteropService.instance(); + const { result, module } = memoryExportModule(); + service.registerModule(module); + + await service.export({ + format: 'memory', + }); + + const exportedNote = (result.items.find(i => i.type === ModelType.Note)).object as NoteEntity; + expect(exportedNote.share_id).toBe(''); + expect(exportedNote.is_shared).toBe(0); + })); + it('should allow registering new import modules', (async () => { const testImportFilePath = `${exportDir()}/testImport${Math.random()}.test`; await shim.fsDriver().writeFile(testImportFilePath, 'test', 'utf8'); diff --git a/packages/lib/services/interop/InteropService.ts b/packages/lib/services/interop/InteropService.ts index 1df11fff03..149bcb5cc3 100644 --- a/packages/lib/services/interop/InteropService.ts +++ b/packages/lib/services/interop/InteropService.ts @@ -4,11 +4,12 @@ import InteropService_Exporter_Custom from './InteropService_Exporter_Custom'; import shim from '../../shim'; import { _ } from '../../locale'; import BaseItem from '../../models/BaseItem'; -import BaseModel from '../../BaseModel'; +import BaseModel, { ModelType } from '../../BaseModel'; import Resource from '../../models/Resource'; import Folder from '../../models/Folder'; import NoteTag from '../../models/NoteTag'; import Note from '../../models/Note'; +import { NoteEntity } from '../database/types'; const ArrayUtils = require('../../ArrayUtils'); const { sprintf } = require('sprintf-js'); const { fileExtension } = require('../../path-utils'); @@ -271,7 +272,7 @@ export default class InteropService { return null; } - async import(options: ImportOptions): Promise { + public async import(options: ImportOptions): Promise { if (!(await shim.fsDriver().exists(options.path))) throw new Error(_('Cannot find "%s".', options.path)); options = { @@ -297,16 +298,6 @@ export default class InteropService { let result: ImportExportResult = { warnings: [] }; - // let importer = null; - // - // Not certain the "modulePath" property still has any use at this point. Modules should be looked up - // based on their format and outputFormat. - // if (options.modulePath) { - // importer = this.newModuleFromPath_(ModuleType.Importer, options); - // } else { - // importer = this.newModuleByFormat_(ModuleType.Importer, options.format, options.outputFormat); - // } - const importer = this.newModuleByFormat_(ModuleType.Importer, options.format, options.outputFormat); await importer.init(options.path, options); @@ -315,7 +306,18 @@ export default class InteropService { return result; } - async export(options: ExportOptions): Promise { + private normalizeItemForExport(itemType: ModelType, item: any): any { + if (itemType === ModelType.Note) { + const output: NoteEntity = { ...item }; + output.is_shared = 0; + output.share_id = ''; + return output; + } else { + return item; + } + } + + public async export(options: ExportOptions): Promise { options = { format: 'jex', ...options, @@ -411,7 +413,7 @@ export default class InteropService { const ItemClass = BaseItem.getClassByItemType(itemType); const itemOrId = itemsToExport[i].itemOrId; - const item = typeof itemOrId === 'object' ? itemOrId : await ItemClass.load(itemOrId); + const item = this.normalizeItemForExport(itemType, typeof itemOrId === 'object' ? itemOrId : await ItemClass.load(itemOrId)); if (!item) { if (itemType === BaseModel.TYPE_RESOURCE) {