telegram-bot/Program.cs
Professional a19ba440c2 Добавлены новые условия и кнопки навигации
В класс Program добавлено условие для обработки данных "back_to_archived_list", которое вызывает метод ViewArchivedReports для отображения архивированных отчетов. Также добавлены кнопки "Назад" и "Главное меню" для улучшения навигации пользователя.
2025-03-19 19:51:10 +07:00

779 lines
33 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"; // Простой пароль для администратора
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();
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 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 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_panel")
{
if (admins.Contains(chatId))
{
await SendAdminPanel(botClient, chatId);
}
else
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!", replyMarkup: keyboard);
Log.Information($"Неавторизованный доступ к админ-панели от {chatId}");
}
}
else if (data == "view_reports")
{
if (admins.Contains(chatId))
{
await ViewReports(botClient, chatId);
}
else
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!", replyMarkup: keyboard);
Log.Information($"Неавторизованный доступ к заявкам от {chatId}");
}
}
else if (data == "view_archived_reports")
{
if (admins.Contains(chatId))
{
await ViewArchivedReports(botClient, chatId);
}
else
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(chatId, "⛔ Вы не являетесь администратором!", replyMarkup: keyboard);
Log.Information($"Неавторизованный доступ к архиву заявок от {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);
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_archived_list")
{
await ViewArchivedReports(botClient, chatId);
}
else if (data == "main_menu")
{
await SendMainMenu(botClient, chatId);
}
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}");
// Обработка команды /admin для авторизации
if (message.Text.StartsWith("/admin"))
{
string[] parts = message.Text.Split(' ');
if (parts.Length == 2 && parts[1] == adminPassword)
{
admins.Add(message.Chat.Id);
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(message.Chat.Id, "✅ Вы авторизованы как администратор!", replyMarkup: keyboard);
Log.Information($"Новый администратор: {message.Chat.Id}");
}
else
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Главное меню", "main_menu")
}
});
await botClient.SendMessage(message.Chat.Id, "❌ Неверный пароль!", replyMarkup: keyboard);
}
return;
}
if (message.Text == "/start")
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Подать заявку", "report"),
InlineKeyboardButton.WithCallbackData("Панель администратора", "admin_panel")
}
});
await botClient.SendMessage(
chatId: message.Chat.Id,
text: "Привет! Я бот для сбора заявок на ремонт оборудования.",
replyMarkup: keyboard
);
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 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 SendMainMenu(ITelegramBotClient botClient, long chatId)
{
var keyboard = new InlineKeyboardMarkup(new[]
{
new[]
{
InlineKeyboardButton.WithCallbackData("Подать заявку", "report"),
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("Главное меню", "main_menu")
}
});
await botClient.SendMessage(
chatId: chatId,
text: "Панель администраторов:",
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 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);
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData(
$"#{id} - {status} - {description}...",
$"report_{id}")
});
}
}
// Добавляем кнопки навигации
buttons.Add(new[]
{
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 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);
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData(
$"#{id} - {status} - {description}...",
$"report_{id}")
});
}
}
// Добавляем кнопки навигации
buttons.Add(new[]
{
InlineKeyboardButton.WithCallbackData("Назад", "back_to_list"),
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 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");
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" +
$"Приоритет: {priority}\n" +
$"Кабинет: {room}\n" +
$"Описание: {description}\n" +
$"ФИО: {reporterName}\n" +
$"Статус: {status}\n" +
$"Дата создания: {dateCreated}";
await botClient.SendMessage(
chatId: chatId,
text: newText,
replyMarkup: statusButtons
);
}
}
}
}
catch (Exception ex)
{
Log.Error($"Ошибка: {ex.Message}");
}
}
private static async Task UpdateReportStatus(long reportId, string newStatus)
{
try
{
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();
}
}
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, 'ожидает');
";
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} успешно сохранена.");
}
}
catch (Exception ex)
{
Log.Error($"Ошибка при сохранении заявки в базу данных: {ex.Message}");
}
}
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" };
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;
}
await alterTableCommand.ExecuteNonQueryAsync();
Log.Information($"Столбец {column} добавлен в таблицу 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 'ожидает'
);
";
await createTableCommand.ExecuteNonQueryAsync();
Log.Information("Таблица Reports успешно создана (если её не было).");
}
}
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;
}
}