From fa790e52d7c2a5e6c2659b1bd5b9f479624d3f77 Mon Sep 17 00:00:00 2001 From: Mef Date: Wed, 19 Mar 2025 20:19:46 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D0=BE=D0=B2=20=D0=B8=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Внесены изменения в класс `Program`: - Инициализация логгера с выводом в консоль и файл. - Загрузка списка администраторов из базы данных при запуске бота. - Метод для сохранения администратора в базе данных при авторизации. - Обновлен метод `UpdateReportStatus` для уведомления администраторов об изменении статуса заявки. - Добавлены методы для создания и загрузки таблицы администраторов. - Изменено форматирование сообщений с использованием emoji для статусов и приоритетов. - Обновлены SQL-запросы для работы с новыми полями и логикой в базе данных. --- Program.cs | 302 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 272 insertions(+), 30 deletions(-) diff --git a/Program.cs b/Program.cs index 7bb4e36..cc0bbb5 100644 --- a/Program.cs +++ b/Program.cs @@ -39,7 +39,7 @@ class Program throw; } - + Log.Logger = new LoggerConfiguration() .WriteTo.Console() .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day) @@ -49,21 +49,25 @@ class Program try { - + _botClient = new TelegramBotClient(_botToken); - var me = await _botClient.GetMe(); + var me = await _botClient.GetMe(); Log.Information($"Бот {me.FirstName} запущен! ID: {me.Id}"); } catch (Exception ex) { Log.Error($"Ошибка при подключении к Telegram API: {ex.Message}"); - + throw; } // Создание базы данных и таблицы, если они не существуют await CreateDatabaseIfNotExists(); + // Загрузка списка администраторов из базы данных + await LoadAdminsFromDatabase(); + Log.Information($"Загружено {admins.Count} администраторов из базы данных"); + var cts = new CancellationTokenSource(); Log.Information("Начало получения обновлений..."); @@ -200,7 +204,7 @@ class Program if (callbackQuery?.Message?.MessageId != null) { int messageId = callbackQuery.Message.MessageId; - await UpdateReportStatus(reportId, newStatus); + await UpdateReportStatus(reportId, newStatus, chatId); await ShowReportDetails(botClient, chatId, reportId, messageId); } } @@ -237,13 +241,15 @@ class Program var message = update.Message; Log.Information($"Получено сообщение от {message.Chat.Id}: {message.Text}"); - // Обработка команды /admin для авторизации if (message.Text.StartsWith("/admin")) { string[] parts = message.Text.Split(' '); if (parts.Length == 2 && parts[1] == adminPassword) { admins.Add(message.Chat.Id); + // Сохраняем администратора в базу данных + await SaveAdminToDatabase(message.Chat.Id); + var authMessage = await botClient.SendMessage(message.Chat.Id, "✅ Вы авторизованы как администратор!"); Log.Information($"Новый администратор: {message.Chat.Id}"); await Task.Delay(2000); @@ -534,6 +540,9 @@ class Program string status = reader.GetString(4); string dateCreated = reader.GetDateTime(5).ToString("yyyy-MM-dd HH:mm:ss"); + string priorityEmoji = GetPriorityEmoji(priority); + string statusEmoji = GetStatusEmoji(status); + var statusButtons = new InlineKeyboardMarkup(new[] { new[] @@ -557,11 +566,11 @@ class Program }); string newText = $"Заявка #{reportId}\n\n" + - $"Приоритет: {priority}\n" + + $"Приоритет: {priorityEmoji} {priority}\n" + $"Кабинет: {room}\n" + $"Описание: {description}\n" + $"ФИО: {reporterName}\n" + - $"Статус: {status}\n" + + $"Статус: {statusEmoji} {status}\n" + $"Дата создания: {dateCreated}"; await botClient.SendMessage( @@ -585,25 +594,44 @@ class Program - private static async Task UpdateReportStatus(long reportId, string newStatus) -{ - try + private static async Task UpdateReportStatus(long reportId, string newStatus, long changerId) { - using (var connection = new SqliteConnection("Data Source=bot.db")) + try { - await connection.OpenAsync(); - var command = connection.CreateCommand(); - command.CommandText = "UPDATE Reports SET Status = @status WHERE Id = @id"; - command.Parameters.AddWithValue("@status", newStatus); - command.Parameters.AddWithValue("@id", reportId); - await command.ExecuteNonQueryAsync(); + string oldStatus = ""; + + // Сначала получаем текущий статус + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + var getStatusCommand = connection.CreateCommand(); + getStatusCommand.CommandText = "SELECT Status FROM Reports WHERE Id = @id"; + getStatusCommand.Parameters.AddWithValue("@id", reportId); + oldStatus = (string)await getStatusCommand.ExecuteScalarAsync(); + } + + // Если статус не изменился, прерываем выполнение + if (oldStatus == newStatus) return; + + // Обновляем статус + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + var command = connection.CreateCommand(); + command.CommandText = "UPDATE Reports SET Status = @status WHERE Id = @id"; + command.Parameters.AddWithValue("@status", newStatus); + command.Parameters.AddWithValue("@id", reportId); + await command.ExecuteNonQueryAsync(); + + // Уведомляем администраторов об изменении статуса + await NotifyAdminsAboutStatusChange(reportId, newStatus, oldStatus, changerId); + } + } + catch (Exception ex) + { + Log.Error($"Ошибка при обновлении статуса заявки: {ex.Message}"); } } - catch (Exception ex) - { - Log.Error($"Ошибка: {ex.Message}"); - } -} private static async Task SaveReportToDatabase(long chatId, Report report) { @@ -620,15 +648,19 @@ class Program @" INSERT INTO Reports (ChatId, Priority, Room, Description, ReporterName, Status) VALUES (@ChatId, @Priority, @Room, @Description, @ReporterName, 'ожидает'); - "; + SELECT last_insert_rowid(); + "; insertCommand.Parameters.AddWithValue("@ChatId", chatId); insertCommand.Parameters.AddWithValue("@Priority", report.Priority); insertCommand.Parameters.AddWithValue("@Room", report.Room); insertCommand.Parameters.AddWithValue("@Description", report.Description); insertCommand.Parameters.AddWithValue("@ReporterName", report.ReporterName); - await insertCommand.ExecuteNonQueryAsync(); - Log.Information($"Заявка от пользователя {chatId} успешно сохранена."); + long reportId = Convert.ToInt64(await insertCommand.ExecuteScalarAsync()); + Log.Information($"Заявка от пользователя {chatId} успешно сохранена с ID {reportId}."); + + // Уведомляем администраторов о новой заявке + await NotifyAdminsAboutNewReport(reportId, report); } } catch (Exception ex) @@ -639,6 +671,7 @@ class Program + // Обновляем метод CreateDatabaseIfNotExists private static async Task CreateDatabaseIfNotExists() { string connectionString = "Data Source=bot.db"; // Путь к вашей базе данных @@ -693,7 +726,7 @@ class Program } } - // Создаем таблицу, если её не существует + // Создаем таблицу Reports, если её не существует var createTableCommand = connection.CreateCommand(); createTableCommand.CommandText = @" @@ -707,15 +740,17 @@ class Program DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP, Status TEXT DEFAULT 'ожидает' ); - "; + "; await createTableCommand.ExecuteNonQueryAsync(); - Log.Information("Таблица Reports успешно создана (если её не было)."); + + // Создаем таблицу администраторов + await CreateAdminsTableIfNotExists(); } } catch (Exception ex) { - Log.Error($"Ошибка при создании таблицы в базе данных: {ex.Message}"); + Log.Error($"Ошибка при создании таблиц в базе данных: {ex.Message}"); } } @@ -725,6 +760,7 @@ class Program + private static Dictionary userReportSteps = new Dictionary(); private static Dictionary userReports = new Dictionary(); @@ -744,4 +780,210 @@ class Program Log.Error($"StackTrace: {exception.StackTrace}"); return Task.CompletedTask; } + // Добавим метод для создания таблицы администраторов + private static async Task CreateAdminsTableIfNotExists() + { + try + { + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + var command = connection.CreateCommand(); + command.CommandText = @" + CREATE TABLE IF NOT EXISTS Admins ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + ChatId INTEGER NOT NULL UNIQUE + );"; + await command.ExecuteNonQueryAsync(); + Log.Information("Таблица Admins успешно создана (если её не было)."); + } + } + catch (Exception ex) + { + Log.Error($"Ошибка при создании таблицы Admins: {ex.Message}"); + } + } + + // Метод для сохранения администратора в базу данных + private static async Task SaveAdminToDatabase(long chatId) + { + try + { + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + + // Проверяем, существует ли уже такой админ + var checkCommand = connection.CreateCommand(); + checkCommand.CommandText = "SELECT COUNT(*) FROM Admins WHERE ChatId = @chatId"; + checkCommand.Parameters.AddWithValue("@chatId", chatId); + int count = Convert.ToInt32(await checkCommand.ExecuteScalarAsync()); + + if (count == 0) + { + // Добавляем нового админа + var insertCommand = connection.CreateCommand(); + insertCommand.CommandText = "INSERT INTO Admins (ChatId) VALUES (@chatId)"; + insertCommand.Parameters.AddWithValue("@chatId", chatId); + await insertCommand.ExecuteNonQueryAsync(); + Log.Information($"Администратор {chatId} добавлен в базу данных"); + } + } + } + catch (Exception ex) + { + Log.Error($"Ошибка при сохранении администратора в базу данных: {ex.Message}"); + } + } + + // Метод для загрузки администраторов из базы данных + private static async Task LoadAdminsFromDatabase() + { + try + { + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + var command = connection.CreateCommand(); + command.CommandText = "SELECT ChatId FROM Admins"; + + using (var reader = await command.ExecuteReaderAsync()) + { + while (await reader.ReadAsync()) + { + long adminId = reader.GetInt64(0); + admins.Add(adminId); + Log.Information($"Загружен администратор с ID: {adminId}"); + } + } + } + Log.Information($"Загружено {admins.Count} администраторов из базы данных"); + } + catch (Exception ex) + { + Log.Error($"Ошибка при загрузке администраторов из базы данных: {ex.Message}"); + } + } + + // Метод для уведомления администраторов о новой заявке + private static async Task NotifyAdminsAboutNewReport(long reportId, Report report) + { + try + { + foreach (var adminId in admins) + { + var statusEmoji = GetPriorityEmoji(report.Priority); + var keyboard = new InlineKeyboardMarkup(new[] + { + new[] + { + InlineKeyboardButton.WithCallbackData("📝 Посмотреть детали", $"report_{reportId}"), + InlineKeyboardButton.WithCallbackData("📋 Все заявки", "view_reports") + } + }); + + await _botClient.SendMessage( + chatId: adminId, + text: $"{statusEmoji} Новая заявка #{reportId}\n\n" + + $"Приоритет: {report.Priority}\n" + + $"Кабинет: {report.Room}\n" + + $"Описание: {report.Description}\n" + + $"От: {report.ReporterName}", + parseMode: ParseMode.Html, + replyMarkup: keyboard + ); + Log.Information($"Уведомление о новой заявке #{reportId} отправлено администратору {adminId}"); + } + } + catch (Exception ex) + { + Log.Error($"Ошибка при отправке уведомлений администраторам о новой заявке: {ex.Message}"); + } + } + + // Метод для уведомления администраторов об изменении статуса заявки + private static async Task NotifyAdminsAboutStatusChange(long reportId, string newStatus, string oldStatus, long changerId) + { + try + { + // Получаем данные о заявке + string description = ""; + string priority = ""; + string room = ""; + + using (var connection = new SqliteConnection("Data Source=bot.db")) + { + await connection.OpenAsync(); + var command = connection.CreateCommand(); + command.CommandText = "SELECT Description, Priority, Room FROM Reports WHERE Id = @id"; + command.Parameters.AddWithValue("@id", reportId); + + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + description = reader.GetString(0); + priority = reader.GetString(1); + room = reader.GetString(2); + } + } + } + + foreach (var adminId in admins) + { + // Не уведомляем админа, который сам изменил статус + if (adminId == changerId) continue; + + string statusEmoji = GetStatusEmoji(newStatus); + var keyboard = new InlineKeyboardMarkup(new[] + { + new[] + { + InlineKeyboardButton.WithCallbackData("📝 Посмотреть детали", $"report_{reportId}") + } + }); + + await _botClient.SendMessage( + chatId: adminId, + text: $"{statusEmoji} Обновление статуса заявки #{reportId}\n\n" + + $"Приоритет: {priority}\n" + + $"Кабинет: {room}\n" + + $"Статус изменен: {oldStatus} ➡️ {newStatus}\n\n" + + $"Фрагмент описания: {description.Substring(0, Math.Min(50, description.Length))}...", + parseMode: ParseMode.Html, + replyMarkup: keyboard + ); + Log.Information($"Уведомление об изменении статуса заявки #{reportId} отправлено администратору {adminId}"); + } + } + catch (Exception ex) + { + Log.Error($"Ошибка при отправке уведомлений об изменении статуса: {ex.Message}"); + } + } + + // Вспомогательный метод для получения emoji в зависимости от приоритета + private static string GetPriorityEmoji(string priority) + { + return priority.ToLower() switch + { + "high" or "высокий" => "🔴", + "medium" or "средний" => "🟠", + "low" or "низкий" => "🟢", + _ => "ℹ️" + }; + } + + // Вспомогательный метод для получения emoji в зависимости от статуса + private static string GetStatusEmoji(string status) + { + return status.ToLower() switch + { + "ожидает" => "🟡", + "в работе" => "🔵", + "закрыта" => "🟢", + _ => "ℹ️" + }; + } + } \ No newline at end of file