From b68186b77c01324ba71d7af0450258a073ea7448 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 1 Aug 2023 14:08:51 +0300 Subject: [PATCH 1/3] change generated uuids to random --- src/utils/constants.ts | 4 +++ src/utils/xmlInnerPartsUtils.ts | 57 ++++++++++++++++++++++++++++++++- src/utils/xmlPartsUtils.ts | 40 +++++++++++++++++++++++ src/workbookManager.ts | 2 ++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 2e2a0ba..44d9000 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -81,6 +81,8 @@ export const element = { dimension: "dimension", selection: "selection", kindCell: "c", + connection: "connection", + worksheet: "worksheet", }; export const elementAttributes = { @@ -113,6 +115,8 @@ export const elementAttributes = { spans: "spans", x14acDyDescent: "x14ac:dyDescent", xr3uid: "xr3:uid", + xr16uid: "xr16:uid", + xruid: "xr:uid", }; export const dataTypeKind = { diff --git a/src/utils/xmlInnerPartsUtils.ts b/src/utils/xmlInnerPartsUtils.ts index c39b968..0b828e0 100644 --- a/src/utils/xmlInnerPartsUtils.ts +++ b/src/utils/xmlInnerPartsUtils.ts @@ -21,6 +21,7 @@ import { emptyValue, } from "./constants"; import documentUtils from "./documentUtils"; +import { v4 } from "uuid"; const updateDocProps = async (zip: JSZip, docProps: DocProps = {}): Promise => { const { doc, properties } = await documentUtils.getDocPropsProperties(zip); @@ -131,7 +132,8 @@ const updateWorksheet = (sheetsXmlString: string, sharedStringIndex: string): st const parser: DOMParser = new DOMParser(); const serializer: XMLSerializer = new XMLSerializer(); const sheetsDoc: Document = parser.parseFromString(sheetsXmlString, xmlTextResultType); - sheetsDoc.getElementsByTagName(element.cellValue)[0].innerHTML = sharedStringIndex.toString(); + const cellValue: Element = sheetsDoc.getElementsByTagName(element.cellValue)[0]; + cellValue.innerHTML = sharedStringIndex; const newSheet: string = serializer.serializeToString(sheetsDoc); return newSheet; @@ -235,6 +237,55 @@ const updatePivotTable = (tableXmlString: string, connectionId: string, refreshO return { isPivotTableUpdated, newPivotTable }; }; +const randomizeConnectionsUUID = (connectionsXmlString: string): string => { + const parser: DOMParser = new DOMParser(); + const serializer: XMLSerializer = new XMLSerializer(); + const connectionsDoc: Document = parser.parseFromString(connectionsXmlString, xmlTextResultType); + const connection: Element = connectionsDoc.getElementsByTagName(element.connection)[0]; + connection.setAttribute(elementAttributes.xr16uid, "{" + v4().toUpperCase() + "}"); + const newConnections: string = serializer.serializeToString(connectionsDoc); + + return newConnections; +}; + +const randomizeWorksheetUUID = (worksheetXmlString: string): string => { + const parser: DOMParser = new DOMParser(); + const serializer: XMLSerializer = new XMLSerializer(); + const worksheetDoc: Document = parser.parseFromString(worksheetXmlString, xmlTextResultType); + const worksheet: Element = worksheetDoc.getElementsByTagName(element.worksheet)[0]; + worksheet.setAttribute(elementAttributes.xruid, "{" + v4().toUpperCase() + "}"); + const newSheet: string = serializer.serializeToString(worksheetDoc); + + return newSheet; +}; + +const randomizeTableUUID = (tableXmlString: string): string => { + const parser: DOMParser = new DOMParser(); + const serializer: XMLSerializer = new XMLSerializer(); + const tableDoc: Document = parser.parseFromString(tableXmlString, xmlTextResultType); + const table: Element = tableDoc.getElementsByTagName(element.table)[0]; + const tableUUID: string = "{" + v4().toUpperCase() + "}"; + table.setAttribute(elementAttributes.xruid, tableUUID); + const autoFilter: Element = tableDoc.getElementsByTagName(element.autoFilter)[0]; + autoFilter.setAttribute(elementAttributes.xruid, tableUUID); + const tableColumn: Element = tableDoc.getElementsByTagName(element.tableColumn)[0]; + tableColumn.setAttribute(elementAttributes.xr3uid, "{" + v4().toUpperCase() + "}"); + const newTable: string = serializer.serializeToString(tableDoc); + + return newTable; +}; + +const randomizeQueryTableUUID = (queryTableXmlString: string): string => { + const parser: DOMParser = new DOMParser(); + const serializer: XMLSerializer = new XMLSerializer(); + const queryTableDoc: Document = parser.parseFromString(queryTableXmlString, xmlTextResultType); + const queryTable: Element = queryTableDoc.getElementsByTagName(element.queryTable)[0]; + queryTable.setAttribute(elementAttributes.xr16uid, "{" + v4().toUpperCase() + "}"); + const newQueryTable: string = serializer.serializeToString(queryTableDoc); + + return newQueryTable; +}; + export default { updateDocProps, updateConnections, @@ -243,4 +294,8 @@ export default { updatePivotTablesandQueryTables, updateQueryTable, updatePivotTable, + randomizeConnectionsUUID, + randomizeWorksheetUUID, + randomizeTableUUID, + randomizeQueryTableUUID }; diff --git a/src/utils/xmlPartsUtils.ts b/src/utils/xmlPartsUtils.ts index c9232b8..6e43039 100644 --- a/src/utils/xmlPartsUtils.ts +++ b/src/utils/xmlPartsUtils.ts @@ -11,6 +11,9 @@ import { sharedStringsNotFoundErr, sheetsXmlPath, sheetsNotFoundErr, + tableXmlPath, + queryTableXmlPath, + queryTableNotFoundErr, } from "./constants"; import { replaceSingleQuery } from "./mashupDocumentParser"; import { DocProps, TableData } from "../types"; @@ -66,8 +69,45 @@ const updateWorkbookSingleQueryAttributes = async (zip: JSZip, queryName: string await xmlInnerPartsUtils.updatePivotTablesandQueryTables(zip, queryName, refreshOnOpen, connectionId!); }; +const updateWorkbookGeneratedUUIDs = async (zip: JSZip, updateQueryTable: boolean = false): Promise => { + const connectionsXmlString: string | undefined = await zip.file(connectionsXmlPath)?.async(textResultType); + if (connectionsXmlString === undefined) { + throw new Error(connectionsNotFoundErr); + } + + const connectionXmlFileString = xmlInnerPartsUtils.randomizeConnectionsUUID(connectionsXmlString); + zip.file(connectionsXmlPath, connectionXmlFileString); + + const sheetsXmlString: string | undefined = await zip.file(sheetsXmlPath)?.async(textResultType); + if (sheetsXmlString === undefined) { + throw new Error(sheetsNotFoundErr); + } + + const worksheetString: string = xmlInnerPartsUtils.randomizeWorksheetUUID(sheetsXmlString); + zip.file(sheetsXmlPath, worksheetString); + + const tableXmlString: string | undefined = await zip.file(tableXmlPath)?.async(textResultType); + if (tableXmlString === undefined) { + throw new Error(sheetsNotFoundErr); + } + + const tableString: string = xmlInnerPartsUtils.randomizeTableUUID(tableXmlString); + zip.file(tableXmlPath, tableString); + + if (updateQueryTable) { + const queryTableXmlString: string | undefined = await zip.file(queryTableXmlPath)?.async(textResultType); + if (queryTableXmlString === undefined) { + throw new Error(queryTableNotFoundErr); + } + + const queryTableString: string = xmlInnerPartsUtils.randomizeQueryTableUUID(queryTableXmlString); + zip.file(queryTableXmlPath, queryTableString); + } +}; + export default { updateWorkbookInitialDataIfNeeded, updateWorkbookPowerQueryDocument, updateWorkbookSingleQueryAttributes, + updateWorkbookGeneratedUUIDs, }; diff --git a/src/workbookManager.ts b/src/workbookManager.ts index b445806..d849feb 100644 --- a/src/workbookManager.ts +++ b/src/workbookManager.ts @@ -44,6 +44,7 @@ export const generateTableWorkbookFromGrid = async (grid: Grid, docProps?: DocPr throw new Error(tableNotFoundErr); } + await xmlPartsUtils.updateWorkbookGeneratedUUIDs(zip); await xmlPartsUtils.updateWorkbookInitialDataIfNeeded(zip, docProps, tableData); return await zip.generateAsync({ @@ -57,6 +58,7 @@ const generateSingleQueryWorkbookFromZip = async (zip: JSZip, query: QueryInfo, query.queryName = defaults.queryName; } + await xmlPartsUtils.updateWorkbookGeneratedUUIDs(zip, true /*updateQueryTable*/); await xmlPartsUtils.updateWorkbookPowerQueryDocument(zip, query.queryName, generateSingleQueryMashup(query.queryName, query.queryMashup)); await xmlPartsUtils.updateWorkbookSingleQueryAttributes(zip, query.queryName, query.refreshOnOpen); await xmlPartsUtils.updateWorkbookInitialDataIfNeeded(zip, docProps, tableData, true /*updateQueryTable*/); From 0381a1f9c9e29d2f70c3f865b9c09a3ad06ce369 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 1 Aug 2023 14:21:48 +0300 Subject: [PATCH 2/3] fix bug in table workbook scneario --- src/utils/xmlPartsUtils.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/utils/xmlPartsUtils.ts b/src/utils/xmlPartsUtils.ts index 6e43039..fea404f 100644 --- a/src/utils/xmlPartsUtils.ts +++ b/src/utils/xmlPartsUtils.ts @@ -70,14 +70,6 @@ const updateWorkbookSingleQueryAttributes = async (zip: JSZip, queryName: string }; const updateWorkbookGeneratedUUIDs = async (zip: JSZip, updateQueryTable: boolean = false): Promise => { - const connectionsXmlString: string | undefined = await zip.file(connectionsXmlPath)?.async(textResultType); - if (connectionsXmlString === undefined) { - throw new Error(connectionsNotFoundErr); - } - - const connectionXmlFileString = xmlInnerPartsUtils.randomizeConnectionsUUID(connectionsXmlString); - zip.file(connectionsXmlPath, connectionXmlFileString); - const sheetsXmlString: string | undefined = await zip.file(sheetsXmlPath)?.async(textResultType); if (sheetsXmlString === undefined) { throw new Error(sheetsNotFoundErr); @@ -95,6 +87,14 @@ const updateWorkbookGeneratedUUIDs = async (zip: JSZip, updateQueryTable: boolea zip.file(tableXmlPath, tableString); if (updateQueryTable) { + const connectionsXmlString: string | undefined = await zip.file(connectionsXmlPath)?.async(textResultType); + if (connectionsXmlString === undefined) { + throw new Error(connectionsNotFoundErr); + } + + const connectionXmlFileString = xmlInnerPartsUtils.randomizeConnectionsUUID(connectionsXmlString); + zip.file(connectionsXmlPath, connectionXmlFileString); + const queryTableXmlString: string | undefined = await zip.file(queryTableXmlPath)?.async(textResultType); if (queryTableXmlString === undefined) { throw new Error(queryTableNotFoundErr); From 083b11eed8faf9daa22a444348c610c52be92d94 Mon Sep 17 00:00:00 2001 From: shanialbeck Date: Tue, 1 Aug 2023 17:05:07 +0300 Subject: [PATCH 3/3] add missing workbook xml changes --- src/utils/constants.ts | 3 +++ src/utils/xmlInnerPartsUtils.ts | 14 +++++++++++++- src/utils/xmlPartsUtils.ts | 17 ++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 44d9000..16e3c4a 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -25,6 +25,7 @@ export const formulaSectionNotFoundErr = "Formula section wasn't found in templa export const templateWithInitialDataErr = "Cannot receive template file with initial data"; export const queryTableNotFoundErr = "Query table wasn't found in template"; export const tableNotFoundErr = "Table wasn't found in template"; +export const workbookNotFoundErr = "Workbook wasn't found in template"; export const invalidValueInColumnErr = "Invalid cell value in column"; export const headerNotFoundErr = "Invalid JSON file, header is missing"; export const invalidDataTypeErr = "Invalid JSON file, invalid data type"; @@ -83,6 +84,7 @@ export const element = { kindCell: "c", connection: "connection", worksheet: "worksheet", + workbookView: "workbookView" }; export const elementAttributes = { @@ -115,6 +117,7 @@ export const elementAttributes = { spans: "spans", x14acDyDescent: "x14ac:dyDescent", xr3uid: "xr3:uid", + xr2uid: "xr2:uid", xr16uid: "xr16:uid", xruid: "xr:uid", }; diff --git a/src/utils/xmlInnerPartsUtils.ts b/src/utils/xmlInnerPartsUtils.ts index 0b828e0..15d7084 100644 --- a/src/utils/xmlInnerPartsUtils.ts +++ b/src/utils/xmlInnerPartsUtils.ts @@ -286,6 +286,17 @@ const randomizeQueryTableUUID = (queryTableXmlString: string): string => { return newQueryTable; }; +const randomizeWorkbookUUID = (workbookXmlString: string): string => { + const parser: DOMParser = new DOMParser(); + const serializer: XMLSerializer = new XMLSerializer(); + const workbookDoc: Document = parser.parseFromString(workbookXmlString, xmlTextResultType); + const workbookView: Element = workbookDoc.getElementsByTagName(element.workbookView)[0]; + workbookView.setAttribute(elementAttributes.xr2uid, "{" + v4().toUpperCase() + "}"); + const newWorkbook: string = serializer.serializeToString(workbookDoc); + + return newWorkbook; +}; + export default { updateDocProps, updateConnections, @@ -297,5 +308,6 @@ export default { randomizeConnectionsUUID, randomizeWorksheetUUID, randomizeTableUUID, - randomizeQueryTableUUID + randomizeQueryTableUUID, + randomizeWorkbookUUID }; diff --git a/src/utils/xmlPartsUtils.ts b/src/utils/xmlPartsUtils.ts index fea404f..97e3e4a 100644 --- a/src/utils/xmlPartsUtils.ts +++ b/src/utils/xmlPartsUtils.ts @@ -14,6 +14,9 @@ import { tableXmlPath, queryTableXmlPath, queryTableNotFoundErr, + workbookXmlPath, + workbookNotFoundErr, + tableNotFoundErr, } from "./constants"; import { replaceSingleQuery } from "./mashupDocumentParser"; import { DocProps, TableData } from "../types"; @@ -75,12 +78,20 @@ const updateWorkbookGeneratedUUIDs = async (zip: JSZip, updateQueryTable: boolea throw new Error(sheetsNotFoundErr); } - const worksheetString: string = xmlInnerPartsUtils.randomizeWorksheetUUID(sheetsXmlString); - zip.file(sheetsXmlPath, worksheetString); + const sheetString: string = xmlInnerPartsUtils.randomizeWorksheetUUID(sheetsXmlString); + zip.file(sheetsXmlPath, sheetString); + + const workbookXmlString: string | undefined = await zip.file(workbookXmlPath)?.async(textResultType); + if (workbookXmlString === undefined) { + throw new Error(workbookNotFoundErr); + } + + const workbookString: string = xmlInnerPartsUtils.randomizeWorkbookUUID(workbookXmlString); + zip.file(workbookXmlPath, workbookString); const tableXmlString: string | undefined = await zip.file(tableXmlPath)?.async(textResultType); if (tableXmlString === undefined) { - throw new Error(sheetsNotFoundErr); + throw new Error(tableNotFoundErr); } const tableString: string = xmlInnerPartsUtils.randomizeTableUUID(tableXmlString);