Skip to content

Commit

Permalink
MWPW-152662: Promote API updated to retain version history (adobecom#22)
Browse files Browse the repository at this point in the history
- The version history of the destination file (where it will get copied into) is retained.
- If the file is in locked state, does not overwrite the destination file. Reports the file as a promote error and marks it explicitly as a locked file in the report.
  • Loading branch information
sukamat authored Jun 17, 2024
1 parent b167c4f commit ffb858e
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 63 deletions.
34 changes: 23 additions & 11 deletions actions/graybox/promote-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ const {
} = require('../utils');
const appConfig = require('../appConfig');
const { getConfig } = require('../config');
const { getAuthorizedRequestOption, fetchWithRetry, updateExcelTable } = require('../sharepoint');
const {
getAuthorizedRequestOption, fetchWithRetry, updateExcelTable,
getFileData, getFileUsingDownloadUrl, saveFileSimple
} = require('../sharepoint');
const helixUtils = require('../helixUtils');
const updateDocument = require('../docxUpdater');
const { saveFile, promoteCopy } = require('../sharepoint');

const logger = getAioLogger();
const MAX_CHILDREN = 1000;
Expand Down Expand Up @@ -75,8 +77,9 @@ async function main(params) {

const promotedPreviewStatuses = [];
let promotedFailedPreviews = [];

let responsePayload = '';
if (helixUtils.canBulkPreview(true)) {
logger.info('Bulk Previewing Graybox files');
const paths = [];
batchArray.forEach((batch) => {
batch.forEach((gbFile) => paths.push(handleExtension(gbFile.filePath)));
Expand Down Expand Up @@ -121,8 +124,11 @@ async function main(params) {
const promotedExcelValues = [['Promoted Files Preview completed', toUTCStr(new Date()), sFailedPromotedPreviews]];
// Update Promoted Preview Status
await updateExcelTable(projectExcelPath, 'PROMOTE_STATUS', promotedExcelValues);
responsePayload = 'Graybox Promote Worker action completed.';
} else {
responsePayload = 'Bulk Preview not enabled for Graybox Content Tree';
}
const responsePayload = 'Graybox Promote Worker action completed.';
logger.info(responsePayload);
return exitAction({
body: responsePayload,
});
Expand Down Expand Up @@ -163,11 +169,12 @@ async function promoteFiles(previewStatuses, experienceName, helixAdminApiKey) {
if (docx) {
// Save file Destination full path with file name and extension
const destinationFilePath = `${stat.path.substring(0, stat.path.lastIndexOf('/') + 1).replace('/'.concat(experienceName), '')}${stat.fileName}`;
const saveStatus = await saveFileSimple(docx, destinationFilePath, sp);

const saveStatus = await saveFile(docx, destinationFilePath, sp);

if (saveStatus && saveStatus.success) {
if (saveStatus?.success) {
promotes.push(destinationFilePath);
} else if (saveStatus?.errorMsg?.includes('File is locked')) {
failedPromotes.push(`${destinationFilePath} (locked file)`);
} else {
failedPromotes.push(destinationFilePath);
}
Expand All @@ -177,13 +184,18 @@ async function promoteFiles(previewStatuses, experienceName, helixAdminApiKey) {
} else {
const copySourceFilePath = `${stat.path.substring(0, stat.path.lastIndexOf('/') + 1)}${stat.fileName}`; // Copy Source full path with file name and extension
const copyDestinationFolder = `${stat.path.substring(0, stat.path.lastIndexOf('/')).replace('/'.concat(experienceName), '')}`; // Copy Destination folder path, no file name
const destFilePath = `${copyDestinationFolder}/${stat.fileName}`;

const promoteCopyFileStatus = await promoteCopy(copySourceFilePath, copyDestinationFolder, stat.fileName, sp);
const { fileDownloadUrl } = await getFileData(copySourceFilePath, true);
const file = await getFileUsingDownloadUrl(fileDownloadUrl);
const saveStatus = await saveFileSimple(file, destFilePath, sp);

if (promoteCopyFileStatus) {
promotes.push(`${copyDestinationFolder}/${stat.fileName}`);
if (saveStatus?.success) {
promotes.push(destFilePath);
} else if (saveStatus?.errorMsg?.includes('File is locked')) {
failedPromotes.push(`${destFilePath} (locked file)`);
} else {
failedPromotes.push(`${copyDestinationFolder}/${stat.fileName}`);
failedPromotes.push(destFilePath);
}
}
}
Expand Down
78 changes: 26 additions & 52 deletions actions/sharepoint.js
Original file line number Diff line number Diff line change
Expand Up @@ -434,62 +434,35 @@ async function saveFile(file, dest, spConfig, isGraybox) {
return { success: false, path: dest };
}

/**
* Promote Copy
* Copies the Graaybox files back to the main content tree.
* Creates intermediate folders if needed.
* @param {*} srcPath Graybox Source Path
* @param {*} destinationFolder Promote Destination Folder
* @param {*} fileName FileName to be promoted
* @param {*} sp sharepoint config
* @returns promote status true/false for the file
*/
async function promoteCopy(srcPath, destinationFolder, fileName, sp) {
const { baseURI } = sp.api.file.copy;
const rootFolder = baseURI.split('/').pop();
await createFolder(destinationFolder, sp);
const payload = { ...sp.api.file.copy.payload, parentReference: { path: `${rootFolder}${destinationFolder}` } };

const options = await getAuthorizedRequestOption({
method: sp.api.file.copy.method,
body: JSON.stringify(payload),
});

// copy source is the Graybox directory for promote
const copyStatusInfo = await fetchWithRetry(`${sp.api.file.copy.gbBaseURI}${srcPath}:/copy?@microsoft.graph.conflictBehavior=replace`, options);
const statusUrl = copyStatusInfo.headers.get('Location');
async function saveFileSimple(file, dest, spConfig, isGraybox) {
const logger = getAioLogger();

let copySuccess = false;
let copyStatusJson = {};
while (statusUrl && !copySuccess && copyStatusJson.status !== 'failed') {
// eslint-disable-next-line no-await-in-loop
const status = await fetchWithRetry(statusUrl);
if (status.ok) {
// eslint-disable-next-line no-await-in-loop
copyStatusJson = await status.json();
copySuccess = copyStatusJson.status === 'completed';
try {
const folder = getFolderFromPath(dest);
const filename = getFileNameFromPath(dest);
logger.info(`Saving file ${filename} to ${folder}`);
await createFolder(folder, spConfig);
let sp;
if (spConfig) {
sp = spConfig;
} else {
sp = await getConfig().sp;
}
}

// If copy failed because it is Locked, try to copy the locked file to a new file,
// then promote copy again, then delete the renamed locked file copy
if (!copySuccess) {
// await releaseUploadSession(sp, uploadFileStatus.sessionUrl);
const lockedFileNewName = getLockedFileNewName(fileName);
// const baseURI = isGraybox ? sp.api.file.get.gbBaseURI : sp.api.file.get.baseURI;
const spFileUrl = `${baseURI}${destinationFolder}/${fileName}`;
await renameFile(spFileUrl, lockedFileNewName);
const folder = getFolderFromPath(`${destinationFolder}/${fileName}`);
const newLockedFilePath = `${folder}/${lockedFileNewName}`;
const copyFileStatus = await copyFile(newLockedFilePath, folder, fileName, false, true, sp);
if (copyFileStatus) {
copySuccess = await promoteCopy(srcPath, destinationFolder, fileName, sp);
if (copySuccess) {
await deleteFile(sp, `${baseURI}${newLockedFilePath}`);
}
const uploadFileStatus = await createSessionAndUploadFile(sp, file, dest, filename, isGraybox);
if (uploadFileStatus.locked) {
logger.info(`Locked file detected: ${dest}`);
return { success: false, path: dest, errorMsg: 'File is locked' };
}
const uploadedFileJson = uploadFileStatus.uploadedFile;
if (uploadedFileJson) {
return { success: true, uploadedFileJson, path: dest };
}
} catch (error) {
logger.info(`Error while saving file: ${dest} ::: ${error.message}`);
return { success: false, path: dest, errorMsg: error.message };
}
return copySuccess;
return { success: false, path: dest };
}

async function getExcelTable(excelPath, tableName) {
Expand Down Expand Up @@ -581,12 +554,13 @@ module.exports = {
executeGQL,
getDriveRoot,
getExcelTable,
getFileData,
getFilesData,
getFile,
getFileUsingDownloadUrl,
copyFile,
saveFile,
promoteCopy,
saveFileSimple,
createFolder,
updateExcelTable,
fetchWithRetry,
Expand Down

0 comments on commit ffb858e

Please sign in to comment.