email and fix
This commit is contained in:
298
database.js
298
database.js
@@ -174,9 +174,176 @@ function createSQLiteTables() {
|
||||
notification_key TEXT NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`);
|
||||
|
||||
|
||||
console.log('✅ База данных SQLite инициализирована');
|
||||
setTimeout(addMissingColumns, 1000);
|
||||
|
||||
// Добавляем таблицу для пользовательских настроек
|
||||
db.run(`CREATE TABLE IF NOT EXISTS user_settings (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER UNIQUE NOT NULL,
|
||||
email_notifications BOOLEAN DEFAULT true,
|
||||
notification_email TEXT,
|
||||
telegram_notifications BOOLEAN DEFAULT false,
|
||||
telegram_chat_id TEXT,
|
||||
vk_notifications BOOLEAN DEFAULT false,
|
||||
vk_user_id TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
)`);
|
||||
|
||||
console.log('✅ Таблица для пользовательских настроек инициализирована');
|
||||
|
||||
// Запускаем проверку и обновление структуры таблиц
|
||||
setTimeout(() => {
|
||||
checkAndUpdateTableStructure();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// Функция для проверки и обновления структуры таблиц
|
||||
function checkAndUpdateTableStructure() {
|
||||
console.log('🔍 Проверка структуры таблиц...');
|
||||
|
||||
// Определяем ожидаемую структуру таблиц
|
||||
const tableSchemas = {
|
||||
users: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'login', type: 'TEXT UNIQUE NOT NULL' },
|
||||
{ name: 'password', type: 'TEXT' },
|
||||
{ name: 'name', type: 'TEXT NOT NULL' },
|
||||
{ name: 'email', type: 'TEXT UNIQUE NOT NULL' },
|
||||
{ name: 'role', type: 'TEXT DEFAULT "teacher"' },
|
||||
{ name: 'auth_type', type: 'TEXT DEFAULT "local"' },
|
||||
{ name: 'groups', type: 'TEXT' },
|
||||
{ name: 'description', type: 'TEXT' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'last_login', type: 'DATETIME' },
|
||||
{ name: 'updated_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
],
|
||||
tasks: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'title', type: 'TEXT NOT NULL' },
|
||||
{ name: 'description', type: 'TEXT' },
|
||||
{ name: 'status', type: 'TEXT DEFAULT "active"' },
|
||||
{ name: 'created_by', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'updated_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'deleted_at', type: 'DATETIME' },
|
||||
{ name: 'deleted_by', type: 'INTEGER' },
|
||||
{ name: 'original_task_id', type: 'INTEGER' },
|
||||
{ name: 'start_date', type: 'DATETIME' },
|
||||
{ name: 'due_date', type: 'DATETIME' },
|
||||
{ name: 'rework_comment', type: 'TEXT' },
|
||||
{ name: 'closed_at', type: 'DATETIME' },
|
||||
{ name: 'closed_by', type: 'INTEGER' }
|
||||
],
|
||||
task_assignments: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'task_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'user_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'status', type: 'TEXT DEFAULT "assigned"' },
|
||||
{ name: 'start_date', type: 'DATETIME' },
|
||||
{ name: 'due_date', type: 'DATETIME' },
|
||||
{ name: 'rework_comment', type: 'TEXT' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'updated_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
],
|
||||
task_files: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'task_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'user_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'filename', type: 'TEXT NOT NULL' },
|
||||
{ name: 'original_name', type: 'TEXT NOT NULL' },
|
||||
{ name: 'file_path', type: 'TEXT NOT NULL' },
|
||||
{ name: 'file_size', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'uploaded_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
],
|
||||
activity_logs: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'task_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'user_id', type: 'INTEGER NOT NULL' },
|
||||
{ name: 'action', type: 'TEXT NOT NULL' },
|
||||
{ name: 'details', type: 'TEXT' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
],
|
||||
notification_logs: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'notification_key', type: 'TEXT NOT NULL' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
],
|
||||
user_settings: [
|
||||
{ name: 'id', type: 'INTEGER PRIMARY KEY AUTOINCREMENT' },
|
||||
{ name: 'user_id', type: 'INTEGER UNIQUE NOT NULL' },
|
||||
{ name: 'email_notifications', type: 'BOOLEAN DEFAULT true' },
|
||||
{ name: 'notification_email', type: 'TEXT' },
|
||||
{ name: 'telegram_notifications', type: 'BOOLEAN DEFAULT false' },
|
||||
{ name: 'telegram_chat_id', type: 'TEXT' },
|
||||
{ name: 'vk_notifications', type: 'BOOLEAN DEFAULT false' },
|
||||
{ name: 'vk_user_id', type: 'TEXT' },
|
||||
{ name: 'created_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'updated_at', type: 'DATETIME DEFAULT CURRENT_TIMESTAMP' }
|
||||
]
|
||||
};
|
||||
|
||||
// Проверяем каждую таблицу
|
||||
Object.entries(tableSchemas).forEach(([tableName, columns]) => {
|
||||
db.all(`PRAGMA table_info(${tableName})`, (err, existingColumns) => {
|
||||
if (err) {
|
||||
console.error(`❌ Ошибка проверки таблицы ${tableName}:`, err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingColumns.length === 0) {
|
||||
console.log(`⚠️ Таблица ${tableName} не существует, создаем...`);
|
||||
// Таблица будет создана автоматически при следующем запуске
|
||||
return;
|
||||
}
|
||||
|
||||
// Создаем массив имен существующих колонок
|
||||
const existingColumnNames = existingColumns.map(col => col.name.toLowerCase());
|
||||
|
||||
// Проверяем каждую ожидаемую колонку
|
||||
columns.forEach(expectedColumn => {
|
||||
const expectedName = expectedColumn.name.toLowerCase();
|
||||
|
||||
if (!existingColumnNames.includes(expectedName)) {
|
||||
console.log(`🔧 Добавляем колонку ${expectedColumn.name} в таблицу ${tableName}...`);
|
||||
|
||||
db.run(
|
||||
`ALTER TABLE ${tableName} ADD COLUMN ${expectedColumn.name} ${expectedColumn.type}`,
|
||||
(alterErr) => {
|
||||
if (alterErr) {
|
||||
console.error(`❌ Ошибка добавления колонки ${expectedColumn.name}:`, alterErr.message);
|
||||
} else {
|
||||
console.log(`✅ Колонка ${expectedColumn.name} добавлена в таблицу ${tableName}`);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Проверяем индекс для таблицы user_settings
|
||||
setTimeout(() => {
|
||||
db.get("SELECT name FROM sqlite_master WHERE type='index' AND name='idx_user_settings_user_id'", (err, index) => {
|
||||
if (err) {
|
||||
console.error('❌ Ошибка проверки индекса:', err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!index) {
|
||||
console.log('🔧 Создаем индекс для таблицы user_settings...');
|
||||
db.run("CREATE INDEX IF NOT EXISTS idx_user_settings_user_id ON user_settings(user_id)", (createErr) => {
|
||||
if (createErr) {
|
||||
console.error('❌ Ошибка создания индекса:', createErr.message);
|
||||
} else {
|
||||
console.log('✅ Индекс для user_settings создан');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function createPostgresAdapter(pool) {
|
||||
@@ -400,6 +567,22 @@ async function createPostgresTables() {
|
||||
)
|
||||
`);
|
||||
|
||||
// Добавляем таблицу для пользовательских настроек
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS user_settings (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER UNIQUE NOT NULL REFERENCES users(id),
|
||||
email_notifications BOOLEAN DEFAULT true,
|
||||
notification_email TEXT,
|
||||
telegram_notifications BOOLEAN DEFAULT false,
|
||||
telegram_chat_id TEXT,
|
||||
vk_notifications BOOLEAN DEFAULT false,
|
||||
vk_user_id TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
// Создаем индексы
|
||||
const indexes = [
|
||||
'CREATE INDEX IF NOT EXISTS idx_tasks_created_by ON tasks(created_by)',
|
||||
@@ -410,7 +593,8 @@ async function createPostgresTables() {
|
||||
'CREATE INDEX IF NOT EXISTS idx_task_assignments_status ON task_assignments(status)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_task_files_task_id ON task_files(task_id)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_activity_logs_task_id ON activity_logs(task_id)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_activity_logs_created_at ON activity_logs(created_at)'
|
||||
'CREATE INDEX IF NOT EXISTS idx_activity_logs_created_at ON activity_logs(created_at)',
|
||||
'CREATE INDEX IF NOT EXISTS idx_user_settings_user_id ON user_settings(user_id)'
|
||||
];
|
||||
|
||||
for (const indexQuery of indexes) {
|
||||
@@ -424,40 +608,91 @@ async function createPostgresTables() {
|
||||
client.release();
|
||||
console.log('✅ Таблицы PostgreSQL проверены/созданы');
|
||||
|
||||
// Проверяем структуру PostgreSQL таблиц
|
||||
await checkPostgresTableStructure();
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка создания таблиц PostgreSQL:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function addMissingColumns() {
|
||||
const columnsToAdd = [
|
||||
{ table: 'tasks', column: 'rework_comment', type: 'TEXT' },
|
||||
{ table: 'tasks', column: 'closed_at', type: 'DATETIME' },
|
||||
{ table: 'tasks', column: 'closed_by', type: 'INTEGER' },
|
||||
{ table: 'task_assignments', column: 'rework_comment', type: 'TEXT' }
|
||||
];
|
||||
|
||||
columnsToAdd.forEach(({ table, column, type }) => {
|
||||
db.all(`PRAGMA table_info(${table})`, (err, rows) => {
|
||||
if (err) {
|
||||
console.error(`Ошибка при проверке таблицы ${table}:`, err);
|
||||
return;
|
||||
}
|
||||
|
||||
const columnExists = rows.some(row => row.name === column);
|
||||
if (!columnExists) {
|
||||
db.run(`ALTER TABLE ${table} ADD COLUMN ${column} ${type}`, (err) => {
|
||||
if (err) {
|
||||
console.error(`Ошибка при добавлении колонки ${column} в таблицу ${table}:`, err);
|
||||
} else {
|
||||
console.log(`✅ Добавлена колонка ${column} в таблицу ${table}`);
|
||||
// Функция для проверки структуры таблиц PostgreSQL
|
||||
async function checkPostgresTableStructure() {
|
||||
if (!USE_POSTGRES) return;
|
||||
|
||||
try {
|
||||
const client = await postgresPool.connect();
|
||||
|
||||
console.log('🔍 Проверка структуры таблиц PostgreSQL...');
|
||||
|
||||
// Определяем ожидаемую структуру таблиц PostgreSQL
|
||||
const tableSchemas = {
|
||||
user_settings: [
|
||||
{ name: 'id', type: 'SERIAL PRIMARY KEY' },
|
||||
{ name: 'user_id', type: 'INTEGER UNIQUE NOT NULL REFERENCES users(id)' },
|
||||
{ name: 'email_notifications', type: 'BOOLEAN DEFAULT true' },
|
||||
{ name: 'notification_email', type: 'TEXT' },
|
||||
{ name: 'telegram_notifications', type: 'BOOLEAN DEFAULT false' },
|
||||
{ name: 'telegram_chat_id', type: 'TEXT' },
|
||||
{ name: 'vk_notifications', type: 'BOOLEAN DEFAULT false' },
|
||||
{ name: 'vk_user_id', type: 'TEXT' },
|
||||
{ name: 'created_at', type: 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP' },
|
||||
{ name: 'updated_at', type: 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP' }
|
||||
]
|
||||
};
|
||||
|
||||
// Проверяем каждую таблицу
|
||||
for (const [tableName, columns] of Object.entries(tableSchemas)) {
|
||||
try {
|
||||
// Проверяем существование таблицы
|
||||
const tableExists = await client.query(
|
||||
"SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $1)",
|
||||
[tableName]
|
||||
);
|
||||
|
||||
if (!tableExists.rows[0].exists) {
|
||||
console.log(`⚠️ Таблица ${tableName} не существует в PostgreSQL`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Получаем существующие колонки
|
||||
const existingColumns = await client.query(`
|
||||
SELECT column_name, data_type, is_nullable, column_default
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = $1
|
||||
ORDER BY ordinal_position
|
||||
`, [tableName]);
|
||||
|
||||
const existingColumnNames = existingColumns.rows.map(col => col.column_name.toLowerCase());
|
||||
|
||||
// Проверяем каждую ожидаемую колонку
|
||||
for (const expectedColumn of columns) {
|
||||
const expectedName = expectedColumn.name.toLowerCase();
|
||||
|
||||
if (!existingColumnNames.includes(expectedName)) {
|
||||
console.log(`🔧 Добавляем колонку ${expectedColumn.name} в таблицу PostgreSQL ${tableName}...`);
|
||||
|
||||
try {
|
||||
await client.query(
|
||||
`ALTER TABLE ${tableName} ADD COLUMN ${expectedColumn.name} ${expectedColumn.type}`
|
||||
);
|
||||
console.log(`✅ Колонка ${expectedColumn.name} добавлена в таблицу PostgreSQL ${tableName}`);
|
||||
} catch (alterErr) {
|
||||
console.error(`❌ Ошибка добавления колонки ${expectedColumn.name}:`, alterErr.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(`✅ Колонка ${column} уже существует в таблице ${table}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Ошибка проверки таблицы PostgreSQL ${tableName}:`, error.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
client.release();
|
||||
console.log('✅ Проверка структуры таблиц PostgreSQL завершена');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка проверки структуры таблиц PostgreSQL:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function createTaskFolder(taskId) {
|
||||
@@ -598,7 +833,8 @@ module.exports = {
|
||||
updateTaskMetadata,
|
||||
checkTaskAccess,
|
||||
USE_POSTGRES,
|
||||
getDatabaseType: () => USE_POSTGRES ? 'PostgreSQL' : 'SQLite'
|
||||
getDatabaseType: () => USE_POSTGRES ? 'PostgreSQL' : 'SQLite',
|
||||
checkAndUpdateTableStructure // Экспортируем для ручного запуска
|
||||
};
|
||||
|
||||
// Запускаем инициализацию при экспорте (но она завершится позже)
|
||||
|
||||
Reference in New Issue
Block a user