Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/1314 resolve email templates #1315

Merged
merged 4 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions lib/metadataTypes/Asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ class Asset extends MetadataType {
*/
static async retrieve(retrieveDir, _, subTypeArr, key) {
const items = [];
if (subTypeArr) {
// check if elements in subTypeArr exist in this.definition.subTypes
const invalidSubTypes = subTypeArr.filter(
(subType) => !this.definition.subTypes.includes(subType)
);
if (invalidSubTypes.length) {
throw new Error(`Invalid subType(s) found: ${invalidSubTypes.join(', ')}`);
}
}
subTypeArr ||= this._getSubTypes();
if (retrieveDir) {
await File.initPrettier();
Expand All @@ -62,6 +71,44 @@ class Asset extends MetadataType {
}
return { metadata: metadata, type: this.definition.type };
}
/**
* Helper for writing Metadata to disk, used for Retrieve and deploy
*
* @param {MetadataTypeMap} results metadata results from deploy
* @param {string} retrieveDir directory where metadata should be stored after deploy/retrieve
* @param {string} [overrideType] for use when there is a subtype (such as folder-queries)
* @param {TemplateMap} [templateVariables] variables to be replaced in the metadata
* @returns {Promise.<MetadataTypeMap>} Promise of saved metadata
*/
static async saveResults(results, retrieveDir, overrideType, templateVariables) {
if (Object.keys(results).length) {
// only execute the following if records were found
await this._postRetrieveTasksBulk(results);
}
return super.saveResults(results, retrieveDir, overrideType, templateVariables);
}
/**
* helper for Journey's {@link Asset.saveResults}. Gets executed after retreive of metadata type and
*
* @param {MetadataTypeMap} metadataMap key=customer key, value=metadata
*/
static async _postRetrieveTasksBulk(metadataMap) {
// Template-Based Email
let needTemplates = false;
for (const key in metadataMap) {
if (metadataMap[key].assetType.name == 'templatebasedemail') {
needTemplates = true;
break;
}
}

if (needTemplates && !cache.getCache()?.asset) {
// for
Util.logger.info(' - Caching dependent Metadata: asset-template');
const result = await this.retrieveForCache(undefined, ['template']);
cache.setMetadata('asset', result.metadata);
}
}

/**
* Retrieves asset metadata for caching
Expand Down Expand Up @@ -514,6 +561,34 @@ class Asset extends MetadataType {
static postRetrieveTasks(metadata) {
// folder
this.setFolderPath(metadata);

// template-based emails
if (metadata.assetType.name === 'templatebasedemail') {
// get template
try {
if (metadata.views?.html?.template?.id) {
metadata.views.html.template.r__assetTemplate_Key = cache.searchForField(
'asset',
metadata.views?.html?.template?.id,
'id',
'customerKey'
);
delete metadata.views.html.template.id;
delete metadata.views.html.template.name;
delete metadata.views.html.template.assetType;
delete metadata.views.html.template.availableViews;
delete metadata.views.html.template.data;
delete metadata.views.html.template.modelVersion;
}
} catch {
Util.logger.warn(
` - ${this.definition.type} '${metadata[this.definition.nameField]}' (${
metadata[this.definition.keyField]
}): Could not find email template with id (${metadata.views.html.template.id})`
);
}
}

// extract HTML for selected subtypes and convert payload for easier processing in MetadataType.saveResults()
return this._extractCode(metadata);
}
Expand Down Expand Up @@ -606,6 +681,39 @@ class Asset extends MetadataType {
// folder
this.setFolderId(metadata);

// template-based emails
if (
metadata.assetType.name === 'templatebasedemail' &&
metadata.views?.html?.template?.r__assetTemplate_Key
) {
// template
metadata.views.html.template.id = cache.searchForField(
'asset',
metadata.views.html.template.r__assetTemplate_Key,
'customerKey',
'id'
);
metadata.views.html.template.name = cache.searchForField(
'asset',
metadata.views.html.template.r__assetTemplate_Key,
'customerKey',
'name'
);
metadata.views.html.template.assetType = {
id: 4,
name: 'template',
displayName: 'Template',
};

metadata.views.html.template.data = {
email: { options: {} },
};

metadata.views.html.template.availableViews = [];
metadata.views.html.template.modelVersion = 2;
delete metadata.views.html.template.r__assetTemplate_Key;
}

// restore asset type id which is needed for deploy
metadata.assetType.id = this.definition.typeMapping[metadata.assetType.name];

Expand Down
56 changes: 55 additions & 1 deletion test/resourceFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ export const handleRESTRequest = async (config) => {
config.baseURL + (config.url.startsWith('/') ? config.url.slice(1) : config.url)
);
let filterName;
let filterBody;
if (urlObj.searchParams.get('$filter')) {
filterName = urlObj.searchParams.get('$filter').split(' eq ')[1];
}
Expand All @@ -256,6 +257,18 @@ export const handleRESTRequest = async (config) => {
'-' +
urlObj.searchParams.get('$filter').replaceAll(' eq ', '=').replaceAll(' ', '')
: null;

if (!testPathFilter && config.method === 'post' && config.data) {
const simpleOperators = { equal: '=', in: 'IN' };
const data = JSON.parse(config.data);
const myObj = data.query?.rightOperand || data.query;
if (myObj) {
const op = simpleOperators[myObj.simpleOperator];
filterBody = `${myObj.property}${op}${op === 'IN' ? myObj.value.join(',') : myObj.value}`;
}
}
const testPathFilterBody = filterBody ? testPath + '-' + filterBody : null;

if (testPathFilter && (await fs.pathExists(testPathFilter + '.json'))) {
// build filter logic to ensure templating works
if (filterName) {
Expand All @@ -282,6 +295,20 @@ export const handleRESTRequest = async (config) => {
encoding: 'utf8',
}),
];
} else if (testPathFilterBody && (await fs.pathExists(testPathFilterBody + '.json'))) {
return [
200,
await fs.readFile(testPathFilterBody + '.json', {
encoding: 'utf8',
}),
];
} else if (testPathFilterBody && (await fs.pathExists(testPathFilterBody + '.txt'))) {
return [
200,
await fs.readFile(testPathFilterBody + '.txt', {
encoding: 'utf8',
}),
];
} else if (await fs.pathExists(testPath + '.json')) {
if (testPathFilter) {
/* eslint-disable no-console */
Expand All @@ -297,6 +324,20 @@ export const handleRESTRequest = async (config) => {
/* eslint-enable no-console */
}

if (testPathFilterBody) {
/* eslint-disable no-console */
console.log(
`${color.bgYellow}${color.fgBlack}TEST-WARNING${
color.reset
}: You are loading your reponse from ${
testPath + '.json'
} instead of the more specific ${
testPathFilterBody + '.json'
}. Make sure this is intended`
);
/* eslint-enable no-console */
}

// build filter logic to ensure templating works
if (filterName) {
const response = JSON.parse(
Expand Down Expand Up @@ -329,6 +370,19 @@ export const handleRESTRequest = async (config) => {
);
/* eslint-enable no-console */
}
if (testPathFilterBody) {
/* eslint-disable no-console */
console.log(
`${color.bgYellow}${color.fgBlack}TEST-WARNING${
color.reset
}: You are loading your reponse from ${
testPath + '.txt'
} instead of the more specific ${
testPathFilterBody + '.txt'
}. Make sure this is intended`
);
/* eslint-enable no-console */
}

return [
200,
Expand All @@ -339,7 +393,7 @@ export const handleRESTRequest = async (config) => {
} else {
/* eslint-disable no-console */
console.log(
`${color.bgRed}${color.fgBlack}TEST-ERROR${color.reset}: Please create file ${testPath}.json/.txt${filterName ? ` or ${testPathFilter}.json/.txt` : ''}`
`${color.bgRed}${color.fgBlack}TEST-ERROR${color.reset}: Please create file ${testPath}.json/.txt${filterName ? ` or ${testPathFilter}.json/.txt` : testPathFilterBody ? ` or ${testPathFilterBody}.json/.txt` : ''}`
);
/* eslint-enable no-console */
process.exitCode = 404;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"customerKey": "testExisting_asset_templatebasedemail",
"contentType": "application/vnd.etmc.email.Message; kind=template",
"assetType": { "name": "templatebasedemail", "displayName": "Template-Based Email" },
"name": " testExisting_asset_templatebasedemail",
"owner": { "email": "joern.berkefeld@accenture.com", "name": "Jörn Berkefeld" },
"createdDate": "2024-04-22T06:36:03.117-06:00",
"createdBy": { "email": "joern.berkefeld@accenture.com", "name": "Jörn Berkefeld" },
"modifiedDate": "2024-05-13T07:15:29.77-06:00",
"modifiedBy": { "name": "IDE - joern.berkefeld app user" },
"memberId": 9999999,
"status": { "name": "Draft" },
"views": {
"subjectline": {
"contentType": "application/vnd.etmc.email.View; kind=subjectline",
"thumbnail": {},
"content": "my subject line",
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"preheader": {
"contentType": "application/vnd.etmc.email.View; kind=preheader",
"thumbnail": {},
"content": "my custom preheader text",
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"text": {
"thumbnail": {},
"availableViews": [],
"data": { "email": { "options": { "generateFrom": "html" } } },
"generateFrom": "html",
"modelVersion": 2
},
"viewAsAWebPage": {
"thumbnail": {},
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"subscriptioncenter": {
"thumbnail": {},
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"forwardHTML": {
"thumbnail": {},
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"forwardText": {
"thumbnail": {},
"availableViews": [],
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
},
"html": {
"thumbnail": {},
"availableViews": [],
"template": {
"meta": { "contentHash": -166410261 },
"r__assetTemplate_Key": "testExisting_asset_template"
},
"data": { "email": { "options": { "generateFrom": null } } },
"modelVersion": 2
}
},
"availableViews": [
"subjectline",
"preheader",
"text",
"viewAsAWebPage",
"subscriptioncenter",
"forwardHTML",
"forwardText",
"html"
],
"data": { "email": { "options": { "characterEncoding": "utf-8" } } },
"modelVersion": 2,
"r__folder_Path": "Content Builder"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"id": 5286,
"customerKey": "testExisting_asset_template",
"objectID": "50855339-3f87-47a7-8677-a8c63eb36a43",
"assetType": {
"id": 4,
"name": "template",
"displayName": "Template"
},
"fileProperties": {
"fileName": " testExisting_asset_template"
},
"name": " testExisting_asset_template",
"owner": {
"id": 710411605,
"email": "joern.berkefeld@accenture.com",
"name": "Jörn Berkefeld",
"userId": "710411605"
},
"createdDate": "2024-04-22T03:33:08.253-06:00",
"createdBy": {
"id": 710411605,
"email": "joern.berkefeld@accenture.com",
"name": "Jörn Berkefeld",
"userId": "710411605"
},
"modifiedDate": "2024-05-13T07:12:13.117-06:00",
"modifiedBy": {
"id": 710420432,
"name": "joern.berkefeld app user",
"userId": "710420432"
},
"enterpriseId": 510004860,
"memberId": 510009653,
"status": {
"id": 1,
"name": "Draft"
},
"thumbnail": {
"thumbnailUrl": "/v1/assets/5286/thumbnail"
},
"category": {
"id": 89397
},
"content": "<a href=\"%%ftaf_url%%\"\n ><img\n src=\"https://www.exacttarget.com/members/newsletters/gfx/forwardafriendicon.gif\"\n border=\"0\" /></a\n><a href=\"%%profile_center_url%%\" alias=\"Update Profile\">Update Profile</a>\n<table cellpadding=\"2\" cellspacing=\"0\" width=\"600\" id=\"Table5\" border=\"0\">\n <tr>\n <td>\n <font face=\"verdana\" size=\"1\" color=\"#444444\"\n >This email was sent by: <b>%%Member_Busname%%</b><br />%%Member_Addr%%\n %%Member_City%%, %%Member_State%%, %%Member_PostalCode%%, %%Member_Country%%<br /><br\n /></font>\n </td>\n </tr>\n</table>\n<a href=\"%%subscription_center_url%%\" alias=\"Manage Subscriptions\">Manage Subscriptions</a\n><img src=\"https://www.exacttarget.com/images/Powered_By_1206.jpg\" border=\"0\" /><custom\n name=\"opencounter\"\n type=\"tracking\"\n/>\n",
"availableViews": [],
"modelVersion": 2
}
Loading
Loading