diff --git a/demo/api/schema.gql b/demo/api/schema.gql
index a3771a37f3b..0ef221b8ecf 100644
--- a/demo/api/schema.gql
+++ b/demo/api/schema.gql
@@ -161,11 +161,13 @@ type PaginatedDamFolders {
totalCount: Int!
}
-type Link implements DocumentInterface {
+type Page implements DocumentInterface {
id: ID!
updatedAt: DateTime!
- content: LinkBlockData!
+ content: PageContentBlockData!
+ seo: SeoBlockData!
createdAt: DateTime!
+ pageTreeNode: PageTreeNode
}
interface DocumentInterface {
@@ -173,23 +175,21 @@ interface DocumentInterface {
updatedAt: DateTime!
}
-"""Link root block data"""
-scalar LinkBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
+"""PageContent root block data"""
+scalar PageContentBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
-type Page implements DocumentInterface {
+"""Seo root block data"""
+scalar SeoBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
+
+type Link implements DocumentInterface {
id: ID!
updatedAt: DateTime!
- content: PageContentBlockData!
- seo: SeoBlockData!
+ content: LinkBlockData!
createdAt: DateTime!
- pageTreeNode: PageTreeNode
}
-"""PageContent root block data"""
-scalar PageContentBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
-
-"""Seo root block data"""
-scalar SeoBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
+"""Link root block data"""
+scalar LinkBlockData @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf")
type PageTreeNodeScope {
domain: String!
diff --git a/demo/api/src/db/fixtures/assets/svgs/comet-color-claim.svg b/demo/api/src/db/fixtures/assets/svgs/comet-color-claim.svg
new file mode 100644
index 00000000000..32eabb4df17
--- /dev/null
+++ b/demo/api/src/db/fixtures/assets/svgs/comet-color-claim.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/demo/api/src/db/fixtures/assets/svgs/comet-logo.svg b/demo/api/src/db/fixtures/assets/svgs/comet-logo.svg
new file mode 100644
index 00000000000..b85951afb72
--- /dev/null
+++ b/demo/api/src/db/fixtures/assets/svgs/comet-logo.svg
@@ -0,0 +1,16 @@
+
diff --git a/demo/api/src/db/fixtures/assets/videos/meer-vogelperspektive-natur-ozean-480p.mp4 b/demo/api/src/db/fixtures/assets/videos/meer-vogelperspektive-natur-ozean-480p.mp4
new file mode 100644
index 00000000000..cefb71a811b
Binary files /dev/null and b/demo/api/src/db/fixtures/assets/videos/meer-vogelperspektive-natur-ozean-480p.mp4 differ
diff --git a/demo/api/src/db/fixtures/fixtures.console.ts b/demo/api/src/db/fixtures/fixtures.console.ts
index 383a98038d4..6d5416a066b 100644
--- a/demo/api/src/db/fixtures/fixtures.console.ts
+++ b/demo/api/src/db/fixtures/fixtures.console.ts
@@ -5,28 +5,19 @@ import { EntityRepository } from "@mikro-orm/postgresql";
import { Inject, Injectable } from "@nestjs/common";
import { Config } from "@src/config/config";
import { CONFIG } from "@src/config/config.module";
-import { generateSeoBlock } from "@src/db/fixtures/generators/blocks/seo.generator";
-import { ImageGeneratorService } from "@src/db/fixtures/generators/image-generator.service";
-import { Link } from "@src/links/entities/link.entity";
+import { FileGeneratorService } from "@src/db/fixtures/generators/file-generator.service";
import { PageTreeNodeScope } from "@src/page-tree/dto/page-tree-node-scope";
import { PageTreeNodeCategory } from "@src/page-tree/page-tree-node-category";
-import { PageContentBlock } from "@src/pages/blocks/page-content.block";
-import { PageInput } from "@src/pages/dto/page.input";
import { Page } from "@src/pages/entities/page.entity";
import faker from "faker";
import { Command, Console } from "nestjs-console";
import slugify from "slugify";
+import { PageContentBlockGeneratorService } from "./generators/blocks/page-content-block.generator";
+import { SeoBlockGeneratorService } from "./generators/blocks/seo.generator";
import { LinkGeneratorService } from "./generators/link-generator.service";
import { PageGeneratorService } from "./generators/page-generator.service";
-const getDefaultPageInput = (): PageInput => {
- const pageInput = new PageInput();
- pageInput.seo = generateSeoBlock();
- pageInput.content = PageContentBlock.blockInputFactory({ blocks: [] });
- return pageInput;
-};
-
@Injectable()
@Console()
export class FixturesConsole {
@@ -35,11 +26,12 @@ export class FixturesConsole {
private readonly blobStorageBackendService: BlobStorageBackendService,
private readonly pageTreeService: PageTreeService,
private readonly pageGeneratorService: PageGeneratorService,
+ private readonly pageContentBlockGeneratorService: PageContentBlockGeneratorService,
+ private readonly seoBlockGeneratorService: SeoBlockGeneratorService,
private readonly linkGeneratorService: LinkGeneratorService,
- private readonly imageGeneratorService: ImageGeneratorService,
+ private readonly fileGeneratorService: FileGeneratorService,
private readonly orm: MikroORM,
@InjectRepository(Page) private readonly pagesRepository: EntityRepository,
- @InjectRepository(Link) private readonly linksRepository: EntityRepository,
) {}
@Command({
@@ -66,8 +58,8 @@ export class FixturesConsole {
const migrator = this.orm.getMigrator();
await migrator.up();
- console.log("Generate Images...");
- await this.imageGeneratorService.generateImages(10);
+ console.log("Generate Files...");
+ await this.fileGeneratorService.generateFiles(5);
console.log("Generate Page Tree...");
const scope: PageTreeNodeScope = {
@@ -90,7 +82,7 @@ export class FixturesConsole {
}
}
- console.log("generate lorem ispum fixtures");
+ // console.log("generate lorem ispum fixtures");
const NUMBER_OF_DOMAINS_WITH_LORUM_IPSUM_CONTENT = 0; // Increase number to generate lorum ipsum fixtures
@@ -119,15 +111,15 @@ export class FixturesConsole {
pagesForLevel.push(page);
pagesCount++;
- const pageInput = getDefaultPageInput();
-
const pageId = faker.datatype.uuid();
+ const content = await this.pageContentBlockGeneratorService.generateBlock();
+ const seo = await this.seoBlockGeneratorService.generateBlock();
await this.pagesRepository.persistAndFlush(
this.pagesRepository.create({
id: pageId,
- content: pageInput.content.transformToBlockData(),
- seo: pageInput.seo.transformToBlockData(),
+ content: content.transformToBlockData(),
+ seo: seo.transformToBlockData(),
}),
);
await this.pageTreeService.attachDocument({ id: pageId, type: "Page" }, page.id);
diff --git a/demo/api/src/db/fixtures/fixtures.module.ts b/demo/api/src/db/fixtures/fixtures.module.ts
index 9d0716c3527..9a85b502a1f 100644
--- a/demo/api/src/db/fixtures/fixtures.module.ts
+++ b/demo/api/src/db/fixtures/fixtures.module.ts
@@ -1,16 +1,56 @@
import { Module } from "@nestjs/common";
import { ConfigModule } from "@src/config/config.module";
import { FixturesConsole } from "@src/db/fixtures/fixtures.console";
-import { ImageGeneratorService } from "@src/db/fixtures/generators/image-generator.service";
+import { FileGeneratorService } from "@src/db/fixtures/generators/file-generator.service";
import { LinksModule } from "@src/links/links.module";
import { PagesModule } from "@src/pages/pages.module";
import { ConsoleModule } from "nestjs-console";
+import { AnchorBlockGeneratorService } from "./generators/blocks/anchor.generator";
+import { ColumnsBlockGeneratorService } from "./generators/blocks/columns.generator";
+import { DamImageBlockGeneratorService } from "./generators/blocks/dam-image.generator";
+import { DamVideoBlockGeneratorService } from "./generators/blocks/dam-video.generator";
+import { FullWidthImageBlockGeneratorService } from "./generators/blocks/full-width-image.generator";
+import { HeadlineBlockGeneratorService } from "./generators/blocks/headline.generator";
+import { LinkBlockGeneratorService } from "./generators/blocks/link.generator";
+import { LinkListBlockGeneratorService } from "./generators/blocks/link-list.generator";
+import { PageContentBlockGeneratorService } from "./generators/blocks/page-content-block.generator";
+import { PixelImageBlockGeneratorService } from "./generators/blocks/pixel-image.generator";
+import { RichTextBlockGeneratorService } from "./generators/blocks/richtext.generator";
+import { SeoBlockGeneratorService } from "./generators/blocks/seo.generator";
+import { SpaceBlockGeneratorService } from "./generators/blocks/space.generator";
+import { SvgImageBlockGeneratorService } from "./generators/blocks/svg-image.generator";
+import { TextImageBlockGeneratorService } from "./generators/blocks/text-image.generator";
+import { TextLinkBlockGeneratorService } from "./generators/blocks/text-link.generator";
+import { YouTubeVideoBlockGeneratorService } from "./generators/blocks/you-tube-video.generator";
import { LinkGeneratorService } from "./generators/link-generator.service";
import { PageGeneratorService } from "./generators/page-generator.service";
@Module({
imports: [ConfigModule, ConsoleModule, PagesModule, LinksModule],
- providers: [FixturesConsole, PageGeneratorService, LinkGeneratorService, ImageGeneratorService],
+ providers: [
+ FixturesConsole,
+ PageGeneratorService,
+ LinkGeneratorService,
+ FileGeneratorService,
+ PageContentBlockGeneratorService,
+ RichTextBlockGeneratorService,
+ DamImageBlockGeneratorService,
+ SeoBlockGeneratorService,
+ TextImageBlockGeneratorService,
+ SpaceBlockGeneratorService,
+ HeadlineBlockGeneratorService,
+ AnchorBlockGeneratorService,
+ FullWidthImageBlockGeneratorService,
+ LinkBlockGeneratorService,
+ LinkListBlockGeneratorService,
+ YouTubeVideoBlockGeneratorService,
+ DamVideoBlockGeneratorService,
+ ColumnsBlockGeneratorService,
+ LinkBlockGeneratorService,
+ TextLinkBlockGeneratorService,
+ SvgImageBlockGeneratorService,
+ PixelImageBlockGeneratorService,
+ ],
})
export class FixturesModule {}
diff --git a/demo/api/src/db/fixtures/generators/blocks/anchor.generator.ts b/demo/api/src/db/fixtures/generators/blocks/anchor.generator.ts
new file mode 100644
index 00000000000..f89a40607a6
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/anchor.generator.ts
@@ -0,0 +1,13 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { AnchorBlock } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+import { random } from "faker";
+
+@Injectable()
+export class AnchorBlockGeneratorService {
+ async generateBlock(): Promise> {
+ return {
+ name: random.word(),
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/blocks.generator.ts b/demo/api/src/db/fixtures/generators/blocks/blocks.generator.ts
deleted file mode 100644
index 2896724af42..00000000000
--- a/demo/api/src/db/fixtures/generators/blocks/blocks.generator.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { BlocksBlockFixturesGeneratorMap, ExtractBlockInput, ExtractBlockInputFactoryProps } from "@comet/blocks-api";
-import { File } from "@comet/cms-api";
-import { Config } from "@src/config/config";
-import { PageContentBlock } from "@src/pages/blocks/page-content.block";
-import faker from "faker";
-
-import { generateImageBlock } from "./image.generator";
-import { generateRichtextBlock } from "./richtext.generator";
-import { generateSpaceBlock } from "./space.generator";
-import { generateTextImageBlock } from "./text-image.generator";
-
-export const generateBlocksBlock = (
- imageFiles: File[],
- config: Config,
- blockCfg: Partial> = {
- space: generateSpaceBlock,
- richtext: generateRichtextBlock,
- image: () => generateImageBlock(imageFiles),
- textImage: () => generateTextImageBlock(imageFiles, config),
- },
-): ExtractBlockInput => {
- const blocks: ExtractBlockInputFactoryProps["blocks"] = [];
- for (let i = 0; i < faker.datatype.number(20); i++) {
- const [type, generator] = faker.random.arrayElement(Object.entries(blockCfg));
- if (generator) {
- blocks.push({
- key: String(i),
- visible: faker.datatype.boolean(),
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- type: type as any,
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- props: generator() as any,
- });
- }
- }
- return PageContentBlock.blockInputFactory({ blocks: blocks });
-};
diff --git a/demo/api/src/db/fixtures/generators/blocks/columns.generator.ts b/demo/api/src/db/fixtures/generators/blocks/columns.generator.ts
new file mode 100644
index 00000000000..73403930863
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/columns.generator.ts
@@ -0,0 +1,61 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { ColumnsBlock, supportedBlocks } from "@src/pages/blocks/columns.block";
+import { datatype, random } from "faker";
+
+import { ColumnsContentBlock } from "../../../../pages/blocks/columns.block";
+import { DamImageBlockGeneratorService } from "./dam-image.generator";
+import { HeadlineBlockGeneratorService } from "./headline.generator";
+import { BlockGenerator } from "./page-content-block.generator";
+import { RichTextBlockGeneratorService } from "./richtext.generator";
+import { SpaceBlockGeneratorService } from "./space.generator";
+
+@Injectable()
+export class ColumnsBlockGeneratorService {
+ constructor(
+ private readonly richtextGeneratorService: RichTextBlockGeneratorService,
+ private readonly damImageBlockGenerator: DamImageBlockGeneratorService,
+ private readonly spaceBlockGenerator: SpaceBlockGeneratorService,
+ private readonly headlineBlockGenerator: HeadlineBlockGeneratorService,
+ ) {}
+
+ async generateBlock(): Promise> {
+ const layoutTypes = ["one-column", "two-columns"];
+ const columnCount = datatype.number({ min: 1, max: 2 });
+ const layout = layoutTypes[columnCount - 1];
+ const columns = [];
+
+ for (let i = 0; i < columnCount; i++) {
+ const blocks: ExtractBlockInputFactoryProps["blocks"] = [];
+
+ const blockCfg: Record = {
+ space: this.spaceBlockGenerator,
+ richtext: this.richtextGeneratorService,
+ headline: this.headlineBlockGenerator,
+ image: this.damImageBlockGenerator,
+ };
+
+ for (let i = 0; i < datatype.number(20); i++) {
+ const [type, generator] = random.arrayElement(Object.entries(blockCfg));
+ if (generator) {
+ const props = await generator.generateBlock();
+
+ blocks.push({
+ key: String(i),
+ visible: datatype.boolean(),
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ type: type as any,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ props: props as any,
+ });
+ }
+ }
+ columns.push({ key: datatype.uuid(), visible: datatype.boolean(), props: { blocks } });
+ }
+
+ return {
+ columns,
+ layout,
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/dam-image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/dam-image.generator.ts
new file mode 100644
index 00000000000..2334bc76b57
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/dam-image.generator.ts
@@ -0,0 +1,54 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { DamImageBlock, FocalPoint, ImageCropAreaInput } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+import { datatype, random } from "faker";
+
+import { PixelImageBlockGeneratorService } from "./pixel-image.generator";
+import { SvgImageBlockGeneratorService } from "./svg-image.generator";
+
+@Injectable()
+export class DamImageBlockGeneratorService {
+ constructor(
+ private readonly svgImageBlockGenerator: SvgImageBlockGeneratorService,
+ private readonly pixelImageBlockGenerator: PixelImageBlockGeneratorService,
+ ) {}
+
+ async generateBlock(): Promise> {
+ let type: "svgImage" | "pixelImage" = "pixelImage";
+ let props = await this.pixelImageBlockGenerator.generateBlock();
+
+ if (datatype.boolean()) {
+ type = "svgImage";
+ props = await this.svgImageBlockGenerator.generateBlock();
+ }
+
+ return {
+ attachedBlocks: [
+ {
+ type,
+ props,
+ },
+ ],
+ activeType: type,
+ };
+ }
+}
+
+export const calculateDefaultCropInput = (): ImageCropAreaInput => {
+ const focalPoint = random.arrayElement([
+ FocalPoint.SMART,
+ FocalPoint.CENTER,
+ FocalPoint.NORTHEAST,
+ FocalPoint.NORTHWEST,
+ FocalPoint.SOUTHEAST,
+ FocalPoint.SOUTHWEST,
+ ]);
+
+ return {
+ focalPoint,
+ x: focalPoint !== FocalPoint.SMART ? 0 : undefined,
+ y: focalPoint !== FocalPoint.SMART ? 0 : undefined,
+ height: focalPoint !== FocalPoint.SMART ? datatype.number({ min: 20, max: 100 }) : undefined,
+ width: focalPoint !== FocalPoint.SMART ? datatype.number({ min: 20, max: 100 }) : undefined,
+ };
+};
diff --git a/demo/api/src/db/fixtures/generators/blocks/dam-video.generator.ts b/demo/api/src/db/fixtures/generators/blocks/dam-video.generator.ts
new file mode 100644
index 00000000000..f083b4dcc5b
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/dam-video.generator.ts
@@ -0,0 +1,23 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { DamVideoBlock } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+import { datatype } from "faker";
+
+import { FileGeneratorService } from "../file-generator.service";
+
+@Injectable()
+export class DamVideoBlockGeneratorService {
+ constructor(private readonly fileGenerator: FileGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ const autoplay = datatype.boolean();
+ const damFileId = this.fileGenerator.getRandomVideo().id;
+
+ return {
+ autoplay,
+ loop: datatype.boolean(),
+ showControls: !autoplay,
+ damFileId,
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/full-width-image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/full-width-image.generator.ts
new file mode 100644
index 00000000000..d7e0278d775
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/full-width-image.generator.ts
@@ -0,0 +1,26 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { FullWidthImageBlock, FullWidthImageContentBlock } from "@src/pages/blocks/full-width-image.block";
+import { datatype } from "faker";
+
+import { DamImageBlockGeneratorService } from "./dam-image.generator";
+import { RichTextBlockGeneratorService } from "./richtext.generator";
+
+@Injectable()
+export class FullWidthImageBlockGeneratorService {
+ constructor(
+ private readonly damImageBlockGeneratorService: DamImageBlockGeneratorService,
+ private readonly richTextBlockGenerator: RichTextBlockGeneratorService,
+ ) {}
+
+ async generateBlock(): Promise> {
+ return {
+ // @ts-expect-error wrong type in full-width-image block, fixed in: https://github.com/vivid-planet/comet/pull/1269
+ image: await this.damImageBlockGeneratorService.generateBlock(),
+ content: FullWidthImageContentBlock.blockInputFactory({
+ visible: datatype.boolean(),
+ block: await this.richTextBlockGenerator.generateBlock(),
+ }).transformToBlockData(), // remove transformToBlockData when block is fixed: https://github.com/vivid-planet/comet/pull/1269
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/headline.generator.ts b/demo/api/src/db/fixtures/generators/blocks/headline.generator.ts
new file mode 100644
index 00000000000..d5a05f1baf8
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/headline.generator.ts
@@ -0,0 +1,18 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { HeadlineBlock, HeadlineLevel } from "@src/pages/blocks/headline.block";
+import { datatype, random } from "faker";
+
+import { RichTextBlockGeneratorService } from "./richtext.generator";
+@Injectable()
+export class HeadlineBlockGeneratorService {
+ constructor(private readonly richtextBlockGeneratorService: RichTextBlockGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ return {
+ headline: await this.richtextBlockGeneratorService.generateBlock(1),
+ eyebrow: random.words(datatype.number({ min: 1, max: 5 })),
+ level: random.arrayElement(Object.values(HeadlineLevel)),
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/image.generator.ts
deleted file mode 100644
index f76b609995c..00000000000
--- a/demo/api/src/db/fixtures/generators/blocks/image.generator.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
-import { DamImageBlock, File, FocalPoint, ImageCropAreaInput } from "@comet/cms-api";
-import faker from "faker";
-
-export const generateImageBlock = (imageFiles: File[] | File, cropArea?: ImageCropAreaInput): ExtractBlockInputFactoryProps => {
- const imageFile = Array.isArray(imageFiles) ? faker.random.arrayElement(imageFiles) : imageFiles;
- const type = imageFile.mimetype == "image/svg+xml" ? "svgImage" : "pixelImage";
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const props: any = {
- damFileId: imageFile.id,
- };
- if (type == "pixelImage") {
- props.cropArea = cropArea ?? calculateDefaultCropInput(imageFile);
- }
- return {
- attachedBlocks: [
- {
- type,
- props,
- },
- ],
- activeType: type,
- };
-};
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-export const calculateDefaultCropInput = ({ image }: File): ImageCropAreaInput => {
- const focalPoint = faker.random.arrayElement([
- FocalPoint.SMART,
- FocalPoint.CENTER,
- FocalPoint.NORTHEAST,
- FocalPoint.NORTHWEST,
- FocalPoint.SOUTHEAST,
- FocalPoint.SOUTHWEST,
- ]);
-
- return {
- focalPoint,
- x: focalPoint !== FocalPoint.SMART ? 0 : undefined,
- y: focalPoint !== FocalPoint.SMART ? 0 : undefined,
- height: focalPoint !== FocalPoint.SMART ? faker.datatype.number({ min: 20, max: 100 }) : undefined,
- width: focalPoint !== FocalPoint.SMART ? faker.datatype.number({ min: 20, max: 100 }) : undefined,
- };
-};
diff --git a/demo/api/src/db/fixtures/generators/blocks/link-list.generator.ts b/demo/api/src/db/fixtures/generators/blocks/link-list.generator.ts
new file mode 100644
index 00000000000..6804b5cd789
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/link-list.generator.ts
@@ -0,0 +1,24 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { LinkListBlock } from "@src/common/blocks/link-list.block";
+import { datatype } from "faker";
+
+import { TextLinkBlockGeneratorService } from "./text-link.generator";
+
+@Injectable()
+export class LinkListBlockGeneratorService {
+ constructor(private readonly textLinkBlockGenerator: TextLinkBlockGeneratorService) {}
+
+ async generateBlock(min = 2, max = 6): Promise> {
+ const blockAmount = datatype.number({ min, max });
+ const blocks = [];
+
+ for (let i = 0; i < blockAmount; i++) {
+ blocks.push({ key: datatype.uuid(), visible: true, props: await this.textLinkBlockGenerator.generateBlock() });
+ }
+
+ return {
+ blocks,
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/link.generator.ts b/demo/api/src/db/fixtures/generators/blocks/link.generator.ts
new file mode 100644
index 00000000000..e8b09b836e1
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/link.generator.ts
@@ -0,0 +1,25 @@
+import { ExternalLinkBlock, ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { LinkBlock } from "@src/common/blocks/linkBlock/link.block";
+import { datatype, random } from "faker";
+
+@Injectable()
+export class LinkBlockGeneratorService {
+ async generateBlock(): Promise> {
+ const externalLinkUrls = ["https://www.comet-dxp.com/", "https://docs.comet-dxp.com/", "https://vivid-planet.com/"];
+
+ // TODO: Internal Link
+ return LinkBlock.blockInputFactory({
+ attachedBlocks: [
+ {
+ type: "external",
+ props: ExternalLinkBlock.blockDataFactory({
+ targetUrl: random.arrayElement(externalLinkUrls),
+ openInNewWindow: datatype.boolean(),
+ }),
+ },
+ ],
+ activeType: "external",
+ });
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/page-content-block.generator.ts b/demo/api/src/db/fixtures/generators/blocks/page-content-block.generator.ts
new file mode 100644
index 00000000000..409a52ab8e0
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/page-content-block.generator.ts
@@ -0,0 +1,74 @@
+import { Block, ExtractBlockInput, ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { PageContentBlock, supportedBlocks } from "@src/pages/blocks/page-content.block";
+import { UserGroup } from "@src/user-groups/user-group";
+import faker from "faker";
+
+import { AnchorBlockGeneratorService } from "./anchor.generator";
+import { ColumnsBlockGeneratorService } from "./columns.generator";
+import { DamImageBlockGeneratorService } from "./dam-image.generator";
+import { DamVideoBlockGeneratorService } from "./dam-video.generator";
+import { FullWidthImageBlockGeneratorService } from "./full-width-image.generator";
+import { HeadlineBlockGeneratorService } from "./headline.generator";
+import { LinkListBlockGeneratorService } from "./link-list.generator";
+import { RichTextBlockGeneratorService } from "./richtext.generator";
+import { SpaceBlockGeneratorService } from "./space.generator";
+import { TextImageBlockGeneratorService } from "./text-image.generator";
+import { YouTubeVideoBlockGeneratorService } from "./you-tube-video.generator";
+
+export type BlockGenerator = { generateBlock: () => Promise> };
+
+@Injectable()
+export class PageContentBlockGeneratorService {
+ constructor(
+ private readonly richtextGeneratorService: RichTextBlockGeneratorService,
+ private readonly damImageBlockGenerator: DamImageBlockGeneratorService,
+ private readonly textImageBlockGenerator: TextImageBlockGeneratorService,
+ private readonly spaceBlockGenerator: SpaceBlockGeneratorService,
+ private readonly headlineBlockGenerator: HeadlineBlockGeneratorService,
+ private readonly anchorBlockGenerator: AnchorBlockGeneratorService,
+ private readonly fullWithBlockGenerator: FullWidthImageBlockGeneratorService,
+ private readonly linkListBlockGenerator: LinkListBlockGeneratorService,
+ private readonly youTubeVideoBlockGenerator: YouTubeVideoBlockGeneratorService,
+ private readonly damVideoBlockGenerator: DamVideoBlockGeneratorService,
+ private readonly columnsBlockGenerator: ColumnsBlockGeneratorService,
+ ) {}
+
+ async generateBlock(): Promise> {
+ const blocks: ExtractBlockInputFactoryProps["blocks"] = [];
+
+ const blockCfg: Record = {
+ richtext: this.richtextGeneratorService,
+ image: this.damImageBlockGenerator,
+ textImage: this.textImageBlockGenerator,
+ space: this.spaceBlockGenerator,
+ linkList: this.linkListBlockGenerator,
+ fullWidthImage: this.fullWithBlockGenerator,
+ anchor: this.anchorBlockGenerator,
+ columns: this.columnsBlockGenerator,
+ damVideo: this.damVideoBlockGenerator,
+ headline: this.headlineBlockGenerator,
+ youTubeVideo: this.youTubeVideoBlockGenerator,
+ };
+
+ for (let i = 0; i < faker.datatype.number(20); i++) {
+ const [type, generator] = faker.random.arrayElement(Object.entries(blockCfg));
+ if (generator) {
+ const props = await generator.generateBlock();
+ const userGroup = faker.random.arrayElement(Object.values(UserGroup));
+ blocks.push({
+ key: String(i),
+ visible: faker.datatype.boolean(),
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ type: type as any,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ props: props as any,
+ // @ts-expect-error wrong typing?
+ userGroup,
+ });
+ }
+ }
+
+ return PageContentBlock.blockInputFactory({ blocks });
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/pixel-image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/pixel-image.generator.ts
new file mode 100644
index 00000000000..5d9ea6bfdc0
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/pixel-image.generator.ts
@@ -0,0 +1,37 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { FocalPoint, ImageCropAreaInput, PixelImageBlock } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+import { datatype, random } from "faker";
+
+import { FileGeneratorService } from "../file-generator.service";
+
+@Injectable()
+export class PixelImageBlockGeneratorService {
+ constructor(private readonly fileGeneratorService: FileGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ return {
+ damFileId: this.fileGeneratorService.getRandomPixelImage().id,
+ cropArea: calculateDefaultCropInput(),
+ };
+ }
+}
+
+export const calculateDefaultCropInput = (): ImageCropAreaInput => {
+ const focalPoint = random.arrayElement([
+ FocalPoint.SMART,
+ FocalPoint.CENTER,
+ FocalPoint.NORTHEAST,
+ FocalPoint.NORTHWEST,
+ FocalPoint.SOUTHEAST,
+ FocalPoint.SOUTHWEST,
+ ]);
+
+ return {
+ focalPoint,
+ x: focalPoint !== FocalPoint.SMART ? 0 : undefined,
+ y: focalPoint !== FocalPoint.SMART ? 0 : undefined,
+ height: focalPoint !== FocalPoint.SMART ? datatype.number({ min: 20, max: 100 }) : undefined,
+ width: focalPoint !== FocalPoint.SMART ? datatype.number({ min: 20, max: 100 }) : undefined,
+ };
+};
diff --git a/demo/api/src/db/fixtures/generators/blocks/richtext.generator.ts b/demo/api/src/db/fixtures/generators/blocks/richtext.generator.ts
index e5a11411f33..a31efd2421e 100644
--- a/demo/api/src/db/fixtures/generators/blocks/richtext.generator.ts
+++ b/demo/api/src/db/fixtures/generators/blocks/richtext.generator.ts
@@ -1,104 +1,111 @@
import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
import { RichTextBlock } from "@src/common/blocks/rich-text.block";
+import faker from "faker";
-export const generateRichtextBlock = (): ExtractBlockInputFactoryProps => {
- return {
- draftContent: {
- blocks: [
- {
- key: "5jda2",
- text: "Another Headline in RTE",
- type: "header-three",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "bifh7",
- text: "1",
- type: "unordered-list-item",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "er118",
- text: "2",
- type: "unordered-list-item",
- depth: 1,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "5e7g4",
- text: "three",
- type: "unordered-list-item",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "bb4fe",
- text: "Test soft-hyphen: pneu\u00admonoultra\u00admicroscopicsilico\u00advolcanoconiosis",
- type: "header-one",
- depth: 0,
- inlineStyleRanges: [
- {
- offset: 18,
- length: 44,
- style: "ITALIC",
- },
- {
- offset: 65,
- length: 1,
- style: "ITALIC",
- },
- ],
- entityRanges: [],
- data: {},
- },
- {
- key: "4oobv",
- text: "Ein paar emojis: 😀🌍️",
- type: "unstyled",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "37lco",
- text: "",
- type: "unstyled",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "a5q4f",
- text: "Custom Headline...",
- type: "header-custom-green",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- {
- key: "af1q4",
- text: "Foo bar...",
- type: "unstyled",
- depth: 0,
- inlineStyleRanges: [],
- entityRanges: [],
- data: {},
- },
- ],
- entityMap: {},
- },
- };
-};
+@Injectable()
+export class RichTextBlockGeneratorService {
+ async generateBlock(textCount = 3): Promise> {
+ const defaultBlocks: ExtractBlockInputFactoryProps["draftContent"]["blocks"] = [
+ {
+ key: "5jda2",
+ text: "Another Headline in RTE",
+ type: "header-three",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "bifh7",
+ text: "1",
+ type: "unordered-list-item",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "er118",
+ text: "2",
+ type: "unordered-list-item",
+ depth: 1,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "5e7g4",
+ text: "three",
+ type: "unordered-list-item",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "bb4fe",
+ text: "Test soft-hyphen: pneu\u00admonoultra\u00admicroscopicsilico\u00advolcanoconiosis",
+ type: "header-one",
+ depth: 0,
+ inlineStyleRanges: [
+ {
+ offset: 18,
+ length: 44,
+ style: "ITALIC",
+ },
+ {
+ offset: 65,
+ length: 1,
+ style: "ITALIC",
+ },
+ ],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "4oobv",
+ text: "Ein paar emojis: 😀🌍️",
+ type: "unstyled",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "37lco",
+ text: "",
+ type: "unstyled",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "a5q4f",
+ text: "Custom Headline...",
+ type: "header-custom-green",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ {
+ key: "af1q4",
+ text: "Foo bar...",
+ type: "unstyled",
+ depth: 0,
+ inlineStyleRanges: [],
+ entityRanges: [],
+ data: {},
+ },
+ ];
+
+ return {
+ draftContent: {
+ blocks: faker.random.arrayElements(defaultBlocks, textCount),
+ entityMap: {},
+ },
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/seo.generator.ts b/demo/api/src/db/fixtures/generators/blocks/seo.generator.ts
index ab307b569eb..db95e867491 100644
--- a/demo/api/src/db/fixtures/generators/blocks/seo.generator.ts
+++ b/demo/api/src/db/fixtures/generators/blocks/seo.generator.ts
@@ -1,20 +1,33 @@
-import { BlockInputInterface } from "@comet/blocks-api";
+import { ExtractBlockInput } from "@comet/blocks-api";
import { SitemapPageChangeFrequency, SitemapPagePriority } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
import { SeoBlock } from "@src/pages/blocks/seo.block";
+import * as faker from "faker";
-export const generateSeoBlock = (): BlockInputInterface => {
- // @TODO Introduce randomness
- return SeoBlock.blockInputFactory({
- htmlTitle: "",
- metaDescription: "",
- openGraphTitle: "",
- openGraphDescription: "",
- openGraphImage: { block: undefined, visible: false },
- structuredData: undefined,
- canonicalUrl: undefined,
- alternativeLinks: [],
- noIndex: false,
- priority: SitemapPagePriority._0_5,
- changeFrequency: SitemapPageChangeFrequency.weekly,
- });
-};
+import { PixelImageBlockGeneratorService } from "./pixel-image.generator";
+
+@Injectable()
+export class SeoBlockGeneratorService {
+ constructor(private readonly pixelImageBlockGeneratorService: PixelImageBlockGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ const alternativeLinks = [];
+ const codes = ["en_US", "en_GB", "es_ES", "fr_FR", "ja_JP", "it_IT"];
+ for (let i = 0; i < faker.datatype.number({ min: 0, max: 5 }); i++) {
+ alternativeLinks.push({ code: codes[i], url: faker.internet.url() });
+ }
+
+ return SeoBlock.blockInputFactory({
+ htmlTitle: faker.random.words(2),
+ metaDescription: faker.random.words(20),
+ openGraphTitle: faker.random.words(2),
+ openGraphDescription: faker.random.words(20),
+ openGraphImage: { block: await this.pixelImageBlockGeneratorService.generateBlock(), visible: faker.datatype.boolean() },
+ noIndex: faker.datatype.boolean(),
+ priority: faker.random.arrayElement(Object.values(SitemapPagePriority)),
+ changeFrequency: faker.random.arrayElement(Object.values(SitemapPageChangeFrequency)),
+ alternativeLinks,
+ structuredData: JSON.stringify({ name: faker.random.words(2), description: faker.random.words(20), datePublished: faker.date.past() }),
+ });
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/space.generator.ts b/demo/api/src/db/fixtures/generators/blocks/space.generator.ts
index 92876f88b2d..77137026431 100644
--- a/demo/api/src/db/fixtures/generators/blocks/space.generator.ts
+++ b/demo/api/src/db/fixtures/generators/blocks/space.generator.ts
@@ -1,4 +1,10 @@
import { ExtractBlockInputFactoryProps, SpaceBlock } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
import faker from "faker";
-export const generateSpaceBlock = (): ExtractBlockInputFactoryProps => ({ height: faker.datatype.number(200) });
+@Injectable()
+export class SpaceBlockGeneratorService {
+ async generateBlock(): Promise> {
+ return { height: faker.datatype.number({ min: 20, max: 200 }) };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/svg-image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/svg-image.generator.ts
new file mode 100644
index 00000000000..a9d05991360
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/svg-image.generator.ts
@@ -0,0 +1,16 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { SvgImageBlock } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+
+import { FileGeneratorService } from "../file-generator.service";
+
+@Injectable()
+export class SvgImageBlockGeneratorService {
+ constructor(private readonly fileGeneratorService: FileGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ return {
+ damFileId: this.fileGeneratorService.getRandomSvg().id,
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/text-image.generator.ts b/demo/api/src/db/fixtures/generators/blocks/text-image.generator.ts
index 8d7baf07e9b..b60ab128737 100644
--- a/demo/api/src/db/fixtures/generators/blocks/text-image.generator.ts
+++ b/demo/api/src/db/fixtures/generators/blocks/text-image.generator.ts
@@ -1,17 +1,28 @@
import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
-import { File, ImagePosition } from "@comet/cms-api";
+import { ImagePosition } from "@comet/cms-api/lib/blocks/createTextImageBlock";
+import { Inject, Injectable } from "@nestjs/common";
import { Config } from "@src/config/config";
+import { CONFIG } from "@src/config/config.module";
import { TextImageBlock } from "@src/pages/blocks/TextImageBlock";
import faker from "faker";
-import { generateImageBlock } from "./image.generator";
-import { generateRichtextBlock } from "./richtext.generator";
+import { DamImageBlockGeneratorService } from "./dam-image.generator";
+import { RichTextBlockGeneratorService } from "./richtext.generator";
-export const generateTextImageBlock = (imageFiles: File[] | File, config: Config): ExtractBlockInputFactoryProps => {
- return {
- text: generateRichtextBlock(),
- image: generateImageBlock(imageFiles),
- imagePosition: faker.random.arrayElement([ImagePosition.Left, ImagePosition.Right]),
- imageAspectRatio: faker.random.arrayElement(config.dam.allowedImageAspectRatios),
- };
-};
+@Injectable()
+export class TextImageBlockGeneratorService {
+ constructor(
+ private readonly richtextBlockGeneratorService: RichTextBlockGeneratorService,
+ private readonly damImageBlockGeneratorService: DamImageBlockGeneratorService,
+ @Inject(CONFIG) private readonly config: Config,
+ ) {}
+
+ async generateBlock(): Promise> {
+ return {
+ text: await this.richtextBlockGeneratorService.generateBlock(),
+ image: await this.damImageBlockGeneratorService.generateBlock(),
+ imagePosition: faker.random.arrayElement([ImagePosition.Left, ImagePosition.Right]),
+ imageAspectRatio: faker.random.arrayElement(this.config.dam.allowedImageAspectRatios),
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/text-link.generator.ts b/demo/api/src/db/fixtures/generators/blocks/text-link.generator.ts
new file mode 100644
index 00000000000..01d6d6cc68d
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/text-link.generator.ts
@@ -0,0 +1,18 @@
+import { ExtractBlockInputFactoryProps } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { TextLinkBlock } from "@src/common/blocks/text-link.block";
+import { datatype, random } from "faker";
+
+import { LinkBlockGeneratorService } from "./link.generator";
+
+@Injectable()
+export class TextLinkBlockGeneratorService {
+ constructor(private readonly linkBlockGeneratorService: LinkBlockGeneratorService) {}
+
+ async generateBlock(): Promise> {
+ return {
+ text: random.words(datatype.number({ min: 1, max: 5 })),
+ link: await this.linkBlockGeneratorService.generateBlock(),
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/blocks/you-tube-video.generator.ts b/demo/api/src/db/fixtures/generators/blocks/you-tube-video.generator.ts
new file mode 100644
index 00000000000..3c7bfdbb369
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/blocks/you-tube-video.generator.ts
@@ -0,0 +1,25 @@
+import { ExtractBlockInputFactoryProps, YouTubeVideoBlock } from "@comet/blocks-api";
+import { Injectable } from "@nestjs/common";
+import { datatype, random } from "faker";
+
+// TODO: Remove when moving this block to the CMS - export it from youtube video block
+enum AspectRatio {
+ "16X9" = "16X9",
+ "4X3" = "4X3",
+}
+
+@Injectable()
+export class YouTubeVideoBlockGeneratorService {
+ async generateBlock(): Promise> {
+ const identifier = ["F_oOtaxb0L8", "Sklc_fQBmcs", "Xoz31I1FuiY", "bMknfKXIFA8"];
+ const autoplay = datatype.boolean();
+
+ return {
+ autoplay,
+ loop: datatype.boolean(),
+ aspectRatio: random.arrayElement(Object.values(AspectRatio)),
+ showControls: !autoplay,
+ youtubeIdentifier: random.arrayElement(identifier),
+ };
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/file-generator.service.ts b/demo/api/src/db/fixtures/generators/file-generator.service.ts
new file mode 100644
index 00000000000..efbecd510c8
--- /dev/null
+++ b/demo/api/src/db/fixtures/generators/file-generator.service.ts
@@ -0,0 +1,88 @@
+import { download, File, FilesService } from "@comet/cms-api";
+import { Injectable } from "@nestjs/common";
+import faker from "faker";
+import * as fs from "fs/promises";
+import path from "path";
+
+@Injectable()
+export class FileGeneratorService {
+ private pixelImageFiles: File[] = [];
+ private svgImageFiles: File[] = [];
+ private videoFiles: File[] = [];
+
+ constructor(private readonly filesService: FilesService) {}
+
+ public getRandomPixelImage() {
+ const randomIndex = faker.datatype.number({
+ min: 0,
+ max: this.pixelImageFiles.length - 1,
+ });
+ return this.pixelImageFiles[randomIndex];
+ }
+
+ public getRandomSvg() {
+ const randomIndex = faker.datatype.number({
+ min: 0,
+ max: this.svgImageFiles.length - 1,
+ });
+ return this.svgImageFiles[randomIndex];
+ }
+
+ public getRandomVideo() {
+ const randomIndex = faker.datatype.number({
+ min: 0,
+ max: this.videoFiles.length - 1,
+ });
+ return this.videoFiles[randomIndex];
+ }
+
+ public async generateFiles(pixelImageCount: number): Promise {
+ this.pixelImageFiles = [];
+ for (let i = 0; i < pixelImageCount; i++) {
+ await this.generatePixelImage();
+ }
+
+ console.log("Generate Videos ...");
+ await this.generateVideos();
+ console.log("Generate SVGs ...");
+ await this.generateSvgImages();
+ }
+
+ private async generatePixelImage(): Promise {
+ const width = faker.datatype.number({
+ min: 1000,
+ max: 3000,
+ });
+ const height = faker.datatype.number({
+ min: 1000,
+ max: 3000,
+ });
+
+ const imageUrl = `https://source.unsplash.com/random/${width}x${height}`;
+ const downloadedImage = await download(imageUrl);
+
+ const image = await this.filesService.upload(downloadedImage);
+ this.pixelImageFiles.push(image);
+ }
+
+ private async generateSvgImages(): Promise {
+ const svgDirectoryPath = "./src/db/fixtures/assets/svgs";
+ const files = await fs.readdir(path.resolve(svgDirectoryPath));
+
+ for (const svg of files) {
+ const file = await download(path.resolve(`${svgDirectoryPath}/${svg}`));
+ file.mimetype = "image/svg+xml"; // mime type is undefined for svg files and wrongly typed in download function (a possible undefined type is typed as string)
+ this.svgImageFiles.push(await this.filesService.upload(file));
+ }
+ }
+
+ private async generateVideos(): Promise {
+ const videoDirectoryPath = "./src/db/fixtures/assets/videos";
+ const files = await fs.readdir(path.resolve(videoDirectoryPath));
+
+ for (const video of files) {
+ const file = await download(path.resolve(`${videoDirectoryPath}/${video}`));
+ this.videoFiles.push(await this.filesService.upload(file));
+ }
+ }
+}
diff --git a/demo/api/src/db/fixtures/generators/image-generator.service.ts b/demo/api/src/db/fixtures/generators/image-generator.service.ts
deleted file mode 100644
index 3b4905423b0..00000000000
--- a/demo/api/src/db/fixtures/generators/image-generator.service.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { download, File, FilesService } from "@comet/cms-api";
-import { Injectable } from "@nestjs/common";
-import faker from "faker";
-
-@Injectable()
-export class ImageGeneratorService {
- private imageFiles: File[] = [];
- constructor(private readonly filesService: FilesService) {}
-
- public getRandomImage() {
- const randomIndex = faker.datatype.number({
- min: 0,
- max: this.imageFiles.length - 1,
- });
- return this.imageFiles[randomIndex];
- }
-
- public async generateImages(imageCount: number): Promise {
- this.imageFiles = [];
- for (let i = 0; i < imageCount; i++) {
- const image = await this.generateImage();
- this.imageFiles.push(image);
- }
- }
-
- private async generateImage(): Promise {
- const width = faker.datatype.number({
- min: 1000,
- max: 3000,
- });
- const height = faker.datatype.number({
- min: 1000,
- max: 3000,
- });
-
- const imageUrl = `https://source.unsplash.com/random/${width}x${height}`;
- const downloadedImage = await download(imageUrl);
-
- return this.filesService.upload(downloadedImage);
- }
-}
diff --git a/demo/api/src/db/fixtures/generators/link-generator.service.ts b/demo/api/src/db/fixtures/generators/link-generator.service.ts
index b0c8b8d928f..7ff4a1a649e 100644
--- a/demo/api/src/db/fixtures/generators/link-generator.service.ts
+++ b/demo/api/src/db/fixtures/generators/link-generator.service.ts
@@ -10,6 +10,8 @@ import { PageTreeNodeCategory } from "@src/page-tree/page-tree-node-category";
import faker from "faker";
import slugify from "slugify";
+import { LinkBlockGeneratorService } from "./blocks/link.generator";
+
interface GenerateLinkInput {
name: string;
scope: PageTreeNodeScope;
@@ -18,7 +20,11 @@ interface GenerateLinkInput {
@Injectable()
export class LinkGeneratorService {
- constructor(private readonly pageTreeService: PageTreeService, @InjectRepository(Link) private readonly linkRepository: EntityRepository) {}
+ constructor(
+ private readonly pageTreeService: PageTreeService,
+ @InjectRepository(Link) private readonly linkRepository: EntityRepository,
+ private readonly linkBlockGenerator: LinkBlockGeneratorService,
+ ) {}
async generateLink({ name, scope, parentId }: GenerateLinkInput): Promise {
const id = faker.datatype.uuid();
diff --git a/demo/api/src/db/fixtures/generators/page-generator.service.ts b/demo/api/src/db/fixtures/generators/page-generator.service.ts
index 7faba7b16e4..fa9a4c530c8 100644
--- a/demo/api/src/db/fixtures/generators/page-generator.service.ts
+++ b/demo/api/src/db/fixtures/generators/page-generator.service.ts
@@ -1,18 +1,15 @@
import { PageTreeNodeInterface, PageTreeNodeVisibility, PageTreeService } from "@comet/cms-api";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityRepository } from "@mikro-orm/postgresql";
-import { Inject, Injectable } from "@nestjs/common";
-import { Config } from "@src/config/config";
-import { CONFIG } from "@src/config/config.module";
-import { generateBlocksBlock } from "@src/db/fixtures/generators/blocks/blocks.generator";
-import { generateSeoBlock } from "@src/db/fixtures/generators/blocks/seo.generator";
+import { Injectable } from "@nestjs/common";
+import { SeoBlockGeneratorService } from "@src/db/fixtures/generators/blocks/seo.generator";
import { PageTreeNodeScope } from "@src/page-tree/dto/page-tree-node-scope";
import { PageTreeNodeCategory } from "@src/page-tree/page-tree-node-category";
import { Page } from "@src/pages/entities/page.entity";
import faker from "faker";
import slugify from "slugify";
-import { ImageGeneratorService } from "./image-generator.service";
+import { PageContentBlockGeneratorService } from "./blocks/page-content-block.generator";
interface GeneratePageInput {
name: string;
@@ -23,10 +20,10 @@ interface GeneratePageInput {
@Injectable()
export class PageGeneratorService {
constructor(
- @Inject(CONFIG) private readonly config: Config,
private readonly pageTreeService: PageTreeService,
@InjectRepository(Page) private readonly pagesRepository: EntityRepository,
- private readonly imageGeneratorService: ImageGeneratorService,
+ private readonly pageContentBlockGenerator: PageContentBlockGeneratorService,
+ private readonly seoBlockGeneratorService: SeoBlockGeneratorService,
) {}
async generatePage({ name, scope, parentId }: GeneratePageInput): Promise {
@@ -48,16 +45,11 @@ export class PageGeneratorService {
);
await this.pageTreeService.updateNodeVisibility(node.id, PageTreeNodeVisibility.Published);
- const imageFiles = [
- this.imageGeneratorService.getRandomImage(),
- this.imageGeneratorService.getRandomImage(),
- this.imageGeneratorService.getRandomImage(),
- ]; // TODO: remove imageFiles here and put into block that needs an image when it is possible to inject imageGeneratorService directly in a block
await this.pagesRepository.persistAndFlush(
this.pagesRepository.create({
id,
- content: generateBlocksBlock(imageFiles, this.config).transformToBlockData(),
- seo: generateSeoBlock().transformToBlockData(),
+ content: (await this.pageContentBlockGenerator.generateBlock()).transformToBlockData(),
+ seo: (await this.seoBlockGeneratorService.generateBlock()).transformToBlockData(),
}),
);
diff --git a/demo/api/src/pages/blocks/columns.block.ts b/demo/api/src/pages/blocks/columns.block.ts
index 3b6b1a260bc..2ef4a99f8f6 100644
--- a/demo/api/src/pages/blocks/columns.block.ts
+++ b/demo/api/src/pages/blocks/columns.block.ts
@@ -4,14 +4,16 @@ import { RichTextBlock } from "@src/common/blocks/rich-text.block";
import { HeadlineBlock } from "./headline.block";
-const ColumnsContentBlock = createBlocksBlock(
+export const supportedBlocks = {
+ space: SpaceBlock,
+ richtext: RichTextBlock,
+ headline: HeadlineBlock,
+ image: DamImageBlock,
+};
+
+export const ColumnsContentBlock = createBlocksBlock(
{
- supportedBlocks: {
- space: SpaceBlock,
- richtext: RichTextBlock,
- headline: HeadlineBlock,
- image: DamImageBlock,
- },
+ supportedBlocks,
},
"ColumnsContent",
);
diff --git a/demo/api/src/pages/blocks/full-width-image.block.ts b/demo/api/src/pages/blocks/full-width-image.block.ts
index 618fc193998..c13aa73530a 100644
--- a/demo/api/src/pages/blocks/full-width-image.block.ts
+++ b/demo/api/src/pages/blocks/full-width-image.block.ts
@@ -13,7 +13,7 @@ import { DamImageBlock } from "@comet/cms-api";
import { RichTextBlock } from "@src/common/blocks/rich-text.block";
import { ValidateNested } from "class-validator";
-const FullWidthImageContentBlock = createOptionalBlock(RichTextBlock);
+export const FullWidthImageContentBlock = createOptionalBlock(RichTextBlock);
class FullWidthImageBlockData extends BlockData {
@ChildBlock(DamImageBlock)
diff --git a/demo/api/src/pages/blocks/page-content.block.ts b/demo/api/src/pages/blocks/page-content.block.ts
index 2199e37dbb3..a4b024ddf7d 100644
--- a/demo/api/src/pages/blocks/page-content.block.ts
+++ b/demo/api/src/pages/blocks/page-content.block.ts
@@ -10,7 +10,7 @@ import { FullWidthImageBlock } from "./full-width-image.block";
import { HeadlineBlock } from "./headline.block";
import { TextImageBlock } from "./TextImageBlock";
-const supportedBlocks = {
+export const supportedBlocks = {
space: SpaceBlock,
richtext: RichTextBlock,
headline: HeadlineBlock,