From 3817361bd6c621420858382961b7c2b501432143 Mon Sep 17 00:00:00 2001 From: Raghu A <125877471+raga-adbe-gh@users.noreply.github.com> Date: Thu, 31 Aug 2023 03:16:26 +0530 Subject: [PATCH] MWPW-134760 Copy/Promote on restricted site (eg: CC) (#52) * MWPW-134760 Copy/Promote on restricted site (eg: CC) Updating the instance path and status key to support drive. E.g. if the a www is present in two different drives like CC and test Enhance the instance path and status key configuration to accommodate different drives, such as CC and test, when the common root path (e.g. "www") is present in multiple locations. Changes - Extract the site absolute path from shareUrl(s). Get the key based on action instead passing from action and is based on absolute path. (One ENV filed is added SITE_ROOT_PATH_REX=.*/sites(/.*)< ) Instead of instance based on root folder base it on absolute folder. Example - Store Key (for copy) - /adobecom/Shared%20Documents/milo Instance Path - milo-floodgate/batching/promoteAction/instance_adobecom_Shared_20Documents_milo_pink Status Action (UI Code Adjustments Required for Milo): Presently, the two fields, projectExcelPath and projectRoot (e.g., /milo, /milo-pink), are passed, determining whether to execute a copy or promote action based on these values. Modifications are needed due to the addition of a delete action. The following parameters should be provided: action: Options include promoteAction, copyAction, and deleteAction. projectExcelPath: This parameter is optional. rootFolder, fgRootFolder, shareUrl, fgShareUrl should be included, similar to the parameters used in copy and promote actions. * typo * Fix for storeState is missing projectExcelPath for copy action Updated to pull status from state using the action type, shareUrls and optional projectExcelPath For Copy { "type": "copy", "projectExcelPath": "/drafts/floodgate/projects/test/sample.xlsx", "shareUrl": "...../Shared%20Documents/milo?web=1", } For Promote { "type": "promote", "fgShareUrl": "....../Shared%20Documents/milo-pink?web=1" } * Removed few logger statements * Updated storeKey for Delete Actio * Applied similar fix in aio for review comment on UI PR. * Fixed typo in storeKey for promote actions. Fixed delete url for supporting restricted sites. * minor logger added --------- Co-authored-by: Raghu A --- actions/appConfig.js | 11 ++++++++++ actions/config.js | 4 +--- actions/copy/copy.js | 5 ++--- actions/copy/worker.js | 3 +-- actions/delete/delete.js | 2 +- actions/delete/worker.js | 5 ++--- actions/fgStatus.js | 35 +++++++++++++++++++++++++++++--- actions/maint/maint.js | 19 +++++++++++++---- actions/promote/createBatch.js | 6 +++--- actions/promote/promote.js | 2 +- actions/promote/triggerNTrack.js | 6 +++--- actions/promote/worker.js | 6 +++--- actions/sharepoint.js | 13 ++++++------ actions/status/status.js | 28 ++++++++++++++----------- app.config.yaml | 1 + 15 files changed, 98 insertions(+), 48 deletions(-) diff --git a/actions/appConfig.js b/actions/appConfig.js index 7e4291f..140029f 100644 --- a/actions/appConfig.js +++ b/actions/appConfig.js @@ -51,6 +51,9 @@ class AppConfig { this.configMap.fgUserGroups = this.getJsonFromStr(params.fgUserGroups, []); this.configMap.fgAdminGroups = this.getJsonFromStr(params.fgAdminGroups, []); this.configMap.fgDirPattern = params.fgDirPattern; + this.configMap.siteRootPathRex = this.siteRootPathRex || '.*/sites(/.*)<'; + this.configMap.siteRootPath = this.getSiteRootPath(params.shareUrl); + this.configMap.siteFgRootPath = this.getSiteRootPath(params.fgShareUrl); this.extractPrivateKey(); } @@ -131,6 +134,14 @@ class AppConfig { getNumBulkReq() { return this.configMap.numBulkReq; } + + getSiteRootPath(shareUrl) { + try { + return shareUrl.match(new RegExp(this.configMap.siteRootPathRex))[1]; + } catch (err) { + return '/'; + } + } } module.exports = new AppConfig(); diff --git a/actions/config.js b/actions/config.js index d187bad..a7bdb3d 100644 --- a/actions/config.js +++ b/actions/config.js @@ -28,7 +28,6 @@ function getSharepointConfig(applicationConfig) { const baseURI = `${applicationConfig.fgSite}${drive}/root:${applicationConfig.payload.rootFolder}`; const fgBaseURI = `${applicationConfig.fgSite}${drive}/root:${applicationConfig.payload.fgRootFolder}`; const baseItemsURI = `${applicationConfig.fgSite}${drive}/items`; - const fgBaseItemsURI = `${applicationConfig.fgSite}${drive}/items`; return { ...applicationConfig, clientApp: { @@ -83,10 +82,9 @@ function getSharepointConfig(applicationConfig) { }, }, excel: { - get: { baseItemsURI, fgBaseItemsURI }, + get: { baseItemsURI }, update: { baseItemsURI, - fgBaseItemsURI, method: 'POST', }, }, diff --git a/actions/copy/copy.js b/actions/copy/copy.js index 207ae2e..45c62aa 100644 --- a/actions/copy/copy.js +++ b/actions/copy/copy.js @@ -33,10 +33,9 @@ async function main(args) { spToken, adminPageUri, projectExcelPath, rootFolder } = args; appConfig.setAppConfig(args); - const projectPath = `${rootFolder}${projectExcelPath}`; const userDetails = sharepointAuth.getUserDetails(spToken); - const fgStatus = new FgStatus({ action: COPY_ACTION, statusKey: projectPath, userDetails }); - logger.info(`Copy action for ${projectPath} triggered by ${JSON.stringify(userDetails)}`); + const fgStatus = new FgStatus({ action: COPY_ACTION, userDetails }); + logger.info(`Copy action for ${fgStatus.getStoreKey()} triggered by ${JSON.stringify(userDetails)}`); try { if (!rootFolder || !projectExcelPath) { payload = 'Could not determine the project path. Try reloading the page and trigger the action again.'; diff --git a/actions/copy/worker.js b/actions/copy/worker.js index 3fdfd7b..f619b83 100644 --- a/actions/copy/worker.js +++ b/actions/copy/worker.js @@ -39,8 +39,7 @@ async function main(params) { adminPageUri, projectExcelPath, rootFolder } = params; appConfig.setAppConfig(params); - const projectPath = `${rootFolder}${projectExcelPath}`; - const fgStatus = new FgStatus({ action: COPY_ACTION, statusKey: projectPath }); + const fgStatus = new FgStatus({ action: COPY_ACTION }); try { if (!rootFolder || !projectExcelPath) { payload = 'Could not determine the project path. Try reloading the page and trigger the action again.'; diff --git a/actions/delete/delete.js b/actions/delete/delete.js index 642d19b..fb03517 100644 --- a/actions/delete/delete.js +++ b/actions/delete/delete.js @@ -35,7 +35,7 @@ async function main(args) { appConfig.setAppConfig(args); const projectPath = `${rootFolder}${projectExcelPath}`; const userDetails = sharepointAuth.getUserDetails(spToken); - const fgStatus = new FgStatus({ action: DELETE_ACTION, statusKey: `${DELETE_ACTION}~${projectPath}`, userDetails }); + const fgStatus = new FgStatus({ action: DELETE_ACTION, userDetails }); logger.info(`Delete action for ${projectPath} triggered by ${JSON.stringify(userDetails)}`); try { if (!rootFolder || !projectExcelPath) { diff --git a/actions/delete/worker.js b/actions/delete/worker.js index d66a4a8..a68741c 100644 --- a/actions/delete/worker.js +++ b/actions/delete/worker.js @@ -31,9 +31,8 @@ async function main(params) { adminPageUri, projectExcelPath, rootFolder, } = params; appConfig.setAppConfig(params); - const projectPath = `${rootFolder}${projectExcelPath}`; const { fgRootFolder } = appConfig.getPayload(); - const fgStatus = new FgStatus({ action: DELETE_ACTION, statusKey: `${DELETE_ACTION}~${fgRootFolder}` }); + const fgStatus = new FgStatus({ action: DELETE_ACTION }); try { if (!rootFolder || !projectExcelPath) { payload = 'Could not determine the project path. Try reloading the page and trigger the action again.'; @@ -54,7 +53,7 @@ async function main(params) { statusMessage: payload }); - const deleteStatus = await deleteFloodgateDir(fgRootFolder); + const deleteStatus = await deleteFloodgateDir(); payload = deleteStatus === false ? 'Error occurred when deleting content. Check project excel sheet for additional information.' : 'Delete action was completed'; diff --git a/actions/fgStatus.js b/actions/fgStatus.js index 0769e4b..c87179f 100644 --- a/actions/fgStatus.js +++ b/actions/fgStatus.js @@ -17,7 +17,8 @@ const stateLib = require('@adobe/aio-lib-state'); const crypto = require('crypto'); -const { getAioLogger } = require('./utils'); +const { getAioLogger, COPY_ACTION, DELETE_ACTION } = require('./utils'); +const appConfig = require('./appConfig'); const FG_KEY = 'FLOODGATE'; @@ -61,13 +62,41 @@ class FgStatus { * @param {*} options statusKey is the key to be used to store * and actionType is the type of FG Action like copy or promote */ - constructor({ action, statusKey, userDetails }) { + constructor({ + action, + statusKey, + keySuffix, + userDetails + }) { this.lastTriggeredBy = userDetails?.oid; this.action = action || ''; - this.storeKey = statusKey || FG_KEY; + this.storeKey = statusKey || this.generateStoreKey(keySuffix) || FG_KEY; this.logger = getAioLogger(); } + generateStoreKey(keySuffix) { + const { siteRootPath, siteFgRootPath } = appConfig.getConfig(); + const { projectExcelPath } = appConfig.getPayload(); + let resp = ''; + + switch (this.action) { + case COPY_ACTION: + resp = `${siteRootPath || ''}${projectExcelPath || ''}`; + break; + case DELETE_ACTION: + resp = `${DELETE_ACTION}${siteFgRootPath}`; + break; + default: + resp = siteFgRootPath; + } + resp += keySuffix || ''; + return resp; + } + + getStoreKey() { + return this.storeKey; + } + /** * Checks if the given status is to be treated as InProgress * @param {*} status Status to be checked diff --git a/actions/maint/maint.js b/actions/maint/maint.js index c9eb403..64498bc 100644 --- a/actions/maint/maint.js +++ b/actions/maint/maint.js @@ -115,19 +115,30 @@ class MaintAction { } async stateStoreKey(key) { - // Split by comma (action, statusKey) - const fgStatus = new FgStatus({ action: PROMOTE_ACTION, statusKey: key }); + const fgStatus = new FgStatus(this.getActionStatusKey(key)); const data = await fgStatus.getStatusFromStateLib(); return data; } async clearStateStore(key) { - // Split by comma (action, statusKey) - const fgStatus = new FgStatus({ action: PROMOTE_ACTION, statusKey: key }); + const fgStatus = new FgStatus(this.getActionStatusKey(key)); await fgStatus.clearState(true); return {}; } + getActionStatusKey(key) { + // Split by comma (action, statusKey) + let action = PROMOTE_ACTION; + let statusKey; + try { + const mtchs = key.match(/(.*?),(.*)/); + [, action, statusKey] = mtchs; + } catch (err) { + logger.error(`Could not parse ${key}`); + } + return { action, statusKey }; + } + async updateTracker({ enable = '' }, ow) { if (enable.toLowerCase() === 'on') { return ow.rules.enable({ name: TRACKER_RULE }); diff --git a/actions/promote/createBatch.js b/actions/promote/createBatch.js index c53282c..6150c67 100644 --- a/actions/promote/createBatch.js +++ b/actions/promote/createBatch.js @@ -50,9 +50,9 @@ async function main(params) { logMemUsage(); let stepMsg; appConfig.setAppConfig(params); - const payload = appConfig.getPayload(); - const fgStatus = new FgStatus({ action: PROMOTE_ACTION, statusKey: payload.fgRootFolder }); - const batchManager = new BatchManager({ key: PROMOTE_ACTION, instanceKey: getInstanceKey({ fgRootFolder: payload.fgRootFolder }) }); + const { payload, siteFgRootPath } = appConfig.getConfig(); + const fgStatus = new FgStatus({ action: PROMOTE_ACTION }); + const batchManager = new BatchManager({ key: PROMOTE_ACTION, instanceKey: getInstanceKey({ fgRootFolder: siteFgRootPath }) }); await batchManager.init(); // For current cleanup files before starting await batchManager.cleanupFiles(); diff --git a/actions/promote/promote.js b/actions/promote/promote.js index 2521169..e0e17e7 100644 --- a/actions/promote/promote.js +++ b/actions/promote/promote.js @@ -32,7 +32,7 @@ async function main(args) { let stepMsg; const payload = appConfig.getPayload(); const userDetails = sharepointAuth.getUserDetails(payload.spToken); - const fgStatus = new FgStatus({ action: PROMOTE_ACTION, statusKey: payload.fgRootFolder, userDetails }); + const fgStatus = new FgStatus({ action: PROMOTE_ACTION, userDetails }); logger.info(`Promote action for ${payload.fgRootFolder} triggered by ${JSON.stringify(userDetails)}`); try { if (!payload.fgRootFolder) { diff --git a/actions/promote/triggerNTrack.js b/actions/promote/triggerNTrack.js index 8e71c75..a632f07 100644 --- a/actions/promote/triggerNTrack.js +++ b/actions/promote/triggerNTrack.js @@ -49,7 +49,7 @@ async function main(params) { }); const payload = appConfig.getPayload(); - const fgStatus = new FgStatus({ action: PROMOTE_ACTION, statusKey: payload.fgRootFolder }); + const fgStatus = new FgStatus({ action: PROMOTE_ACTION }); try { if (!payload.fgRootFolder) { stepMsg = 'Required data is not available to proceed with FG Promote action.'; @@ -132,10 +132,10 @@ async function checkBatchesInProg(fgRootFolder, actDtls, ow) { if (activationId && !done) { fgStatus = new FgStatus({ action: `${PROMOTE_BATCH}_${batchNumber}`, - statusKey: `${fgRootFolder}~Batch_${batchNumber}` + keySuffix: `Batch_${batchNumber}` }); batchInProg = await fgStatus?.getStatusFromStateLib().then((result) => { - if (result.action && FgStatus.isInProgress(result.action.status)) { + if (result?.action && FgStatus.isInProgress(result.action.status)) { return true; } return false; diff --git a/actions/promote/worker.js b/actions/promote/worker.js index f80da56..22eac1d 100644 --- a/actions/promote/worker.js +++ b/actions/promote/worker.js @@ -38,9 +38,9 @@ async function main(params) { const { batchNumber } = params; appConfig.setAppConfig(params); // Tracker uses the below hence change here might need change in tracker as well. - const payload = appConfig.getPayload(); - const fgStatus = new FgStatus({ action: `${PROMOTE_BATCH}_${batchNumber}`, statusKey: `${payload.fgRootFolder}~Batch_${batchNumber}` }); - const batchManager = new BatchManager({ key: PROMOTE_ACTION, instanceKey: getInstanceKey({ fgRootFolder: payload.fgRootFolder }) }); + const { payload, siteFgRootPath } = appConfig.getConfig(); + const fgStatus = new FgStatus({ action: `${PROMOTE_BATCH}_${batchNumber}`, keySuffix: `Batch_${batchNumber}` }); + const batchManager = new BatchManager({ key: PROMOTE_ACTION, instanceKey: getInstanceKey({ fgRootFolder: siteFgRootPath }) }); await batchManager.init({ batchNumber }); try { if (!payload.fgRootFolder) { diff --git a/actions/sharepoint.js b/actions/sharepoint.js index f08471a..90da55a 100644 --- a/actions/sharepoint.js +++ b/actions/sharepoint.js @@ -363,22 +363,21 @@ async function getExcelTable(excelPath, tableName) { return []; } -async function deleteFloodgateDir(fgRootFolder) { +async function deleteFloodgateDir() { const logger = getAioLogger(); logger.info('Deleting content started.'); - const baseURI = `${appConfig.getConfig().fgSite}/drive/root:${fgRootFolder}`; + const { sp } = await getConfig(); let deleteSuccess = false; const { fgDirPattern } = appConfig.getConfig(); const fgRegExp = new RegExp(fgDirPattern); logger.info(fgRegExp); - if (fgRegExp.test(baseURI)) { - logger.info(`Deleting the folder ${baseURI} `); + if (fgRegExp.test(sp.api.file.update.fgBaseURI)) { const temp = '/temp'; - const finalBaserURI = baseURI + temp; + const finalBaserURI = `${sp.api.file.delete.fgBaseURI}${temp}`; + logger.info(`Deleting the folder ${finalBaserURI} `); try { - const { sp } = await getConfig(); - await deleteFile(sp, `${finalBaserURI}`); + await deleteFile(sp, finalBaserURI); deleteSuccess = true; } catch (error) { logger.info(`Error occurred when trying to delete files of main content tree ${error.message}`); diff --git a/actions/status/status.js b/actions/status/status.js index 084a83d..e6b1a99 100644 --- a/actions/status/status.js +++ b/actions/status/status.js @@ -16,29 +16,33 @@ ************************************************************************* */ // eslint-disable-next-line import/no-extraneous-dependencies -const { getAioLogger } = require('../utils'); +const appConfig = require('../appConfig'); +const { + getAioLogger, COPY_ACTION, PROMOTE_ACTION, DELETE_ACTION +} = require('../utils'); const FgStatus = require('../fgStatus'); +const actionMap = { + copy: COPY_ACTION, + promote: PROMOTE_ACTION, + delete: DELETE_ACTION +}; + // This returns the activation ID of the action that it called async function main(args) { const logger = getAioLogger(); let payload; - let statusKey; try { - const { projectExcelPath, projectRoot } = args; - statusKey = projectRoot; - if (!projectExcelPath && !projectRoot) { + appConfig.setAppConfig(args); + const { + type, shareUrl, fgShareUrl + } = args; + if (!type || !(shareUrl || fgShareUrl)) { payload = 'Status : Required data is not available to get the status.'; logger.error(payload); } else { - if (projectExcelPath) { - statusKey = `${projectRoot}${projectExcelPath}`; - } - logger.info(`Status key -- ${statusKey}`); - const fgStatus = new FgStatus({ statusKey }); + const fgStatus = new FgStatus({ action: actionMap[type] }); payload = await fgStatus.getStatusFromStateLib(); - - logger.info(`Status here -- ${JSON.stringify(payload)}`); } } catch (err) { logger.error(err); diff --git a/app.config.yaml b/app.config.yaml index 0260ae8..e84a79d 100644 --- a/app.config.yaml +++ b/app.config.yaml @@ -22,6 +22,7 @@ application: fgUserGroups: $FG_USER_GROUPS fgAdminGroups: $FG_ADMIN_GROUPS fgDirPattern: $FG_DIR_PATTERN + siteRootPathRex: $SITE_ROOT_PATH_REX actions: copy: function: actions/copy/copy.js