c0af5502bf
Политика «все учебники наши»: нигде не упоминаются сторонние авторы. - Миграции (15 файлов): колонка author → 'LearnSpace'; из описаний убран оборот «по учебнику <автор>:»; авторские фамилии вычищены из комментариев. Покрыты Арефьева/Пирютко, Казаков, Латотин/Чеботаревский/Горбунова/Цыбулько, Исаченкова, Жилко/Маркович/Сокольский, Герасимов/Лобанов. - HTML: physics_9_ch5 («по канве учебника Исаченковой» → «по учебной программе»), physics_11_hub (hdr-sub с авторами → описание курса), mocks-redesign (карточки-авторы → LearnSpace). - Генераторы gen_phys9_ch.js/gen_phys11_stubs.js — шаблоны без авторов. - НОВОЕ: update_textbook_authors.js — идемпотентный апдейтер ЖИВОЙ БД (миграции уже применены): author→'LearnSpace' у всех 107 учебников + чистка описаний. DRY-RUN по умолч. ⚠️ Живую БД правит ПОЛЬЗОВАТЕЛЬ: node backend/scripts/update_textbook_authors.js --apply (в БД сейчас author пуст у всех, видимые упоминания были в описаниях «по учебнику …»). review_geom10/11.js не тронуты — там фамилии как поисковые шаблоны детектора, не атрибуция. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
3.8 KiB
JavaScript
71 lines
3.8 KiB
JavaScript
'use strict';
|
||
/* ───────────────────────────────────────────────────────────────────────────
|
||
update_textbook_authors.js
|
||
Приводит метаданные учебников к политике «все учебники наши»:
|
||
• колонка textbooks.author → 'LearnSpace' (у всех учебников и их глав);
|
||
• в textbooks.description убирается оборот «по учебнику <автор>:» → «:».
|
||
|
||
Миграции 004/008/017–027/031/038/049/050 уже применены к БД с фамилиями сторонних
|
||
авторов — их исходники почищены, но ЖИВУЮ БД правит этот идемпотентный скрипт.
|
||
|
||
Запуск:
|
||
node backend/scripts/update_textbook_authors.js # DRY-RUN (по умолчанию)
|
||
node backend/scripts/update_textbook_authors.js --apply # запись в БД
|
||
|
||
⚠️ Массовую запись в БД запускает ПОЛЬЗОВАТЕЛЬ вручную. Без --apply ничего не пишется.
|
||
─────────────────────────────────────────────────────────────────────────── */
|
||
|
||
const { DatabaseSync } = require('node:sqlite');
|
||
const path = require('path');
|
||
|
||
const APPLY = process.argv.includes('--apply');
|
||
const AUTHOR = 'LearnSpace';
|
||
const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
|
||
|
||
const stripDesc = d => (d ? d.replace(/ по учебнику [^:]*:/g, ':') : d);
|
||
|
||
const db = new DatabaseSync(DB);
|
||
|
||
// есть ли таблица/колонки
|
||
const cols = db.prepare(`PRAGMA table_info(textbooks)`).all().map(c => c.name);
|
||
if (!cols.includes('author')) { console.error('✗ В таблице textbooks нет колонки author. Прерывание.'); db.close(); process.exit(1); }
|
||
|
||
const rows = db.prepare(`SELECT id, slug, author, description FROM textbooks`).all();
|
||
const changes = [];
|
||
for (const r of rows) {
|
||
const newDesc = stripDesc(r.description);
|
||
const authorChange = (r.author || '') !== AUTHOR;
|
||
const descChange = newDesc !== r.description;
|
||
if (authorChange || descChange) changes.push({ id: r.id, slug: r.slug, oldAuthor: r.author, authorChange, descChange, newDesc });
|
||
}
|
||
|
||
console.log(`\n=== update_textbook_authors (учебников: ${rows.length}) ===`);
|
||
console.log(`Режим: ${APPLY ? 'APPLY (запись)' : 'DRY-RUN (только показ)'}\n`);
|
||
console.log(`Под изменение: ${changes.length}`);
|
||
for (const c of changes) {
|
||
const tags = [c.authorChange ? `author: ${c.oldAuthor || '∅'} → ${AUTHOR}` : null, c.descChange ? 'описание: убран «по учебнику …»' : null].filter(Boolean).join('; ');
|
||
console.log(` ${String(c.slug).padEnd(20)} ${tags}`);
|
||
}
|
||
|
||
if (!changes.length) { console.log('\nНечего менять — БД уже чистая.'); db.close(); process.exit(0); }
|
||
|
||
if (!APPLY) {
|
||
console.log('\nDRY-RUN: ничего не записано. Для записи: node backend/scripts/update_textbook_authors.js --apply\n');
|
||
db.close();
|
||
process.exit(0);
|
||
}
|
||
|
||
const upd = db.prepare(`UPDATE textbooks SET author = ?, description = ? WHERE id = ?`);
|
||
let n = 0;
|
||
db.exec('BEGIN');
|
||
try {
|
||
for (const c of changes) { upd.run(AUTHOR, c.newDesc, c.id); n++; }
|
||
db.exec('COMMIT');
|
||
console.log(`\n✓ Обновлено строк: ${n}. Все учебники → author='${AUTHOR}', обороты «по учебнику …» убраны.\n`);
|
||
} catch (e) {
|
||
db.exec('ROLLBACK');
|
||
console.error('\n✗ Ошибка записи, откат:', e.message);
|
||
process.exitCode = 1;
|
||
}
|
||
db.close();
|