UNPKG

mcdev

Version:

Accenture Salesforce Marketing Cloud DevTools

307 lines (288 loc) 11.8 kB
'use strict'; import MetadataType from './MetadataType.js'; import { Util } from '../util/util.js'; import cache from '../util/cache.js'; /** * @typedef {import('../../types/mcdev.d.js').BuObject} BuObject * @typedef {import('../../types/mcdev.d.js').CodeExtract} CodeExtract * @typedef {import('../../types/mcdev.d.js').CodeExtractItem} CodeExtractItem * @typedef {import('../../types/mcdev.d.js').MetadataTypeItem} MetadataTypeItem * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemDiff} MetadataTypeItemDiff * @typedef {import('../../types/mcdev.d.js').MetadataTypeItemObj} MetadataTypeItemObj * @typedef {import('../../types/mcdev.d.js').MetadataTypeMap} MetadataTypeMap * @typedef {import('../../types/mcdev.d.js').MetadataTypeMapObj} MetadataTypeMapObj * @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams * @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap * @typedef {import('../../types/mcdev.d.js').DomainVerificationItem} DomainVerificationItem */ /** * DomainVerification MetadataType * * @augments MetadataType */ class DomainVerification extends MetadataType { /** * Retrieves Metadata ofDomainVerification. * Endpoint /automation/v1/dataextracts/ returns all items * * @param {string} retrieveDir Directory where retrieved metadata directory will be saved * @param {void | string[]} [_] unused parameter * @param {void | string[]} [__] unused parameter * @param {string} [key] customer key of single item to retrieve * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata */ static async retrieve(retrieveDir, _, __, key) { return super.retrieveREST(retrieveDir, '/messaging/v1/domainverification/', null, key); } /** * Retrieves Metadata of DomainVerification for caching * * @returns {Promise.<MetadataTypeMapObj>} Promise of metadata */ static async retrieveForCache() { return super.retrieveREST(null, '/messaging/v1/domainverification/'); } /** * Creates a single item * * @param {DomainVerificationItem} metadataItem a single item * @returns {Promise} Promise */ static create(metadataItem) { return metadataItem.domain === 'bulk' && (Array.isArray(metadataItem.addresses) || (metadataItem.deTable && metadataItem.deColumn)) ? this.createRESTBulk(metadataItem, '/messaging/v1/domainverification/') // bulk/insert : super.createREST(metadataItem, '/messaging/v1/domainverification/'); } /** * Creates a multiple metadata entries via REST * * @param {MetadataTypeItem} metadataEntry a single metadata Entry * @param {string} uri rest endpoint for POST * @returns {Promise.<object> | null} Promise of API response or null in case of an error */ static async createRESTBulk(metadataEntry, uri) { if (metadataEntry.deTable || metadataEntry.deColumn) { Util.logger.error( 'It seems the deTable/deColumn approach does not work. Supply emails via addresses-array instead' ); return; } const createResults = {}; for (const address of metadataEntry.addresses) { if (cache.getByKey(this.definition.type, address)) { Util.logger.warn(` - ${this.definition.type} ${address} already exists`); continue; } const item = { domain: address }; if (await this.createREST(item, uri)) { createResults[address] = true; } } if (Object.keys(createResults).length) { // trigger re-retrieve to get all fields await this.postDeployTasks(createResults); await this.saveResults( createResults, [ this.properties.directories.retrieve, this.buObject.credential, this.buObject.businessUnit, ].join('/'), null ); } Util.logger.info( `${this.definition.type} bulk load: ${Object.keys(createResults).length} of ${metadataEntry.addresses.length} created` ); if (Object.keys(createResults).length) { Util.logger.warn('Please ignore the next message about filtering 1 item'); return `bulk successfully added.`; } else { return null; } } /** * helper for {@link MetadataType.createREST} * * @param {DomainVerificationItem} metadataEntry a single metadata Entry * @param {object} apiResponse varies depending on the API call * @returns {Promise.<DomainVerificationItem>} apiResponse */ static async postCreateTasks(metadataEntry, apiResponse) { if (apiResponse && apiResponse === `${metadataEntry.domain} successfully added.`) { return metadataEntry; } else { throw new Error(apiResponse); } } /** * helper for {@link update} * * @param {DomainVerificationItem} metadataEntry a single metadata Entry * @param {object} apiResponse varies depending on the API call * @returns {Promise.<DomainVerificationItem>} apiResponse, potentially modified */ static async postUpdateTasks(metadataEntry, apiResponse) { if (apiResponse && apiResponse === `1 records successfully updated!`) { metadataEntry.domain = metadataEntry.emailAddress; return metadataEntry; } else { throw new Error(apiResponse); } } /** * Updates a single item; replaces super.updateREST because we need to send metadataItem as an array for some reason and also get an array back * * @param {DomainVerificationItem} metadataItem a single item * @returns {Promise.<DomainVerificationItem>} Promise */ static async update(metadataItem) { const uri = '/messaging/v1/domainverification/update'; this.removeNotUpdateableFields(metadataItem); try { // set to empty object in case API returned nothing to be able to update it in helper classes let response = (await this.client.rest.post(uri, [metadataItem])) || {}; this.getErrorsREST(response); response = await this.postUpdateTasks(metadataItem, response); // some times, e.g. automation dont return a key in their update response and hence we need to fall back to name Util.logger.info(` - updated ${Util.getTypeKeyName(this.definition, metadataItem)}`); return metadataItem; } catch (ex) { const parsedErrors = this.getErrorsREST(ex); Util.logger.error( ` ☇ error updating ${Util.getTypeKeyName(this.definition, metadataItem)}:` ); for (const msg of parsedErrors) { Util.logger.error(' • ' + msg); } return null; } } /** * manages post retrieve steps * * @param {DomainVerificationItem} metadataItem a single item * @returns {DomainVerificationItem|void} metadata */ static postRetrieveTasks(metadataItem) { if (typeof metadataItem === 'string' && metadataItem === 'bulk successfully added.') { // this is a hack for bulk-creation only return; } if (metadataItem.status !== 'Verified') { Util.logger.warn( Util.getMsgPrefix(this.definition, metadataItem) + ` is not verified. Current status: ${metadataItem.status}` ); } if (!metadataItem.isSendable) { Util.logger.warn( Util.getMsgPrefix(this.definition, metadataItem) + ` is not sendable.` ); } return metadataItem; } /** * Gets executed after deployment of metadata type * * @param {MetadataTypeMap} upsertResults metadata mapped by their keyField as returned by update/create * @returns {Promise.<void>} - */ static async postDeployTasks(upsertResults) { // re-retrieve all upserted items to ensure we have all fields (createdDate and modifiedDate are otherwise not present) if (!Object.keys(upsertResults).length) { return; } Util.logger.debug( `Caching all ${this.definition.type} post-deploy to ensure we have all fields` ); const typeCache = await this.retrieveForCache(); // update values in upsertResults with retrieved values before saving to disk for (const key of Object.keys(upsertResults)) { if (typeCache.metadata[key]) { upsertResults[key] = typeCache.metadata[key]; } } } /** * prepares a single item for deployment * * @param {DomainVerificationItem} metadata a single item * @returns {Promise.<DomainVerificationItem>} Promise */ static async preDeployTasks(metadata) { if (metadata.domainType && metadata.domainType !== 'UserDomain') { throw new Error( `Can only delete entries of type 'UserDomain'. Found: ${metadata.domainType}` ); } // prep for update which uses emailAddress instead of domain metadata.emailAddress = metadata.domain; return metadata; } /** * Gets executed before deleting a list of keys for the current type * * @returns {Promise.<void>} - */ static async preDeleteTasks() { if (!cache.getCache()) { cache.initCache(this.buObject); } if (!cache.getCache()?.[this.definition.type]) { const cached = await this.retrieveForCache(); if (cached) { cache.setMetadata(this.definition.type, cached?.metadata); } } } /** * Delete a metadata item from the specified business unit * * @param {string} key Identifier of data extension * @returns {Promise.<boolean>} deletion success flag */ static async deleteByKey(key) { const metadataItem = cache.getByKey(this.definition.type, key); if (!metadataItem) { await this.deleteNotFound(key); return false; } if (metadataItem.domainType !== 'UserDomain') { Util.logger.error( ` - ${this.definition.type} ${key}: Can only delete entries of type UserDomain. Found: ${metadataItem.domainType}` ); return false; } try { const response = await this.client.rest.post( '/messaging/v1/domainverification/delete', [ { emailAddress: metadataItem.domain, domainType: metadataItem.domainType, }, ] ); if (response === '1 records successfully updated!') { Util.logger.info(` - deleted ${this.definition.type}: ${key}`); this.postDeleteTasks(key); return true; } else { Util.logger.error( ` - Deleting ${this.definition.type} '${key}' failed: ` + response ); return false; } } catch (ex) { Util.logger.errorStack(ex, ` - Deleting ${this.definition.type} '${key}' failed`); return false; } } } // Assign definition to static attributes import MetadataTypeDefinitions from '../MetadataTypeDefinitions.js'; DomainVerification.definition = MetadataTypeDefinitions.domainVerification; export default DomainVerification;