Skip to content

Commit

Permalink
Merge pull request #1239 from Accenture/feature/1238-get-name-and-key…
Browse files Browse the repository at this point in the history
…-for-content-block-id

Feature/1238: find contentblock by id
  • Loading branch information
JoernBerkefeld committed Mar 25, 2024
2 parents c2352b1 + 3ac6d8f commit 0f22fd8
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 1 deletion.
77 changes: 77 additions & 0 deletions docs/dist/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ helper for <a href="DataExtension.#fixShared_item">DataExtension.#fixShared_item
<dt><a href="#setupSDK">setupSDK(sessionKey, authObject)</a> ⇒ <code><a href="#SDK">SDK</a></code></dt>
<dd><p>Returns an SDK instance to be used for API calls</p>
</dd>
<dt><a href="#getActualJson">getActualJson(customerKey, type, subtype, [buName])</a> ⇒ <code>Promise.&lt;string&gt;</code></dt>
<dd><p>gets file from Retrieve folder</p>
</dd>
<dt><a href="#getActualFile">getActualFile(customerKey, type, subtype, ext)</a> ⇒ <code>string</code></dt>
<dd><p>gets file from Retrieve folder</p>
</dd>
</dl>

## Typedefs
Expand Down Expand Up @@ -533,6 +539,7 @@ main class
* [.findBUs(credentialsName)](#Mcdev.findBUs) ⇒ <code>Promise.&lt;void&gt;</code>
* [.document(businessUnit, type)](#Mcdev.document) ⇒ <code>Promise.&lt;void&gt;</code>
* [.deleteByKey(businessUnit, type, customerKey)](#Mcdev.deleteByKey) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.resolveId(businessUnit, type, id)](#Mcdev.resolveId) ⇒ <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code>
* [.refresh(businessUnit, type, [keyArr])](#Mcdev.refresh) ⇒ <code>Promise.&lt;void&gt;</code>
* [.badKeys(businessUnit)](#Mcdev.badKeys) ⇒ <code>Promise.&lt;void&gt;</code>
* [.retrieveAsTemplate(businessUnit, selectedType, name, market)](#Mcdev.retrieveAsTemplate) ⇒ <code>Promise.&lt;TYPE.MultiMetadataTypeList&gt;</code>
Expand Down Expand Up @@ -703,6 +710,20 @@ deletes metadata from MC instance by key
| type | <code>string</code> | supported metadata type |
| customerKey | <code>string</code> | Identifier of metadata |

<a name="Mcdev.resolveId"></a>

### Mcdev.resolveId(businessUnit, type, id) ⇒ <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code>
get name & key for provided id

**Kind**: static method of [<code>Mcdev</code>](#Mcdev)
**Returns**: <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code> - key, name and path of metadata; null if not found

| Param | Type | Description |
| --- | --- | --- |
| businessUnit | <code>string</code> | references credentials from properties.json |
| type | <code>string</code> | supported metadata type |
| id | <code>string</code> | Identifier of metadata |

<a name="Mcdev.refresh"></a>

### Mcdev.refresh(businessUnit, type, [keyArr]) ⇒ <code>Promise.&lt;void&gt;</code>
Expand Down Expand Up @@ -893,6 +914,7 @@ FileTransfer MetadataType
* [.getFilesToCommit(keyArr)](#Asset.getFilesToCommit) ⇒ <code>Array.&lt;string&gt;</code>
* [.deleteByKey(customerKey)](#Asset.deleteByKey) ⇒ <code>Promise.&lt;boolean&gt;</code>
* [.postDeleteTasks(customerKey)](#Asset.postDeleteTasks) ⇒ <code>void</code>
* [.resolveId(id)](#Asset.resolveId) ⇒ <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code>

<a name="Asset.retrieve"></a>

Expand Down Expand Up @@ -1292,6 +1314,18 @@ cannot use the generic method due to the complexity of how assets are saved to d
| --- | --- | --- |
| customerKey | <code>string</code> | Identifier of metadata item |

<a name="Asset.resolveId"></a>

### Asset.resolveId(id) ⇒ <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code>
get name & key for provided id

**Kind**: static method of [<code>Asset</code>](#Asset)
**Returns**: <code>Promise.&lt;{key:string, name:string, path:string}&gt;</code> - key, name and path of metadata; null if not found

| Param | Type | Description |
| --- | --- | --- |
| id | <code>string</code> | Identifier of metadata |

<a name="AttributeGroup"></a>

## AttributeGroup ⇐ [<code>MetadataType</code>](#MetadataType)
Expand Down Expand Up @@ -3457,6 +3491,7 @@ Provides default functionality that can be overwritten by child metadata type cl
* [.buildDefinition(templateDir, targetDir, templateName, variables)](#MetadataType.buildDefinition) ⇒ <code>Promise.&lt;TYPE.MetadataTypeMapObj&gt;</code>
* [.getErrorsREST(ex)](#MetadataType.getErrorsREST) ⇒ <code>Array.&lt;string&gt;</code> \| <code>void</code>
* [.document([metadata], [isDeploy])](#MetadataType.document) ⇒ <code>void</code>
* [.resolveId(id)](#MetadataType.resolveId) ⇒ <code>Promise.&lt;string&gt;</code>
* [.deleteByKey(customerKey)](#MetadataType.deleteByKey) ⇒ <code>boolean</code>
* [.postDeleteTasks(customerKey, [additionalExtensions])](#MetadataType.postDeleteTasks) ⇒ <code>Promise.&lt;void&gt;</code>
* [.deleteByKeySOAP(customerKey, [overrideKeyField], [handleOutside])](#MetadataType.deleteByKeySOAP) ⇒ <code>Promise.&lt;boolean&gt;</code>
Expand Down Expand Up @@ -4227,6 +4262,18 @@ Gets metadata cache with limited fields and does not store value to disk
| [metadata] | <code>TYPE.MetadataTypeMap</code> | a list of type definitions |
| [isDeploy] | <code>boolean</code> | used to skip non-supported message during deploy |

<a name="MetadataType.resolveId"></a>

### MetadataType.resolveId(id) ⇒ <code>Promise.&lt;string&gt;</code>
get name & key for provided id

**Kind**: static method of [<code>MetadataType</code>](#MetadataType)
**Returns**: <code>Promise.&lt;string&gt;</code> - key of metadata

| Param | Type | Description |
| --- | --- | --- |
| id | <code>string</code> | Identifier of metadata |

<a name="MetadataType.deleteByKey"></a>

### MetadataType.deleteByKey(customerKey) ⇒ <code>boolean</code>
Expand Down Expand Up @@ -8476,6 +8523,36 @@ Returns an SDK instance to be used for API calls
| sessionKey | <code>string</code> | key for specific BU |
| authObject | <code>TYPE.AuthObject</code> | credentials for specific BU |

<a name="getActualJson"></a>

## getActualJson(customerKey, type, subtype, [buName]) ⇒ <code>Promise.&lt;string&gt;</code>
gets file from Retrieve folder

**Kind**: global function
**Returns**: <code>Promise.&lt;string&gt;</code> - file in string form

| Param | Type | Default | Description |
| --- | --- | --- | --- |
| customerKey | <code>string</code> | | of metadata |
| type | <code>string</code> | | of metadata |
| subtype | <code>string</code> | | of metadata |
| [buName] | <code>string</code> | <code>&quot;testBU&quot;</code> | used when we need to test on ParentBU |

<a name="getActualFile"></a>

## getActualFile(customerKey, type, subtype, ext) ⇒ <code>string</code>
gets file from Retrieve folder

**Kind**: global function
**Returns**: <code>string</code> - file path

| Param | Type | Description |
| --- | --- | --- |
| customerKey | <code>string</code> | of metadata |
| type | <code>string</code> | of metadata |
| subtype | <code>string</code> | of metadata |
| ext | <code>string</code> | file extension |

<a name="TypeKeyCombo"></a>

## TypeKeyCombo : <code>Object.&lt;string, string&gt;</code>
Expand Down
32 changes: 31 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ yargs(hideBin(process.argv))
})
.positional('TYPE', {
type: 'string',
describe: 'metadata type to delete from; currently supported: dataExtension',
describe: 'metadata type to delete from;',
})
.positional('EXTERNALKEY', {
type: 'string',
Expand All @@ -208,6 +208,36 @@ yargs(hideBin(process.argv))
Mcdev.deleteByKey(argv.BU, argv.TYPE, argv.EXTERNALKEY);
},
})
.command({
command: 'resolveId <BU> <TYPE> <ID>',
aliases: ['rid'],
desc: 'resolves metadata key by ID',
builder: (yargs) => {
yargs
.positional('BU', {
type: 'string',
describe:
'the business unit to search in (in format "credential name/BU name")',
})
.positional('TYPE', {
type: 'string',
describe: 'metadata type to search in; currently supported: asset',
})
.positional('ID', {
type: 'string',
describe: 'the id to resolve',
})
.option('json', {
type: 'boolean',
group: 'Options for explainTypes:',
describe: 'optionaly return info in json format',
});
},
handler: (argv) => {
Mcdev.setOptions(argv);
Mcdev.resolveId(argv.BU, argv.TYPE, argv.ID);
},
})
.command({
command: 'retrieveAsTemplate <BU> <TYPE> <NAME> <MARKET>',
aliases: ['rt'],
Expand Down
43 changes: 43 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,49 @@ class Mcdev {
}
}
}
/**
* get name & key for provided id
*
* @param {string} businessUnit references credentials from properties.json
* @param {string} type supported metadata type
* @param {string} id Identifier of metadata
* @returns {Promise.<{key:string, name:string, path:string}>} key, name and path of metadata; null if not found
*/
static async resolveId(businessUnit, type, id) {
Util.startLogger();
if (!Util.OPTIONS.json) {
Util.logger.info('mcdev:: resolveId');
}
if (!Util._isValidType(type)) {
return;
}
const properties = await config.getProperties();
if (!(await config.checkProperties(properties))) {
return null;
}
const buObject = await Cli.getCredentialObject(properties, businessUnit);
if (buObject !== null) {
try {
MetadataTypeInfo[type].client = auth.getSDK(buObject);
} catch (ex) {
Util.logger.error(ex.message);
return;
}
if (!Util.OPTIONS.json) {
Util.logger.info(
Util.getGrayMsg(` - Searching ${type} with id ${id} on BU ${businessUnit}`)
);
}
try {
MetadataTypeInfo[type].properties = properties;
MetadataTypeInfo[type].buObject = buObject;
return await MetadataTypeInfo[type].resolveId(id);
} catch (ex) {
Util.logger.errorStack(ex, ` - Could not resolve ID of ${type} ${id}`);
}
}
}

/**
* ensures triggered sends are restarted to ensure they pick up on changes of the underlying emails
*
Expand Down
64 changes: 64 additions & 0 deletions lib/metadataTypes/Asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -1689,6 +1689,70 @@ class Asset extends MetadataType {
await File.remove(filePath);
}
}
/**
* get name & key for provided id
*
* @param {string} id Identifier of metadata
* @returns {Promise.<{key:string, name:string, path:string}>} key, name and path of metadata; null if not found
*/
static async resolveId(id) {
let response;
try {
response = await this.client.rest.get('asset/v1/content/assets/' + id);
} catch (ex) {
if (ex.response?.status !== 404) {
throw ex;
}
}
if (response?.id) {
const item = response;
const subType = this._getMainSubtype(item.assetType.name);
// find path for code of content block, fall back to json if not found; undefined if not even the json exists
const pathBase1 = `./retrieve/${this.buObject.credential}/${this.buObject.businessUnit}/${this.definition.type}/${subType}/${item[this.definition.keyField]}.${this.definition.type}-${subType}-meta.`;
const pathBase2 = `./retrieve/${this.buObject.credential}/${this.buObject.businessUnit}/${this.definition.type}/${subType}/${item[this.definition.keyField]}/${item[this.definition.keyField]}.${this.definition.type}-${subType}-meta.`;
const paths = [];
for (const ext of ['html', 'ssjs', 'amp', 'json']) {
paths.push(pathBase1 + ext, pathBase2 + ext);
}
const path = paths.find((p) => File.pathExistsSync(p));

// prep response object
const json = {
key: item[this.definition.keyField],
name: item[this.definition.nameField],
mid: item.memberId,
};
if (path) {
json.path = path;
} else {
json.error = 'file not found on local disk';
}
if (Util.OPTIONS.json) {
// for automated processing by VSCode extension, optionally print the json
console.log(JSON.stringify(json, null, 2)); // eslint-disable-line no-console
} else {
Util.logger.info(
` - ${this.definition.type}-${subType} found: ${item[this.definition.keyField]} (${item[this.definition.nameField]})`
);
Util.logger.info(
' - link: ' +
(path ||
`404. Try running mcdev r ${this.buObject.credential}/${this.buObject.businessUnit} ${this.definition.type}-${subType} ${item[this.definition.keyField]}`)
);
}
return json;
} else {
const json = {
error: 'id not found',
};
if (Util.OPTIONS.json) {
console.log(JSON.stringify(json, null, 2)); // eslint-disable-line no-console
return json;
}
Util.logger.error(` - ${this.definition.type} with id ${id} not found on BU`);
return json;
}
}
}

// Assign definition to static attributes
Expand Down
11 changes: 11 additions & 0 deletions lib/metadataTypes/MetadataType.js
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,17 @@ class MetadataType {
}
}

/**
* get name & key for provided id
*
* @param {string} id Identifier of metadata
* @returns {Promise.<string>} key of metadata
*/
static resolveId(id) {
Util.logger.error(`resolveId type ${this.definition.type} is not supported.`);
return false;
}

/**
* Delete a metadata item from the specified business unit
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "error": "id not found" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"key": "mcdev-issue-1157",
"mid": 9999999,
"name": "mcdev-issue-1157-Mcdev-strips-content",
"error": "file not found on local disk"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"key": "mcdev-issue-1157",
"mid": 9999999,
"name": "mcdev-issue-1157-Mcdev-strips-content",
"path": "./retrieve/testInstance/testBU/asset/block/mcdev-issue-1157.asset-block-meta.html"
}
61 changes: 61 additions & 0 deletions test/type.asset.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,65 @@ describe('type: asset', () => {
return;
});
});

describe('ResolveID ================', () => {
it('Should resolve the id of the item but NOT find the asset locally', async () => {
// WHEN
const resolveIdJson = await handler.resolveId(
'testInstance/testBU',
'asset',
'1295064'
);
// THEN
assert.equal(process.exitCode, 0, 'resolveId should not have thrown an error');
assert.deepEqual(
resolveIdJson,
await testUtils.getExpectedJson('9999999', 'asset', 'resolveId-1295064-noPath'),
'returned response was not equal expected'
);
return;
});

it('Should resolve the id with --json option enabled', async () => {
handler.setOptions({ json: true });
// WHEN
await handler.resolveId('testInstance/testBU', 'asset', '1295064');
// THEN
assert.equal(process.exitCode, 0, 'resolveId should not have thrown an error');
return;
});

it('Should resolve the id of the item AND find the asset locally', async () => {
// prep test by retrieving the file
await handler.retrieve('testInstance/testBU', ['asset-block'], ['mcdev-issue-1157']);
// WHEN
const resolveIdJson = await handler.resolveId(
'testInstance/testBU',
'asset',
'1295064'
);
// THEN
assert.equal(process.exitCode, 0, 'resolveId should not have thrown an error');
assert.deepEqual(
resolveIdJson,
await testUtils.getExpectedJson('9999999', 'asset', 'resolveId-1295064-withPath'),
'returned response was not equal expected'
);
return;
});

it('Should NOT resolve the id of the item', async () => {
// WHEN
const resolveIdJson = await handler.resolveId('testInstance/testBU', 'asset', '-1234');
// THEN
assert.equal(process.exitCode, 404, 'resolveId should have thrown an error');
// IMPORTANT: this will throw a false "TEST-ERROR" but our testing framework currently needs to not find the file to throw a 404
assert.deepEqual(
resolveIdJson,
await testUtils.getExpectedJson('9999999', 'asset', 'resolveId-1234-notFound'),
'returned response was not equal expected'
);
return;
});
});
});

0 comments on commit 0f22fd8

Please sign in to comment.