22c7b38e9a
Добавлено такое же действие, как [Z] в control-panel: POST /api/admin/reset-system (+ /reset-system/plan для предпросмотра), только admin. Общая логика вынесена в src/services/systemReset.js (classify/pickKeptAdmin/runReset) — реюзится CLI и эндпоинтом. Веб-эндпоинт безопаснее CLI: сохраняет ТЕКУЩЕГО админа (оператор остаётся залогинен), делает бэкап БД ДО сброса (wal_checkpoint + копия в data/backups/), требует body.confirm='СБРОС'. UI — «Опасная зона» в overview-секции: предпросмотр плана + ввод «СБРОС» + результат с именем бэкапа. db.js: добавлен db._path (нужен бэкапу при сбросе). Логика проверена смоуком на копии живой БД (16 юзеров удалено, контент сохранён, REASSIGN на админа, гейм-счётчики обнулены, 0 висячих FK). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
62 lines
4.0 KiB
JavaScript
62 lines
4.0 KiB
JavaScript
'use strict';
|
|
/* ───────────────────────────────────────────────────────────────────────────
|
|
reset-system.js — CLI «ЧИСТЫЙ ЗАПУСК» (тонкая обёртка над src/services/systemReset.js).
|
|
|
|
⚠️ ДЕСТРУКТИВНО. По умолчанию DRY-RUN. Выполнение — только с --apply --confirm=RESET.
|
|
Перед сбросом сделайте бэкап (control-panel «Бэкап БД» делает автоматически).
|
|
Та же логика доступна в админ-веб-панели (POST /api/admin/reset-system).
|
|
|
|
Запуск:
|
|
node backend/scripts/reset-system.js # план
|
|
node backend/scripts/reset-system.js --apply --confirm=RESET # выполнить
|
|
─────────────────────────────────────────────────────────────────────────── */
|
|
|
|
const { DatabaseSync } = require('node:sqlite');
|
|
const path = require('path');
|
|
const reset = require('../src/services/systemReset');
|
|
|
|
const APPLY = process.argv.includes('--apply');
|
|
const CONFIRM = process.argv.includes('--confirm=RESET');
|
|
|
|
const DB = path.join(__dirname, '..', 'data', 'learnspace.db');
|
|
const db = new DatabaseSync(DB);
|
|
|
|
const keptAdmin = reset.pickKeptAdmin(db);
|
|
if (!keptAdmin) {
|
|
console.error('✗ В системе нет ни одного админа — сброс отменён (иначе залочитесь). Создайте админа сначала.');
|
|
db.close(); process.exit(1);
|
|
}
|
|
|
|
const plan = reset.classify(db);
|
|
console.log(`\n=== reset-system «ЧИСТЫЙ ЗАПУСК» (${APPLY ? (CONFIRM ? 'APPLY' : 'нужен --confirm=RESET') : 'DRY-RUN'}) ===`);
|
|
console.log(`Сохраняемый админ: id=${keptAdmin.id} ${keptAdmin.email} «${keptAdmin.name}»`);
|
|
console.log(`Пользователей: ${plan.totalUsers} → останется 1, удалится ${plan.totalUsers - 1}\n`);
|
|
console.log('REASSIGN (контент → админу):');
|
|
plan.reassign.forEach(r => console.log(` ${r.table.padEnd(22)} ${r.col.padEnd(12)} строк: ${r.rows}`));
|
|
console.log('\nWIPE (полная очистка):');
|
|
plan.wipe.forEach(w => console.log(` ${w.table.padEnd(28)} строк: ${w.rows}`));
|
|
console.log(` — всего к удалению (без каскада users): ~${plan.wipeRows}`);
|
|
console.log(`\nKEEP (контент/конфиг): ${plan.keepCount} таблиц.`);
|
|
if (plan.unknown.length) console.log(`\n⚠️ НЕИЗВЕСТНЫЕ таблицы (НЕ трогаем): ${plan.unknown.join(', ')}`);
|
|
|
|
if (!APPLY) {
|
|
console.log('\nDRY-RUN: ничего не изменено. Выполнить: node backend/scripts/reset-system.js --apply --confirm=RESET\n');
|
|
db.close(); process.exit(0);
|
|
}
|
|
if (!CONFIRM) {
|
|
console.error('\n✗ Нужен флаг --confirm=RESET (защита от случайного запуска). Отмена.');
|
|
db.close(); process.exit(1);
|
|
}
|
|
|
|
try {
|
|
const res = reset.runReset(db, keptAdmin.id);
|
|
console.log(`\n✓ ЧИСТЫЙ ЗАПУСК выполнен. Удалено пользователей: ${res.deletedUsers}, осталось: ${res.remainingUsers}.`);
|
|
console.log(`✓ Контент сохранён: учебники ${res.kept.textbooks}, вопросы ${res.kept.questions}, тесты ${res.kept.tests}, курсы ${res.kept.courses}, exam-prep ${res.kept.exam_tasks}.`);
|
|
if (res.fkDangling) console.log(`⚠️ foreign_key_check: ${res.fkDangling} висячих ссылок — проверьте.`);
|
|
console.log(`\nВойдите под ${keptAdmin.email}. Перезапустите сервер.\n`);
|
|
} catch (e) {
|
|
console.error('\n✗ Ошибка — откат, изменений нет:', e.message);
|
|
db.close(); process.exit(1);
|
|
}
|
|
db.close();
|