@getanthill/datastore
Version:
Event-Sourced Datastore
372 lines (312 loc) • 7.88 kB
JavaScript
const fs = require('fs');
const merge = require('lodash/merge');
const { Datastore } = require('../../dist/sdk');
const DEFAULT_CONFIG = {
sections: [
'purpose',
'owner',
'persons',
'recipients',
'duration',
'security_policies',
'updated_at',
],
i18n: {
title: 'Data Processings',
'section.purpose': 'Purpose',
'section.owner': 'Responsible for processing personal data',
'section.contact-details': 'Contact Details',
'section.persons': 'Categories of people concerned',
'section.recipients': 'Categories of recipients of data',
'section.duration': 'Shelf life of data',
'section.security_policies': 'Security Policies',
'section.updated_at': 'Updated At',
activity: 'Activity',
address: 'Address',
email: 'Email',
phone: 'Phone',
url: 'URL',
},
persons: {
users: 'Users of the platform',
},
};
function i18n(config, key, defaultValue = key) {
if (process.env.I18N_DISABLED === 'false') {
return key;
}
return config.i18n[key] ?? defaultValue;
}
function buildHeader(config) {
return `
# ${i18n(config, 'title')}
${config.header}
`;
}
function buildFooter(config) {
return `
${config.footer ?? i18n(config, 'title', '')}
`;
}
function buildSection(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
section,
) {
return `
#### ${i18n(config, 'section.' + section)}
${
config[section] ??
i18n(
config,
`${modelConfig.name}.${processing.field}.${processing.name}.${section}`,
processing[section],
)
}
`;
}
function buildCategory(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.category')}
${i18n(config, `category.${processing.category}`, processing.category)}
`;
}
function buildOwner(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
const owner = processing.owner || config.owner;
return `
#### ${i18n(config, 'section.owner')}
${owner.name}
#### ${i18n(config, 'section.contact-details')}
| <!-- --> | <!-- --> |
|-------------|-------------|
| ${i18n(config, 'address')} | ${owner.location?.address ?? '<address>'} - ${
owner.location?.postal_code ?? '<postal_code>'
} ${owner.location?.city ?? '<city>'} |
| ${i18n(config, 'email')} | ${owner.email ?? 'NA'} |
| ${i18n(config, 'phone')} | ${owner.phone ?? 'NA'} |
| ${i18n(config, 'url')} | ${owner.url ?? 'NA'} |
`;
}
function buildSource(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.source')}
${i18n(config, `roles.${processing.source}`, processing.source)}.`;
}
function buildPersons(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.persons')}
| <!-- --> | <!-- --> |
|-------------|-------------|
${processing.persons
.map((p) => `| \`${p}\` | ${i18n(config, `roles.${p}`, p ?? 'NA')} |`)
.join('\n')}
`;
}
function buildRecipients(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.recipients')}
| <!-- --> | <!-- --> |
|-------------|-------------|
${processing.recipients
.map((r) => `| \`${r}\` | ${i18n(config, `roles.${r}`, r ?? 'NA')} |`)
.join('\n')}
`;
}
function buildDuration(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.duration')}
- ${Math.round(processing.duration_in_seconds / (60 * 60 * 24 * 365))} years
- ${Math.round(processing.duration_in_seconds / (60 * 60 * 24 * 30))} months
- ${Math.round(processing.duration_in_seconds / (60 * 60 * 24))} days
- ${Math.round(processing.duration_in_seconds / (60 * 60))} hours
- ${Math.round(processing.duration_in_seconds / 60)} minutes
- ${processing.duration_in_seconds} seconds
`;
}
function buildUpdatedAt(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
return `
#### ${i18n(config, 'section.updated_at')}
${new Date(modelConfig.updated_at).toLocaleDateString(config.locale || 'en', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
})}
`;
}
function withSection(body, property, config, modelConfig, processing, pi, ai) {
if (property === 'updated_at') {
body += buildUpdatedAt(config, modelConfig, processing, pi, ai);
}
if (!processing[property] && !config[property]) {
return body;
}
switch (property) {
case 'owner':
body += buildOwner(config, modelConfig, processing, pi, ai);
break;
case 'category':
body += buildCategory(config, modelConfig, processing, pi, ai);
break;
case 'source':
body += buildSource(config, modelConfig, processing, pi, ai);
break;
case 'persons':
body += buildPersons(config, modelConfig, processing, pi, ai);
break;
case 'recipients':
body += buildRecipients(config, modelConfig, processing, pi, ai);
break;
case 'duration_in_seconds':
body += buildDuration(config, modelConfig, processing, pi, ai);
break;
default:
if (processing[property] || config[property]) {
body += buildSection(config, modelConfig, processing, pi, ai, property);
}
}
return body;
}
function buildProcessing(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
) {
let body = '\n<div class="page"/>\n\n';
if (processingIndex === 0) {
body +=
'## ' +
i18n(config, `model.${modelConfig.name}`, `${modelConfig.name}`) +
'\n\n';
}
body +=
'### ' +
i18n(config, 'activity') +
' ' +
(activityIndex + 1) +
'.' +
(processingIndex + 1) +
' - ' +
i18n(
config,
`field.${modelConfig.name}.${processing.field}`,
`\`${processing.field}\``,
) +
' - ' +
i18n(config, 'processing.' + processing.name, null) ??
processing.name + '\n\n';
for (const section of config.sections) {
body = withSection(
body,
section,
config,
modelConfig,
processing,
processingIndex,
activityIndex,
);
}
body += '\n---\n';
return body;
}
function buildProcessings(config, modelConfig, processings, activityIndex) {
let body = '';
body += processings
.map((processing, processingIndex) =>
buildProcessing(
config,
modelConfig,
processing,
processingIndex,
activityIndex,
),
)
.join(`\n`);
return body;
}
async function main(configPath) {
console.log('[gdpr#processings] Starting the generation...');
const datastore = new Datastore({
baseUrl: process.env.DATASTORE_API_URL || 'http://localhost:3001',
token: process.env.DATASTORE_ACCESS_TOKEN || 'token',
debug: false,
});
const { data: models } = await datastore.getModels();
const config = require(configPath);
const buildConfig = merge({}, DEFAULT_CONFIG, config);
let body = buildHeader(buildConfig);
let activityIndex = -1;
for (const modelConfig of Object.values(models)) {
if (config.only?.length > 0 && !config.only.includes(modelConfig.name)) {
continue;
}
const processings = modelConfig.processings ?? [];
if (processings.length === 0) {
continue;
}
activityIndex += 1;
body += buildProcessings(
buildConfig,
modelConfig,
processings,
activityIndex,
);
}
body += buildFooter(buildConfig);
fs.writeFileSync('/tmp/processings.md', body);
console.log('[gdpr#processings] Generation ended successfully');
}
main(...process.argv.slice(2)).catch((err) => {
console.error(err);
if (err?.response?.data) {
console.error('[gdpr#processings] Error', err?.response?.data);
}
process.exit(1);
});