feat: add redirect processing script

This commit is contained in:
Michael Zetterberg
2025-05-21 13:24:08 +02:00
parent e2a4fa6c07
commit c52da4bec6
7 changed files with 171 additions and 0 deletions

2
apps/scandic-redirect/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
scripts/csv/*.csv
scripts/json/*.json

View File

@@ -6,3 +6,20 @@ This function will be called by the `web` app's middleware to check if the incom
The "source of truth" for which URLs should be redirected where will be provided by the SEO team and put in a JSON file within this app.
If no match for the incoming request is found, the request is passed on through the middleware.
## Update the redirects from the source
The Excel source file used is located at:
https://scandichotelsab.sharepoint.com/:x:/s/921-ContentNewweb/ETGStOQAARtJhJXG9dy8ijYBccpmKhLVjS2SF_2E69QrAQ
- Open it
- Each domain/language has its own sheet
- Export each sheet into their respective language code
- File > Export > Download as CSV UTF-8
- Save as [lang].csv in `./scripts/csv` folder
- Run the `update` script target
- E.g. `yarn workspace @scandic-hotels/scandic-redirect update`
- Commit and push the JSON files in `./netlify/functions/data`.
- Create a PR
- Profit!

View File

@@ -5,5 +5,11 @@
"packageManager": "yarn@4.6.0",
"dependencies": {
"@netlify/functions": "^3.0.0"
},
"devDependencies": {
"convert-csv-to-json": "^3.4.0"
},
"scripts": {
"update": "node ./scripts/update.mjs"
}
}

View File

@@ -0,0 +1,138 @@
import fs from 'node:fs';
import path from 'node:path';
import csvToJson from 'convert-csv-to-json';
const langs = ['da', 'de', 'en', 'fi', 'no', 'sv'];
const csvHeaders = {
current: 'Current URL',
redirect: 'Redirect URL',
};
function csvFilePath(lang) {
return `${import.meta.dirname}/csv/${lang}.csv`;
}
function jsonFilePath(lang) {
return `${import.meta.dirname}/json/${lang}.json`;
}
function outputFilepath(lang) {
return path.resolve(
import.meta.dirname,
`../netlify/functions/data/${lang}.json`
);
}
function removeDomain(str) {
return str.replace(
/^https?:\/\/((www|test|stage|prod)\.)?scandichotels.(com|de|dk|fi|no|se)/,
''
);
}
function akamaiRedirect(str) {
return str.replace(
/^https?:\/\/((www|test|stage|prod)\.)?scandichotels.(com|de|dk|fi|no|se)/,
(...match) => {
if (match[3]) {
switch (match[3]) {
case 'com':
return '/en';
case 'de':
return '/de';
case 'dk':
return '/da';
case 'fi':
return '/fi';
case 'no':
return '/no';
case 'se':
return '/sv';
}
}
return '';
}
);
}
function checkPrerequisites() {
const missingLangs = langs.reduce((acc, lang) => {
const filepath = csvFilePath(lang);
if (!fs.existsSync(filepath)) {
acc.push(filepath);
}
return acc;
}, []);
if (missingLangs.length > 0) {
console.error(`Missing CSV file:\n${missingLangs.join('\n')}`);
process.exit(1);
}
}
// convert-csv-to-json writes async without callback support
// so we workaround it be overriding console.log which it uses when it is done
async function convertCsvToJson() {
return new Promise((resolve, reject) => {
const _consoleLog = console.log;
let resolved = 0;
console.log = function (str) {
if (str.indexOf('File saved:') >= 0) {
resolved++;
}
if (resolved === langs.length) {
console.log = _consoleLog;
resolve();
}
};
for (const lang of langs) {
csvToJson
.utf8Encoding()
.fieldDelimiter(',')
.generateJsonFileFromCsv(csvFilePath(lang), jsonFilePath(lang));
}
setTimeout(() => {
reject('timeout');
}, 5000);
});
}
async function makeOutput() {
for (const lang of langs) {
try {
const json = JSON.parse(
fs.readFileSync(jsonFilePath(lang), {
encoding: 'utf-8',
})
);
if (Array.isArray(json)) {
const finalUrls = json.reduce((acc, url) => {
const from = removeDomain(akamaiRedirect(url[csvHeaders.current]));
const to = removeDomain(url[csvHeaders.redirect]);
return {
...acc,
[from]: to,
};
}, {});
fs.writeFileSync(outputFilepath(lang), JSON.stringify(finalUrls), {
encoding: 'utf-8',
});
} else {
throw new Error(`JSON was not an array: ${jsonFilePath(lang)}`);
}
} catch (e) {
console.error(e);
}
}
}
checkPrerequisites();
await convertCsvToJson();
await makeOutput();

View File

@@ -7052,6 +7052,7 @@ __metadata:
resolution: "@scandic-hotels/scandic-redirect@workspace:apps/scandic-redirect"
dependencies:
"@netlify/functions": "npm:^3.0.0"
convert-csv-to-json: "npm:^3.4.0"
languageName: unknown
linkType: soft
@@ -11775,6 +11776,13 @@ __metadata:
languageName: node
linkType: hard
"convert-csv-to-json@npm:^3.4.0":
version: 3.4.0
resolution: "convert-csv-to-json@npm:3.4.0"
checksum: 10c0/06ec3cb348591322b9b2083464eff41907688d6eb4cb8b364d7d969ea08eb559d872733292034f72dcf404fe3150def092194ccfe14d89ded3b35dfc694fdb87
languageName: node
linkType: hard
"convert-source-map@npm:^2.0.0":
version: 2.0.0
resolution: "convert-source-map@npm:2.0.0"