From 3ac69be2b4a793327cd949e3150e9c0ef9f29b49 Mon Sep 17 00:00:00 2001 From: Arthur Date: Mon, 13 Jan 2025 04:26:30 +0000 Subject: [PATCH] update writeOneTrustAssessment to write in csv format --- src/oneTrust/codecs.ts | 2 +- src/oneTrust/constants.ts | 7 +-- src/oneTrust/writeOneTrustAssessment.ts | 63 +++++++++++-------------- 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/src/oneTrust/codecs.ts b/src/oneTrust/codecs.ts index e04b2c59..441ab96f 100644 --- a/src/oneTrust/codecs.ts +++ b/src/oneTrust/codecs.ts @@ -1,7 +1,7 @@ /* eslint-disable max-lines */ import * as t from 'io-ts'; -// TODO: move all to privacy-types +// TODO: move to privacy-types export const OneTrustAssessmentCodec = t.type({ /** ID of the assessment. */ diff --git a/src/oneTrust/constants.ts b/src/oneTrust/constants.ts index bb34c2d2..3daa79e9 100644 --- a/src/oneTrust/constants.ts +++ b/src/oneTrust/constants.ts @@ -4,12 +4,13 @@ import { flattenOneTrustAssessment } from './flattenOneTrustAssessment'; /** * An object with default values of type OneTrustCombinedAssessmentCodec. It's very - * valuable when converting assessments to CSV. When we flatten it, the resulting - * value always contains all keys that eventually we add to the header. + * valuable when converting assessments to CSV, as it contains all keys that + * make up the CSV header in the expected order */ const DEFAULT_ONE_TRUST_COMBINED_ASSESSMENT: OneTrustCombinedAssessmentCodec = createDefaultCodec(OneTrustCombinedAssessmentCodec); -export const DEFAULT_ONE_TRUST_ASSESSMENT_CSV_KEYS = Object.keys( +/** The header of the OneTrust ASsessment CSV file */ +export const DEFAULT_ONE_TRUST_ASSESSMENT_CSV_HEADER = Object.keys( flattenOneTrustAssessment(DEFAULT_ONE_TRUST_COMBINED_ASSESSMENT), ); diff --git a/src/oneTrust/writeOneTrustAssessment.ts b/src/oneTrust/writeOneTrustAssessment.ts index da9f9747..530f3f0c 100644 --- a/src/oneTrust/writeOneTrustAssessment.ts +++ b/src/oneTrust/writeOneTrustAssessment.ts @@ -9,7 +9,7 @@ import { } from './codecs'; import fs from 'fs'; import { flattenOneTrustAssessment } from './flattenOneTrustAssessment'; -import { DEFAULT_ONE_TRUST_ASSESSMENT_CSV_KEYS } from './constants'; +import { DEFAULT_ONE_TRUST_ASSESSMENT_CSV_HEADER } from './constants'; /** * Write the assessment to disk at the specified file path. @@ -96,23 +96,24 @@ export const writeOneTrustAssessment = ({ fs.writeFileSync(file, '[\n'); } - // const stringifiedAssessment = JSON.stringify(enrichedAssessment, null, 2); + const stringifiedAssessment = JSON.stringify(enrichedAssessment, null, 2); - // // Add comma for all items except the last one - // const comma = index < total - 1 ? ',' : ''; + // Add comma for all items except the last one + const comma = index < total - 1 ? ',' : ''; - // // write to file - // fs.appendFileSync(file, stringifiedAssessment + comma); + // write to file + fs.appendFileSync(file, stringifiedAssessment + comma); - // // end with closing bracket - // if (index === total - 1) { - // fs.appendFileSync(file, ']'); - // } + // end with closing bracket + if (index === total - 1) { + fs.appendFileSync(file, ']'); + } } else if (fileFormat === OneTrustFileFormat.Csv) { - // flatten the json object - // start with an opening bracket + const csvRows = []; + + // write csv header at the beginning of the file if (index === 0) { - fs.writeFileSync('./oneTrust.json', '[\n'); + csvRows.push(DEFAULT_ONE_TRUST_ASSESSMENT_CSV_HEADER.join(',')); } // flatten the assessment object so it does not have nested properties @@ -122,29 +123,21 @@ export const writeOneTrustAssessment = ({ }); // transform the flat assessment to have all CSV keys in the expected order - const flatAssessmentWithCsvKeys = - DEFAULT_ONE_TRUST_ASSESSMENT_CSV_KEYS.reduce( - (acc, key) => ({ - ...acc, - [key]: flatAssessment[key] ?? '', - }), - {}, - ); - const csvEntry = JSON.stringify(flatAssessmentWithCsvKeys, null, 2); + const assessmentRow = DEFAULT_ONE_TRUST_ASSESSMENT_CSV_HEADER.map( + (header) => { + const value = flatAssessment[header] ?? ''; + // Escape values containing commas or quotes + return typeof value === 'string' && + (value.includes(',') || value.includes('"')) + ? `"${value.replace(/"/g, '""')}"` + : value; + }, + ); - // const stringifiedAssessment = JSON.stringify(enrichedAssessment, null, 2); + // append the rows to the file + csvRows.push(`${assessmentRow.join(',')}\n`); + fs.appendFileSync('./oneTrust.csv', csvRows.join('\n')); - // Add comma for all items except the last one - const comma = index < total - 1 ? ',' : ''; - - // TODO: might be better not to convert it to CSV at all! The importOneTrustAssessments does not actually accept CSV. - // write to file - // fs.appendFileSync(file, stringifiedAssessment + comma); - fs.appendFileSync('./oneTrust.json', csvEntry + comma); - - // end with closing bracket - if (index === total - 1) { - fs.appendFileSync('./oneTrust.json', ']'); - } + // TODO: consider not to convert it to CSV at all! The importOneTrustAssessments does not actually accept CSV. } };