Skip to content

Commit

Permalink
Merge pull request #334 from Kentico/custom-assets-domain
Browse files Browse the repository at this point in the history
feat: Adds support for custom asset domains (fixes #333)
  • Loading branch information
Enngage committed Dec 16, 2021
2 parents d584e08 + 361d62d commit 2e5ae06
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 12 deletions.
5 changes: 5 additions & 0 deletions lib/config/delivery-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,9 @@ export interface IDeliveryClientConfig {
* with circular refences)
*/
linkedItemsReferenceHandler?: LinkedItemsReferenceHandler;

/**
* Sets custom domain for assets
*/
assetsDomain?: string;
}
62 changes: 56 additions & 6 deletions lib/mappers/element.mapper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { enumHelper } from '@kentico/kontent-core';
import { deliveryUrlHelper } from '../utilities';

import { IDeliveryClientConfig } from '../config';
import { Contracts } from '../contracts';
Expand All @@ -13,6 +14,11 @@ import {
IContentItemWithRawElements
} from '../models';

interface IRichTextImageUrlRecord {
originalUrl: string;
newUrl: string;
}

export class ElementMapper {
constructor(private readonly config: IDeliveryClientConfig) {}

Expand Down Expand Up @@ -185,17 +191,23 @@ export class ElementMapper {
}
}

// get rich text images
const richTextImagesResult = this.getRichTextImages(rawElement.images);

// extract and map links & images
const links: ILink[] = this.mapRichTextLinks(rawElement.links);
const images: IRichTextImage[] = this.mapRichTextImages(rawElement.images);
const images: IRichTextImage[] = richTextImagesResult.richTextImages;

// replace asset urls in html
const richTextHtml: string = this.getRichTextHtml(rawElement.value, richTextImagesResult.imageUrlRecords);

return {
images: images,
linkedItemCodenames: rawElement.modular_content,
links: links,
name: rawElement.name,
type: ElementType.RichText,
value: rawElement.value
value: richTextHtml
};
}

