feat: добавлен режим "Каникулы" и улучшения админ-панели
- Добавлен режим "Каникулы" который полностью заменяет главную страницу:
* Карточка с эмодзи 🎉 и праздничным сообщением
* Поддержка произвольного текста в формате Markdown
* Карточка центрируется по вертикали при отсутствии текста
- Улучшения админ-панели:
* Переключатель режима "Каникулы"
* Редактор текста с подсказками по форматированию Markdown
* Исправлена проблема с обновлением настроек (сохранение существующих значений)
* Исправлена проблема с debug опциями в production (не блокируют обновление обычных настроек)
- Оптимизация загрузки:
* Проверка режима каникул перед загрузкой групп
* Динамическая загрузка ReactMarkdown только при необходимости
* Кеш настроек сбрасывается на главной странице для актуальности
- Добавлен скрипт для сброса пароля администратора (scripts/reset-admin-password.js)
- Установлена библиотека react-markdown для рендеринга Markdown контента
This commit is contained in:
121
scripts/reset-admin-password.js
Executable file
121
scripts/reset-admin-password.js
Executable file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Скрипт для сброса пароля администратора
|
||||
*
|
||||
* Использование:
|
||||
* node scripts/reset-admin-password.js [новый_пароль]
|
||||
* или
|
||||
* node scripts/reset-admin-password.js (интерактивный режим)
|
||||
*/
|
||||
|
||||
const Database = require('better-sqlite3');
|
||||
const bcrypt = require('bcrypt');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const readline = require('readline');
|
||||
|
||||
// Определяем путь к базе данных
|
||||
function findDatabase() {
|
||||
const possiblePaths = [
|
||||
path.join(process.cwd(), 'data', 'schedule-app.db'),
|
||||
path.join(process.cwd(), '.next', 'standalone', 'data', 'schedule-app.db'),
|
||||
'/opt/kspguti-schedule/data/schedule-app.db',
|
||||
'/opt/kspguti-schedule/.next/standalone/data/schedule-app.db',
|
||||
];
|
||||
|
||||
for (const dbPath of possiblePaths) {
|
||||
if (fs.existsSync(dbPath)) {
|
||||
return dbPath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Функция для чтения пароля из терминала (простая версия)
|
||||
function readPassword(prompt) {
|
||||
return new Promise((resolve) => {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
rl.question(prompt, (password) => {
|
||||
rl.close();
|
||||
resolve(password);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('🔐 Сброс пароля администратора\n');
|
||||
|
||||
// Находим базу данных
|
||||
const dbPath = findDatabase();
|
||||
if (!dbPath) {
|
||||
console.error('❌ Ошибка: База данных не найдена!');
|
||||
console.log('\nИскали в следующих местах:');
|
||||
console.log(' - ' + path.join(process.cwd(), 'data', 'schedule-app.db'));
|
||||
console.log(' - ' + path.join(process.cwd(), '.next', 'standalone', 'data', 'schedule-app.db'));
|
||||
console.log(' - /opt/kspguti-schedule/data/schedule-app.db');
|
||||
console.log(' - /opt/kspguti-schedule/.next/standalone/data/schedule-app.db');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('✓ Найдена база данных: ' + dbPath + '\n');
|
||||
|
||||
// Получаем новый пароль
|
||||
let newPassword;
|
||||
if (process.argv[2]) {
|
||||
newPassword = process.argv[2];
|
||||
} else {
|
||||
newPassword = await readPassword('Введите новый пароль (минимум 8 символов): ');
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
console.error('❌ Ошибка: Пароль должен содержать минимум 8 символов');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const confirmPassword = await readPassword('Подтвердите пароль: ');
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
console.error('❌ Ошибка: Пароли не совпадают');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (newPassword.length < 8) {
|
||||
console.error('❌ Ошибка: Пароль должен содержать минимум 8 символов');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Открываем базу данных и обновляем пароль
|
||||
try {
|
||||
console.log('\n⏳ Обновление пароля...');
|
||||
|
||||
const db = new Database(dbPath);
|
||||
|
||||
// Хешируем новый пароль
|
||||
const saltRounds = 10;
|
||||
const hash = bcrypt.hashSync(newPassword, saltRounds);
|
||||
|
||||
// Обновляем пароль в базе данных
|
||||
db.prepare('INSERT OR REPLACE INTO admin_password (id, password_hash) VALUES (1, ?)').run(hash);
|
||||
|
||||
db.close();
|
||||
|
||||
console.log('✅ Пароль успешно изменен!');
|
||||
console.log('\n⚠️ ВАЖНО: Сохраните пароль в безопасном месте!');
|
||||
if (process.argv[2]) {
|
||||
console.log('Новый пароль: ' + newPassword);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при изменении пароля:');
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user