Browse Source

Pattern to start writing bot

Tigran 4 years ago
parent
commit
3c7c015d39

+ 0 - 7
CardCollector/Commands/CallbackQueries/CallbackQuery.cs

@@ -1,7 +0,0 @@
-namespace CardCollector.Commands.CallbackQueries
-{
-    public class CallbackQuery
-    {
-        
-    }
-}

+ 51 - 0
CardCollector/Commands/CallbackQuery/CallbackQuery.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    using static Logs;
+    public abstract class CallbackQuery : UpdateModel
+    {
+        
+        private static readonly List<CallbackQuery> List = new()
+        {
+
+        };
+
+        public static async Task<UpdateModel> Factory(Update update)
+        {
+            try
+            {
+                // Текст команды
+                var command = update.CallbackQuery.Data;
+
+                // Объект пользователя
+                var user = await UserDao.GetOrAddNew(update.CallbackQuery.From);
+
+                // Добавляем сообщения пользователя в пул для удаления
+                MessageController.AddNewMessageToPool(user, update.CallbackQuery.Message.MessageId);
+
+                // Возвращаем объект, если команда совпала
+                foreach (var item in List.Where(item => item.IsMatches(command)))
+                    if (Activator.CreateInstance(item.GetType(), user, update) is CallbackQuery executor && executor.IsMatches(command))
+                        return executor;
+
+                // Возвращаем команда не найдена, если код дошел до сюда
+                return new CommandNotFound(user, update, command);
+            }
+            catch (Exception e)
+            {
+                LogOutError(e);
+                throw;
+            }
+        }
+
+        protected CallbackQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 23 - 0
CardCollector/Commands/CommandNotFound.cs

@@ -0,0 +1,23 @@
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands
+{
+    public class CommandNotFound : UpdateModel
+    {
+        protected override string Command => "";
+        private readonly string _command;
+
+        public override async Task<Telegram.Bot.Types.Message> Execute()
+        {
+            return await MessageController.SendMessage(User, "Команда не найдена " + _command);
+        }
+
+        public CommandNotFound(UserEntity user, Update update, string command) : base(user, update)
+        {
+            _command = command;
+        }
+    }
+}

+ 52 - 0
CardCollector/Commands/Message/Message.cs

@@ -0,0 +1,52 @@
+using System;
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using System.Collections.Generic;
+using System.Linq;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.Message
+{
+    using static Logs;
+    public abstract class Message : UpdateModel
+    {
+        private static readonly List<Message> List = new()
+        {
+
+        };
+
+        public static async Task<UpdateModel> Factory(Update update)
+        {
+            try
+            {
+                // Текст команды
+                var command = update.Message!.Text;
+            
+                // Id пользователя, отправившего команду
+                var userId = update.Message!.From!.Id;
+                // Объект пользователя
+                var user = await UserDao.GetById(userId) ?? await UserDao.AddNew(update.Message.From);
+            
+                // Добавляем сообщения пользователя в пул для удаления
+                MessageController.AddNewMessageToPool(user, update.Message.MessageId);
+            
+                // Возвращаем объект, если команда совпала
+                foreach (var item in List.Where(item => item.IsMatches(command)))
+                    if(Activator.CreateInstance(item.GetType(), user, update) is Message executor && executor.IsMatches(command))
+                        return executor;
+            
+                // Возвращаем команда не найдена, если код дошел до сюда
+                return new CommandNotFound(user, update, command);
+            }
+            catch (Exception e)
+            {
+                LogOutError(e);
+                throw;
+            }
+        }
+
+        protected Message(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 0 - 19
CardCollector/Commands/MessageCommands/CommandNotFound.cs

@@ -1,19 +0,0 @@
-using System.Threading.Tasks;
-using CardCollector.Controllers;
-using CardCollector.DataBase.Entity;
-using Telegram.Bot.Types;
-
-namespace CardCollector.Commands.MessageCommands
-{
-    public class CommandNotFound : MessageCommand
-    {
-        protected override string Command => "";
-
-        public override async Task<Message> Execute()
-        {
-            return await MessageController.SendMessage(User.ChatId, "Команда не найдена");
-        }
-
-        public CommandNotFound(UserEntity user) : base(user) { }
-    }
-}

+ 0 - 46
CardCollector/Commands/MessageCommands/MessageCommand.cs

@@ -1,46 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using CardCollector.Controllers;
-using CardCollector.DataBase.Entity;
-using CardCollector.DataBase.EntityDao;
-using Telegram.Bot.Types;
-
-namespace CardCollector.Commands.MessageCommands
-{
-    public abstract class MessageCommand : UpdateModel
-    {
-        private static readonly List<MessageCommand> List = new()
-        {
-
-        };
-
-        public static async Task<MessageCommand> Factory(Update update)
-        {
-            // Текст команды
-            var command = update.Message!.Text;
-            
-            // Id пользователя, отправившего команду
-            var userId = update.Message!.From!.Id;
-            // Объект пользователя
-            var user = (await UserDao.GetById(userId)) ?? (await UserDao.AddNew(update.Message.From));
-            
-            // Удаляем предыдущие сообщения пользователя и бота
-            MessageController.AddNewMessageToPool(update.Message.Chat.Id, update.Message.MessageId);
-            await MessageController.DeleteMessagesFromPool(update.Message.Chat.Id);
-            
-            // Возвращаем объект, если команда совпала
-            foreach (var item in List)
-                if (item.IsMatches(command))
-                    return (MessageCommand) Activator.CreateInstance(item.GetType(), user);
-            
-            // Возвращаем команда не найдена, если код дошел до сюда
-            return new CommandNotFound(user);
-        }
-
-        protected MessageCommand(UserEntity user)
-        {
-            User = user;
-        }
-    }
-}

+ 62 - 0
CardCollector/Commands/MyChatMember/MyChatMember.cs

@@ -0,0 +1,62 @@
+using System;
+using System.Threading.Tasks;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using Telegram.Bot.Types;
+using Telegram.Bot.Types.Enums;
+
+namespace CardCollector.Commands.MyChatMember
+{
+    public class MyChatMember : UpdateModel
+    {
+        protected override string Command => "";
+        private readonly ChatMemberStatus _status;
+        public override async Task<Telegram.Bot.Types.Message> Execute()
+        {
+            switch (_status)
+            {
+                case ChatMemberStatus.Creator:
+                    await UserDao.GetOrAddNew(ChatToUser(Update.MyChatMember.Chat));
+                    break;
+                case ChatMemberStatus.Administrator:
+                    await UserDao.GetOrAddNew(ChatToUser(Update.MyChatMember.Chat));
+                    break;
+                case ChatMemberStatus.Member:
+                    User.IsBlocked = false;
+                    break;
+                case ChatMemberStatus.Kicked:
+                    User.IsBlocked = false;
+                    break;
+                case ChatMemberStatus.Restricted or ChatMemberStatus.Left:
+                    break;
+                default:
+                    return await new CommandNotFound(User, Update, _status.ToString()).Execute();
+            }
+
+            return new Telegram.Bot.Types.Message();
+        }
+        public static async Task<UpdateModel> Factory(Update update)
+        {
+            // Объект пользователя
+            var user = await UserDao.GetOrAddNew(update.MyChatMember.From);
+            return new MyChatMember(user, update, update.MyChatMember.NewChatMember.Status);
+        }
+        
+        protected static User ChatToUser(Chat chat)
+        {
+            return new User
+            {
+                Username = chat.Username,
+                FirstName = chat.FirstName ?? chat.Title ?? "",
+                LastName = chat.LastName ?? "",
+                Id = chat.Id,
+                IsBot = chat.Id < 0
+            };
+        }
+
+        protected MyChatMember(UserEntity user, Update update, ChatMemberStatus status) : base(user, update)
+        {
+            _status = status;
+        }
+    }
+}

+ 13 - 3
CardCollector/Commands/UpdateModel.cs

@@ -1,6 +1,4 @@
-using System.Collections.Generic;
 using System.Threading.Tasks;
-using CardCollector.Commands.MessageCommands;
 using CardCollector.DataBase.Entity;
 using Telegram.Bot.Types;
 
@@ -10,12 +8,24 @@ namespace CardCollector.Commands
     {
         protected abstract string Command { get; }
         protected UserEntity User;
+        protected Update Update;
 
-        public abstract Task<Message> Execute();
+        public abstract Task<Telegram.Bot.Types.Message> Execute();
 
         protected virtual bool IsMatches(string command)
         {
             return command.Contains(Command);
         }
+
+        protected UpdateModel()
+        {
+            User = null;
+        }
+
+        protected UpdateModel(UserEntity user, Update update)
+        {
+            User = user;
+            Update = update;
+        }
     }
 }

+ 129 - 30
CardCollector/Controllers/MessageController.cs

@@ -2,12 +2,17 @@ using System;
 using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
-using CardCollector.Commands.MessageCommands;
+using CardCollector.DataBase.Entity;
 using Telegram.Bot;
 using Telegram.Bot.Exceptions;
 using Telegram.Bot.Types;
 using Telegram.Bot.Types.Enums;
+using Telegram.Bot.Types.InputFiles;
 using Telegram.Bot.Types.ReplyMarkups;
+using Message = CardCollector.Commands.Message.Message;
+using CallBackQuery = CardCollector.Commands.CallbackQuery.CallbackQuery;
+using MyChatMember = CardCollector.Commands.MyChatMember.MyChatMember;
+using TgMessage = Telegram.Bot.Types.Message;
 
 namespace CardCollector.Controllers
 {
@@ -15,7 +20,7 @@ namespace CardCollector.Controllers
 
     public static class MessageController
     {
-        private static Dictionary<long, List<int>> _deletingMessagePool = new();
+        private static readonly Dictionary<long, List<int>> DeletingMessagePool = new();
 
         public static async Task HandleUpdateAsync(ITelegramBotClient client, Update update, CancellationToken ct)
         {
@@ -23,19 +28,28 @@ namespace CardCollector.Controllers
             {
                 var executor = update.Type switch
                 {
-                    UpdateType.Message => await MessageCommand.Factory(update),
+                    UpdateType.Message => await Message.Factory(update),
+                    UpdateType.CallbackQuery => await CallBackQuery.Factory(update),
+                    UpdateType.MyChatMember => await MyChatMember.Factory(update),
                     _ => throw new ArgumentOutOfRangeException()
                 };
-                var message = await executor.Execute();
-                AddNewMessageToPool(message.Chat.Id, message.MessageId);
-            }
-            catch (ArgumentOutOfRangeException)
-            {
-                LogOut(update.Type.ToString());
+                // var message =
+                await executor.Execute();
             }
             catch (Exception e)
             {
-                await HandleErrorAsync(client, e, ct);
+                switch (e)
+                {
+                    case ArgumentOutOfRangeException:
+                        LogOut(update.Type);
+                        break;
+                    case ApiRequestException:
+                        LogOutWarning(e.Message);
+                        break;
+                    default:
+                        LogOutError(e);
+                        break;
+                }
             }
         }
 
@@ -43,54 +57,139 @@ namespace CardCollector.Controllers
         {
             switch (e)
             {
-                case ApiRequestException apiRequestException:
-                    LogOutWarning($"API Error:[{apiRequestException.ErrorCode}] - {apiRequestException.Message}");
+                case ApiRequestException:
+                    LogOutWarning(e.Message);
                     break;
                 default:
-                    LogOutError(e.ToString());
+                    LogOutError(e);
                     break;
             }
-
             return Task.CompletedTask;
         }
 
-        public static async Task DeleteMessageAsync(long chatId, int messageId)
+        public static void AddNewMessageToPool(UserEntity user, int messageId)
         {
-            await Bot.Client.DeleteMessageAsync(chatId, messageId);
+            try
+            {
+                DeletingMessagePool[user.ChatId].Add(messageId);
+            }
+            catch (Exception)
+            {
+                DeletingMessagePool.Add(user.ChatId, new List<int>());
+                DeletingMessagePool[user.ChatId].Add(messageId);
+            }
         }
 
-        public static void AddNewMessageToPool(long chatId, int messageId)
+        public static async Task DeleteMessagesFromPool(UserEntity user)
         {
             try
             {
-                _deletingMessagePool[chatId].Add(messageId);
+                foreach (var id in DeletingMessagePool[user.ChatId])
+                    await DeleteMessage(user, id);
+                DeletingMessagePool[user.ChatId].Clear();
+                DeletingMessagePool.Remove(user.ChatId);
             }
             catch (Exception)
             {
-                _deletingMessagePool.Add(chatId, new List<int>());
-                _deletingMessagePool[chatId].Add(messageId);
+                /* ignore */
             }
         }
 
-        public static async Task DeleteMessagesFromPool(long chatId)
+        public static async Task<TgMessage> SendMessage(UserEntity user, string message, IReplyMarkup keyboard = null)
         {
             try
             {
-                foreach (var id in _deletingMessagePool[chatId])
-                    await Bot.Client.DeleteMessageAsync(chatId, id);
-                _deletingMessagePool[chatId].Clear();
-                _deletingMessagePool.Remove(chatId);
+                if (!user.IsBlocked)
+                    return await Bot.Client.SendTextMessageAsync(user.ChatId, message, replyMarkup: keyboard, disableNotification: true);
             }
-            catch (Exception)
+            catch (Exception e)
             {
-                /* ignore */
+                LogOutWarning("Can't send text message " + e);
+            }
+            return new TgMessage();
+        }
+        
+        public static async Task<TgMessage> SendTextWithHtml(UserEntity info, string message, IReplyMarkup keyboard = null)
+        {
+            try
+            {
+                if (!info.IsBlocked)
+                    return await Bot.Client.SendTextMessageAsync(info.ChatId, message, ParseMode.Html, replyMarkup: keyboard, disableNotification: true);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't send text message with html " + e);
+            }
+            return new TgMessage();
+        }
+        
+        public static async Task<TgMessage> SendSticker(UserEntity info, string fileId)
+        {
+            try
+            {
+                if (!info.IsBlocked)
+                    return await Bot.Client.SendStickerAsync(info.ChatId, fileId, true);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't send sticker " + e);
+            }
+            return new TgMessage();
+        }
+
+        public static async Task<TgMessage> EditMessage(UserEntity info, int messageId, string message, InlineKeyboardMarkup keyboard = null)
+        {
+            try
+            {
+                if (!info.IsBlocked)
+                    return await Bot.Client.EditMessageTextAsync(info.ChatId, messageId, message, replyMarkup: keyboard);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't edit message text " + e);
             }
+            return new TgMessage();
         }
 
-        public static async Task<Message> SendMessage(long chatId, string messageText, IReplyMarkup keyboard = null)
+        public static async Task<TgMessage> EditReplyMarkup(UserEntity info, int messageId, InlineKeyboardMarkup keyboard)
+        {
+            try
+            {
+                if (!info.IsBlocked)
+                    return await Bot.Client.EditMessageReplyMarkupAsync(info.ChatId, messageId, keyboard);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't edit reply markup " + e);
+            }
+            return new TgMessage();
+        }
+        
+        public static async Task DeleteMessage(UserEntity user, int messageId)
         {
-            return await Bot.Client.SendTextMessageAsync(chatId, messageText, ParseMode.Html,
-                replyMarkup: keyboard, disableNotification: true);
+            try
+            {
+                if (!user.IsBlocked)
+                    await Bot.Client.DeleteMessageAsync(user.ChatId, messageId);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't delete message " + e);
+            }
+        }
+
+        public static async Task<TgMessage> SendImage(UserEntity info, InputOnlineFile inputOnlineFile, string message = null, InlineKeyboardMarkup replyMarkup = null)
+        {
+            try
+            {
+                if (!info.IsBlocked)
+                    return await Bot.Client.SendPhotoAsync(info.ChatId, inputOnlineFile, message, replyMarkup: replyMarkup, disableNotification: true);
+            }
+            catch (Exception e)
+            {
+                LogOutWarning("Can't send photo " + e);
+            }
+            return new TgMessage();
         }
     }
 }

+ 1 - 0
CardCollector/DataBase/Entity/UserEntity.cs

@@ -9,5 +9,6 @@ namespace CardCollector.DataBase.Entity
         [Column("id"), MaxLength(127)] public long Id { get; set; }
         [Column("chat_id"), MaxLength(127)] public long ChatId { get; set; }
         [Column("username"), MaxLength(256)] public string Username { get; set; }
+        [Column("is_blocked"), MaxLength(11)] public bool IsBlocked { get; set; }
     }
 }

+ 14 - 6
CardCollector/DataBase/EntityDao/UserDao.cs

@@ -10,9 +10,14 @@ namespace CardCollector.DataBase.EntityDao
 {
     public static class UserDao
     {
-        private static CardCollectorDatabase DataBase = CardCollectorDatabase.Instance;
+        private static readonly CardCollectorDatabase DataBase = CardCollectorDatabase.Instance;
         
-        private static Dictionary<long, UserEntity> ActiveUsers = new();
+        private static readonly Dictionary<long, UserEntity> ActiveUsers = new();
+
+        public static async Task<UserEntity> GetOrAddNew(User user)
+        {
+            return await GetById(user.Id) ?? await AddNew(user);
+        }
         
         public static async Task<UserEntity?> GetById(long userId)
         {
@@ -32,10 +37,13 @@ namespace CardCollector.DataBase.EntityDao
 
         public static async Task<UserEntity> AddNew(User user)
         {
-            var userEntity = new UserEntity();
-            userEntity.Id = user.Id;
-            userEntity.ChatId = user.Id;
-            userEntity.Username = user.Username;
+            var userEntity = new UserEntity
+            {
+                Id = user.Id,
+                ChatId = user.Id,
+                Username = user.Username,
+                IsBlocked = false
+            };
             await DataBase.Users.AddAsync(userEntity);
             await DataBase.SaveChangesAsync();
             return userEntity;

+ 3 - 3
CardCollector/Logs.cs

@@ -6,15 +6,15 @@ namespace CardCollector
 {
     public static class Logs
     {
-        public static void LogOut(string message)
+        public static void LogOut(object message)
         {
             Console.WriteLine($"[INFO] [{DateTime.Now.ToString(CultureInfo.CurrentCulture)}] {message}");
         }
-        public static void LogOutWarning(string message)
+        public static void LogOutWarning(object message)
         {
             Console.WriteLine($"[WARNING] [{DateTime.Now.ToString(CultureInfo.CurrentCulture)}] {message}");
         }
-        public static void LogOutError(string message)
+        public static void LogOutError(object message)
         {
             Console.WriteLine($"[ERROR] [{DateTime.Now.ToString(CultureInfo.CurrentCulture)}] {message}");
         }