Files
TTW_Bot/udatabase.cpp
T
PTyTb 5094834ea1 Добавил привязку действий к событиям
за баллы канала и за донаты можено можно выполнять списки действий, за каждое событие свой набор
2026-02-22 10:20:04 +03:00

1803 lines
57 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "udatabase.h"
#include <QMetaProperty>
#include <QSqlRecord>
#include <QDateTime>
#include <QTableWidget>
#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<TimerInfo> &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<TimerInfo> &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<ChatSettings> uDataBase::loadAllChats()
{
QList<ChatSettings> 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<NotificationSettings> uDataBase::loadAllNotifications()
{
QList<NotificationSettings> 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<ActionData> uDataBase::loadAllActions()
{
QList<ActionData> 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<DonationTrigger> uDataBase::loadAllDonationTriggers()
{
QList<DonationTrigger> 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<EventActionLink> uDataBase::getLinksForEvent(const QString &eventType, const QString &eventName)
{
QList<EventActionLink> 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;
}