Skip to content

Commit

Permalink
Merge branch 'refs/heads/main' into N21-2022-close-wizard-with-migration
Browse files Browse the repository at this point in the history
  • Loading branch information
arnegns committed Jun 24, 2024
2 parents 601ca75 + dc46eb2 commit b50f254
Show file tree
Hide file tree
Showing 92 changed files with 1,872 additions and 998 deletions.
29 changes: 19 additions & 10 deletions apps/server/src/modules/board/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,37 @@
export { BoardModule } from './board.module';
export { BoardConfig } from './board.config';
export { BoardModule } from './board.module';
export { AnyElementContentBody, LinkContentBody, RichTextContentBody } from './controller/dto';
export {
BoardNode,
BoardNodeAuthorizable,
BoardExternalReferenceType,
AnyBoardNode,
BoardExternalReference,
BoardExternalReferenceType,
BoardLayout,
BoardNode,
BoardNodeAuthorizable,
BoardNodeFactory,
ColumnBoard,
// @modules/authorization/domain/rules/board-node.rule.ts
BoardRoles,
Card,
Column,
ColumnBoard,
ContentElementType,
// @modules/tool/tool-launch/service/auto-parameter-strategy/auto-context-name.strategy.ts
MediaBoard,
SubmissionItem,
UserWithBoardRoles,
isCard,
isColumn,
isDrawingElement,
isLinkElement,
isRichTextElement,
isSubmissionItem,
isSubmissionItemContent,
SubmissionItem,
UserWithBoardRoles,
// @modules/tool/tool-launch/service/auto-parameter-strategy/auto-context-name.strategy.ts
MediaBoard,
} from './domain';

export {
BoardCommonToolService,
BoardNodeAuthorizableService,
BoardNodeService,
BoardCommonToolService,
ColumnBoardService,
MediaAvailableLineService,
MediaBoardService,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,109 +1,95 @@
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';
createCommonCartridgeMetadataElementProps,
createCommonCartridgeOrganizationProps,
} from '../../testing/common-cartridge-element-props.factory';
import { createCommonCartridgeWebLinkResourceProps } from '../../testing/common-cartridge-resource-props.factory';
import { CommonCartridgeVersion } from '../common-cartridge.enums';
import { CommonCartridgeElementFactory } from '../elements/common-cartridge-element-factory';
import { MissingMetadataLoggableException } from '../errors';
import { CommonCartridgeFileBuilder, CommonCartridgeFileBuilderProps } from './common-cartridge-file-builder';
import { CommonCartridgeOrganizationNode } from './common-cartridge-organization-node';

describe('CommonCartridgeFileBuilder', () => {
const getFileContentAsString = (zip: AdmZip, path: string): string | undefined =>
zip.getEntry(path)?.getData().toString();
let sut: CommonCartridgeFileBuilder;

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 };
};
const builderProps: CommonCartridgeFileBuilderProps = {
version: CommonCartridgeVersion.V_1_1_0,
identifier: faker.string.uuid(),
};

