Часть 1
Почему?
Решил я попрактиковаться в написании приложений на шарпе с использованием EF. Пока разбирался заметил, что туториалов и примеров как написать бота на C# немного, поэтому решил поделиться своими наработками.
Что может бот:
Задача бота - устроить обмен сообщениями между главным и подчиненными так, чтобы главный(диспетчер) мог писать всем или только одному подчиненному(водителю), а подчиненные могли общаться только с главным. WebHook не нужен, т.к. бот сугубо для практики.
Модель БД
Итак, для начала решил описать все необходимые таблицы, для хранения информации. Однако по итогу модель немного изменилась.

Шаг 1:
Для хранения таблиц я использовал Postgre SQL 15, а для мониторинга PgAdmin 4. Создал бд Users и развернул локально.
скачать
Шаг 2:
Установим все необходимые пакеты в VS через NuGET:
Microsoft.EntityFrameworkCore.Tools
Newtonsoft.Json
Npgsql.EntityFrameworkCore.PostgreSQL
Telegram.Bot
Telegram.Bot.Extensions.Polling

Шаг 3:
Получаем токен https://telegram.me/BotFather и плавно переходим к коду.

Шаг 4:
Создадим пустой класс Program.cs и внесем в него все необходимые для работы Методы:
using Telegram.Bot; using Telegram.Bot.Extensions.Polling; using Telegram.Bot.Types.ReplyMarkups; using CETmsgr.keyboards; using CETmsgr.dbutils; using Update = Telegram.Bot.Types.Update; using Telegram.Bot.Types.Enums; namespace CETmsgr { class Program { static ITelegramBotClient bot = new TelegramBotClient("TOKEN"); public static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(update)); if (update.Type == UpdateType.Message) { // Тут бот получает сообщения от пользователя // Дальше код отвечает за команду старт, которую можно добавить через botfather // Если все хорошо при запуске program.cs в консоль выведется, что бот запущен // а при отправке команды бот напишет Привет if (message.Text.ToLower() == "/start") { await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0); await botClient.SendTextMessageAsync( chatId: message.Chat, text: "Привет"); return; } if (update.Type == UpdateType.CallbackQuery) { // Тут получает нажатия на inline кнопки } public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) { // Данный Хендлер получает ошибки и выводит их в консоль в виде JSON Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(exception)); } static void Main(string[] args) { Console.WriteLine("Запущен бот " + bot.GetMeAsync().Result.FirstName); var cts = new CancellationTokenSource(); var cancellationToken = cts.Token; var receiverOptions = new ReceiverOptions { AllowedUpdates = { }, // разрешено получать все виды апдейтов }; bot.StartReceiving( HandleUpdateAsync, HandleErrorAsync, receiverOptions, cancellationToken ); Console.ReadLine(); } } }
Шаг 5:
Теперь приступим к созданию классов для таблиц, я создал отдельную папку dbutils для этих нужд.
UserRoles необходима для того, чтобы можно было сортировать id пользователей по ролям.
TrafficControllers и Drivers просто будут хранить информацию по юзерам.
DialogMembers будет хранить уникальные id диалогов и связывать их между id 2х юзеров
DialogMsgs эта таблица будет хранить сообщения, связанные с id диалога из DialogMembers
DialogStatus а вот эта таблица необходима для проверок при написании сообщений юзеров боту.
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class UserRoles { [Key] public long TgId { get; set; } public string Role { get; set; } public string? TgUsername { get; set; } public long TgChatId { get; set; } public int StageReg { get; set; } } }
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class Drivers { [Key] public long IdDriver { get; set; } public string Name { get; set; } public string IdRoute { get; set; } public string VehichleRegNum { get; set; } public string DeviceSerialNum { get; set; } } }
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class TrafficControllers { [Key] public long IdTc { get; set; } public string Name { get; set; } } }
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class DialogMembers { [Key] public int IdThread { get; set; } public long IdTc { get; set; } public long IdDriver { get; set; } } }
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class DialogMsgs { [Key] public long IdUnique { get; set; } public int IdThread { get; set; } public string Created { get; set; } public string UrgentLevel { get; set; } public string Message { get; set; } } }
using System.ComponentModel.DataAnnotations; namespace CETmsgr.dbutils { public partial class DialogStatus { [Key] public long TgId { get; set; } public int Status { get; set; } public long CurrentDialog { get; set; } } }
Чтобы на основании этого добра появились таблицы в бд необходимо провести миграцию. Поэтому создаем модель данных для наших классов и задаем подключение к бд:
using Microsoft.EntityFrameworkCore; namespace CETmsgr.dbutils { public class ApplicationContext : DbContext { public DbSet<UserRoles> UserRoles { get; set; } public DbSet<Drivers> Drivers { get; set; } public DbSet<TrafficControllers> TrafficControllers { get; set; } public DbSet<DialogMsgs> DialogMsgs { get; set; } public DbSet<DialogMembers> DialogMembers { get; set; } public DbSet<DialogStatus> DialogStatus { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql( "Host=localhost;" + "Port=5433;" + "Database=Users;" + "Username=postgres;" + "Password=zaqwsxzaq"); } } }
теперь выполняем миграцию:
для этого в консоль диспетчера пакетов вводим команды:
enable-migrations
Add-migration *Имя миграции*
update-database
теперь когда есть таблицы для хранения всех необходимых данных можем приступать к написанию логики.
Шаг 6:
Итак для работы с БД, нам необходимо написать методов для работы с ним. для этого в раннее созданную папку создаем файл DataBaseMethods.cs. Поскольку мой бот уже готов я выложу исходный файл, дабы не запутывать вас раздельным повествованием.
using Microsoft.EntityFrameworkCore; using System.Data; namespace CETmsgr.dbutils { internal class DataBaseMethods { // метод для создания сообщения водителем. данные методы мне кажутся излишними, но я решил их оставить тк все работает public static async Task<long> MsgCreateByDriverToTc(int IdThread, string Msg, string Crtd, string UL) { using (ApplicationContext db = new ApplicationContext()) { DialogMsgs newMSG = new DialogMsgs { IdThread = IdThread, Created = Crtd, UrgentLevel = UL, Message = Msg }; await db.DialogMsgs.AddAsync(newMSG); await db.SaveChangesAsync(); try { var getMSG = await db.DialogMsgs.OrderBy(x => x.Created).LastOrDefaultAsync(x => x.IdThread == IdThread); return getMSG.IdUnique; } catch(Exception ex) { return 123123; } } } // метод для создания сообщения диспетчером public static async Task<long> MsgCreateByTcToDriver(int IdThread, string Msg, string Crtd, string UL) { using (ApplicationContext db = new ApplicationContext()) { DialogMsgs newMSG = new DialogMsgs { IdThread = IdThread, Created = Crtd, UrgentLevel = UL, Message = Msg }; await db.DialogMsgs.AddAsync(newMSG); await db.SaveChangesAsync(); try { var getMSG = await db.DialogMsgs.OrderBy(x => x.IdUnique).LastOrDefaultAsync(x => x.IdThread == IdThread); return getMSG.IdUnique; } catch (Exception ex) { return 123123; } } } // метод для получения сообщений диспетчером public static async Task<long> MsgRecievierTc(long IdUnique, int IdThread, long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var getMSG = await db.DialogMsgs.FirstOrDefaultAsync(x => x.IdUnique == IdUnique); var getId = await db.DialogMembers.FirstOrDefaultAsync(x => (x.IdThread == IdThread && x.IdDriver == IdDriver)); if (getMSG.IdThread == getId.IdThread) { return getId.IdTc; } else { return 404; } } } // метод для получения сообщений водителем public static async Task<long> MsgRecievierDriver(long IdUnique, int IdThread, long IdTc) { using (ApplicationContext db = new ApplicationContext()) { var getMSG = await db.DialogMsgs.FirstOrDefaultAsync(x => x.IdUnique == IdUnique); var getId = await db.DialogMembers.FirstOrDefaultAsync(x => (x.IdThread == IdThread && x.IdTc == IdTc)); if (getMSG.IdThread == getId.IdThread) { return getId.IdDriver; } else { return 404; } } } // получение стаутса пользователя, чтобы бот мог разделять сообщения от пользователя по данному фильтру public static async Task<int> GetStatus(long TgId) { using (ApplicationContext db = new ApplicationContext()) { var status = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId); return status.Status; } } // получение id юзера для отправки сообщения через бота из другого юзера при условии нажатия кнопок в диалогах public static async Task<long> GetAddress(long TgId) { using (ApplicationContext db = new ApplicationContext()) { var status = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId); return status.CurrentDialog; } } // получение id диалога из бд public static async Task<int> GetThreadByDriver(long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var dialog = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); return dialog.IdThread; } } // получение id диалога из бд public static async Task<int> GetThreadByTc(long IdTc, long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var dialog = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdTc == IdTc && x.IdDriver == IdDriver); return dialog.IdThread; } } // получение роли юзера public static async Task<UserRoles> GetUserRole(long TgId) { using (ApplicationContext db = new ApplicationContext()) { var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == TgId); return user; } } // получение данных водителя public static async Task<Drivers> GetDriverData(long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); return driver; } } // получение данных диспетчера public static async Task<TrafficControllers> GetTcData(long IdTc) { using (ApplicationContext db = new ApplicationContext()) { var tc = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdTc); return tc; } } // обновление статуса юзера и id получателя сообщения public static async Task ToggleInDialogStatus(long TgId, int Status, long receivier) { using (ApplicationContext db = new ApplicationContext()) { var dialogStatus = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId ); if (dialogStatus is null) { DialogStatus StatusCreate = new DialogStatus { TgId = TgId, Status = Status, CurrentDialog = receivier}; var result = await db.DialogStatus.AddAsync(StatusCreate); await db.SaveChangesAsync(); } else { dialogStatus.Status = Status; dialogStatus.CurrentDialog = receivier; db.DialogStatus.Update(dialogStatus); await db.SaveChangesAsync(); } } } // обновление статуса юзера public static async Task ToggleInDialogStatus(long TgId, int Status) { using (ApplicationContext db = new ApplicationContext()) { var dialogStatus = await db.DialogStatus.FirstOrDefaultAsync(x => x.TgId == TgId); if (dialogStatus is null) { DialogStatus StatusCreate = new DialogStatus { TgId = TgId, Status = Status, CurrentDialog = 0 }; var result = await db.DialogStatus.AddAsync(StatusCreate); await db.SaveChangesAsync(); } else { dialogStatus.Status = Status; dialogStatus.CurrentDialog = 0; db.DialogStatus.Update(dialogStatus); await db.SaveChangesAsync(); } } } // добавление или обновление юзера public static async Task AddOrUpdateUser(long tg_ID, string role, string tg_username, long tg_chat_id, int StageReg) { using (ApplicationContext db = new ApplicationContext()) { var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == tg_ID); if (user is null) { if (tg_username == null) { tg_username = "Без ника"; } UserRoles newuser = new UserRoles { TgId = tg_ID, Role = role, TgUsername = tg_username, TgChatId = tg_chat_id, StageReg = StageReg }; await db.UserRoles.AddAsync(newuser); await db.SaveChangesAsync(); } else { user.Role = role; user.TgUsername = tg_username; db.UserRoles.Update(user); await db.SaveChangesAsync(); } } } // создание диалога public static async Task DialogCreate(long IdTc, long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var dialogWithDriver = await db.DialogMembers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver && x.IdTc == IdTc); if (dialogWithDriver is null) { DialogMembers newDialog = new DialogMembers { IdDriver = IdDriver, IdTc = IdTc }; var result = await db.DialogMembers.AddAsync(newDialog); await db.SaveChangesAsync(); } else { } } } // изменение статуса пользователя public static async Task StageIncrement(long tg_ID, int StageReg) { using (ApplicationContext db = new ApplicationContext()) { var user = await db.UserRoles.FirstOrDefaultAsync(x => x.TgId == tg_ID); user.StageReg = StageReg; db.UserRoles.Update(user); await db.SaveChangesAsync(); } } // добавление водителя до регистрации все строки по нулям, чтобы exception не словить public static async Task AddDriver(long IdDriver) { using (ApplicationContext db = new ApplicationContext()) { var user = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); if (user is null) { string Name = "0"; string IdRoute = "0"; string VehichleRegNum = "0"; string DeviceSerialNum = "0"; Drivers newDriver = new Drivers { IdDriver = IdDriver, Name = Name, IdRoute = IdRoute, VehichleRegNum = VehichleRegNum, DeviceSerialNum = DeviceSerialNum}; var result = db.Drivers.AddAsync(newDriver); await db.SaveChangesAsync(); } } } // добавление диспетчера public static async Task AddTc(long IdTc) { using (ApplicationContext db = new ApplicationContext()) { var user = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdTc); if (user is null) { string Name = "0"; TrafficControllers newTc = new TrafficControllers { IdTc = IdTc, Name = Name}; var result = await db.TrafficControllers.AddAsync(newTc); await db.SaveChangesAsync(); } } } // добавление данных в бд водителя public static async Task AddDataDriverName(long IdDriver, string Name) { using (ApplicationContext db = new ApplicationContext()) { var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); Driver.Name = Name; db.Drivers.Update(Driver); await db.SaveChangesAsync(); } } public static async Task AddDataDriverIdRoute(long IdDriver, string IdRoute) { using (ApplicationContext db = new ApplicationContext()) { var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); Driver.IdRoute = IdRoute; db.Drivers.Update(Driver); await db.SaveChangesAsync(); } } public static async Task AddDataDriverVehichleRegNum(long IdDriver, string VehichleRegNum) { using (ApplicationContext db = new ApplicationContext()) { var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); Driver.VehichleRegNum = VehichleRegNum; db.Drivers.Update(Driver); await db.SaveChangesAsync(); } } public static async Task AddDataDriverDeviceSerialNum(long IdDriver, string DeviceSerialNum) { using (ApplicationContext db = new ApplicationContext()) { var Driver = await db.Drivers.FirstOrDefaultAsync(x => x.IdDriver == IdDriver); Driver.DeviceSerialNum = DeviceSerialNum; db.Drivers.Update(Driver); await db.SaveChangesAsync(); } } // добавление данных в бд диспетчера public static async Task AddDataTcName(long IdDriver, string Name) { using (ApplicationContext db = new ApplicationContext()) { var tc = await db.TrafficControllers.FirstOrDefaultAsync(x => x.IdTc == IdDriver); tc.Name = Name; db.TrafficControllers.Update(tc); await db.SaveChangesAsync(); } } // вывод списка водителей public static List<long> GetAllDriversId(string role) { //Dictionary<long, string> driversId_Name = new Dictionary<long, string>(); using (ApplicationContext db = new ApplicationContext()) { var AllDrivers = db.UserRoles.Where(x => x.Role == role).ToList(); List<long> driversIDs = new List<long>(); foreach (var u in AllDrivers) driversIDs.Add(u.TgId); return driversIDs; } } } }
Финал:
Теперь можно рассмотреть логику реагирования бота на нажатия и сообщения. Поэтому опишем все необходимые кнопки в классе kb.
namespace CETmsgr.keyboards { public static class kb { public static ReplyKeyboardMarkup Register = new(new[] { new KeyboardButton[] { "/reg" }, }) { ResizeKeyboard = true }; public static InlineKeyboardMarkup Role = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Водитель", callbackData: "driver"), InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "controller"), }, }); public static InlineKeyboardMarkup Menu = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Диалоги", callbackData: "dialogs"), InlineKeyboardButton.WithCallbackData(text: "Профиль", callbackData: "profile"), }, //new [] //{ // InlineKeyboardButton.WithCallbackData(text: "Регистрация", callbackData: "register"), //}, }); public static InlineKeyboardMarkup ToMenu = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Меню", callbackData: "menu"), }, }); public static InlineKeyboardMarkup StartRegDriver = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Ваше ФИО", callbackData: "DriverName"), }, new [] { InlineKeyboardButton.WithCallbackData(text: "Идентификатор маршрута", callbackData: "IdRoute"), }, new [] { InlineKeyboardButton.WithCallbackData(text: "Регистрационный номер тс", callbackData: "VehichleRegNum"), }, new [] { InlineKeyboardButton.WithCallbackData(text: "Серийный номер устройства", callbackData: "DeviceSerialNum"), }, new [] { InlineKeyboardButton.WithCallbackData(text: "Окончить Регистрацию", callbackData: "FinReg"), }, }); public static InlineKeyboardMarkup StartRegTC = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Ваше ФИО", callbackData: "TcName"), }, new [] { InlineKeyboardButton.WithCallbackData(text: "Окончить Регистрацию", callbackData: "FinReg"), }, }); public static InlineKeyboardMarkup MsgToDriver = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Водитель", callbackData: "driver"), InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "controller"), }, }); public static InlineKeyboardMarkup MsgDispetcher = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Диспетчер", callbackData: "callTC"), }, }); public static InlineKeyboardMarkup TextAll = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: "Написать всем", callbackData: "textall"), }, }); } }
Вернемся в класс program
using Telegram.Bot; using Telegram.Bot.Extensions.Polling; using Telegram.Bot.Types.ReplyMarkups; using CETmsgr.keyboards; using CETmsgr.dbutils; using Update = Telegram.Bot.Types.Update; using Telegram.Bot.Types.Enums; namespace CETmsgr { class Program { static ITelegramBotClient bot = new TelegramBotClient("TOKEN"); public static async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(update)); if (update.Type == UpdateType.Message) { string Time = DateTime.Now.ToShortTimeString(); var message = update.Message; if (message.Text.ToLower() == "/reg") { await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0); await botClient.SendTextMessageAsync( message.Chat.Id, "загрузка...", replyMarkup: new ReplyKeyboardRemove()); var userData = await DataBaseMethods.GetUserRole(message.From.Id); if (userData != null) { await botClient.SendTextMessageAsync( message.Chat.Id, text: "Вы уже зарегистрировались", replyMarkup: kb.ToMenu); } else { await botClient.SendTextMessageAsync( message.Chat.Id, text: "Выберите свою должность", replyMarkup: kb.Role); } return; } if (message.Text.ToLower() == "/start") { await DataBaseMethods.ToggleInDialogStatus(update.Message.Chat.Id, 0); await botClient.SendTextMessageAsync( chatId: message.Chat, text: "Главное меню", replyMarkup: kb.Menu); return; } // это условие для того, чтобы команды не попадали туда куда не надо if (!message.Text.StartsWith("/")) { int dialogStatus = await DataBaseMethods.GetStatus(message.Chat.Id); var userDataReg = await DataBaseMethods.GetUserRole(message.Chat.Id); string role = userDataReg.Role; int countReg = userDataReg.StageReg; // так выглядит регистрациЯ ДИСПЕТЧЕРА И ВОДИТЕЛЯ, собственно счетчики нужны для корректного отслеживания сообщений от пользователя if (countReg == 1 && role == "driver" && dialogStatus == 0) { await DataBaseMethods.AddDataDriverName(message.From.Id, message.Text); } if (countReg == 1 && role == "controller" && dialogStatus == 0) { await DataBaseMethods.AddDataTcName(message.From.Id, message.Text); await botClient.SendTextMessageAsync( message.Chat.Id, text: "Хотите вернуться в меню?", replyMarkup: kb.ToMenu); } if (countReg == 2 && dialogStatus == 0) { await DataBaseMethods.AddDataDriverIdRoute(message.From.Id, message.Text); } if (countReg == 3 && dialogStatus == 0) { await DataBaseMethods.AddDataDriverVehichleRegNum(message.From.Id, message.Text); } if (countReg == 4 && dialogStatus == 0) { await DataBaseMethods.AddDataDriverDeviceSerialNum(message.From.Id, message.Text); await botClient.SendTextMessageAsync( message.Chat.Id, text: "Хотите вернуться в меню?", replyMarkup: kb.ToMenu); } // а вот пригодились статусы, чтобы оставаться в неком диалоге, внутри бота, // пока юзер не вернется в меню if (role == "driver" && dialogStatus == 1) { var getDialog = await DataBaseMethods.GetThreadByDriver( message.Chat.Id); var msgID = await DataBaseMethods.MsgCreateByDriverToTc( getDialog, message.Text, Time, "3"); var reciever = await DataBaseMethods.MsgRecievierTc(msgID, getDialog, message.Chat.Id); var msgFrom = await DataBaseMethods.GetDriverData(message.Chat.Id); await botClient.SendTextMessageAsync( reciever, text: $"{msgFrom.Name}:" + "\n" + $"Маршрут: {msgFrom.IdRoute}:" + "\n" + $"{message.Text}"); } if (role == "controller" && dialogStatus == 1) { var getAddress = await DataBaseMethods.GetAddress(message.Chat.Id); var getDialog = await DataBaseMethods.GetThreadByTc( message.Chat.Id, IdDriver: getAddress); var msgID = await DataBaseMethods.MsgCreateByTcToDriver( getDialog, message.Text, Time, "3"); var reciever = await DataBaseMethods.MsgRecievierDriver(msgID, getDialog, message.Chat.Id); var msgFrom = await DataBaseMethods.GetTcData(message.Chat.Id); await botClient.SendTextMessageAsync( reciever, text: $"{msgFrom.Name}:" + "\n" + $"{message.Text}"); } // это отдельная фича под рассылку всем В от Д в боте if (role == "controller" && dialogStatus == 2) { var getAddress = DataBaseMethods.GetAllDriversId("driver"); foreach (var address in getAddress) { var getDialog = await DataBaseMethods.GetThreadByTc( message.Chat.Id, IdDriver: address); var msgID = await DataBaseMethods.MsgCreateByTcToDriver( getDialog, message.Text, Time, "3"); var reciever = await DataBaseMethods.MsgRecievierDriver(msgID, getDialog, message.Chat.Id); var msgFrom = await DataBaseMethods.GetTcData(message.Chat.Id); await botClient.SendTextMessageAsync( reciever, text: $"{msgFrom.Name}:" + "\n" + $"{message.Text}"); } } else return; } } if (update.Type == UpdateType.CallbackQuery) { // Тут идет обработка всех нажатий на кнопки, тут никаких особых доп условий не надо, тк у каждой кнопки своя ссылка var callbackQuery = update.CallbackQuery; var userRole = await DataBaseMethods.GetUserRole(callbackQuery.Message.Chat.Id); long userTgId; try { userTgId = Convert.ToInt64(callbackQuery.Data); } catch { userTgId = 0; } var checkUserCallback = await DataBaseMethods.GetUserRole(userTgId); // тут единственнок место где условие чуть сложнее // здесь по простому мы запоминаем ид пользвоателя в отд бд, откуда в дальнейем рлдгрузим данные if (checkUserCallback != null) { if (callbackQuery.Data == checkUserCallback.TgId.ToString() != null && userRole.Role == "controller") { await DataBaseMethods.DialogCreate(userTgId, callbackQuery.Message.Chat.Id); await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 1, userTgId); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Напишите сообщение водителю", replyMarkup: kb.ToMenu); } if (callbackQuery.Data == checkUserCallback.TgId.ToString() && userRole.Role == "driver") { await DataBaseMethods.DialogCreate(userTgId, callbackQuery.Message.Chat.Id); await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 1, userTgId); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Напишите сообщение диспетчеру", replyMarkup: kb.ToMenu); } } if (callbackQuery.Data == "menu") { await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 0); await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Главное Меню", replyMarkup: kb.Menu); } if (callbackQuery.Data == "register") { await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, "/reg это способ пройти регистрацию"); } if (callbackQuery.Data == "profile") { await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); var driverData = await DataBaseMethods.GetDriverData(callbackQuery.Message.Chat.Id); var tcData = await DataBaseMethods.GetTcData(callbackQuery.Message.Chat.Id); if (userRole != null && driverData != null) { var name = driverData.Name; var route = driverData.IdRoute; var vrn = driverData.VehichleRegNum; var dsn = driverData.DeviceSerialNum; var role = userRole.Role; await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: $"ваша должность: {role}"); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: $"Ваше ФИО: {name}" + "\n" + $"Маршрут номер: {route}" + "\n" + $"Номер тс: {vrn}" + "\n" + $"Номер устройства: {dsn}"); } if (userRole != null && tcData != null) { var name = tcData.Name; var role = userRole.Role; await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: $"ваша должность: {role}"); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: $"Ваше ФИО: {name}"); } else { await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "для регистрации нажмите /reg", replyMarkup: kb.Register); } await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Хотите вернуться в меню?", replyMarkup: kb.ToMenu); } if (callbackQuery.Data == "dialogs") { var role = userRole.Role; if (role == "controller") { await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); var driversList = DataBaseMethods.GetAllDriversId("driver"); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, "Водители:", replyMarkup: kb.TextAll); foreach (var driver in driversList) { var driverName = await DataBaseMethods.GetDriverData(driver); InlineKeyboardMarkup driverButton = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: $"{driver}", callbackData: $"{driver}"), }, }); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, $"<code>{driverName.Name}</code> ", ParseMode.Html, replyMarkup: driverButton); } } else { await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); var tcList = DataBaseMethods.GetAllDriversId("controller"); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, "Диспетчеры:"); foreach (var tc in tcList) { var tcName = await DataBaseMethods.GetTcData(tc); InlineKeyboardMarkup tcButton = new(new[] { new [] { InlineKeyboardButton.WithCallbackData(text: $"{tc}", callbackData: $"{tc}"), }, }); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, $"<code>{tcName.Name}</code> ", ParseMode.Html, replyMarkup: tcButton); } } } if (callbackQuery.Data == "textall") { var allDrivers = DataBaseMethods.GetAllDriversId("driver"); foreach (long driver in allDrivers) { await DataBaseMethods.DialogCreate(callbackQuery.Message.Chat.Id, driver); await DataBaseMethods.ToggleInDialogStatus(callbackQuery.Message.Chat.Id, 2, driver); } await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Напишите сообщение для всех водителей", replyMarkup: kb.ToMenu); } if (callbackQuery.Data == "driver") { await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Нажмите на кнопку для ввода данных", replyMarkup: kb.StartRegDriver); int StageRegDriver = 1; await DataBaseMethods.AddOrUpdateUser( callbackQuery.Message.Chat.Id, callbackQuery.Data.ToString(), callbackQuery.From.Username, callbackQuery.Message.From.Id, StageRegDriver); await DataBaseMethods.AddDriver( callbackQuery.Message.Chat.Id); } // начало регистрации Водителя if (callbackQuery.Data == "DriverName") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 1); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Введите ФИО:"); } if (callbackQuery.Data == "IdRoute") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 2); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Введите номер маршрута:"); } if (callbackQuery.Data == "VehichleRegNum") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 3); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Введите номер тс:"); } if (callbackQuery.Data == "DeviceSerialNum") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 4); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Введите номер устройства:"); } if (callbackQuery.Data == "controller") { await botClient.DeleteMessageAsync( callbackQuery.Message.Chat.Id, callbackQuery.Message.MessageId); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Нажмите на кнопку для ввода данных", replyMarkup: kb.StartRegTC); int StageRegTC = 1; await DataBaseMethods.AddOrUpdateUser( callbackQuery.Message.Chat.Id, callbackQuery.Data.ToString(), callbackQuery.From.Username, callbackQuery.Message.From.Id, StageRegTC); await DataBaseMethods.AddTc( callbackQuery.Message.Chat.Id); } // начало регистрации Диспетчера if (callbackQuery.Data == "TcName") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 1); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Введите ФИО:"); } if (callbackQuery.Data == "FinReg") { await DataBaseMethods.StageIncrement(callbackQuery.Message.Chat.Id, 5); await botClient.SendTextMessageAsync( callbackQuery.Message.Chat.Id, text: "Регистрация окончена", replyMarkup: kb.ToMenu); } // общее окончание Регистрации } } public static async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) { // Некоторые действия Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(exception)); } static void Main(string[] args) { Console.WriteLine("Запущен бот " + bot.GetMeAsync().Result.FirstName); var cts = new CancellationTokenSource(); var cancellationToken = cts.Token; var receiverOptions = new ReceiverOptions { AllowedUpdates = { }, // receive all update types }; bot.StartReceiving( HandleUpdateAsync, HandleErrorAsync, receiverOptions, cancellationToken ); Console.ReadLine(); } } }
Все необходимые на мой взгляд комментарии я написал в коде, если будут вопросы или критика, буду рад.
Всем хорошего дня!
