telegram-bot/Program.cs

1862 lines
85 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Data.Sqlite;
using Serilog;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;
class Program
{
private static string _botToken = string.Empty;
private static TelegramBotClient _botClient = null!;
private static Dictionary<long, bool> usersWaitingForReport = new Dictionary<long, bool>(); // Отслеживаем состояние пользователей
private static HashSet<long> admins = new HashSet<long>(); // Хранение списка администраторов
private static string adminPassword = "admin123"; // Простой пароль для администратора
private static Dictionary<long, string> adminFullNames = new Dictionary<long, string>();
static async Task Main()
{
// Загружаем конфигурацию из appsettings.json
try
{
Log.Information("Загрузка конфигурации из appsettings.json...");
var config = new ConfigurationBuilder()
.SetBasePath(AppContext.BaseDirectory) // <-- Используем правильный путь
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();
_botToken = config["BotToken"] ?? throw new Exception("BotToken не найден в конфигурации!");
Log.Information("Конфигурация успешно загружена");
}
catch (Exception ex)
{
Log.Error($"Ошибка при загрузке конфигурации: {ex.Message}");
throw;
}
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
Log.Information("Запуск Telegram-бота...");
try
{
_botClient = new TelegramBotClient(_botToken);
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 CreateUserSettingsTableIfNotExists();
// Загрузка списка администраторов из базы данных
await LoadAdminsFromDatabase();
Log.Information($"Загружено {admins.Count} администраторов из базы данных");
var cts = new CancellationTokenSource();
Log.Information("Начало получения обновлений...");
try
{
// Применение StartReceiving для работы с задачами
_botClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, cancellationToken: cts.Token);
Log.Information("Получение обновлений успешно началось.");
}
catch (Exception ex)
{
Log.Error($"Ошибка при запуске получения обновлений: {ex.Message}");
throw;
}
// Создание TaskCompletionSource для удержания процесса бота
var tcs = new TaskCompletionSource();
await tcs.Task; // Это заставит бота работать до тех пор, пока не будет отменен
// Ожидаем отмены через token
cts.Token.WaitHandle.WaitOne();
}
private static async Task MonitorReportStatus(long reportId, CancellationToken token)
{
// Ждем 15 секунд перед первой проверкой
await Task.Delay(TimeSpan.FromHours(1), token);
while (!token.IsCancellationRequested)
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = @"
SELECT Status
FROM Reports
WHERE Id = @id";
command.Parameters.AddWithValue("@id", reportId);
var status = (string?)await command.ExecuteScalarAsync();
if (status == "в работе" || status == "закрыта")
{
// Если статус изменился на "в работе" или "закрыта", прекращаем мониторинг
return;
}
foreach (var adminId in admins)
{
await _botClient.SendMessage(
chatId: adminId,
text: $"⚠️ Заявка #{reportId} остается в статусе 'Ожидает'."
);
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при мониторинге статуса заявки #{reportId}: {ex.Message}");
}
// Ждем 15 секунд перед следующей проверкой
await Task.Delay(TimeSpan.FromHours(1), token);
}
}
private static async Task DeletePreviousMessage(ITelegramBotClient botClient, long chatId, int messageId)
{
try
{
await botClient.DeleteMessage(chatId, messageId);
Log.Information($"Сообщение {messageId} в чате {chatId} удалено.");
}
catch (Exception ex)
{
Log.Error($"Ошибка при удалении сообщения {messageId} в чате {chatId}: {ex.Message}");
}
}
private static async Task CreateUserSettingsTableIfNotExists()
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = @"
CREATE TABLE IF NOT EXISTS UserSettings (
UserId INTEGER PRIMARY KEY,
NotificationsEnabled INTEGER NOT NULL DEFAULT 1
);";
await command.ExecuteNonQueryAsync();
Log.Information("Таблица UserSettings успешно создана (если её не было).");
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при создании таблицы UserSettings: {ex.Message}");
}
}
private static async Task ShowUserSettings(ITelegramBotClient botClient, long chatId)
{
try
{
// Получаем текущие настройки пользователя
bool notificationsEnabled = true; // По умолчанию уведомления включены
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "SELECT NotificationsEnabled FROM UserSettings WHERE UserId = @userId";
command.Parameters.AddWithValue("@userId", chatId);
var result = await command.ExecuteScalarAsync();
// Отладочная информация
Log.Information($"[Отладка] Для пользователя {chatId} проверяем настройки уведомлений. Результат из БД: {result}");
if (result != null && result != DBNull.Value)
{
int dbValue = Convert.ToInt32(result);
notificationsEnabled = dbValue == 1;
Log.Information($"[Отладка] Для пользователя {chatId} настройка уведомлений из БД: {dbValue} => notificationsEnabled={notificationsEnabled}");
}
else
{
// Если запись для пользователя отсутствует, создаем ее
var insertCommand = connection.CreateCommand();
insertCommand.CommandText = "INSERT INTO UserSettings (UserId, NotificationsEnabled) VALUES (@userId, 1)";
insertCommand.Parameters.AddWithValue("@userId", chatId);
await insertCommand.ExecuteNonQueryAsync();
Log.Information($"[Отладка] Создали запись для пользователя {chatId} с notificationsEnabled=true");
}
}
// Создаем клавиатуру с настройками
string notificationStatus = notificationsEnabled ? "✅ Включены" : "❌ Отключены";
string toggleAction = notificationsEnabled ? "toggle_off" : "toggle_on";
Log.Information($"[Отладка] Для пользователя {chatId} показываем статус: {notificationStatus}, toggleAction: {toggleAction}");
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData($"Уведомления: {notificationStatus}", $"notifications_{toggleAction}")
},
new[]
{
InlineKeyboardButton.WithCallbackData("🔙 Назад в меню", "main_menu")
}
});
await botClient.SendMessage(
chatId: chatId,
text: "⚙️ <b>Настройки пользователя</b>\n\n" +
"Здесь вы можете настроить параметры бота:",
parseMode: ParseMode.Html,
replyMarkup: keyboard
);
}
catch (Exception ex)
{
Log.Error($"Ошибка при отображении настроек пользователя: {ex.Message}");
Log.Error($"StackTrace: {ex.StackTrace}");
await botClient.SendMessage(chatId, "Произошла ошибка при загрузке настроек.");
}
}
private static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
try
{
// Обработка нажатий на кнопки
if (update.Type == UpdateType.CallbackQuery)
{
var callbackQuery = update.CallbackQuery;
if (callbackQuery?.From != null)
{
long chatId = callbackQuery.From.Id;
string? data = callbackQuery.Data;
if (callbackQuery?.Message?.MessageId != null)
{
int messageId = callbackQuery.Message.MessageId;
await DeletePreviousMessage(botClient, chatId, messageId); // Удаляем предыдущее сообщение
}
if (callbackQuery?.Id != null)
{
await botClient.AnswerCallbackQuery(callbackQuery.Id); // Убираем "часики" у кнопки
}
if (data == "report")
{
usersWaitingForReport[chatId] = true;
userReportSteps[chatId] = 1;
userReports[chatId] = new Report();
var priorityKeyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Низкий", "priority_low"),
InlineKeyboardButton.WithCallbackData("Средний", "priority_medium"),
InlineKeyboardButton.WithCallbackData("Высокий", "priority_high")
}
});
await botClient.SendMessage(chatId, "Пожалуйста, выберите приоритет:", replyMarkup: priorityKeyboard);
Log.Information($"Пользователь {chatId} начал создание заявки");
}
else if (data == "admin_settings")
{
if (admins.Contains(chatId))
{
await ShowAdminSettings(botClient, chatId);
}
else
{
await botClient.SendMessage(chatId, "⛔ У вас нет прав для доступа к настройкам администраторов!");
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
}
}
else if (data == "view_admins")
{
if (admins.Contains(chatId))
{
await ShowAdminsList(botClient, chatId);
}
else
{
await botClient.SendMessage(chatId, "⛔ У вас нет прав для просмотра администраторов!");
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
}
}
else if (data != null && data.StartsWith("removeadmin_"))
{
long adminIdToRemove = long.Parse(data.Substring(11).Replace("_", ""));
// Проверяем, что пользователь является администратором
if (admins.Contains(chatId))
{
// Проверяем, не пытается ли пользователь удалить себя
if (adminIdToRemove == chatId)
{
var warningMessage = await botClient.SendMessage(
chatId: chatId,
text: "⚠️ Вы не можете удалить себя из администраторов!"
);
await Task.Delay(2000);
await botClient.DeleteMessage(chatId, warningMessage.MessageId);
await ShowAdminsList(botClient, chatId);
}
else
{
await RemoveAdminFromDatabase(adminIdToRemove);
string username = "администратор";
try
{
var user = await botClient.GetChat(adminIdToRemove);
username = user.Username ?? user.FirstName ?? "администратор";
}
catch { }
await botClient.SendMessage(
chatId: chatId,
text: $"✅ Пользователь {username} (ID: {adminIdToRemove}) удален из администраторов."
);
await Task.Delay(2000);
await ShowAdminsList(botClient, chatId);
}
}
else
{
await botClient.SendMessage(chatId, "⛔ У вас нет прав для удаления администраторов!");
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
}
}
// Также добавим обработку команды /removeadmin в секцию обработки текстовых сообщений:
// В блоке для обработки текстовых сообщений (после if (message.Text.StartsWith("/admin")))
else if (update.Type == UpdateType.Message && update.Message?.Text != null)
{
var message = update.Message;
Log.Information($"Получено сообщение от {message.Chat.Id}: {message.Text}");
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, ""); // Добавляем пустую строку для fullName
var authMessage = await botClient.SendMessage(message.Chat.Id, "✅ Вы авторизованы как администратор!");
Log.Information($"Новый администратор: {message.Chat.Id}");
await Task.Delay(2000);
await botClient.DeleteMessage(message.Chat.Id, authMessage.MessageId);
await SendMainMenu(botClient, message.Chat.Id);
}
else
{
var authMessage = await botClient.SendMessage(message.Chat.Id, "❌ Неверный пароль!");
await Task.Delay(2000);
await botClient.DeleteMessage(message.Chat.Id, authMessage.MessageId);
await SendMainMenu(botClient, message.Chat.Id);
}
return;
}
}
else if (data == "admin_panel")
{
if (admins.Contains(chatId))
{
await SendAdminPanel(botClient, chatId);
}
else
{
var authMessage = await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!");
Log.Information($"Неавторизованный доступ к админ-панели от {chatId}");
await Task.Delay(2000);
await botClient.DeleteMessage(chatId, authMessage.MessageId);
await SendMainMenu(botClient, chatId);
}
}
else if (data == "view_reports")
{
if (admins.Contains(chatId))
{
await ViewReports(botClient, chatId);
}
else
{
var authMessage = await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!");
Log.Information($"Неавторизованный доступ к заявкам от {chatId}");
await Task.Delay(2000);
await botClient.DeleteMessage(chatId, authMessage.MessageId);
await SendMainMenu(botClient, chatId);
}
}
else if (data == "view_archived_reports")
{
if (admins.Contains(chatId))
{
await ViewArchivedReports(botClient, chatId);
}
else
{
var authMessage = await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!");
Log.Information($"Неавторизованный доступ к архиву заявок от {chatId}");
await Task.Delay(2000);
await botClient.DeleteMessage(chatId, authMessage.MessageId);
await SendMainMenu(botClient, chatId);
}
}
else if (data == "delete_all_reports")
{
if (admins.Contains(chatId))
{
var confirmKeyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("✅ Подтвердить", "confirm_delete_all_reports"),
InlineKeyboardButton.WithCallbackData("❌ Отмена", "admin_panel")
}
});
await botClient.SendMessage(
chatId: chatId,
text: "Вы уверены, что хотите удалить все заявки? Это действие необратимо.",
replyMarkup: confirmKeyboard
);
}
else
{
await botClient.SendMessage(chatId, "⛔ У вас нет прав для удаления всех заявок!");
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
}
}
else if (data == "confirm_delete_all_reports")
{
if (admins.Contains(chatId))
{
await DeleteAllReports(botClient, chatId);
}
else
{
await botClient.SendMessage(chatId, "⛔ У вас нет прав для удаления всех заявок!");
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
}
}
else if (data != null && data.StartsWith("report_"))
{
long reportId = long.Parse(data.Substring(7));
if (callbackQuery?.Message?.MessageId != null)
{
int messageId = callbackQuery.Message.MessageId;
await ShowReportDetails(botClient, chatId, reportId, messageId);
}
}
else if (data != null && data.StartsWith("status_"))
{
string[] parts = data.Split('_');
long reportId = long.Parse(parts[1]);
string newStatus = parts[2];
if (callbackQuery?.Message?.MessageId != null)
{
int messageId = callbackQuery.Message.MessageId;
await UpdateReportStatus(reportId, newStatus, chatId);
await ShowReportDetails(botClient, chatId, reportId, messageId);
}
}
else if (data != null && data.StartsWith("delete_"))
{
long reportId = long.Parse(data.Substring(7));
await DeleteReport(botClient, chatId, reportId);
}
else if (data == "back_to_list")
{
await ViewReports(botClient, chatId);
}
else if (data == "back_to_admin_panel")
{
await SendAdminPanel(botClient, chatId);
}
else if (data == "main_menu")
{
await SendMainMenu(botClient, chatId);
}
else if (data == "user_settings")
{
await ShowUserSettings(botClient, chatId);
}
else if (data != null && data.StartsWith("notifications_toggle_"))
{
string action = data.Substring("notifications_toggle_".Length); // "on" или "off"
await ToggleNotifications(botClient, chatId, action);
}
else if (data != null && data.StartsWith("priority_"))
{
string priority = data.Substring(9);
userReports[chatId].Priority = priority;
userReportSteps[chatId] = 2;
await botClient.SendMessage(chatId, "Пожалуйста, укажите кабинет.");
}
}
}
// Обработка текстовых сообщений
if (update.Type == UpdateType.Message && update.Message?.Text != null)
{
var message = update.Message;
Log.Information($"Получено сообщение от {message.Chat.Id}: {message.Text}");
// Обработка текстовых сообщений
if (update.Type == UpdateType.Message && update.Message?.Text != null)
{
var receivedMessage = update.Message;
Log.Information($"Получено сообщение от {receivedMessage.Chat.Id}: {receivedMessage.Text}");
if (receivedMessage.Text.StartsWith("/admin"))
{
string[] parts = receivedMessage.Text.Split(new[] { ' ' }, 3); // Разделяем на 3 части: команду, пароль и остаток как ФИО
if (parts.Length >= 3 && parts[1] == adminPassword)
{
string fullName = parts[2]; // Вся оставшаяся строка - это ФИО
admins.Add(receivedMessage.Chat.Id);
adminFullNames[receivedMessage.Chat.Id] = fullName;
// Сохраняем администратора в базу данных
await SaveAdminToDatabase(receivedMessage.Chat.Id, fullName);
var authMessage = await botClient.SendMessage(receivedMessage.Chat.Id, $"✅ Вы авторизованы как администратор, {fullName}!");
Log.Information($"Новый администратор: {receivedMessage.Chat.Id}, ФИО: {fullName}");
await Task.Delay(2000);
await botClient.DeleteMessage(receivedMessage.Chat.Id, authMessage.MessageId);
await SendMainMenu(botClient, receivedMessage.Chat.Id);
}
else
{
var authMessage = await botClient.SendMessage(receivedMessage.Chat.Id, "❌ Неверный формат команды или пароль! Используйте: /admin пароль Фамилия Имя Отчество");
await Task.Delay(2000);
await botClient.DeleteMessage(receivedMessage.Chat.Id, authMessage.MessageId);
await SendMainMenu(botClient, receivedMessage.Chat.Id);
}
return;
}
// В блоке для обработки текстовых сообщений
else if (message.Text == "/admins")
{
if (admins.Contains(message.Chat.Id))
{
await ShowAdminsList(botClient, message.Chat.Id);
}
else
{
var authMessage = await botClient.SendMessage(
chatId: message.Chat.Id,
text: "⛔ У вас нет прав для просмотра списка администраторов!"
);
await Task.Delay(2000);
await botClient.DeleteMessage(message.Chat.Id, authMessage.MessageId);
await SendMainMenu(botClient, message.Chat.Id);
}
}
if (message.Text == "/start")
{
await SendMainMenu(botClient, message.Chat.Id);
Log.Information($"Ответ на команду /start с кнопками отправлен.");
}
else if (usersWaitingForReport.TryGetValue(message.Chat.Id, out bool isWaiting) && isWaiting)
{
if (userReportSteps.TryGetValue(message.Chat.Id, out int step))
{
switch (step)
{
case 2:
userReports[message.Chat.Id].Room = message.Text;
userReportSteps[message.Chat.Id] = 3;
await botClient.SendMessage(message.Chat.Id, "Пожалуйста, опишите проблему.");
break;
case 3:
userReports[message.Chat.Id].Description = message.Text;
userReportSteps[message.Chat.Id] = 4;
await botClient.SendMessage(message.Chat.Id, "Пожалуйста, укажите ваше ФИО.");
break;
case 4:
userReports[message.Chat.Id].ReporterName = message.Text;
await SaveReportToDatabase(message.Chat.Id, userReports[message.Chat.Id]);
var mainMenuKeyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(
message.Chat.Id,
"✅ Спасибо за заявку! Мы обработаем её в ближайшее время.",
replyMarkup: mainMenuKeyboard
);
usersWaitingForReport[message.Chat.Id] = false;
userReportSteps.Remove(message.Chat.Id);
userReports.Remove(message.Chat.Id);
Log.Information($"Заявка пользователя {message.Chat.Id} сохранена в базе данных.");
break;
}
}
}
}
else
{
await botClient.SendMessage(message.Chat.Id, " Используйте команду /start для начала работы с ботом.");
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при обработке обновлений: {ex.Message}");
Log.Error($"StackTrace: {ex.StackTrace}");
}
}
private static async Task DeleteAllReports(ITelegramBotClient botClient, long chatId)
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM Reports";
await command.ExecuteNonQueryAsync();
var deletionMessage = await botClient.SendMessage(chatId, "Все заявки успешно удалены.");
Log.Information($"Все заявки удалены пользователем {chatId}.");
// Ждем 2 секунды
await Task.Delay(2000);
// Удаляем сообщение об удалении
await botClient.DeleteMessage(chatId, deletionMessage.MessageId);
// Возвращаемся к панели администратора
await SendAdminPanel(botClient, chatId);
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при удалении всех заявок: {ex.Message}");
await botClient.SendMessage(chatId, "Ошибка при удалении всех заявок.");
}
}
private static async Task DeleteReport(ITelegramBotClient botClient, long chatId, long reportId)
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM Reports WHERE Id = @id";
command.Parameters.AddWithValue("@id", reportId);
await command.ExecuteNonQueryAsync();
var deletionMessage = await botClient.SendMessage(chatId, $"Заявка #{reportId} успешно удалена.");
Log.Information($"Заявка #{reportId} удалена пользователем {chatId}.");
// Ждем 2 секунды
await Task.Delay(2000);
// Удаляем сообщение об удалении
await botClient.DeleteMessage(chatId, deletionMessage.MessageId);
// Отображаем список заявок
await ViewReports(botClient, chatId);
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при удалении заявки #{reportId}: {ex.Message}");
await botClient.SendMessage(chatId, $"Ошибка при удалении заявки #{reportId}.");
}
}
private static async Task NotifyUserAboutStatusChange(long chatId, long reportId, string newStatus)
{
try
{
// Проверяем настройки пользователя
bool notificationsEnabled = true; // По умолчанию уведомления включены
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "SELECT NotificationsEnabled FROM UserSettings WHERE UserId = @userId";
command.Parameters.AddWithValue("@userId", chatId);
var result = await command.ExecuteScalarAsync();
if (result != null && result != DBNull.Value)
{
notificationsEnabled = Convert.ToInt32(result) == 1;
}
}
// Если уведомления отключены, не отправляем сообщение
if (!notificationsEnabled)
{
Log.Information($"Уведомление о смене статуса заявки #{reportId} не отправлено пользователю {chatId} (уведомления отключены)");
return;
}
string statusEmoji = GetStatusEmoji(newStatus);
await _botClient.SendMessage(
chatId: chatId,
text: $"{statusEmoji} <b>Статус вашей заявки #{reportId} был изменен на: {newStatus}</b>",
parseMode: ParseMode.Html
);
Log.Information($"Уведомление о смене статуса заявки #{reportId} отправлено пользователю {chatId}");
}
catch (Exception ex)
{
Log.Error($"Ошибка при отправке уведомления пользователю о смене статуса: {ex.Message}");
}
}
private static async Task ToggleNotifications(ITelegramBotClient botClient, long chatId, string action)
{
try
{
// Проверка текущего состояния перед изменением
bool currentState = true;
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var checkCommand = connection.CreateCommand();
checkCommand.CommandText = "SELECT NotificationsEnabled FROM UserSettings WHERE UserId = @userId";
checkCommand.Parameters.AddWithValue("@userId", chatId);
var result = await checkCommand.ExecuteScalarAsync();
if (result != null && result != DBNull.Value)
{
currentState = Convert.ToInt32(result) == 1;
}
}
Log.Information($"[Отладка] Переключение уведомлений для пользователя {chatId}: текущее состояние={currentState}, action={action}");
// Если action = "toggle_on", то нужно ВКЛЮЧИТЬ уведомления (установить в БД 1)
// Если action = "toggle_off", то нужно ВЫКЛЮЧИТЬ уведомления (установить в БД 0)
bool newValue = action == "on";
int dbValue = newValue ? 1 : 0;
Log.Information($"[Отладка] Переключение уведомлений для пользователя {chatId}: action={action}, новое значение={newValue}, значение в БД={dbValue}");
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = @"
INSERT INTO UserSettings (UserId, NotificationsEnabled)
VALUES (@userId, @value)
ON CONFLICT(UserId)
DO UPDATE SET NotificationsEnabled = @value";
command.Parameters.AddWithValue("@userId", chatId);
command.Parameters.AddWithValue("@value", dbValue);
int rowsAffected = await command.ExecuteNonQueryAsync();
Log.Information($"[Отладка] Запрос выполнен, затронуто {rowsAffected} строк");
}
// Проверка после изменения
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var checkCommand = connection.CreateCommand();
checkCommand.CommandText = "SELECT NotificationsEnabled FROM UserSettings WHERE UserId = @userId";
checkCommand.Parameters.AddWithValue("@userId", chatId);
var result = await checkCommand.ExecuteScalarAsync();
bool updatedState = false;
if (result != null && result != DBNull.Value)
{
updatedState = Convert.ToInt32(result) == 1;
}
Log.Information($"[Отладка] После обновления: значение в БД для пользователя {chatId} = {result}, обновленное состояние={updatedState}");
}
// Показываем обновленные настройки
await ShowUserSettings(botClient, chatId);
string statusText = newValue ? "включены" : "отключены";
Log.Information($"Пользователь {chatId}: уведомления {statusText}");
}
catch (Exception ex)
{
Log.Error($"Ошибка при изменении настроек уведомлений: {ex.Message}");
Log.Error($"StackTrace: {ex.StackTrace}");
await botClient.SendMessage(chatId, "Произошла ошибка при обновлении настроек.");
}
}
private static async Task SendMainMenu(ITelegramBotClient botClient, long chatId)
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("📝 Подать заявку", "report"),
InlineKeyboardButton.WithCallbackData("⚙️ Настройки", "user_settings")
},
new[]
{
InlineKeyboardButton.WithCallbackData("🔐 Панель администратора", "admin_panel")
}
});
await botClient.SendMessage(
chatId: chatId,
text: "Главное меню:",
replyMarkup: keyboard
);
}
private static async Task SendAdminPanel(ITelegramBotClient botClient, long chatId)
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("📋 Менеджер заявок", "view_reports"),
InlineKeyboardButton.WithCallbackData("🗃️ Архив заявок", "view_archived_reports")
},
new[]
{
InlineKeyboardButton.WithCallbackData("⚙️ Управление администраторами", "admin_settings")
},
new[]
{
InlineKeyboardButton.WithCallbackData("❌ Удалить все заявки", "delete_all_reports")
},
new[]
{
InlineKeyboardButton.WithCallbackData("🏠 Главное меню", "main_menu")
}
});
await botClient.SendMessage(
chatId: chatId,
text: "🔐 <b>Панель администраторов:</b>",
parseMode: ParseMode.Html,
replyMarkup: keyboard
);
}
private static async Task ViewReports(ITelegramBotClient botClient, long chatId)
{
string connectionString = "Data Source=bot.db";
try
{
using (var connection = new SqliteConnection(connectionString))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "SELECT Id, Description, Status, Priority FROM Reports WHERE Status != 'закрыта'";
var buttons = new List<InlineKeyboardButton[]>();
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
long id = reader.GetInt64(0);
string description = reader.GetString(1).Substring(0, Math.Min(20, reader.GetString(1).Length));
string status = reader.GetString(2);
string priority = reader.GetString(3);
string statusEmoji = GetStatusEmoji(status);
string priorityMarker = priority.ToLower() == "высокий" ? "⚠️ " : "";
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData(
$"{priorityMarker}#{id} - {statusEmoji} {status} - {description}...",
$"report_{id}")
});
}
}
// Добавляем кнопки навигации
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData("🔙 Назад", "back_to_admin_panel"),
InlineKeyboardButton.WithCallbackData("🏠 Главное меню", "main_menu")
});
await botClient.SendMessage(
chatId: chatId,
text: "Список заявок:",
replyMarkup: new InlineKeyboardMarkup(buttons)
);
}
}
catch (Exception ex)
{
Log.Error($"Ошибка: {ex.Message}");
await botClient.SendMessage(chatId, "Ошибка при получении заявок");
}
}
private static async Task ViewArchivedReports(ITelegramBotClient botClient, long chatId)
{
string connectionString = "Data Source=bot.db";
try
{
using (var connection = new SqliteConnection(connectionString))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "SELECT Id, Description, Status, Priority FROM Reports WHERE Status = 'закрыта'";
var buttons = new List<InlineKeyboardButton[]>();
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
long id = reader.GetInt64(0);
string description = reader.GetString(1).Substring(0, Math.Min(20, reader.GetString(1).Length));
string status = reader.GetString(2);
string priority = reader.GetString(3);
string statusEmoji = GetStatusEmoji(status);
string priorityMarker = priority.ToLower() == "высокий" ? "⚠️ " : "";
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData(
$"{priorityMarker}#{id} - {statusEmoji} {status} - {description}...",
$"report_{id}")
});
}
}
// Добавляем кнопки навигации
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData("🔙 Назад", "back_to_admin_panel"),
InlineKeyboardButton.WithCallbackData("🏠 Главное меню", "main_menu")
});
await botClient.SendMessage(
chatId: chatId,
text: "Архив заявок:",
replyMarkup: new InlineKeyboardMarkup(buttons)
);
}
}
catch (Exception ex)
{
Log.Error($"Ошибка: {ex.Message}");
await botClient.SendMessage(chatId, "Ошибка при получении архива заявок");
}
}
private static async Task ShowReportDetails(ITelegramBotClient botClient, long chatId, long reportId, int messageId)
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "SELECT Priority, Room, Description, ReporterName, Status, DateCreated, AdminId FROM Reports WHERE Id = @id";
command.Parameters.AddWithValue("@id", reportId);
using (var reader = await command.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
string priority = reader.GetString(0);
string room = reader.GetString(1);
string description = reader.GetString(2);
string reporterName = reader.GetString(3);
string status = reader.GetString(4);
string dateCreated = reader.GetDateTime(5).ToString("yyyy-MM-dd HH:mm:ss");
// Проверяем существование столбца AdminId
long adminId = 0;
try
{
if (!reader.IsDBNull(6))
adminId = reader.GetInt64(6);
}
catch
{
Log.Warning($"Столбец AdminId для заявки {reportId} не найден или содержит NULL");
}
string adminFullName = adminId > 0 && adminFullNames.ContainsKey(adminId)
? adminFullNames[adminId]
: "Не назначен";
string priorityEmoji = GetPriorityEmoji(priority);
string statusEmoji = GetStatusEmoji(status);
var statusButtons = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("🟡 Ожидает", $"status_{reportId}_ожидает"),
InlineKeyboardButton.WithCallbackData("🔵 В работе", $"status_{reportId}_в работе")
},
new[]
{
InlineKeyboardButton.WithCallbackData("🟢 Закрыта", $"status_{reportId}_закрыта")
},
new[]
{
InlineKeyboardButton.WithCallbackData("❌ Удалить заявку", $"delete_{reportId}")
},
new[]
{
InlineKeyboardButton.WithCallbackData("Назад", "back_to_list"),
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
string newText = $"Заявка #{reportId}\n\n" +
$"Приоритет: {priorityEmoji} {priority}\n" +
$"Кабинет: {room}\n" +
$"Описание: {description}\n" +
$"ФИО: {reporterName}\n" +
$"Статус: {statusEmoji} {status}\n" +
$"Дата создания: {dateCreated}\n" +
$"Администратор: {adminFullName}";
await botClient.SendMessage(
chatId: chatId,
text: newText,
replyMarkup: statusButtons
);
}
else
{
// Если заявка не найдена
await botClient.SendMessage(
chatId: chatId,
text: $"⚠️ Заявка #{reportId} не найдена!"
);
Log.Warning($"Заявка #{reportId} не найдена при попытке просмотра деталей.");
await Task.Delay(2000);
await ViewReports(botClient, chatId);
}
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при отображении деталей заявки #{reportId}: {ex.Message}");
await botClient.SendMessage(
chatId: chatId,
text: $"Произошла ошибка при загрузке заявки #{reportId}."
);
}
}
// Метод для удаления администратора из базы данных
private static async Task RemoveAdminFromDatabase(long chatId)
{
try
{
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "DELETE FROM Admins WHERE ChatId = @chatId";
command.Parameters.AddWithValue("@chatId", chatId);
int rowsAffected = await command.ExecuteNonQueryAsync();
if (rowsAffected > 0)
{
admins.Remove(chatId);
Log.Information($"Администратор {chatId} удален из базы данных");
}
else
{
Log.Information($"Администратор {chatId} не найден в базе данных");
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при удалении администратора из базы данных: {ex.Message}");
}
}
// Метод для отображения списка администраторов
private static async Task ShowAdminsList(ITelegramBotClient botClient, long chatId)
{
try
{
// Проверяем, что запрашивающий пользователь - администратор
if (!admins.Contains(chatId))
{
await botClient.SendMessage(
chatId: chatId,
text: "⛔ У вас нет прав для просмотра списка администраторов."
);
return;
}
// Получаем список всех администраторов из базы данных
var adminsList = new List<(long chatId, string username)>();
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);
string username = "Неизвестно";
// Пытаемся получить имя пользователя
try
{
var user = await botClient.GetChat(adminId);
username = user.Username ?? user.FirstName ?? "Неизвестно";
}
catch
{
// Если возникает ошибка при получении информации о пользователе,
// просто используем "Неизвестно"
}
adminsList.Add((adminId, username));
}
}
}
// Формируем сообщение
if (adminsList.Count == 0)
{
await botClient.SendMessage(
chatId: chatId,
text: "⚠️ В системе нет зарегистрированных администраторов."
);
return;
}
var buttons = new List<InlineKeyboardButton[]>();
var messageText = new System.Text.StringBuilder();
messageText.AppendLine("📋 <b>Список администраторов:</b>\n");
for (int i = 0; i < adminsList.Count; i++)
{
var (adminId, username) = adminsList[i];
messageText.AppendLine($"{i + 1}. {username} (ID: {adminId})");
buttons.Add(new[] {
InlineKeyboardButton.WithCallbackData($"❌ Удалить {username}", $"removeadmin_{adminId}")
});
}
buttons.Add(new[] {
InlineKeyboardButton.WithCallbackData("🔙 Назад", "admin_settings")
});
var keyboard = new InlineKeyboardMarkup(buttons);
await botClient.SendMessage(
chatId: chatId,
text: messageText.ToString(),
parseMode: ParseMode.Html,
replyMarkup: keyboard
);
}
catch (Exception ex)
{
Log.Error($"Ошибка при отображении списка администраторов: {ex.Message}");
await botClient.SendMessage(
chatId: chatId,
text: "❌ Произошла ошибка при отображении списка администраторов."
);
}
}
// Добавим метод для отображения раздела настроек администраторов
private static async Task ShowAdminSettings(ITelegramBotClient botClient, long chatId)
{
try
{
// Проверяем, что запрашивающий пользователь - администратор
if (!admins.Contains(chatId))
{
await botClient.SendMessage(
chatId: chatId,
text: "⛔ У вас нет прав для доступа к настройкам администраторов."
);
await Task.Delay(2000);
await SendMainMenu(botClient, chatId);
return;
}
// Получаем список всех администраторов из базы данных
var adminsList = new List<(long chatId, string username)>();
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);
string username = "Неизвестно";
// Пытаемся получить имя пользователя
try
{
var user = await botClient.GetChat(adminId);
username = user.Username ?? user.FirstName ?? "Неизвестно";
}
catch
{
// Если возникает ошибка при получении информации о пользователе,
// просто используем "Неизвестно"
}
adminsList.Add((adminId, username));
}
}
}
// Формируем сообщение
if (adminsList.Count == 0)
{
await botClient.SendMessage(
chatId: chatId,
text: "⚠️ В системе нет зарегистрированных администраторов."
);
return;
}
var buttons = new List<InlineKeyboardButton[]>();
var messageText = new System.Text.StringBuilder();
messageText.AppendLine("📋 <b>Список администраторов:</b>\n");
for (int i = 0; i < adminsList.Count; i++)
{
var (adminId, username) = adminsList[i];
messageText.AppendLine($"{i + 1}. {username} (ID: {adminId})");
buttons.Add(new[] {
InlineKeyboardButton.WithCallbackData($"❌ Удалить {username}", $"removeadmin_{adminId}")
});
}
buttons.Add(new[] {
InlineKeyboardButton.WithCallbackData("🔙 Назад к панели администратора", "admin_panel"),
InlineKeyboardButton.WithCallbackData("🏠 Главное меню", "main_menu")
});
var keyboard = new InlineKeyboardMarkup(buttons);
await botClient.SendMessage(
chatId: chatId,
text: messageText.ToString(),
parseMode: ParseMode.Html,
replyMarkup: keyboard
);
}
catch (Exception ex)
{
Log.Error($"Ошибка при отображении настроек администраторов: {ex.Message}");
}
}
private static async Task NotifyAdminsAboutWorkAssignment(long reportId, long changerId)
{
try
{
// Получаем данные о заявке
string description = "";
string priority = "";
string room = "";
string changerFullName = adminFullNames[changerId];
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 priorityEmoji = GetPriorityEmoji(priority);
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("📝 Посмотреть детали", $"report_{reportId}")
}
});
await _botClient.SendMessage(
chatId: adminId,
text: $"{priorityEmoji} <b>Заявка #{reportId} взята в работу администратором {changerFullName}</b>\n\n" +
$"<b>Приоритет:</b> {priority}\n" +
$"<b>Кабинет:</b> {room}\n" +
$"<b>Фрагмент описания:</b> {description.Substring(0, Math.Min(50, description.Length))}...",
parseMode: ParseMode.Html,
replyMarkup: keyboard
);
Log.Information($"Уведомление о взятии в работу заявки #{reportId} отправлено администратору {adminId}");
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при отправке уведомлений о взятии в работу: {ex.Message}");
}
}
private static async Task UpdateReportStatus(long reportId, string newStatus, long changerId)
{
try
{
string oldStatus = "";
long userChatId = 0;
// Сначала получаем текущий статус и chatId пользователя
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var getStatusCommand = connection.CreateCommand();
getStatusCommand.CommandText = "SELECT Status, ChatId FROM Reports WHERE Id = @id";
getStatusCommand.Parameters.AddWithValue("@id", reportId);
using (var reader = await getStatusCommand.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
oldStatus = reader.GetString(0);
userChatId = reader.GetInt64(1);
}
}
}
// Если статус не изменился, прерываем выполнение
if (oldStatus == newStatus) return;
// Обновляем статус и сохраняем ID администратора
using (var connection = new SqliteConnection("Data Source=bot.db"))
{
await connection.OpenAsync();
var command = connection.CreateCommand();
command.CommandText = "UPDATE Reports SET Status = @status, AdminId = @adminId WHERE Id = @id";
command.Parameters.AddWithValue("@status", newStatus);
command.Parameters.AddWithValue("@adminId", changerId);
command.Parameters.AddWithValue("@id", reportId);
await command.ExecuteNonQueryAsync();
// Уведомляем администраторов об изменении статуса
await NotifyAdminsAboutStatusChange(reportId, newStatus, oldStatus, changerId);
// Уведомляем пользователя об изменении статуса
await NotifyUserAboutStatusChange(userChatId, reportId, newStatus);
// Уведомляем администраторов, если заявка взята в работу
if (newStatus == "в работе")
{
await NotifyAdminsAboutWorkAssignment(reportId, changerId);
}
// Перезапускаем мониторинг, если статус изменился обратно на "ожидает"
if (newStatus == "ожидает")
{
var cts = new CancellationTokenSource();
_ = Task.Run(() => MonitorReportStatus(reportId, cts.Token));
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при обновлении статуса заявки: {ex.Message}");
}
}
private static async Task SaveReportToDatabase(long chatId, Report report)
{
string connectionString = "Data Source=bot.db"; // Используем SQLite
try
{
using (var connection = new SqliteConnection(connectionString))
{
await connection.OpenAsync();
var insertCommand = connection.CreateCommand();
insertCommand.CommandText =
@"
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);
long reportId = Convert.ToInt64(await insertCommand.ExecuteScalarAsync());
Log.Information($"Заявка от пользователя {chatId} успешно сохранена с ID {reportId}.");
// Уведомляем администраторов о новой заявке
await NotifyAdminsAboutNewReport(reportId, report);
// Запускаем мониторинг статуса заявки
var cts = new CancellationTokenSource();
_ = Task.Run(() => MonitorReportStatus(reportId, cts.Token));
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при сохранении заявки в базу данных: {ex.Message}");
}
}
// Обновляем метод CreateDatabaseIfNotExists
private static async Task CreateDatabaseIfNotExists()
{
string connectionString = "Data Source=bot.db"; // Путь к вашей базе данных
try
{
using (var connection = new SqliteConnection(connectionString))
{
await connection.OpenAsync();
// Проверяем, существует ли таблица Reports
var checkTableCommand = connection.CreateCommand();
checkTableCommand.CommandText = "PRAGMA table_info(Reports);";
var tableInfo = await checkTableCommand.ExecuteReaderAsync();
var requiredColumns = new HashSet<string> { "Id", "ChatId", "Priority", "Room", "Description", "ReporterName", "DateCreated", "Status", "AdminId" };
var existingColumns = new HashSet<string>();
while (await tableInfo.ReadAsync())
{
existingColumns.Add(tableInfo["name"]?.ToString() ?? string.Empty);
}
foreach (var column in requiredColumns)
{
if (!existingColumns.Contains(column))
{
var alterTableCommand = connection.CreateCommand();
switch (column)
{
case "Priority":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN Priority TEXT NOT NULL DEFAULT 'низкий';";
break;
case "Room":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN Room TEXT NOT NULL DEFAULT '';";
break;
case "Description":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN Description TEXT NOT NULL DEFAULT '';";
break;
case "ReporterName":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN ReporterName TEXT NOT NULL DEFAULT '';";
break;
case "DateCreated":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP;";
break;
case "Status":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN Status TEXT DEFAULT 'ожидает';";
break;
case "AdminId":
alterTableCommand.CommandText = "ALTER TABLE Reports ADD COLUMN AdminId INTEGER DEFAULT 0;";
break;
}
await alterTableCommand.ExecuteNonQueryAsync();
Log.Information($"Столбец {column} добавлен в таблицу Reports.");
}
}
// Создаем таблицу Reports, если её не существует
var createTableCommand = connection.CreateCommand();
createTableCommand.CommandText =
@"
CREATE TABLE IF NOT EXISTS Reports (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
ChatId INTEGER NOT NULL,
Priority TEXT NOT NULL,
Room TEXT NOT NULL,
Description TEXT NOT NULL,
ReporterName TEXT NOT NULL,
DateCreated DATETIME DEFAULT CURRENT_TIMESTAMP,
Status TEXT DEFAULT 'ожидает',
AdminId INTEGER DEFAULT 0
);
";
await createTableCommand.ExecuteNonQueryAsync();
Log.Information("Таблица Reports успешно создана (если её не было).");
// Создаем таблицу администраторов
await CreateAdminsTableIfNotExists();
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при создании таблиц в базе данных: {ex.Message}");
}
}
private static Dictionary<long, int> userReportSteps = new Dictionary<long, int>();
private static Dictionary<long, Report> userReports = new Dictionary<long, Report>();
private class Report
{
public string Priority { get; set; } = string.Empty;
public string Room { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string ReporterName { get; set; } = string.Empty;
}
private static Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
{
Log.Error($"Ошибка в процессе работы с ботом: {exception.Message}");
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,
FullName TEXT NOT NULL
);";
await command.ExecuteNonQueryAsync();
Log.Information("Таблица Admins успешно создана (если её не было).");
// Проверяем наличие столбца FullName
command.CommandText = "PRAGMA table_info(Admins);";
var tableInfo = await command.ExecuteReaderAsync();
bool fullNameColumnExists = false;
while (await tableInfo.ReadAsync())
{
if (tableInfo["name"].ToString() == "FullName")
{
fullNameColumnExists = true;
break;
}
}
await tableInfo.CloseAsync(); // Закрываем DataReader перед изменением CommandText
if (!fullNameColumnExists)
{
command.CommandText = "ALTER TABLE Admins ADD COLUMN FullName TEXT NOT NULL DEFAULT '';";
await command.ExecuteNonQueryAsync();
Log.Information("Столбец FullName добавлен в таблицу Admins.");
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при создании таблицы Admins: {ex.Message}");
}
}
// Метод для сохранения администратора в базу данных
private static async Task SaveAdminToDatabase(long chatId, string fullName)
{
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, FullName) VALUES (@chatId, @fullName)";
insertCommand.Parameters.AddWithValue("@chatId", chatId);
insertCommand.Parameters.AddWithValue("@fullName", fullName);
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, FullName FROM Admins";
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
long adminId = reader.GetInt64(0);
string fullName = reader.GetString(1);
admins.Add(adminId);
adminFullNames[adminId] = fullName;
Log.Information($"Загружен администратор с ID: {adminId}, ФИО: {fullName}");
}
}
}
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} <b>Новая заявка #{reportId}</b>\n\n" +
$"<b>Приоритет:</b> {report.Priority}\n" +
$"<b>Кабинет:</b> {report.Room}\n" +
$"<b>Описание:</b> {report.Description}\n" +
$"<b>От:</b> {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} <b>Обновление статуса заявки #{reportId}</b>\n\n" +
$"<b>Приоритет:</b> {priority}\n" +
$"<b>Кабинет:</b> {room}\n" +
$"<b>Статус изменен:</b> {oldStatus} ➡️ {newStatus}\n\n" +
$"<b>Фрагмент описания:</b> {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
{
"ожидает" => "🟡",
"в работе" => "🔵",
"закрыта" => "🟢",
_ => ""
};
}
}