it('should have a imsmanifest.xml in archive root', async () => {
const { archive } = await setup();
beforeEach(() => {
sut = new CommonCartridgeFileBuilder(builderProps);
jest.clearAllMocks();
});

const manifest = getFileContentAsString(archive, 'imsmanifest.xml');
describe('addMetadata', () => {
describe('when metadata is added to the CommonCartridgeFileBuilder', () => {
const setup = () => {
const createElementSpy = jest.spyOn(CommonCartridgeElementFactory, 'createElement');
const metadataProps = createCommonCartridgeMetadataElementProps();

expect(manifest).toBeDefined();
});
return { metadataProps, createElementSpy };
};

it('should have included the resource in organization folder', async () => {
const { archive, organizationOptions, resourceProps } = await setup();
it('should set the metadata element', () => {
const { metadataProps, createElementSpy } = setup();

const resource = getFileContentAsString(
archive,
`${organizationOptions.identifier}/${resourceProps.identifier}.html`
);
sut.addMetadata(metadataProps);

expect(resource).toBeDefined();
expect(createElementSpy).toHaveBeenCalledWith({ ...metadataProps, version: builderProps.version });
});
});
});

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`
);
describe('createOrganization', () => {
describe('when an organization is created in the CommonCartridgeFileBuilder', () => {
const setup = () => {
const organizationProps = createCommonCartridgeOrganizationProps();

expect(resource).toBeDefined();
});
return { organizationProps };
};

it('should have included the resource in sub-sub-organization folder', async () => {
const { archive, organizationOptions, resourceProps } = await setup();
it('should create and return an organization node', () => {
const { organizationProps } = setup();

const resource = getFileContentAsString(
archive,
`${organizationOptions.identifier}/${organizationOptions.identifier}/${organizationOptions.identifier}/${resourceProps.identifier}.html`
);
const organizationNode = sut.createOrganization(organizationProps);

expect(resource).toBeDefined();
expect(organizationNode).toBeInstanceOf(CommonCartridgeOrganizationNode);
});
});
});

describe('when metadata has not been provide', () => {
const sut = new CommonCartridgeFileBuilder({
version: CommonCartridgeVersion.V_1_1_0,
identifier: faker.string.uuid(),
describe('build', () => {
describe('when metadata has not been provided', () => {
it('should throw MissingMetadataLoggableException', () => {
expect(() => {
sut.build();
}).toThrow(MissingMetadataLoggableException);
});
});

describe('when metadata has been provided', () => {
const setup = () => {
const metadataProps = createCommonCartridgeMetadataElementProps();
const organizationProps = createCommonCartridgeOrganizationProps();
const resourceProps = createCommonCartridgeWebLinkResourceProps();

return { metadataProps, organizationProps, resourceProps };
};

it('should build the common cartridge file', () => {
const { metadataProps, organizationProps, resourceProps } = setup();

sut.addMetadata(metadataProps);

const org = sut.createOrganization(organizationProps);

org.addResource(resourceProps);

const result = sut.build();

it('should throw an error', async () => {
await expect(sut.build()).rejects.toThrow('Metadata is not defined');
expect(result).toBeDefined();
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,80 +1,81 @@
import AdmZip from 'adm-zip';
import { CommonCartridgeResourceType, CommonCartridgeVersion } from '../common-cartridge.enums';
import {
CommonCartridgeElementType,
CommonCartridgeResourceType,
CommonCartridgeVersion,
} from '../common-cartridge.enums';
import {
CommonCartridgeElementFactory,
CommonCartridgeElementProps,
} from '../elements/common-cartridge-element-factory';
import { CommonCartridgeElement, CommonCartridgeResource } from '../interfaces';
import { MissingMetadataLoggableException } from '../errors';
import { CommonCartridgeElement } from '../interfaces';
import { CommonCartridgeResourceFactory } from '../resources/common-cartridge-resource-factory';
import { OmitVersion } from '../utils';
import {
CommonCartridgeOrganizationBuilder,
CommonCartridgeOrganizationBuilderOptions,
} from './common-cartridge-organization-builder';
CommonCartridgeOrganizationNode,
CommonCartridgeOrganizationNodeProps,
} from './common-cartridge-organization-node';
import { CommonCartridgeResourceCollectionBuilder } from './common-cartridge-resource-collection-builder';

export type CommonCartridgeFileBuilderProps = {
version: CommonCartridgeVersion;
identifier: string;
};

export class CommonCartridgeFileBuilder {
private readonly archive: AdmZip = new AdmZip();
export type CommonCartridgeOrganizationProps = Omit<CommonCartridgeOrganizationNodeProps, 'version' | 'type'>;

private readonly organizationBuilders = new Array<CommonCartridgeOrganizationBuilder>();
export class CommonCartridgeFileBuilder {
private readonly resourcesBuilder: CommonCartridgeResourceCollectionBuilder =
new CommonCartridgeResourceCollectionBuilder();

private readonly resources = new Array<CommonCartridgeResource>();
private readonly organizationsRoot: CommonCartridgeOrganizationNode[] = [];

private metadata?: CommonCartridgeElement;
private metadataElement: CommonCartridgeElement | null = null;

constructor(private readonly props: CommonCartridgeFileBuilderProps) {}

public addMetadata(props: CommonCartridgeElementProps): CommonCartridgeFileBuilder {
this.metadata = CommonCartridgeElementFactory.createElement({
public addMetadata(metadataProps: CommonCartridgeElementProps): void {
this.metadataElement = CommonCartridgeElementFactory.createElement({
version: this.props.version,
...props,
...metadataProps,
});

return this;
}

public addOrganization(
props: OmitVersion<CommonCartridgeOrganizationBuilderOptions>
): CommonCartridgeOrganizationBuilder {
const builder = new CommonCartridgeOrganizationBuilder(
{ ...props, version: this.props.version },
(resource: CommonCartridgeResource) => this.resources.push(resource)
public createOrganization(organizationProps: CommonCartridgeOrganizationProps): CommonCartridgeOrganizationNode {
const organization = new CommonCartridgeOrganizationNode(
{ ...organizationProps, version: this.props.version, type: CommonCartridgeElementType.ORGANIZATION },
this.resourcesBuilder,
null
);

this.organizationBuilders.push(builder);
this.organizationsRoot.push(organization);

return builder;
return organization;
}

public async build(): Promise<Buffer> {
if (!this.metadata) {
throw new Error('Metadata is not defined');
public build(): Buffer {
if (!this.metadataElement) {
throw new MissingMetadataLoggableException();
}

const organizations = this.organizationBuilders.map((builder) => builder.build());
const archive = new AdmZip();
const organizations = this.organizationsRoot.map((organization) => organization.build());
const resources = this.resourcesBuilder.build();
const manifest = CommonCartridgeResourceFactory.createResource({
type: CommonCartridgeResourceType.MANIFEST,
version: this.props.version,
identifier: this.props.identifier,
metadata: this.metadata,
metadata: this.metadataElement,
organizations,
resources: this.resources,
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()));
archive.addFile(manifest.getFilePath(), Buffer.from(manifest.getFileContent()));

const buffer = await this.archive.toBufferPromise();
resources.forEach((resource) => {
archive.addFile(resource.getFilePath(), Buffer.from(resource.getFileContent()));
});

return buffer;
return archive.toBuffer();
}
}
Loading

0 comments on commit b50f254

Please sign in to comment.