510d7ca4ec
Primo passo della separazione sito / piattaforme decisa da Adriano il 03/09: due applicazioni autosufficienti, senza workspace di root, cosi' che ognuna resti un progetto Astro completo ed estraibile. Qui non cambia niente del codice: solo la radice. I pattern del .gitignore che avevano una barra erano ancorati alla radice e dopo lo spostamento non avrebbero piu' coperto niente (data/*.db*, uploads/*): resi validi a qualunque profondita'. Suite: 45 file, 347 test verdi prima e dopo lo spostamento. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EndnceRA5WnA6rvA5iV9WL
87 lines
4.0 KiB
JavaScript
87 lines
4.0 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Porta nel database i testi decisi dal cliente il 17/08/2026 (MODIFICHE_PER_SITO.pdf).
|
||
*
|
||
* Perché serve uno script e non basta il deploy: i testi mostrati dal sito vivono in
|
||
* `content_blocks`, e `resolveContent` legge **prima** il database e solo dopo il seed nel
|
||
* codice. Un tag già presente in tabella continua quindi a mostrare il vecchio valore anche
|
||
* dopo che il seed è stato aggiornato — in produzione sono 19 righe.
|
||
*
|
||
* Perché una tantum e non una migrazione all'avvio: una riscrittura a ogni restart
|
||
* rimetterebbe le mani su testi che il cliente può cambiare dal pannello. Qui si passa una
|
||
* volta, si guarda cosa è cambiato, e poi quei testi tornano suoi.
|
||
*
|
||
* Uso: node scripts/testi-17-agosto.mjs [percorso.db] [--dry-run]
|
||
*/
|
||
import Database from 'better-sqlite3';
|
||
|
||
/**
|
||
* "Small Group" diventa "Personalized Training Group", **con gli articoli giusti**.
|
||
*
|
||
* Una sostituzione meccanica produrrebbe "Lo Personalized Training Group" e "gli
|
||
* personalized training group": le due frasi che portano un articolo si correggono per
|
||
* intero, prima. Il resto è la sostituzione del nome, che resta capitalizzato come nome
|
||
* proprio anche dove prima era minuscolo ("in formula small group" → "in formula
|
||
* Personalized Training Group").
|
||
*
|
||
* Idempotente: al secondo giro non c'è più niente da sostituire.
|
||
*/
|
||
export function rinominaSmallGroup(value) {
|
||
return value
|
||
.replace(/\bLo Small Group\b/g, 'Il Personalized Training Group')
|
||
.replace(/\bgli small groups?\b/gi, 'i Personalized Training Group')
|
||
.replace(/\bsmall groups?\b/gi, 'Personalized Training Group');
|
||
}
|
||
|
||
/**
|
||
* I testi riscritti per intero, tag per tag: il cliente ne ha dettato il contenuto nuovo,
|
||
* quindi non c'è una parola da sostituire ma una frase da rimpiazzare.
|
||
*
|
||
* Sono solo i tag che in produzione esistono già con il valore vecchio. Quelli nuovi (la
|
||
* sezione «Check-up Avanzato», gli eventi, la pagina di scelta) non stanno in tabella e li
|
||
* serve il seed dal codice, senza bisogno di scriverli qui.
|
||
*/
|
||
export const TESTI = {
|
||
'service.profilazione.title': 'Check-up',
|
||
'service.profilazione.subtitle': 'Base e avanzato',
|
||
'service.profilazione.excerpt':
|
||
'Il Check-up Base fotografa la tua condizione di partenza e rappresenta il punto di inizio del metodo InsanityLab. Attraverso la profilazione e la valutazione fisica definiamo lo stato di salute iniziale e le priorità del percorso.\n\nIl Check-up Avanzato va oltre: con macchinari di ultima generazione misuriamo composizione corporea, parametri vitali, spirometria, HRV — un’analisi completa e scientifica che guida le nostre scelte.',
|
||
'footer.services.4.label': 'Check-up',
|
||
'services.meta.description':
|
||
'I servizi InsanityLab: Personal Training, Class, Coaching, Check-up, Osteopatia e Nutrizione.',
|
||
};
|
||
|
||
/** I cambiamenti da fare, con il prima e il dopo. Non tocca niente. */
|
||
export function calcola(db) {
|
||
const righe = db.prepare('SELECT tag, value FROM content_blocks').all();
|
||
return righe
|
||
.map((r) => ({
|
||
tag: r.tag,
|
||
prima: r.value,
|
||
dopo: r.tag in TESTI ? TESTI[r.tag] : rinominaSmallGroup(r.value),
|
||
}))
|
||
.filter((c) => c.prima !== c.dopo);
|
||
}
|
||
|
||
export function applica(db, { dryRun = false } = {}) {
|
||
const cambi = calcola(db);
|
||
if (!dryRun && cambi.length) {
|
||
const upd = db.prepare(
|
||
"UPDATE content_blocks SET value = ?, updated_at = datetime('now'), updated_by = 'testi-17-agosto' WHERE tag = ?",
|
||
);
|
||
db.transaction(() => { for (const c of cambi) upd.run(c.dopo, c.tag); })();
|
||
}
|
||
return cambi;
|
||
}
|
||
|
||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||
const args = process.argv.slice(2);
|
||
const dryRun = args.includes('--dry-run');
|
||
const path = args.find((a) => !a.startsWith('--')) ?? process.env.DB_PATH ?? 'data/insanitylab.db';
|
||
const db = new Database(path);
|
||
const cambi = applica(db, { dryRun });
|
||
for (const c of cambi) console.log(`${c.tag}\n - ${c.prima}\n + ${c.dopo}\n`);
|
||
console.log(`${cambi.length} contenuti ${dryRun ? 'da aggiornare (dry-run, niente scritto)' : 'aggiornati'} in ${path}`);
|
||
db.close();
|
||
}
|