-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
117 changed files
with
4,489 additions
and
1,588 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
...server/src/modules/common-cartridge/export/builders/common-cartridge-file-builder.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { faker } from '@faker-js/faker'; | ||
import AdmZip from 'adm-zip'; | ||
import { | ||
CommonCartridgeElementType, | ||
CommonCartridgeIntendedUseType, | ||
CommonCartridgeResourceType, | ||
CommonCartridgeVersion, | ||
} from '../common-cartridge.enums'; | ||
import { CommonCartridgeElementProps } from '../elements/common-cartridge-element-factory'; | ||
import { CommonCartridgeResourceProps } from '../resources/common-cartridge-resource-factory'; | ||
import { CommonCartridgeFileBuilder } from './common-cartridge-file-builder'; | ||
import { CommonCartridgeOrganizationBuilderOptions } from './common-cartridge-organization-builder'; | ||
|
||
describe('CommonCartridgeFileBuilder', () => { | ||
const getFileContentAsString = (zip: AdmZip, path: string): string | undefined => | ||
zip.getEntry(path)?.getData().toString(); | ||
|
||
describe('build', () => { | ||
describe('when a common cartridge archive has been created', () => { | ||
const setup = async () => { | ||
const metadataProps: CommonCartridgeElementProps = { | ||
type: CommonCartridgeElementType.METADATA, | ||
title: faker.lorem.words(), | ||
creationDate: new Date(), | ||
copyrightOwners: ['John Doe', 'Jane Doe'], | ||
}; | ||
const organizationOptions: CommonCartridgeOrganizationBuilderOptions = { | ||
identifier: faker.string.uuid(), | ||
title: faker.lorem.words(), | ||
}; | ||
const resourceProps: CommonCartridgeResourceProps = { | ||
type: CommonCartridgeResourceType.WEB_CONTENT, | ||
identifier: faker.string.uuid(), | ||
title: faker.lorem.words(), | ||
html: faker.lorem.paragraphs(), | ||
intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, | ||
}; | ||
const builder = new CommonCartridgeFileBuilder({ | ||
version: CommonCartridgeVersion.V_1_1_0, | ||
identifier: faker.string.uuid(), | ||
}); | ||
|
||
builder | ||
.addMetadata(metadataProps) | ||
.addOrganization(organizationOptions) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps); | ||
|
||
const archive = new AdmZip(await builder.build()); | ||
|
||
return { archive, metadataProps, organizationOptions, resourceProps }; | ||
}; | ||
|
||
it('should have a imsmanifest.xml in archive root', async () => { | ||
const { archive } = await setup(); | ||
|
||
const manifest = getFileContentAsString(archive, 'imsmanifest.xml'); | ||
|
||
expect(manifest).toBeDefined(); | ||
}); | ||
|
||
it('should have included the resource in organization folder', async () => { | ||
const { archive, organizationOptions, resourceProps } = await setup(); | ||
|
||
const resource = getFileContentAsString( | ||
archive, | ||
`${organizationOptions.identifier}/${resourceProps.identifier}.html` | ||
); | ||
|
||
expect(resource).toBeDefined(); | ||
}); | ||
|
||
it('should have included the resource in sub-organization folder', async () => { | ||
const { archive, organizationOptions, resourceProps } = await setup(); | ||
|
||
const resource = getFileContentAsString( | ||
archive, | ||
`${organizationOptions.identifier}/${organizationOptions.identifier}/${resourceProps.identifier}.html` | ||
); | ||
|
||
expect(resource).toBeDefined(); | ||
}); | ||
|
||
it('should have included the resource in sub-sub-organization folder', async () => { | ||
const { archive, organizationOptions, resourceProps } = await setup(); | ||
|
||
const resource = getFileContentAsString( | ||
archive, | ||
`${organizationOptions.identifier}/${organizationOptions.identifier}/${organizationOptions.identifier}/${resourceProps.identifier}.html` | ||
); | ||
|
||
expect(resource).toBeDefined(); | ||
}); | ||
}); | ||
|
||
describe('when metadata has not been provide', () => { | ||
const sut = new CommonCartridgeFileBuilder({ | ||
version: CommonCartridgeVersion.V_1_1_0, | ||
identifier: faker.string.uuid(), | ||
}); | ||
|
||
it('should throw an error', async () => { | ||
await expect(sut.build()).rejects.toThrow('Metadata is not defined'); | ||
}); | ||
}); | ||
}); | ||
}); |
80 changes: 80 additions & 0 deletions
80
apps/server/src/modules/common-cartridge/export/builders/common-cartridge-file-builder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import AdmZip from 'adm-zip'; | ||
import { CommonCartridgeResourceType, CommonCartridgeVersion } from '../common-cartridge.enums'; | ||
import { | ||
CommonCartridgeElementFactory, | ||
CommonCartridgeElementProps, | ||
} from '../elements/common-cartridge-element-factory'; | ||
import { CommonCartridgeElement, CommonCartridgeResource } from '../interfaces'; | ||
import { CommonCartridgeResourceFactory } from '../resources/common-cartridge-resource-factory'; | ||
import { OmitVersion } from '../utils'; | ||
import { | ||
CommonCartridgeOrganizationBuilder, | ||
CommonCartridgeOrganizationBuilderOptions, | ||
} from './common-cartridge-organization-builder'; | ||
|
||
export type CommonCartridgeFileBuilderProps = { | ||
version: CommonCartridgeVersion; | ||
identifier: string; | ||
}; | ||
|
||
export class CommonCartridgeFileBuilder { | ||
private readonly archive: AdmZip = new AdmZip(); | ||
|
||
private readonly organizationBuilders = new Array<CommonCartridgeOrganizationBuilder>(); | ||
|
||
private readonly resources = new Array<CommonCartridgeResource>(); | ||
|
||
private metadata?: CommonCartridgeElement; | ||
|
||
constructor(private readonly props: CommonCartridgeFileBuilderProps) {} | ||
|
||
public addMetadata(props: CommonCartridgeElementProps): CommonCartridgeFileBuilder { | ||
this.metadata = CommonCartridgeElementFactory.createElement({ | ||
version: this.props.version, | ||
...props, | ||
}); | ||
|
||
return this; | ||
} | ||
|
||
public addOrganization( | ||
props: OmitVersion<CommonCartridgeOrganizationBuilderOptions> | ||
): CommonCartridgeOrganizationBuilder { | ||
const builder = new CommonCartridgeOrganizationBuilder( | ||
{ ...props, version: this.props.version }, | ||
(resource: CommonCartridgeResource) => this.resources.push(resource) | ||
); | ||
|
||
this.organizationBuilders.push(builder); | ||
|
||
return builder; | ||
} | ||
|
||
public async build(): Promise<Buffer> { | ||
if (!this.metadata) { | ||
throw new Error('Metadata is not defined'); | ||
} | ||
|
||
const organizations = this.organizationBuilders.map((builder) => builder.build()); | ||
const manifest = CommonCartridgeResourceFactory.createResource({ | ||
type: CommonCartridgeResourceType.MANIFEST, | ||
version: this.props.version, | ||
identifier: this.props.identifier, | ||
metadata: this.metadata, | ||
organizations, | ||
resources: this.resources, | ||
}); | ||
|
||
for (const resources of this.resources) { | ||
if (!resources.canInline()) { | ||
this.archive.addFile(resources.getFilePath(), Buffer.from(resources.getFileContent())); | ||
} | ||
} | ||
|
||
this.archive.addFile(manifest.getFilePath(), Buffer.from(manifest.getFileContent())); | ||
|
||
const buffer = await this.archive.toBufferPromise(); | ||
|
||
return buffer; | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
...rc/modules/common-cartridge/export/builders/common-cartridge-organization-builder.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { faker } from '@faker-js/faker/locale/af_ZA'; | ||
import { createCommonCartridgeWebContentResourcePropsV110 } from '../../testing/common-cartridge-resource-props.factory'; | ||
import { CommonCartridgeVersion } from '../common-cartridge.enums'; | ||
import { CommonCartridgeElement, CommonCartridgeResource } from '../interfaces'; | ||
import { | ||
CommonCartridgeOrganizationBuilder, | ||
CommonCartridgeOrganizationBuilderOptions, | ||
} from './common-cartridge-organization-builder'; | ||
|
||
describe('CommonCartridgeOrganizationBuilder', () => { | ||
describe('build', () => { | ||
describe('when building a Common Cartridge organization with resources', () => { | ||
const setup = () => { | ||
const resources = new Array<CommonCartridgeResource>(); | ||
|
||
const organizationOptions: CommonCartridgeOrganizationBuilderOptions = { | ||
identifier: faker.string.uuid(), | ||
title: faker.lorem.words(), | ||
}; | ||
|
||
const resourceProps = createCommonCartridgeWebContentResourcePropsV110(); | ||
|
||
const sut = new CommonCartridgeOrganizationBuilder( | ||
{ | ||
...organizationOptions, | ||
version: CommonCartridgeVersion.V_1_1_0, | ||
}, | ||
(resource) => resources.push(resource) | ||
) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps); | ||
|
||
return { sut, resources }; | ||
}; | ||
|
||
it('should return a common cartridge element', () => { | ||
const { sut, resources } = setup(); | ||
|
||
const element = sut.build(); | ||
|
||
expect(element).toBeInstanceOf(CommonCartridgeElement); | ||
expect(resources.length).toBe(3); | ||
}); | ||
}); | ||
|
||
describe('when building a Common Cartridge organization with items', () => { | ||
const setup = () => { | ||
const resources = new Array<CommonCartridgeResource>(); | ||
|
||
const organizationOptions: CommonCartridgeOrganizationBuilderOptions = { | ||
identifier: faker.string.uuid(), | ||
title: faker.lorem.words(), | ||
}; | ||
|
||
const resourceProps = createCommonCartridgeWebContentResourcePropsV110(); | ||
|
||
const sut = new CommonCartridgeOrganizationBuilder( | ||
{ | ||
...organizationOptions, | ||
version: CommonCartridgeVersion.V_1_1_0, | ||
}, | ||
(resource) => resources.push(resource) | ||
) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps) | ||
.addSubOrganization(organizationOptions) | ||
.addResource(resourceProps) | ||
.addResource(resourceProps); | ||
|
||
return { sut, resources }; | ||
}; | ||
|
||
it('should return a common cartridge element', () => { | ||
const { sut, resources } = setup(); | ||
|
||
const element = sut.build(); | ||
|
||
expect(element).toBeInstanceOf(CommonCartridgeElement); | ||
expect(resources.length).toBe(4); | ||
}); | ||
}); | ||
}); | ||
}); |
82 changes: 82 additions & 0 deletions
82
...ver/src/modules/common-cartridge/export/builders/common-cartridge-organization-builder.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { CommonCartridgeElementType, CommonCartridgeVersion } from '../common-cartridge.enums'; | ||
import { CommonCartridgeElementFactory } from '../elements/common-cartridge-element-factory'; | ||
import { CommonCartridgeElement } from '../interfaces/common-cartridge-element.interface'; | ||
import { CommonCartridgeResource } from '../interfaces/common-cartridge-resource.interface'; | ||
import { | ||
CommonCartridgeResourceFactory, | ||
CommonCartridgeResourceProps, | ||
} from '../resources/common-cartridge-resource-factory'; | ||
import { OmitVersionAndFolder } from '../utils'; | ||
|
||
export type CommonCartridgeOrganizationBuilderOptions = | ||
OmitVersionAndFolder<CommonCartridgeOrganizationBuilderOptionsInternal>; | ||
|
||
type CommonCartridgeOrganizationBuilderOptionsInternal = { | ||
version: CommonCartridgeVersion; | ||
identifier: string; | ||
title: string; | ||
folder?: string; | ||
}; | ||
|
||
export class CommonCartridgeOrganizationBuilder { | ||
private readonly resources: CommonCartridgeResource[] = []; | ||
|
||
private readonly subOrganizations: CommonCartridgeOrganizationBuilder[] = []; | ||
|
||
constructor( | ||
protected readonly options: CommonCartridgeOrganizationBuilderOptionsInternal, | ||
private readonly addResourceToFileBuilder: (resource: CommonCartridgeResource) => void | ||
) {} | ||
|
||
private get folder(): string { | ||
return this.options.folder ? `${this.options.folder}/${this.options.identifier}` : this.options.identifier; | ||
} | ||
|
||
public addSubOrganization( | ||
options: OmitVersionAndFolder<CommonCartridgeOrganizationBuilderOptions> | ||
): CommonCartridgeOrganizationBuilder { | ||
const subOrganization = new CommonCartridgeOrganizationBuilder( | ||
{ ...options, version: this.options.version, folder: this.folder }, | ||
(resource: CommonCartridgeResource) => this.addResourceToFileBuilder(resource) | ||
); | ||
|
||
this.subOrganizations.push(subOrganization); | ||
|
||
return subOrganization; | ||
} | ||
|
||
public addResource(props: CommonCartridgeResourceProps): CommonCartridgeOrganizationBuilder { | ||
const resource = CommonCartridgeResourceFactory.createResource({ | ||
version: this.options.version, | ||
folder: this.folder, | ||
...props, | ||
}); | ||
|
||
this.resources.push(resource); | ||
this.addResourceToFileBuilder(resource); | ||
|
||
return this; | ||
} | ||
|
||
public build(): CommonCartridgeElement { | ||
const organizationElement = CommonCartridgeElementFactory.createElement({ | ||
type: CommonCartridgeElementType.ORGANIZATION, | ||
version: this.options.version, | ||
identifier: this.options.identifier, | ||
title: this.options.title, | ||
items: this.buildItems(), | ||
}); | ||
|
||
return organizationElement; | ||
} | ||
|
||
private buildItems(): (CommonCartridgeElement | CommonCartridgeResource)[] { | ||
if (this.resources.length === 1 && this.subOrganizations.length === 0) { | ||
return [...this.resources]; | ||
} | ||
|
||
const items = [...this.resources, ...this.subOrganizations.map((subOrganization) => subOrganization.build())]; | ||
|
||
return items; | ||
} | ||
} |
Oops, something went wrong.