@paperbits/common
Version:
Paperbits common components.
295 lines (224 loc) • 11.5 kB
text/typescript
import * as Utils from "../utils";
import * as Constants from "../constants";
import * as Objects from "../objects";
import { PopupContract } from "../popups/popupContract";
import { IPopupService } from "../popups/IPopupService";
import { IObjectStorage, Query, Page } from "../persistence";
import { Contract } from "../contract";
import { ILocaleService } from "../localization";
import { PopupMetadata } from "./popupMetadata";
import { PopupLocalizedContract } from "./popupLocalizedContract";
import { IBlockService } from "../blocks";
import { Logger } from "../logging";
const popupsPath = "popups";
const documentsPath = "files";
const defaultTemplateBlockKey = "blocks/new-popup-template";
export class PopupService implements IPopupService {
constructor(
private readonly objectStorage: IObjectStorage,
private readonly localeService: ILocaleService,
private readonly blockService: IBlockService,
private readonly logger: Logger
) { }
public async getPopupByKey(key: string, requestedLocale?: string): Promise<PopupContract> {
if (!key) {
throw new Error(`Parameter "key" not specified.`);
}
const popupContract = await this.objectStorage.getObject<PopupLocalizedContract>(key);
if (!popupContract) {
return null;
}
const defaultLocale = await this.localeService.getDefaultLocaleCode();
const currentLocale = await this.localeService.getCurrentLocaleCode();
return this.localizedContractToContract(defaultLocale, currentLocale, requestedLocale, popupContract);
}
/**
* Copies limited number of metadata properties.
*/
private copyMetadata(sourceMetadata: PopupMetadata, targetMetadata: PopupMetadata): PopupMetadata {
if (!sourceMetadata) {
throw new Error(`Parameter "sourceMetadata" not specified.`);
}
if (!targetMetadata) {
throw new Error(`Parameter "targetMetadata" not specified.`);
}
targetMetadata.title = sourceMetadata.title;
targetMetadata.description = sourceMetadata.description;
return targetMetadata;
}
private localizedContractToContract(defaultLocale: string, currentLocale: string, requestedLocale: string, localizedPopupContract: PopupLocalizedContract): PopupContract {
const locales = localizedPopupContract[Constants.localePrefix];
const popupMetadata = (requestedLocale
? locales[requestedLocale]
: locales[currentLocale])
|| this.copyMetadata(locales[defaultLocale], {});
if (!popupMetadata) {
return null;
}
const popupContract: any = {
key: localizedPopupContract.key,
...popupMetadata
};
return popupContract;
}
private convertPopup(localizedPopup: Page<PopupLocalizedContract>, defaultLocale: string, searchLocale: string, requestedLocale: string): Page<PopupContract> {
const resultPopup: Page<PopupContract> = {
value: localizedPopup.value.map(x => this.localizedContractToContract(defaultLocale, searchLocale, requestedLocale, x)),
takeNext: async (): Promise<Page<PopupContract>> => {
const nextLocalizedPopup = await localizedPopup.takeNext();
return this.convertPopup(nextLocalizedPopup, defaultLocale, searchLocale, requestedLocale);
}
};
if (!localizedPopup.takeNext) {
resultPopup.takeNext = null;
}
return resultPopup;
}
public async search(query: Query<PopupContract>, requestedLocale?: string): Promise<Page<PopupContract>> {
if (!query) {
throw new Error(`Parameter "query" not specified.`);
}
const defaultLocale = await this.localeService.getDefaultLocaleCode();
const currentLocale = await this.localeService.getCurrentLocaleCode();
const searchLocale = requestedLocale || currentLocale;
const localizedQuery = Utils.localizeQuery(query, searchLocale);
try {
const popupOfResults = await this.objectStorage.searchObjects<PopupLocalizedContract>(popupsPath, localizedQuery);
return this.convertPopup(popupOfResults, defaultLocale, searchLocale, requestedLocale);
}
catch (error) {
throw new Error(`Unable to search popups: ${error.stack || error.message}`);
}
}
public async deletePopup(popup: PopupContract): Promise<void> {
const deletePopupPromise = this.objectStorage.deleteObject(popup.key);
await Promise.all([deletePopupPromise]);
}
public async createPopup(title: string, description: string = null, templateBlockKey: string = defaultTemplateBlockKey): Promise<PopupContract> {
const locale = await this.localeService.getDefaultLocaleCode();
const identifier = Utils.guid();
const popupKey = `${popupsPath}/${identifier}`;
const contentKey = `${documentsPath}/${identifier}`;
const localizedPopup: PopupLocalizedContract = {
key: popupKey,
locales: {
[locale]: {
title: title,
description: description,
contentKey: contentKey
}
}
};
await this.objectStorage.addObject<PopupLocalizedContract>(popupKey, localizedPopup);
const template = await this.blockService.getBlockContent(templateBlockKey);
template["key"] = contentKey; // rewriting own key
await this.objectStorage.addObject<Contract>(contentKey, template);
const popupContract: PopupContract = {
key: popupKey,
title: title,
description: description,
contentKey: contentKey
};
return popupContract;
}
public async copyPopup(key: string): Promise<PopupContract> {
const originalPopup = await this.objectStorage.getObject<PopupLocalizedContract>(key);
const identifier = Utils.guid();
const targetKey = `${popupsPath}/${identifier}`;
const targetPage: PopupLocalizedContract = {
key: targetKey,
locales: {}
};
const sourceLocales = Object.keys(originalPopup.locales);
for (const locale of sourceLocales) {
const sourceMetadata = originalPopup.locales[locale];
const sourceContentKey = sourceMetadata.contentKey;
const sourcePageContent = await this.objectStorage.getObject<Contract>(sourceContentKey);
const targetIdentifier = Utils.guid();
const targetContentKey = `${documentsPath}/${targetIdentifier}`;
const targetMetadata: PopupMetadata = {
title: sourceMetadata.title + " (copy)",
description: sourceMetadata.description,
contentKey: targetContentKey
};
targetPage.locales[locale] = targetMetadata;
const targetPageContent = Objects.clone<Contract>(sourcePageContent);
targetPageContent["key"] = targetContentKey;
await this.objectStorage.addObject<Contract>(targetContentKey, targetPageContent);
this.logger.trackEvent("PopupCopied", { key: targetKey, sourcePageKey: key });
}
await this.objectStorage.addObject<PopupLocalizedContract>(targetKey, targetPage);
return this.getPopupByKey(targetKey);
}
public async updatePopup(popup: PopupContract, requestedLocale?: string): Promise<void> {
if (!popup) {
throw new Error(`Parameter "popup" not specified.`);
}
if (!requestedLocale) {
requestedLocale = await this.localeService.getCurrentLocaleCode();
}
const popupContract = await this.objectStorage.getObject<PopupLocalizedContract>(popup.key);
if (!popupContract) {
throw new Error(`Could not update popup. Popup with key "${popup.key}" doesn't exist.`);
}
const existingLocaleMetadata = popupContract.locales[requestedLocale] || <PopupMetadata>{};
popupContract.locales[requestedLocale] = this.copyMetadata(popup, existingLocaleMetadata);
await this.objectStorage.updateObject<PopupLocalizedContract>(popup.key, popupContract);
}
public async getPopupContent(popupKey: string, requestedLocale?: string): Promise<Contract> {
if (!popupKey) {
throw new Error(`Parameter "popupKey" not specified.`);
}
if (!requestedLocale) {
requestedLocale = await this.localeService.getCurrentLocaleCode();
}
const defaultLocale = await this.localeService.getDefaultLocaleCode();
const localizedPopupContract = await this.objectStorage.getObject<PopupLocalizedContract>(popupKey);
let popupMetadata = localizedPopupContract.locales[requestedLocale];
if (!popupMetadata) {
popupMetadata = localizedPopupContract.locales[defaultLocale];
}
let popupContent;
if (popupMetadata.contentKey) {
popupContent = await this.objectStorage.getObject<Contract>(popupMetadata.contentKey);
}
else {
const popupDefaultLocaleMetadata = localizedPopupContract.locales[defaultLocale];
popupContent = await this.objectStorage.getObject<Contract>(popupDefaultLocaleMetadata.contentKey);
}
return popupContent;
}
public async updatePopupContent(popupKey: string, content: Contract, requestedLocale?: string): Promise<void> {
if (!popupKey) {
throw new Error(`Parameter "popupKey" not specified.`);
}
if (!content) {
throw new Error(`Parameter "content" not specified.`);
}
const localizedPopupContract = await this.objectStorage.getObject<PopupLocalizedContract>(popupKey);
if (!localizedPopupContract) {
throw new Error(`Popup with key "${popupKey}" not found.`);
}
if (!requestedLocale) {
requestedLocale = await this.localeService.getCurrentLocaleCode();
}
let popupMetadata = localizedPopupContract.locales[requestedLocale];
if (!popupMetadata) {
const defaultLocale = await this.localeService.getDefaultLocaleCode();
const defaultPopupMetadata = localizedPopupContract.locales[defaultLocale];
const identifier = Utils.guid();
popupMetadata = this.copyMetadata(defaultPopupMetadata, {
contentKey: `${documentsPath}/${identifier}`
});
localizedPopupContract.locales[requestedLocale] = popupMetadata;
await this.objectStorage.updateObject(popupKey, localizedPopupContract);
}
else if (!popupMetadata.contentKey) {
const identifier = Utils.guid();
popupMetadata.contentKey = `${documentsPath}/${identifier}`;
await this.objectStorage.updateObject(popupKey, popupMetadata);
}
content["key"] = popupMetadata.contentKey;
await this.objectStorage.updateObject(popupMetadata.contentKey, content);
}
}