Часть 1
Почему?
Решил я попрактиковаться в написании приложений на шарпе с использованием EF. Пока разбирался заметил, что туториалов и примеров как написать бота на C# немного, поэтому решил поделиться своими наработками.
Что может бот:
Задача бота - устроить обмен сообщениями между главным и подчиненными так, чтобы главный(диспетчер) мог писать всем или только одному подчиненному(водителю), а подчиненные могли общаться только с главным. WebHook не нужен, т.к. бот сугубо для практики.
Модель БД
Итак, для начала решил описать все необходимые таблицы, для хранения информации. Однако по итогу модель немного изменилась.
![](https://habrastorage.org/getpro/habr/upload_files/68a/5b5/db6/68a5b5db680fbf303b5b5815ba942cd1.jpg)
Шаг 1:
Для хранения таблиц я использовал Postgre SQL 15, а для мониторинга PgAdmin 4. Создал бд Users и развернул локально.
скачать
Шаг 2:
Установим все необходимые пакеты в VS через NuGET:
Microsoft.EntityFrameworkCore.Tools
Newtonsoft.Json
Npgsql.EntityFrameworkCore.PostgreSQL
Telegram.Bot
Telegram.Bot.Extensions.Polling
![](https://habrastorage.org/getpro/habr/upload_files/b65/68f/178/b6568f178263d6cbe36db40400733fc6.png)
Шаг 3:
Получаем токен https://telegram.me/BotFather и плавно переходим к коду.
![](https://habrastorage.org/getpro/habr/upload_files/868/d1f/9f7/868d1f9f77960080eabba12fd2374227.png)
Шаг 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();
}
}
}
Все необходимые на мой взгляд комментарии я написал в коде, если будут вопросы или критика, буду рад.
Всем хорошего дня!