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,