@viewdo/dxp-story-cli
Version:
DXP Story Management CLI
330 lines • 19.4 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TemplateManager = void 0;
const ActionTemplateConfiguration_1 = require("./../models/configuration/ActionTemplateConfiguration");
const typedi_1 = require("typedi");
const ConfigurationManager_1 = require("./ConfigurationManager");
const TaskService_1 = require("../services/TaskService");
const FileService_1 = require("../services/FileService");
const EpisodeConfiguration_1 = require("../models/configuration/EpisodeConfiguration");
const StoryTemplateConfiguration_1 = require("../models/configuration/StoryTemplateConfiguration");
const ConfigurationFileService_1 = require("../services/ConfigurationFileService");
const ContentType_1 = require("../models/configuration/support/ContentType");
const path_1 = __importDefault(require("path"));
const promises_1 = __importDefault(require("fs/promises"));
const lodash_1 = __importDefault(require("lodash"));
const ConsoleService_1 = require("../services/ConsoleService");
const child_process_1 = require("child_process");
const ContentType_2 = require("../models/configuration/support/ContentType");
let TemplateManager = class TemplateManager {
constructor(file_service, configuration_manager, task_service, console_service) {
this.file_service = file_service;
this.configuration_manager = configuration_manager;
this.task_service = task_service;
this.console_service = console_service;
// Story Template Readers ----------------------------------------------
this.storyTemplatesDirectory = `./.dxp/templates/stories`;
this.actionTemplatesDirectory = `./.dxp/templates/actions`;
}
get templateKeys() {
return (this._templateKeys ||
this.file_service.listDirectories(this.storyTemplatesDirectory));
}
set templateKeys(keys) {
this._templateKeys = keys;
}
getActionTemplateDirectory(template_key) {
return `${this.actionTemplatesDirectory}/${template_key}`;
}
_actionTemplateConfigAccessor(template_key) {
return new ConfigurationFileService_1.ConfigurationFileService(`${this.getActionTemplateDirectory(template_key)}/${ActionTemplateConfiguration_1.ActionTemplateConfiguration.file_name}`, ActionTemplateConfiguration_1.ActionTemplateConfiguration);
}
hasActionTemplateConfig(template_key) {
return this._actionTemplateConfigAccessor(template_key).exists();
}
getActionTemplateConfig(template_key) {
return this._actionTemplateConfigAccessor(template_key).read({});
}
hasStoryTemplateConfig(template_key) {
return this._storyTemplateConfigAccessor(template_key).exists();
}
getStoryTemplateDirectory(story_key) {
return `./stories/${story_key}`;
}
getStoryTemplateConfig(template_key) {
return this._storyTemplateConfigAccessor(template_key).read({});
}
_storyTemplateConfigAccessor(template_key) {
return new ConfigurationFileService_1.ConfigurationFileService(`${this.getStoryTemplateDirectory(template_key)}/${StoryTemplateConfiguration_1.StoryTemplateConfiguration.file_name}`, StoryTemplateConfiguration_1.StoryTemplateConfiguration);
}
// SCAFFOLD API ----------------------------------------------
scaffoldStory(storyKey_1, organizationKey_1, templateKey_1) {
return __awaiter(this, arguments, void 0, function* (storyKey, organizationKey, templateKey, extra_args = undefined) {
let subTasks = [
{
title: "Scaffold Story",
task: () => __awaiter(this, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
const command = `npx`;
let args = ['--yes', `@archer-edu/create-story@latest`, `${storyKey}`, `--dxp_org_key`, `${organizationKey}`];
if (extra_args)
args = [...args, ...extra_args];
if (templateKey)
args.push(`--template`, `${templateKey}`);
console.log(`Running command ${command} ${args.join(' ')}`);
const child = (0, child_process_1.spawn)('bash', ['-c', `${command} ${args.join(' ')}`], { stdio: 'inherit' });
child.on('exit', (code) => {
if (code === 0)
resolve(true);
else
reject(`Shell command failed with exit code ${code}`);
});
child.on('error', (error) => {
reject(error);
});
});
})
},
{
title: "Configure Story Data",
task: () => {
let story_config = this.configuration_manager.getStoryConfig(storyKey);
story_config.key = storyKey;
story_config.organizationKey = organizationKey;
story_config.name = storyKey;
this.configuration_manager.setStoryAssetConfig(story_config);
}
},
{
title: "Configure Templated Data Points",
task: () => {
if (this.hasStoryTemplateConfig(storyKey)) {
const templateConfig = this.getStoryTemplateConfig(storyKey);
if (templateConfig && templateConfig.organization_configuration) {
const org_config = this.configuration_manager.getOrganizationConfig(organizationKey);
let templateData = templateConfig.organization_configuration.dataPoints;
let orgData = org_config.dataPoints;
templateData.forEach((dataPoint) => {
if (!lodash_1.default.find(orgData, (d) => d.key == dataPoint.key)) {
orgData.push(dataPoint);
}
});
this.configuration_manager.setOrganizationConfig(org_config);
}
}
}
},
{
title: "Cleanup",
task: () => __awaiter(this, void 0, void 0, function* () {
if (this.hasStoryTemplateConfig(storyKey)) {
const templateConfigPath = `${this.getStoryTemplateDirectory(storyKey)}/${StoryTemplateConfiguration_1.StoryTemplateConfiguration.file_name}`;
try {
yield promises_1.default.access(templateConfigPath);
//file exists, remove it
yield promises_1.default.unlink(templateConfigPath);
}
catch (err) {
this.console_service.error(`Error removing file ${templateConfigPath}`);
}
}
})
}
];
yield this.task_service.runTasks(subTasks);
});
}
scaffoldEpisode(story_key, episode_key, template_key) {
const story_config = this.configuration_manager.getStoryConfig(story_key);
const episode = new EpisodeConfiguration_1.EpisodeConfiguration({
key: episode_key,
name: episode_key,
isEnabled: true,
});
story_config.episodes.push(episode);
this.configuration_manager.saveStoryConfig(story_config);
const index = story_config.episodes.length - 1;
this._scaffoldEpisodeAsset(story_config, index, "html_file", "");
this._scaffoldEpisodeAsset(story_config, index, "json_file", "{}");
this._scaffoldEpisodeAsset(story_config, index, "js_file", "");
this._scaffoldEpisodeAsset(story_config, index, "css_file", "");
}
_scaffoldEpisodeAsset(story_config, episode_index, asset_type, default_content) {
const assets = story_config.getAssets();
const assetConfig = this.configuration_manager.getStoryAssetConfig(story_config.key);
const defaultAsset = assets.find((asset) => asset.key == asset_type);
const assetPath = assetConfig.getLocalPath(defaultAsset);
const assetExists = this.file_service.exists(assetPath);
const defaultContent = assetExists
? defaultAsset.convertFromLocal(this.file_service.read(assetPath))
: default_content;
const assetKey = story_config._getEpisodeAssetKey(episode_index, asset_type);
const episodeAsset = assets.find((asset) => asset.key == assetKey);
this.file_service.write(episodeAsset.local_path, episodeAsset.convertFromRemote(defaultContent));
if (defaultAsset.source_path) {
const sourceExists = this.file_service.exists(defaultAsset.local_path);
const assetSource = sourceExists
? this.file_service.read(defaultAsset.source_path)
: default_content;
this.file_service.write(episodeAsset.source_path, assetSource);
}
}
scaffoldState(story_key, state_key, state_type) {
// 1. Need to define all scene types. List as array?
// 2. Need to validate the stateType selected against what is avaialable
// * Loop through current states and validate that the new key is unique
//
// Based on which state type we selected, grab the designated template (i.e. video, toc, html, cta, navigation)
// * stamp it out in as a new state
// 3. Need to push new state data into the designated episoded 'default-data.yml'
// * Something like story_config.episodes.push(episode)
// * Although, the story_config doesn't need to be updated. Just the data for the episode
}
scaffoldScene(story_key, episode_key, template_key, scene_key, scene_id) {
const story_config = this.configuration_manager.getStoryConfig(story_key);
const template_config = this.getStoryTemplateConfig(template_key);
const assets = story_config.getAssets();
const assetConfig = this.configuration_manager.getStoryAssetConfig(story_config.key);
// 1. Need to push new scene data into the designated episode' scenes list ('default-data.yml')
// * Although, the story_config doesn't need to be updated. Just the data for the episode
let episodeIndex = story_config.episodes.findIndex(p => p.key == episode_key);
let assetKey = episodeIndex > 0
? story_config._getEpisodeAssetKey(episodeIndex, "json_file")
: "json_file";
const assetDef = story_config.getAssetDefinition(assetKey);
const assetPath = assetConfig.getLocalPath(assetDef);
if (!this.file_service.exists(assetPath))
throw new Error("The story data file does not exist: " + assetPath);
const scene = template_config.scene_templates.find((s) => s.key == scene_key);
scene.id = scene_id;
delete scene.key;
const storyDataText = assetDef.convertFromLocal(this.file_service.read(assetPath));
const storyData = JSON.parse(storyDataText);
if (storyData.states.find((s) => s.id == scene_id) != null)
throw new Error(`The sceneId ${scene_id} already exists.`);
storyData.states.push(scene);
// 2. Unpack the story-data afterwards to build out the scene folder w/any embedded HTML
this.file_service.write(assetPath, assetDef.convertFromRemote(JSON.stringify(storyData)));
// 3. Copy over assets from parent template to story's asset folder,
// but without overwriting existing files.
this.file_service.syncDirectories(template_config.templateAssetDirectory, story_config.assets_directory, false);
}
scaffoldTemplate(story_key, template_key, template_type) {
// let fake_story = this._getFakeStory(story_key, organization_key)
// let story_config = this.configuration_manager.setStoryConfig(fake_story)
// this.configuration_manager.setStoryAssetConfig(story_config)
}
addActionTemplates(story_config, action) {
// no need to manage templates for actions that don't use them
if (!this.hasActionTemplateConfig(action.actionType))
return;
let template_config = this.getActionTemplateConfig(action.actionType);
Object.keys(action.parameters).forEach((param_key) => {
let template = template_config.parameter_templates[param_key];
let param_value = action.parameters[param_key];
if (template != undefined) {
let content = template.content;
if (content.startsWith("./")) {
let content_path = path_1.default.join(template_config.getTemplateDirectory(), content);
content = this.file_service.read(content_path) || "";
}
let assetDef = null;
switch (template.type) {
case "Email": {
// Check if the template already exists in the array
const exists = story_config.emailTemplates.some((existingTemplate) => existingTemplate.key === param_value);
if (!exists) {
const fileType = ContentType_2.contentTypeToExtension[ContentType_1.ContentType.LIQUID];
const parsedData = this.file_service.parseKeyToPathAndFile(param_value.toString());
story_config.emailTemplates.push({
key: param_value.toString(),
name: story_config.getTemplateName(param_value.toString()),
file: `${parsedData.file}${fileType}`,
path: parsedData.path,
type: ContentType_1.ContentType.LIQUID
});
assetDef = story_config.getAssetDefinition(`email_templates.${param_value.toString()}`);
}
break;
}
default: {
const exists = story_config.textTemplates.some((existingTemplate) => existingTemplate.key === param_value);
if (!exists) {
const fileType = ContentType_2.contentTypeToExtension[template.type];
const parsedData = this.file_service.parseKeyToPathAndFile(param_value.toString());
story_config.textTemplates.push({
key: param_value.toString(),
name: story_config.getTemplateName(param_value.toString()),
file: `${parsedData.file}${fileType}`,
path: parsedData.path,
type: template.type
});
assetDef = story_config.getAssetDefinition(`text_templates.${param_value.toString()}`);
}
break;
}
}
if (assetDef) {
try {
var compiled = lodash_1.default.template(content);
content = compiled({
story: story_config,
action,
});
this.file_service.write(assetDef.local_path, content);
}
catch (error) {
this.file_service.write(assetDef.local_path, content);
}
if (template.supportFiles) {
template.supportFiles.forEach((s) => {
let templatePath = path_1.default.join(template_config.getTemplateDirectory(), s);
let supportContent = this.file_service.read(templatePath) || "";
let destinationPath = path_1.default.join(assetDef.local_path.replace(path_1.default.basename(assetDef.local_path), ""), s);
try {
let supportContentCompiled = lodash_1.default.template(supportContent);
supportContent = supportContentCompiled({
story: story_config,
action,
});
}
catch (error) { }
this.file_service.write(destinationPath, supportContent);
});
}
}
}
});
//this.file_service.syncDirectories(template_config.getTemplateSyncDirectory(), story_config.local_root, false);
}
};
exports.TemplateManager = TemplateManager;
exports.TemplateManager = TemplateManager = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [FileService_1.FileService,
ConfigurationManager_1.ConfigurationManager,
TaskService_1.TaskService,
ConsoleService_1.ConsoleService])
], TemplateManager);
//# sourceMappingURL=TemplateManager.js.map