Simple Telegram.Bot messenger in C#

Part 1

Why?

I decided to practice writing sharp applications using EF. While sorting it out, I noticed that there are not many tutorials and examples on how to write a bot in C #, so I decided to share my best practices.

What the bot can do:

The task of the bot is to arrange the exchange of messages between the master and subordinates so that the master (dispatcher) can write to everyone or only one slave (driver), and the subordinates can only communicate with the master. WebHook is not needed, because bot purely for practice.

DB model

So, for starters, I decided to describe all the necessary tables for storing information. However, as a result, the model has changed slightly.

Step 1:

I used Postgre SQL 15 for table storage, and PgAdmin 4 for monitoring. I created a Users database and deployed it locally.

download

Step 2:

Install all required packages in VS via NuGET:

  • Microsoft.EntityFrameworkCore.Tools

  • newtonsoft.json

  • Npgsql.EntityFrameworkCore.PostgreSQL

  • Telegram.Bot

  • Telegram.Bot.Extensions.Polling

Step 3:

Getting a token https://telegram.me/BotFather and smoothly move on to the code.

Step 4:

Let’s create an empty Program.cs class and add all the Methods necessary for work to it:

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();
            
        }
    }
}

Step 5:

Now let’s start creating classes for the tables, I created a separate dbutils folder for these needs.

UserRoles is needed in order to be able to sort user ids by roles.

TrafficControllers and Drivers will simply store user information.

DialogMembers will store unique dialog ids and link them between 2 user ids

DialogMsgs this table will store the messages associated with the dialog id from DialogMembers

DialogStatus and this table is necessary for checks when writing user messages to the bot.

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; }

    }
}

In order for tables to appear in the database on the basis of this stuff, it is necessary to migrate. Therefore, we create a data model for our classes and set up a connection to the database:

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");
        }
    }
}
    

now let’s do the migration:

To do this, enter the commands in the package manager console:

enable-migrations
Add-migration *Имя миграции*
update-database

now that we have tables to store all the necessary data, we can start writing logic.

Step 6:

So, to work with the database, we need to write methods for working with it. To do this, create the DataBaseMethods.cs file in the previously created folder. Since my bot is ready, I will post the source file so as not to confuse you with a separate story.

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;
            }

        }
    }
}

The final:

Now you can consider the logic of the bot’s response to clicks and messages. Therefore, we will describe all the necessary buttons in the kb class.

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"),
            },
        });
    }
}

Let’s return to the program class

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("5779421408:AAGiyZ27J89BRda8YYSM-CinHgjQbEWvAOo");
        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();
            
        }
    }
}

I wrote all the necessary comments in my opinion in the code, if there are questions or criticism, I will be glad.

Have a nice day, everyone!

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *