#include "udatabase.h" #include #include #include #include #include "qlistwidget.h" #include "webserverchat.h" uDataBase::uDataBase(const QString& dbFileName, QObject* parent) : QObject(parent) , m_dbFileName(dbFileName) { // Создаем уникальное имя подключения QString connectionName = QString("settings_connection_%1").arg((quintptr)this); // Открываем базу данных m_db = QSqlDatabase::addDatabase("QSQLITE", connectionName); m_db.setDatabaseName(m_dbFileName); if (!m_db.open()) { m_lastError = m_db.lastError().text(); qWarning() << "Failed to open database:" << m_lastError; return; } // Инициализируем базу данных if (!initializeDatabase()) { qWarning() << "Failed to initialize database"; } } uDataBase::~uDataBase() { if (m_db.isOpen()) { QString connectionName = m_db.connectionName(); m_db.close(); m_db = QSqlDatabase(); // сбрасываем объект базы данных QSqlDatabase::removeDatabase(connectionName); // удаляем соединение } } bool uDataBase::close() { if (!isConnected()) { return true; // Уже закрыто } // Сохраняем имя соединения перед закрытием QString connectionName = m_db.connectionName(); // Закрываем базу данных m_db.close(); // Очищаем объект базы данных m_db = QSqlDatabase(); // Удаляем соединение из пула Qt QSqlDatabase::removeDatabase(connectionName); return true; } bool uDataBase::initializeDatabase() { // Создаем таблицу настроек, если она не существует QString createTableQuery = "CREATE TABLE IF NOT EXISTS params (" "name TEXT PRIMARY KEY," "value TEXT" ")"; QSqlQuery query(m_db); if (!query.exec(createTableQuery)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create table:" << m_lastError; return false; } // Создаем таблицу для чатов if (!createChatsTable()) { qWarning() << "Failed to create chats table"; // Продолжаем, даже если не удалось создать таблицу чатов } return true; } QString uDataBase::readSetting(const QString& aName, const QString& aDefault) { if (!m_db.isOpen()) { qWarning() << "Database is not open"; return aDefault; } QSqlQuery query(m_db); query.prepare("SELECT value FROM params WHERE name = :name"); query.bindValue(":name", aName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to read setting" << aName << ":" << m_lastError; return aDefault; } if (query.next()) { return query.value(0).toString(); } // Если настройка не найдена, возвращаем значение по умолчанию return aDefault; } bool uDataBase::writeSetting(const QString& aName, const QString& aValue) { if (!m_db.isOpen()) { qWarning() << "Database is not open"; return false; } // Используем INSERT OR REPLACE для обновления существующей записи или создания новой QSqlQuery query(m_db); query.prepare( "INSERT OR REPLACE INTO params (name, value) " "VALUES (:name, :value)" ); query.bindValue(":name", aName); query.bindValue(":value", aValue); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to write setting" << aName << ":" << m_lastError; return false; } return true; } // В классе uDataBase добавьте эти методы: /** * @brief Специальная загрузка для таблицы таймеров с сохранением состояния * @param tableWidget Таблица для загрузки * @param timers Список таймеров для заполнения * @return true если успешно */ bool uDataBase::LoadTimers(QTableWidget *tableWidget, QList &timers) { if (!tableWidget) { m_lastError = "Table widget is null"; qWarning() << m_lastError; return false; } // Получаем имя таблицы из objectName виджета QString tableName = tableWidget->objectName(); if (tableName.isEmpty()) { m_lastError = "Table widget has no object name"; qWarning() << m_lastError; return false; } // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Очищаем таблицу и список таймеров tableWidget->setRowCount(0); timers.clear(); // Выполняем SQL запрос QSqlQuery query(m_db); QString sql = QString("SELECT * FROM %1 ORDER BY id").arg(tableName); if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Query failed:" << m_lastError; qWarning() << "SQL:" << sql; return false; } int rowCount = 0; while (query.next()) { // Создаем объект таймера TimerInfo timer; timer.id = query.value("id").toInt(); timer.message = query.value("message").toString(); timer.interval = query.value("interval").toInt(); timer.isActive = query.value("is_active").toBool(); timer.isAnnouncement = query.value("is_announcement").toBool(); timer.timer = nullptr; // Добавляем в список timers.append(timer); // Добавляем строку в таблицу int row = tableWidget->rowCount(); tableWidget->insertRow(row); // Чекбокс "Вкл" QTableWidgetItem* enabledItem = new QTableWidgetItem(); enabledItem->setCheckState(timer.isActive ? Qt::Checked : Qt::Unchecked); tableWidget->setItem(row, 0, enabledItem); // Сообщение QTableWidgetItem* messageItem = new QTableWidgetItem(timer.message); tableWidget->setItem(row, 1, messageItem); // Интервал QTableWidgetItem* intervalItem = new QTableWidgetItem(QString::number(timer.interval)); tableWidget->setItem(row, 2, intervalItem); // Чекбокс "О" QTableWidgetItem* announcementItem = new QTableWidgetItem(); announcementItem->setCheckState(timer.isAnnouncement ? Qt::Checked : Qt::Unchecked); tableWidget->setItem(row, 3, announcementItem); rowCount++; } return true; } /** * @brief Специальное сохранение для таблицы таймеров * @param tableWidget Таблица для сохранения * @param timers Список таймеров * @return true если успешно */ bool uDataBase::SaveTimers(QTableWidget *tableWidget, const QList &timers) { if (!tableWidget) { m_lastError = "Table widget is null"; qWarning() << m_lastError; return false; } // Получаем имя таблицы из objectName виджета QString tableName = tableWidget->objectName(); if (tableName.isEmpty()) { m_lastError = "Table widget has no object name"; qWarning() << m_lastError; return false; } // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Создаем таблицу если не существует QString createTableQuery = QString( "CREATE TABLE IF NOT EXISTS %1 (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "message TEXT NOT NULL," "interval INTEGER NOT NULL," "is_active BOOLEAN DEFAULT 1," "is_announcement BOOLEAN DEFAULT 0" ")" ).arg(tableName); QSqlQuery createQuery(m_db); if (!createQuery.exec(createTableQuery)) { m_lastError = createQuery.lastError().text(); qWarning() << "Failed to create table:" << m_lastError; return false; } // Начинаем транзакцию if (!m_db.transaction()) { m_lastError = m_db.lastError().text(); qWarning() << "Failed to start transaction:" << m_lastError; return false; } // Очищаем таблицу QSqlQuery clearQuery(m_db); QString clearSql = QString("DELETE FROM %1").arg(tableName); if (!clearQuery.exec(clearSql)) { m_lastError = clearQuery.lastError().text(); qWarning() << "Failed to clear table:" << m_lastError; m_db.rollback(); return false; } // Сохраняем таймеры QSqlQuery insertQuery(m_db); insertQuery.prepare(QString( "INSERT INTO %1 (message, interval, is_active, is_announcement) " "VALUES (:message, :interval, :is_active, :is_announcement)" ).arg(tableName)); int savedRows = 0; for (const TimerInfo &timer : timers) { insertQuery.bindValue(":message", timer.message); insertQuery.bindValue(":interval", timer.interval); insertQuery.bindValue(":is_active", timer.isActive); insertQuery.bindValue(":is_announcement", timer.isAnnouncement); if (!insertQuery.exec()) { m_lastError = insertQuery.lastError().text(); qWarning() << "Failed to insert timer:" << m_lastError; m_db.rollback(); return false; } savedRows++; } // Завершаем транзакцию if (!m_db.commit()) { m_lastError = m_db.lastError().text(); qWarning() << "Failed to commit transaction:" << m_lastError; m_db.rollback(); return false; } return true; } bool uDataBase::LoadTableWidget(QTableWidget *tableWidget) { if (!tableWidget) { m_lastError = "Table widget is null"; qWarning() << m_lastError; return false; } // Получаем имя таблицы из objectName виджета QString tableName = tableWidget->objectName(); if (tableName.isEmpty()) { m_lastError = "Table widget has no object name"; qWarning() << m_lastError; return false; } // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Очищаем таблицу (но сохраняем заголовки) tableWidget->setRowCount(0); // Выполняем SQL запрос QSqlQuery query(m_db); QString sql = QString("SELECT * FROM %1 ORDER BY id").arg(tableName); if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Query failed:" << m_lastError; qWarning() << "SQL:" << sql; return false; } // Получаем информацию о колонках в результате запроса QSqlRecord record = query.record(); int dbColumnCount = record.count(); // Определяем сколько колонок нам нужно в QTableWidget int widgetColumnCount = tableWidget->columnCount(); int columnsToLoad = qMin(dbColumnCount - 1, widgetColumnCount); // -1 потому что пропускаем id int rowCount = 0; while (query.next()) { // Добавляем новую строку int row = tableWidget->rowCount(); tableWidget->insertRow(row); // Заполняем ячейки (начиная с col0, пропускаем id) for (int col = 0; col < columnsToLoad; col++) { QString columnName = QString("col%1").arg(col); QVariant value = query.value(columnName); QTableWidgetItem *item = new QTableWidgetItem(); if (value.isNull()) { item->setText(""); } else { item->setText(value.toString()); } // Устанавливаем выравнивание по умолчанию item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); tableWidget->setItem(row, col, item); } rowCount++; } return true; } bool uDataBase::SaveTableWidget(QTableWidget *tableWidget) { if (!tableWidget) { m_lastError = "Table widget is null"; qWarning() << m_lastError; return false; } // Получаем имя таблицы из objectName виджета QString tableName = tableWidget->objectName(); if (tableName.isEmpty()) { m_lastError = "Table widget has no object name"; qWarning() << m_lastError; return false; } // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Проверяем существует ли таблица if (!tableExists(tableName)) { // Создаем таблицу с нужным количеством колонок if (!createTableForWidget(tableName, tableWidget->columnCount())) { return false; } } else { // Очищаем существующую таблицу if (!clearTable(tableName)) { return false; } } // Сохраняем данные из таблицы QSqlQuery query(m_db); // Начинаем транзакцию для быстрой вставки if (!m_db.transaction()) { m_lastError = m_db.lastError().text(); qWarning() << "Failed to start transaction:" << m_lastError; return false; } int rowCount = tableWidget->rowCount(); int colCount = tableWidget->columnCount(); if (colCount == 0) { m_lastError = "Table widget has no columns"; qWarning() << m_lastError; m_db.rollback(); return false; } // Подготавливаем SQL запрос для вставки QStringList columnNames; QStringList valuePlaceholders; // Добавляем id (автоинкремент) columnNames << "id"; valuePlaceholders << "NULL"; // Добавляем col0, col1, col2 и т.д. for (int col = 0; col < colCount; col++) { columnNames << QString("col%1").arg(col); valuePlaceholders << QString(":col%1").arg(col); } QString sql = QString("INSERT INTO %1 (%2) VALUES (%3)") .arg(tableName) .arg(columnNames.join(", ")) .arg(valuePlaceholders.join(", ")); query.prepare(sql); int savedRows = 0; for (int row = 0; row < rowCount; row++) { // Пропускаем пустые строки (если все ячейки пустые) bool isEmptyRow = true; for (int col = 0; col < colCount; col++) { QTableWidgetItem *item = tableWidget->item(row, col); if (item && !item->text().trimmed().isEmpty()) { isEmptyRow = false; break; } } if (isEmptyRow) { continue; // Пропускаем полностью пустые строки } // Биндим значения для каждой колонки for (int col = 0; col < colCount; col++) { QString paramName = QString(":col%1").arg(col); QTableWidgetItem *item = tableWidget->item(row, col); if (item && !item->text().isEmpty()) { query.bindValue(paramName, item->text()); } else { query.bindValue(paramName, QVariant(QVariant::String)); } } if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to insert row:" << m_lastError; qWarning() << "SQL:" << sql; m_db.rollback(); return false; } savedRows++; } // Завершаем транзакцию if (!m_db.commit()) { m_lastError = m_db.lastError().text(); qWarning() << "Failed to commit transaction:" << m_lastError; m_db.rollback(); return false; } return true; } // Вспомогательные методы bool uDataBase::tableExists(const QString &tableName) { QSqlQuery query(m_db); QString sql = QString("SELECT name FROM sqlite_master WHERE type='table' AND name='%1'") .arg(tableName); if (query.exec(sql) && query.next()) { return true; } return false; } bool uDataBase::createTableForWidget(const QString &tableName, int columnCount) { if (columnCount <= 0) { m_lastError = "Invalid column count"; return false; } QSqlQuery query(m_db); // Создаем SQL для создания таблицы QStringList columns; columns << "id INTEGER PRIMARY KEY AUTOINCREMENT"; for (int i = 0; i < columnCount; i++) { columns << QString("col%1 TEXT").arg(i); } QString sql = QString("CREATE TABLE %1 (%2)").arg(tableName).arg(columns.join(", ")); if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create table:" << m_lastError; qWarning() << "SQL:" << sql; return false; } return true; } bool uDataBase::clearTable(const QString &tableName) { QSqlQuery query(m_db); QString sql = QString("DELETE FROM %1").arg(tableName); if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to clear table:" << m_lastError; return false; } // Сбрасываем автоинкремент sql = QString("DELETE FROM sqlite_sequence WHERE name='%1'").arg(tableName); query.exec(sql); // Игнорируем ошибки, т.к. может не быть sqlite_sequence return true; } bool uDataBase::LoadRandomGroups(QListWidget *listWidget) { if (!listWidget) { m_lastError = "List widget is null"; qWarning() << m_lastError; return false; } listWidget->clear(); m_lastError.clear(); // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Проверяем существование таблицы if (!tableExists("GroupResponse")) { qWarning() << "Table GroupResponse doesn't exist"; // Можно создать таблицу автоматически if (!createGroupResponseTable()) { return false; } } // Выполняем SQL запрос для получения уникальных имен QSqlQuery query(m_db); QString sql = "SELECT DISTINCT Name FROM GroupResponse ORDER BY Name"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Query failed:" << m_lastError; qWarning() << "SQL:" << sql; return false; } int count = 0; while (query.next()) { QString groupName = query.value(0).toString(); if (!groupName.isEmpty()) { listWidget->addItem(groupName); count++; } } return true; } // Метод для загрузки ответов конкретной группы bool uDataBase::LoadRandomResponses(const QString &groupName, QListWidget *listWidget) { if (!listWidget) { m_lastError = "List widget is null"; qWarning() << m_lastError; return false; } if (groupName.isEmpty()) { m_lastError = "Group name is empty"; qWarning() << m_lastError; return false; } listWidget->clear(); m_lastError.clear(); // Проверяем соединение с БД if (!m_db.isOpen()) { m_lastError = "Database is not open"; qWarning() << m_lastError; return false; } // Проверяем существование таблицы if (!tableExists("GroupResponse")) { m_lastError = "Table GroupResponse doesn't exist"; qWarning() << m_lastError; return false; } // Выполняем SQL запрос для получения ответов группы QSqlQuery query(m_db); query.prepare("SELECT Response FROM GroupResponse WHERE Name = :name ORDER BY id"); query.bindValue(":name", groupName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Query failed:" << m_lastError; return false; } int count = 0; while (query.next()) { QString response = query.value(0).toString(); listWidget->addItem(response); count++; } return true; } // Метод для получения случайного ответа из группы QString uDataBase::GetRandomResponse(const QString &groupName) { if (groupName.isEmpty()) { qWarning() << "Group name is empty"; return QString(); } if (!m_db.isOpen()) { qWarning() << "Database is not open"; return QString(); } if (!tableExists("GroupResponse")) { qWarning() << "Table GroupResponse doesn't exist"; return QString(); } QSqlQuery query(m_db); query.prepare("SELECT Response FROM GroupResponse WHERE Name = :name ORDER BY RANDOM() LIMIT 1"); query.bindValue(":name", groupName); if (!query.exec()) { qWarning() << "Query failed for group:" << groupName << "Error:" << query.lastError().text(); return QString(); } if (!query.next()) { qWarning() << "No responses found for group:" << groupName; return QString(); } return query.value(0).toString(); } // Метод для обработки текста с заменой {{grN}} QString uDataBase::ProcessResponseTemplate(const QString &templateText) { QRegularExpression re("\\{\\{(.+?)\\}\\}"); QRegularExpressionMatchIterator i = re.globalMatch(templateText); QString result = templateText; while (i.hasNext()) { QRegularExpressionMatch match = i.next(); QString fullMatch = match.captured(0); // {{ANY_GROUP_NAME}} QString groupName = match.captured(1).trimmed(); // ANY_GROUP_NAME if (groupName.isEmpty()) { continue; // Пропускаем пустые имена групп } QString replacement = GetRandomResponse(groupName); if (replacement.isEmpty()) { qWarning() << "No response found for group:" << groupName; // Можно оставить оригинальный текст или заменить на что-то другое replacement = QString("[Группа '%1' не найдена]").arg(groupName); } result.replace(fullMatch, replacement); } return result; } // Методы для добавления/удаления групп и ответов bool uDataBase::AddGroupResponse(const QString &groupName, const QString &response) { if (groupName.isEmpty() || response.isEmpty()) { m_lastError = "Group name or response is empty"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Создаем таблицу если она не существует if (!tableExists("GroupResponse")) { if (!createGroupResponseTable()) { return false; } } QSqlQuery query(m_db); query.prepare("INSERT INTO GroupResponse (Name, Response) VALUES (:name, :response)"); query.bindValue(":name", groupName); query.bindValue(":response", response); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to add response:" << m_lastError; return false; } return true; } bool uDataBase::DeleteGroup(const QString &groupName) { if (groupName.isEmpty()) { m_lastError = "Group name is empty"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM GroupResponse WHERE Name = :name"); query.bindValue(":name", groupName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete group:" << m_lastError; return false; } return true; } bool uDataBase::DeleteResponse(const QString &groupName, const QString &ResponseName) { if (groupName.isEmpty()) { m_lastError = "Group name is empty"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Получаем ID ответа по индексу в группе QSqlQuery query(m_db); // Удаляем ответ по ID query.prepare("DELETE FROM GroupResponse WHERE Name = :name and Response = :response"); query.bindValue(":name", groupName); query.bindValue(":response", ResponseName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete response:" << m_lastError; return false; } return true; } // Вспомогательные методы bool uDataBase::createGroupResponseTable() { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS GroupResponse (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " Name TEXT NOT NULL," " Response TEXT NOT NULL" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create GroupResponse table:" << m_lastError; return false; } // Создаем индекс для быстрого поиска по имени группы sql = "CREATE INDEX IF NOT EXISTS idx_groupresponse_name ON GroupResponse (Name)"; query.exec(sql); // Игнорируем ошибки, если индекс уже существует return true; } // Метод для сохранения списка ответов группы (заменяет все существующие) bool uDataBase::SaveGroupResponses(const QString &groupName, const QStringList &responses) { if (groupName.isEmpty()) { m_lastError = "Group name is empty"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Начинаем транзакцию if (!m_db.transaction()) { m_lastError = m_db.lastError().text(); return false; } // Удаляем старые ответы группы QSqlQuery query(m_db); query.prepare("DELETE FROM GroupResponse WHERE Name = :name"); query.bindValue(":name", groupName); if (!query.exec()) { m_lastError = query.lastError().text(); m_db.rollback(); return false; } // Добавляем новые ответы query.prepare("INSERT INTO GroupResponse (Name, Response) VALUES (:name, :response)"); foreach (const QString &response, responses) { if (!response.trimmed().isEmpty()) { query.bindValue(":name", groupName); query.bindValue(":response", response); if (!query.exec()) { m_lastError = query.lastError().text(); m_db.rollback(); return false; } } } if (!m_db.commit()) { m_lastError = m_db.lastError().text(); m_db.rollback(); return false; } return true; } bool uDataBase::isConnected() const { return m_db.isOpen(); } QString uDataBase::lastError() const { return m_lastError; } /** * @brief Создает таблицу для хранения настроек чатов */ bool uDataBase::createChatsTable() { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS chats (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " name TEXT NOT NULL," " type TEXT NOT NULL," // "chat" или "notification" " port INTEGER NOT NULL," " font_list TEXT," " background_color TEXT," " block_color TEXT," " border_color TEXT," " border_size INTEGER," " padding INTEGER," " transparency INTEGER," " font_family TEXT," " font_size INTEGER," " font_color TEXT," " freez BOOLEAN," " message_timeout INTEGER," " max_msg_count INTEGER," " delete_by_time BOOLEAN," " created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create chats table:" << m_lastError; return false; } // Создаем индекс для быстрого поиска по порту sql = "CREATE INDEX IF NOT EXISTS idx_chats_port ON chats (port)"; query.exec(sql); return true; } /** * @brief Сохраняет настройки чата в базу данных */ bool uDataBase::saveChat(const QString &name, const QString &type, HttpServerChat *server, const QString &fontList) { if (!server) { m_lastError = "Server is null"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Создаем таблицу если не существует if (!tableExists("chats")) { if (!createChatsTable()) { return false; } } QSqlQuery query(m_db); query.prepare( "INSERT OR REPLACE INTO chats (" " name, type, port, font_list, background_color, " " block_color, border_color, border_size, padding, " " transparency, font_family, font_size, font_color, " " freez, message_timeout, max_msg_count, delete_by_time" ") VALUES (" " :name, :type, :port, :font_list, :background_color, " " :block_color, :border_color, :border_size, :padding, " " :transparency, :font_family, :font_size, :font_color, " " :freez, :message_timeout, :max_msg_count, :delete_by_time" ")" ); query.bindValue(":name", name); query.bindValue(":type", type); query.bindValue(":port", server->port()); query.bindValue(":font_list", fontList); query.bindValue(":background_color", server->getBackgroundColor()); query.bindValue(":block_color", server->getBlockColor()); query.bindValue(":border_color", server->getBorderColor()); query.bindValue(":border_size", server->getBorderSize()); query.bindValue(":padding", server->getPadding()); query.bindValue(":transparency", server->getTransparency()); query.bindValue(":font_family", server->getFontFamily()); query.bindValue(":font_size", server->getFontSize()); query.bindValue(":font_color", server->getFontColor()); query.bindValue(":freez", server->isFreez()); query.bindValue(":message_timeout", server->getMessageTimeout()); query.bindValue(":max_msg_count", server->getMaxMsgCount()); query.bindValue(":delete_by_time", !server->isFreez()); // delete_by_time = !freez if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to save chat:" << m_lastError; return false; } return true; } /** * @brief Загружает все сохраненные чаты из базы данных */ QList uDataBase::loadAllChats() { QList chats; if (!m_db.isOpen()) { m_lastError = "Database is not open"; return chats; } if (!tableExists("chats")) { // Если таблицы нет, ничего не загружаем return chats; } QSqlQuery query(m_db); QString sql = "SELECT * FROM chats ORDER BY created_at"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to load chats:" << m_lastError; return chats; } while (query.next()) { ChatSettings settings; settings.id = query.value("id").toInt(); settings.name = query.value("name").toString(); settings.type = query.value("type").toString(); settings.port = query.value("port").toInt(); settings.fontList = query.value("font_list").toString().split(',', Qt::SkipEmptyParts); settings.backgroundColor = query.value("background_color").toString(); settings.blockColor = query.value("block_color").toString(); settings.borderColor = query.value("border_color").toString(); settings.borderSize = query.value("border_size").toInt(); settings.padding = query.value("padding").toInt(); settings.transparency = query.value("transparency").toInt(); settings.fontFamily = query.value("font_family").toString(); settings.fontSize = query.value("font_size").toInt(); settings.fontColor = query.value("font_color").toString(); settings.freez = query.value("freez").toBool(); settings.messageTimeout = query.value("message_timeout").toInt(); settings.maxMsgCount = query.value("max_msg_count").toInt(); settings.deleteByTime = query.value("delete_by_time").toBool(); chats.append(settings); } return chats; } /** * @brief Удаляет чат из базы данных по порту */ bool uDataBase::deleteChat(int port) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM chats WHERE port = :port"); query.bindValue(":port", port); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete chat:" << m_lastError; return false; } return true; } /** * @brief Обновляет настройки существующего чата */ bool uDataBase::updateChat(const QString &name, HttpServerChat *server, const QString &fontList, int oldPort) { if (!server) { m_lastError = "Server is null"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare( "UPDATE chats SET " " name = :name, " " port = :port, " " font_list = :font_list, " " background_color = :background_color, " " block_color = :block_color, " " border_color = :border_color, " " border_size = :border_size, " " padding = :padding, " " transparency = :transparency, " " font_family = :font_family, " " font_size = :font_size, " " font_color = :font_color, " " freez = :freez, " " message_timeout = :message_timeout, " " max_msg_count = :max_msg_count, " " delete_by_time = :delete_by_time " "WHERE port = :old_port" ); query.bindValue(":name", name); query.bindValue(":port", server->port()); query.bindValue(":font_list", fontList); query.bindValue(":background_color", server->getBackgroundColor()); query.bindValue(":block_color", server->getBlockColor()); query.bindValue(":border_color", server->getBorderColor()); query.bindValue(":border_size", server->getBorderSize()); query.bindValue(":padding", server->getPadding()); query.bindValue(":transparency", server->getTransparency()); query.bindValue(":font_family", server->getFontFamily()); query.bindValue(":font_size", server->getFontSize()); query.bindValue(":font_color", server->getFontColor()); query.bindValue(":freez", server->isFreez()); query.bindValue(":message_timeout", server->getMessageTimeout()); query.bindValue(":max_msg_count", server->getMaxMsgCount()); query.bindValue(":delete_by_time", !server->isFreez()); query.bindValue(":old_port", oldPort); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to update chat:" << m_lastError; return false; } return true; } bool uDataBase::createNotificationsTable() { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS notifications (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " name TEXT NOT NULL," " type TEXT NOT NULL," // "notification" " port INTEGER NOT NULL," " block_color TEXT," " border_color TEXT," " border_size INTEGER," " transparency INTEGER," " page_background_color TEXT," " title_family TEXT," " title_size INTEGER," " title_color TEXT," " content_family TEXT," " content_size INTEGER," " content_color TEXT," " duration INTEGER," " created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create notifications table:" << m_lastError; return false; } // Создаем индекс для быстрого поиска по порту sql = "CREATE INDEX IF NOT EXISTS idx_notifications_port ON notifications (port)"; query.exec(sql); return true; } bool uDataBase::saveNotification(const QString &name, HttpServer *server) { if (!server) { m_lastError = "Server is null"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Создаем таблицу если не существует if (!tableExists("notifications")) { if (!createNotificationsTable()) { return false; } } QSqlQuery query(m_db); query.prepare( "INSERT INTO notifications (" " name, type, port, block_color, border_color, border_size," " transparency, page_background_color, title_family, title_size," " title_color, content_family, content_size, content_color, duration" ") VALUES (" " :name, :type, :port, :block_color, :border_color, :border_size," " :transparency, :page_background_color, :title_family, :title_size," " :title_color, :content_family, :content_size, :content_color, :duration" ")" ); // Используем реальные значения из сервера query.bindValue(":name", name); query.bindValue(":type", "notification"); query.bindValue(":port", server->port()); query.bindValue(":block_color", server->getBlockColor()); query.bindValue(":border_color", server->getBorderColor()); query.bindValue(":border_size", server->getBorderSize()); query.bindValue(":transparency", server->getTransparency()); query.bindValue(":page_background_color", server->getPageBackgroundColor()); query.bindValue(":title_family", server->getTitleFamily()); query.bindValue(":title_size", server->getTitleSize()); query.bindValue(":title_color", server->getTitleColor()); query.bindValue(":content_family", server->getContentFamily()); query.bindValue(":content_size", server->getContentSize()); query.bindValue(":content_color", server->getContentColor()); query.bindValue(":duration", server->getDuration()); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to save notification:" << m_lastError; return false; } return true; } bool uDataBase::updateNotification(const QString &name, HttpServer *server, int oldPort) { if (!server) { m_lastError = "Server is null"; return false; } if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare( "UPDATE notifications SET " " name = :name, " " port = :port, " " block_color = :block_color, " " border_color = :border_color, " " border_size = :border_size, " " transparency = :transparency, " " page_background_color = :page_background_color, " " title_family = :title_family, " " title_size = :title_size, " " title_color = :title_color, " " content_family = :content_family, " " content_size = :content_size, " " content_color = :content_color, " " duration = :duration " "WHERE port = :old_port" ); query.bindValue(":name", name); query.bindValue(":port", server->port()); query.bindValue(":block_color", server->getBlockColor()); query.bindValue(":border_color", server->getBorderColor()); query.bindValue(":border_size", server->getBorderSize()); query.bindValue(":transparency", server->getTransparency()); query.bindValue(":page_background_color", server->getPageBackgroundColor()); query.bindValue(":title_family", server->getTitleFamily()); query.bindValue(":title_size", server->getTitleSize()); query.bindValue(":title_color", server->getTitleColor()); query.bindValue(":content_family", server->getContentFamily()); query.bindValue(":content_size", server->getContentSize()); query.bindValue(":content_color", server->getContentColor()); query.bindValue(":duration", server->getDuration()); query.bindValue(":old_port", oldPort); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to update notification:" << m_lastError; return false; } return true; } QList uDataBase::loadAllNotifications() { QList notifications; if (!m_db.isOpen()) { m_lastError = "Database is not open"; return notifications; } if (!tableExists("notifications")) { // Если таблицы нет, ничего не загружаем return notifications; } QSqlQuery query(m_db); QString sql = "SELECT * FROM notifications ORDER BY created_at"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to load notifications:" << m_lastError; return notifications; } while (query.next()) { NotificationSettings settings; settings.id = query.value("id").toInt(); settings.name = query.value("name").toString(); settings.type = query.value("type").toString(); settings.port = query.value("port").toInt(); settings.blockColor = query.value("block_color").toString(); settings.borderColor = query.value("border_color").toString(); settings.borderSize = query.value("border_size").toInt(); settings.transparency = query.value("transparency").toInt(); settings.pageBackgroundColor = query.value("page_background_color").toString(); settings.titleFamily = query.value("title_family").toString(); settings.titleSize = query.value("title_size").toInt(); settings.titleColor = query.value("title_color").toString(); settings.contentFamily = query.value("content_family").toString(); settings.contentSize = query.value("content_size").toInt(); settings.contentColor = query.value("content_color").toString(); settings.duration = query.value("duration").toInt(); settings.createdAt = query.value("created_at").toDateTime(); notifications.append(settings); } return notifications; } bool uDataBase::deleteNotification(int port) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM notifications WHERE port = :port"); query.bindValue(":port", port); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete notification:" << m_lastError; return false; } return true; } bool uDataBase::createActionsTable() { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS actions (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " type INTEGER NOT NULL," " key_combination TEXT," " audio_file TEXT," " notification_title TEXT," " notification_description TEXT," " notification_image TEXT," " notification_sound TEXT," " created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create actions table:" << m_lastError; return false; } return true; } bool uDataBase::saveAction(const ActionData &action) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } // Создаём таблицу, если ещё нет if (!tableExists("actions")) { if (!createActionsTable()) return false; } QSqlQuery query(m_db); query.prepare( "INSERT INTO actions (" " type, key_combination, audio_file, notification_title," " notification_description, notification_image, notification_sound" ") VALUES (" " :type, :key_combination, :audio_file, :notification_title," " :notification_description, :notification_image, :notification_sound" ")" ); query.bindValue(":type", action.type); query.bindValue(":key_combination", action.keyCombination); query.bindValue(":audio_file", action.audioFile); query.bindValue(":notification_title", action.notificationTitle); query.bindValue(":notification_description", action.notificationDescription); query.bindValue(":notification_image", action.notificationImage); query.bindValue(":notification_sound", action.notificationSound); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to save action:" << m_lastError; return false; } return true; } bool uDataBase::updateAction(int id, const ActionData &action) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare( "UPDATE actions SET " " type = :type," " key_combination = :key_combination," " audio_file = :audio_file," " notification_title = :notification_title," " notification_description = :notification_description," " notification_image = :notification_image," " notification_sound = :notification_sound " "WHERE id = :id" ); query.bindValue(":type", action.type); query.bindValue(":key_combination", action.keyCombination); query.bindValue(":audio_file", action.audioFile); query.bindValue(":notification_title", action.notificationTitle); query.bindValue(":notification_description", action.notificationDescription); query.bindValue(":notification_image", action.notificationImage); query.bindValue(":notification_sound", action.notificationSound); query.bindValue(":id", id); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to update action:" << m_lastError; return false; } return true; } bool uDataBase::deleteAction(int id) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM actions WHERE id = :id"); query.bindValue(":id", id); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete action:" << m_lastError; return false; } return true; } QList uDataBase::loadAllActions() { QList actions; if (!m_db.isOpen()) { m_lastError = "Database is not open"; return actions; } if (!tableExists("actions")) { return actions; // таблицы нет – пустой список } QSqlQuery query(m_db); query.prepare("SELECT * FROM actions ORDER BY id"); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to load actions:" << m_lastError; return actions; } while (query.next()) { ActionData a; a.id = query.value("id").toInt(); a.type = query.value("type").toInt(); a.keyCombination = query.value("key_combination").toString(); a.audioFile = query.value("audio_file").toString(); a.notificationTitle = query.value("notification_title").toString(); a.notificationDescription = query.value("notification_description").toString(); a.notificationImage = query.value("notification_image").toString(); a.notificationSound = query.value("notification_sound").toString(); actions.append(a); } return actions; } bool uDataBase::clearActionsTable() { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); if (!query.exec("DELETE FROM actions")) { m_lastError = query.lastError().text(); return false; } // Сброс автоинкремента query.exec("DELETE FROM sqlite_sequence WHERE name='actions'"); return true; } bool uDataBase::createDonationTriggersTable() { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS donation_triggers (" " id INTEGER PRIMARY KEY AUTOINCREMENT," " name TEXT NOT NULL," " rule TEXT NOT NULL," " created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create donation_triggers table:" << m_lastError; return false; } return true; } int uDataBase::saveDonationTrigger(const DonationTrigger &trigger) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return -1; } if (!tableExists("donation_triggers")) { if (!createDonationTriggersTable()) return -1; } QSqlQuery query(m_db); query.prepare("INSERT INTO donation_triggers (name, rule) VALUES (:name, :rule)"); query.bindValue(":name", trigger.name); query.bindValue(":rule", trigger.rule); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to save donation trigger:" << m_lastError; return -1; } return query.lastInsertId().toInt(); } bool uDataBase::deleteDonationTrigger(int id) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM donation_triggers WHERE id = :id"); query.bindValue(":id", id); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete donation trigger:" << m_lastError; return false; } return true; } QList uDataBase::loadAllDonationTriggers() { QList list; if (!m_db.isOpen()) { m_lastError = "Database is not open"; return list; } if (!tableExists("donation_triggers")) { return list; // таблицы нет – пусто } QSqlQuery query(m_db); query.prepare("SELECT id, name, rule FROM donation_triggers ORDER BY id"); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to load donation triggers:" << m_lastError; return list; } while (query.next()) { DonationTrigger t; t.id = query.value("id").toInt(); t.name = query.value("name").toString(); t.rule = query.value("rule").toString(); // Парсить rule будем в DonationManager, здесь только храним list.append(t); } return list; } bool uDataBase::saveEventActionLink(const QString &eventType, const QString &eventName, int actionId) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QString et = eventType.trimmed(); QString en = eventName.trimmed(); // Создаём таблицу, если её нет if (!tableExists("event_action_links")) { QSqlQuery query(m_db); QString sql = "CREATE TABLE IF NOT EXISTS event_action_links (" "id INTEGER PRIMARY KEY AUTOINCREMENT," "event_type TEXT NOT NULL," "event_name TEXT NOT NULL," "action_id INTEGER NOT NULL," "created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP" ")"; if (!query.exec(sql)) { m_lastError = query.lastError().text(); qWarning() << "Failed to create event_action_links table:" << m_lastError; return false; } } qDebug()<<"Я ТУТ НАХУЙ"; // Проверяем, нет ли уже такой связи QSqlQuery checkQuery(m_db); checkQuery.prepare("SELECT id FROM event_action_links WHERE event_type=:et AND event_name=:en AND action_id=:aid"); checkQuery.bindValue(":et", et); checkQuery.bindValue(":en", en); checkQuery.bindValue(":aid", actionId); if (checkQuery.exec() && checkQuery.next()) { m_lastError = "Такая связь уже существует"; return false; } QSqlQuery query(m_db); query.prepare("INSERT INTO event_action_links (event_type, event_name, action_id) VALUES (:et, :en, :aid)"); query.bindValue(":et", eventType); query.bindValue(":en", eventName); query.bindValue(":aid", actionId); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to save event-action link:" << m_lastError; return false; } return true; } bool uDataBase::deleteEventActionLink(int id) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM event_action_links WHERE id = :id"); query.bindValue(":id", id); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete event-action link:" << m_lastError; return false; } if (query.numRowsAffected() == 0) { m_lastError = "Связь с указанным ID не найдена"; return false; } return true; } QList uDataBase::getLinksForEvent(const QString &eventType, const QString &eventName) { QList links; if (!m_db.isOpen()) { m_lastError = "Database is not open"; return links; } if (!tableExists("event_action_links")) { return links; } QSqlQuery query(m_db); query.prepare("SELECT id, event_type, event_name, action_id FROM event_action_links WHERE event_type=:et AND event_name=:en"); query.bindValue(":et", eventType); query.bindValue(":en", eventName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to get links for event:" << m_lastError; return links; } while (query.next()) { EventActionLink link; link.id = query.value(0).toInt(); link.eventType = query.value(1).toString(); link.eventName = query.value(2).toString(); link.actionId = query.value(3).toInt(); links.append(link); } return links; } bool uDataBase::deleteLinksForEvent(const QString &eventType, const QString &eventName) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM event_action_links WHERE event_type=:et AND event_name=:en"); query.bindValue(":et", eventType); query.bindValue(":en", eventName); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete links for event:" << m_lastError; return false; } return true; } bool uDataBase::deleteLinksByActionId(int actionId) { if (!m_db.isOpen()) { m_lastError = "Database is not open"; return false; } QSqlQuery query(m_db); query.prepare("DELETE FROM event_action_links WHERE action_id = :aid"); query.bindValue(":aid", actionId); if (!query.exec()) { m_lastError = query.lastError().text(); qWarning() << "Failed to delete links by action id:" << m_lastError; return false; } return true; }