diff --git a/modules/ChatManagement/ChatManagement.cs b/modules/ChatManagement/ChatManagement.cs index 1ad0f41..747c2f0 100644 --- a/modules/ChatManagement/ChatManagement.cs +++ b/modules/ChatManagement/ChatManagement.cs @@ -16,7 +16,9 @@ public class ChatManagement : Module { services.AddScoped(); services.AddScoped(); + services.AddTelegramBotParameterParser(); + services.AddTelegramBotRawUpdateParser(); WarnService.WarnEvent += Notifier.WarnNotify; WarnService.UnWarnEvent += Notifier.UnWarnNotify; diff --git a/modules/ChatManagement/ChatManagement.csproj b/modules/ChatManagement/ChatManagement.csproj index 0b39224..ff72078 100644 --- a/modules/ChatManagement/ChatManagement.csproj +++ b/modules/ChatManagement/ChatManagement.csproj @@ -9,10 +9,6 @@ - - - - diff --git a/modules/ChatManagement/Handler/BanStickerSet.Handler.cs b/modules/ChatManagement/Handler/BanStickerSet.Handler.cs new file mode 100644 index 0000000..34e517c --- /dev/null +++ b/modules/ChatManagement/Handler/BanStickerSet.Handler.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using BotFramework.Attributes; +using BotFramework.Enums; +using BotFramework.Utils; +using Kruzya.TelegramBot.Core.Extensions; +using Telegram.Bot; +using West.TelegramBot.ChatManagement.ParamParser; + +namespace West.TelegramBot.ChatManagement.Handler; + +public partial class BanStickerSet +{ + [ParametrizedCommand(InChat.Public, "stick_ban", CommandParseMode.Both)] + public async Task HandleBanSticker(StickerSet.Param stickerSet) + { + if (!await PreCommand(stickerSet)) + { + return; + } + + var option = await GetBannedStickerSetOption(); + var stickerSetList = option.GetValue(new List()); + + var setName = stickerSet.Set.Name; + if (stickerSetList.Contains(setName)) + { + await Reply("Этот набор стикеров уже заблокирован."); + return; + } + + stickerSetList.Add(setName); + option.SetValue(stickerSetList); + Db.AddOrUpdate(option); + + var replyToMsgId = Message?.ReplyToMessage?.MessageId; + if (replyToMsgId != null) + { + await Bot.DeleteMessageAsync(Chat.Id, (int) replyToMsgId); + } + + await Reply(FormatStickerSetAction(stickerSet.Set, "заблокирован")); + } + + [ParametrizedCommand(InChat.Public, "stick_unban", CommandParseMode.Both)] + public async Task HandleUnBanSticker(StickerSet.Param stickerSet) + { + if (!await PreCommand(stickerSet)) + { + return; + } + + var option = await GetBannedStickerSetOption(); + var list = option.GetValue>(); + if (list == null) + { + return; + } + + var setName = stickerSet.Set.Name; + + list.Remove(setName); + option.SetValue(list); + Db.AddOrUpdate(option); + + await Reply(FormatStickerSetAction(stickerSet.Set, "разблокирован")); + } + + [Command(InChat.Public, "stick_banlist", CommandParseMode.Both)] + public async Task HandleSBanList() + { + var option = await GetBannedStickerSetOption(); + var list = option.GetValue>(); + if (list == null) + { + return; + } + + string msg; + if (list.Count > 0) + { + var htmlString = new HtmlString().Bold("Заблокированные наборы стикеров:").Br(); + for (var i = 0; i < list.Count; i++) + { + var stickerSet = await Bot.GetStickerSetAsync(list[i]); + htmlString.Text($"{i + 1}. ") + .Url("https://t.me/addstickers/" + stickerSet.Name, stickerSet.Title) + .Br(); + } + + msg = htmlString.ToString(); + } + else + { + msg = "Нет заблокированных наборов стикеров."; + } + + await Reply(msg); + } + + [Message(InChat.Public, MessageFlag.HasSticker)] + public async Task HandleMessage() + { + if (!await CanBotDeleteMessages()) + { + await Reply( + "Этот набор стикеров заблокирован. Чтобы я мог его удалить, выдайте мне право на удаление сообщений."); + } + + var message = Message!; + if (await IsStickerBanned(message.Sticker!)) + { + await Bot.DeleteMessageAsync(Chat.Id, message.MessageId); + } + } +} \ No newline at end of file diff --git a/modules/ChatManagement/Handler/BanStickerSet.Utils.cs b/modules/ChatManagement/Handler/BanStickerSet.Utils.cs new file mode 100644 index 0000000..9028efa --- /dev/null +++ b/modules/ChatManagement/Handler/BanStickerSet.Utils.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using BotFramework.Utils; +using Kruzya.TelegramBot.Core.Data; +using Kruzya.TelegramBot.Core.Extensions; +using Telegram.Bot; +using Telegram.Bot.Types; + +namespace West.TelegramBot.ChatManagement.Handler; + +public partial class BanStickerSet +{ + private async Task CanBotDeleteMessages() + { + return await Bot.GetChatMemberAsync( + Chat.Id, + (await Bot.GetMeAsync()).Id + ) is ChatMemberAdministrator {CanDeleteMessages: true}; + } + + private async Task IsStickerBanned(Sticker sticker) + { + var bannedList = (await GetBannedStickerSetOption()).GetValue>(); + + return bannedList != null && sticker.SetName != null && bannedList.Contains(sticker.SetName); + } + + private async Task GetBannedStickerSetOption() + { + return await Db.UserValues.FindOrCreateOption(Chat.Id, "cmBannedStickers"); + } + + public async Task PreCommand(ParamParser.StickerSet.Param stickerSetParam) + { + if (!stickerSetParam.IsValid) + { + await Reply("Неверный набор стикеров."); + return false; + } + + return await CanUseCommands(); + } + + public string FormatStickerSetAction(StickerSet stickerSet, string action) + { + return new HtmlString() + .Text("Набор стикеров ") + .Url($"https://t.me/addstickers/{stickerSet.Name}", stickerSet.Title) + .Text($" {action}.") + .ToString(); + } + + private async Task CanUseCommands() + { + return await Bot.GetChatMemberAsync(Chat.Id, From.Id) is ChatMemberAdministrator {CanDeleteMessages: true} + or ChatMemberOwner; + } +} \ No newline at end of file diff --git a/modules/ChatManagement/Handler/BanStickerSet.cs b/modules/ChatManagement/Handler/BanStickerSet.cs new file mode 100644 index 0000000..c179c1f --- /dev/null +++ b/modules/ChatManagement/Handler/BanStickerSet.cs @@ -0,0 +1,9 @@ +using Kruzya.TelegramBot.Core; +using Kruzya.TelegramBot.Core.Data; + +namespace West.TelegramBot.ChatManagement.Handler; + +public partial class BanStickerSet : CommonHandler +{ + public BanStickerSet(CoreContext db) : base(db) { } +} \ No newline at end of file diff --git a/modules/ChatManagement/ParamParser/StickerSet.cs b/modules/ChatManagement/ParamParser/StickerSet.cs new file mode 100644 index 0000000..676ae02 --- /dev/null +++ b/modules/ChatManagement/ParamParser/StickerSet.cs @@ -0,0 +1,77 @@ +using System; +using System.Linq; +using BotFramework; +using BotFramework.Abstractions; +using Microsoft.Extensions.Logging; +using Telegram.Bot; +using Telegram.Bot.Types; +using TgStickerSet = Telegram.Bot.Types.StickerSet; + +namespace West.TelegramBot.ChatManagement.ParamParser; + +public class StickerSet +{ + public class Param + { + public TgStickerSet Set { get; set; } + public bool IsValid { get; set; } = false; + } + + public class Parser : IRawParameterParser + { + private readonly IBotInstance _bot; + private readonly ILogger _logger; + + public Parser(IBotInstance bot, ILogger logger) + { + _bot = bot; + _logger = logger; + } + + public Param DefaultInstance() + { + return new Param(); + } + + public bool TryGetValueByRawUpdate(Update update, out Param result) + { + result = DefaultInstance(); + + var bot = _bot.BotClient; + + var message = update?.Message; + var sticker = message?.ReplyToMessage?.Sticker; + if (sticker is { SetName: { } }) + { + result.Set = bot.GetStickerSetAsync(sticker.SetName).GetAwaiter().GetResult(); + result.IsValid = true; + return true; + } + + var messageText = message?.Text; + if (messageText != null) + { + var setName = messageText.Split(' ').Skip(1).ToList(); + if (setName.Any()) + { + try + { + result.Set = bot.GetStickerSetAsync(setName.First()) + .GetAwaiter() + .GetResult(); + result.IsValid = true; + + return true; + } + catch (Exception e) + { + _logger.LogError("Got error while fetching sticker set: {ErrorMessage}", e.Message); + return true; + } + } + } + + return false; + } + } +} \ No newline at end of file