Expand Down Expand Up @@ -231,6 +243,11 @@ export class ElementMapper {
for (const assetContract of assetContracts) {
let renditions: { [renditionPresetCodename: string]: ElementModels.Rendition } | null = null;

// get asset url (custom domain may be configured)
const assetUrl: string = this.config.assetsDomain
? deliveryUrlHelper.replaceAssetDomain(assetContract.url, this.config.assetsDomain)
: assetContract.url;

if (assetContract.renditions) {
renditions = {};

Expand All @@ -239,13 +256,14 @@ export class ElementMapper {

renditions[renditionKey] = {
...rendition,
url: `${assetContract.url}?${rendition.query}` // enhance rendition with absolute url
url: `${assetUrl}?${rendition.query}` // enhance rendition with absolute url
};
}
}

const asset: ElementModels.AssetModel = {
...assetContract,
url: assetUrl, // use custom url of asset which may contain custom domain
renditions
};

Expand Down Expand Up @@ -384,21 +402,53 @@ export class ElementMapper {
return links;
}

private mapRichTextImages(imagesJson: Contracts.IRichTextElementImageWrapperContract): IRichTextImage[] {
private getRichTextHtml(richTextHtml: string, richTextImageRecords: IRichTextImageUrlRecord[]): string {
for (const richTextImageRecord of richTextImageRecords) {
// replace rich text image url if it differs
if (richTextImageRecord.newUrl !== richTextImageRecord.originalUrl) {
richTextHtml = richTextHtml.replace(
new RegExp(richTextImageRecord.originalUrl, 'g'),
richTextImageRecord.newUrl
);
}
}

return richTextHtml;
}

private getRichTextImages(imagesJson: Contracts.IRichTextElementImageWrapperContract): {
richTextImages: IRichTextImage[];
imageUrlRecords: IRichTextImageUrlRecord[];
} {
const images: IRichTextImage[] = [];
const imageUrlRecords: IRichTextImageUrlRecord[] = [];

for (const imageId of Object.keys(imagesJson)) {
const imageRaw = imagesJson[imageId];

// image may contain custom asset domain
const imageUrl: string = this.config.assetsDomain
? deliveryUrlHelper.replaceAssetDomain(imageRaw.url, this.config.assetsDomain)
: imageRaw.url;

images.push({
description: imageRaw.description ?? null,
imageId: imageRaw.image_id,
url: imageRaw.url,
url: imageUrl,
height: imageRaw.height ?? null,
width: imageRaw.width ?? null
});

imageUrlRecords.push({
originalUrl: imageRaw.url,
newUrl: imageUrl
});
}

return images;
return {
imageUrlRecords: imageUrlRecords,
richTextImages: images
};
}

private resolveElementMap(
Expand Down
17 changes: 17 additions & 0 deletions lib/utilities/delivery-url.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as urlParse from 'url-parse';

export class DeliveryUrlHelper {
replaceAssetDomain(originalAssetUrl: string, customDomain: string): string {
const urlPath = this.getUrlPathname(originalAssetUrl);

return `${customDomain}${urlPath}`;
}

getUrlPathname(url: string): string {
const parsedUrl = urlParse(url);

return parsedUrl.pathname;
}
}

export const deliveryUrlHelper = new DeliveryUrlHelper();
1 change: 1 addition & 0 deletions lib/utilities/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './linked-items.helper';
export * from './guid.helper';
export * from './delivery-url.helper';
48 changes: 44 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,11 @@
},
"dependencies": {
"@kentico/kontent-core": "9.4.0",
"uuid": "8.3.2"
"uuid": "8.3.2",
"url-parse": "1.5.3"
},
"devDependencies": {
"@types/url-parse": "1.4.5",
"@types/jasmine": "3.10.2",
"@types/node": "16.11.12",
"@types/uuid": "8.3.3",
Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ Following is a list of configuration options for DeliveryClient (`IDeliveryClien
| globalHeaders? | (queryConfig: IQueryConfig) => IHeader[] | Adds ability to add extra headers to each http request |
| retryStrategy? | IRetryStrategyOptions | Retry strategy configuration |
| linkedItemsReferenceHandler? | LinkedItemsReferenceHandler | Indicates if content items are automatically mapped. Available values: 'map' or 'ignore' |
| propertyNameResolver? | PropertyNameResolver | Used to map properties. Choose one of following default resolvers: `snakeCasePropertyNameResolver`, `pascalCasePropertyNameResolver` & `camelCasePropertyNameResolver` or create your own PropertyNameResolver function |
| propertyNameResolver? | PropertyNameResolver | Used to map properties. Choose one of following default resolvers: `snakeCasePropertyNameResolver`, `pascalCasePropertyNameResolver` & `camelCasePropertyNameResolver` or create your own PropertyNameResolver function |
| assetsDomain? | string | Custom domain for assets. Changes url of assets in both asset & rich text elements |

### Create typed models

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"item": {
"system": {
"id": "335d17ac-b6ba-4c6a-ae31-23c1193215cb",
"collection": "default",
"name": "My article",
"codename": "my_article",
"language": "en-US",
"type": "article",
"sitemap_locations": [],
"last_modified": "2019-03-27T13:21:11.38Z",
"workflow_step": "published"
},
"elements": {
"property1": {
"type": "asset",
"name": "Teaser image",
"value": [
{
"name": "sources.jpg",
"type": "image/jpeg",
"size": 45376,
"description": "Description of what the asset represents.",
"url": "https://assets-us-01.kc-usercontent.com/975bf280-fd91-488c-994c-2f04416e5ee3/3e76909f-599f-4742-b472-77fd4b510e92/sources.jpg",
"width": 640,
"height": 457,
"renditions": {
"default": {
"rendition_id": "b447ca6c-8020-4e8f-be57-1d110721e535",
"preset_id": "a6d98cd5-8b2c-4e50-99c9-15192bce2490",
"width": 1280,
"height": 1024,
"query": "w=1280&h=1024&fit=clip&rect=2396,169,1280,1024"
}
}
}
]
},
"property2": {
"type": "asset",
"name": "Teaser image",
"value": [
{
"name": "sources.jpg",
"type": "image/jpeg",
"size": 45376,
"description": "Description of what the asset represents.",
"url": "https://assets-us-01.kc-usercontent.com/975bf280-fd91-488c-994c-2f04416e5ee3/3e76909f-599f-4742-b472-77fd4b510e92/sources.jpg",
"width": 640,
"height": 457,
"renditions": {
"default": {
"rendition_id": "b447ca6c-8020-4e8f-be57-1d110721e535",
"preset_id": "a6d98cd5-8b2c-4e50-99c9-15192bce2490",
"width": 1280,
"height": 1024,
"query": "w=1280&h=1024&fit=clip&rect=2396,169,1280,1024"
}
}
}
]
}
}
},
"modular_content": {}
}
Loading

0 comments on commit 2e5ae06

Please sign in to comment.