Przeglądaj źródła

Giveaways message parsing and sending in channel

Tigran 4 lat temu
rodzic
commit
4b29c4cf5e

+ 2 - 1
MafiaTelegramBot.sln.DotSettings.user

@@ -11,8 +11,9 @@
 &lt;/SessionState&gt;</s:String>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002Fappsettings/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002FResources_002Fkeyboard/@EntryIndexedValue">False</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002FResources_002Fkeywords/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002FResources_002Froles/@EntryIndexedValue">False</s:Boolean>
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002FResources_002Fstrings/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=MafiaTelegramBot_002FResources_002Fstrings/@EntryIndexedValue">False</s:Boolean>
 	
 	
 	

+ 2 - 0
MafiaTelegramBot/Controllers/MessageController.cs

@@ -2,6 +2,7 @@ using System;
 using System.Threading;
 using System.Threading.Tasks;
 using MafiaTelegramBot.Models;
+using MafiaTelegramBot.Models.ChannelPost;
 using MafiaTelegramBot.Models.Commands;
 using MafiaTelegramBot.Models.Inlines;
 using Telegram.Bot;
@@ -23,6 +24,7 @@ namespace MafiaTelegramBot.Controllers
                     UpdateType.Message => Command.Update(update),
                     UpdateType.CallbackQuery => Query.Update(update),
                     UpdateType.PreCheckoutQuery => Bot.AnswerPreCheckoutQuery(update.PreCheckoutQuery.Id),
+                    UpdateType.ChannelPost => ChannelPost.Update(update),
                     _ => UnknownUpdateHandlerAsync(update)
                 };
                 await handle;

+ 9 - 0
MafiaTelegramBot/MafiaTelegramBot.csproj

@@ -27,6 +27,10 @@
         <Generator>ResXFileCodeGenerator</Generator>
         <LastGenOutput>roles.Designer.cs</LastGenOutput>
       </EmbeddedResource>
+      <EmbeddedResource Update="Resources\keywords.resx">
+        <Generator>ResXFileCodeGenerator</Generator>
+        <LastGenOutput>keywords.Designer.cs</LastGenOutput>
+      </EmbeddedResource>
     </ItemGroup>
 
     <ItemGroup>
@@ -45,6 +49,11 @@
         <AutoGen>True</AutoGen>
         <DependentUpon>roles.resx</DependentUpon>
       </Compile>
+      <Compile Update="Resources\keywords.Designer.cs">
+        <DesignTime>True</DesignTime>
+        <AutoGen>True</AutoGen>
+        <DependentUpon>keywords.resx</DependentUpon>
+      </Compile>
     </ItemGroup>
 
 </Project>

+ 44 - 0
MafiaTelegramBot/Models/ChannelPost/ChannelPost.cs

@@ -0,0 +1,44 @@
+#nullable enable
+using System;
+using System.Threading.Tasks;
+using System.Timers;
+using MafiaTelegramBot.Resources;
+using Telegram.Bot.Types;
+
+namespace MafiaTelegramBot.Models.ChannelPost
+{
+    public abstract class ChannelPost : UpdateModel<string>
+    {
+        protected int MessageId;
+        protected string Text = "";
+        protected override bool IsMatches(string command)
+        {
+            return command.Contains(Name);
+        }
+
+        public static async Task<Message> Update(Update update)
+        {
+            var text = update.ChannelPost.Text;
+            var chatId = update.ChannelPost.Chat.Id;
+            var messageId = update.ChannelPost.MessageId;
+            if (text == null) return new Message();
+            if (text.Contains(keywords.giveaway)) return await new GiveawayChannelPost(text, chatId, messageId).Execute(update);
+            return new Message();
+        }
+
+        protected async Task<Message> SendErrorAndDelete(string message)
+        {
+            var error = await Bot.SendWithMarkdown2(ChatId, message);
+            var timer = new Timer { AutoReset = false, Interval = 10 * 1000 };
+            timer.Elapsed += async (_, _) =>
+            {
+                try
+                {
+                    await DeletePreviousMessage(ChatId, error.MessageId);
+                } catch (Exception) { /* ignore */ }
+            };
+            timer.Start();
+            return error;
+        }
+    }
+}

+ 60 - 0
MafiaTelegramBot/Models/ChannelPost/GiveawayChannelPost.cs

@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MafiaTelegramBot.Other;
+using MafiaTelegramBot.Resources;
+using Telegram.Bot.Types;
+
+namespace MafiaTelegramBot.Models.ChannelPost
+{
+    public class GiveawayChannelPost : ChannelPost
+    {
+        protected override string Name => keywords.giveaway;
+        protected override async Task<Message> Execute(Update update)
+        {
+            await DeletePreviousMessage(ChatId, MessageId);
+            var structure = ParseMessage();
+            if (structure[keywords.message] == "" && structure[keywords.picture] == "") return await SendErrorAndDelete(strings.message_could_contain_text_or_image);
+            if (structure[keywords.prize] == "") return await SendErrorAndDelete(strings.message_could_contain_prize);
+            if (structure[keywords.button] == "") return await SendErrorAndDelete(strings.message_could_contain_button_name);
+            if (structure[keywords.count] == "") return await SendErrorAndDelete(strings.message_could_contain_count);
+            if (!int.TryParse(structure[keywords.count], out var count)) return await SendErrorAndDelete(strings.count_of_prizes_must_be_int);
+            if (!Enum.TryParse<Roles>(structure[keywords.prize], out var prize)) return await SendErrorAndDelete(strings.prize_name_must_be_an_english_keyword);
+            var giveaway = new GiveAway(count, prize);
+            return await giveaway.PostGiveAway(ChatId, structure[keywords.button], 
+                structure[keywords.message] != "" ? structure[keywords.message] : null, 
+                structure[keywords.picture] != "" ? structure[keywords.picture] : null,
+                structure[keywords.to] != "" ? structure[keywords.to] : null);
+        }
+
+        private Dictionary<string, string> ParseMessage()
+        {
+            string GetPart(string keyword)
+            {
+                if (!Text.Contains(keyword)) return "";
+                var start = Text.IndexOf(keyword, StringComparison.Ordinal);
+                start = Text.IndexOf('<', start) + 1;
+                var end = Text.IndexOf('>', start);
+                return end - start > 0 || end == -1 || start == -1 ? Text.Substring(start, end - start) : "";
+            }
+            
+            var result = new Dictionary<string, string>
+            {
+                { keywords.message, GetPart(keywords.message) },
+                { keywords.picture, GetPart(keywords.picture) },
+                { keywords.prize, GetPart(keywords.prize) },
+                { keywords.button, GetPart(keywords.button) },
+                { keywords.count, GetPart(keywords.count) },
+                { keywords.to, GetPart(keywords.to) },
+            };
+            return result;
+        }
+
+        public GiveawayChannelPost(string text, long chatId, int messageId)
+        {
+            Text = text;
+            ChatId = chatId;
+            MessageId = messageId;
+        }
+    }
+}

+ 81 - 0
MafiaTelegramBot/Other/GiveAway.cs

@@ -0,0 +1,81 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using MafiaTelegramBot.DataBase.EntityDao;
+using MafiaTelegramBot.Models;
+using MafiaTelegramBot.Resources;
+using Telegram.Bot.Types;
+using Telegram.Bot.Types.InputFiles;
+using Telegram.Bot.Types.ReplyMarkups;
+
+namespace MafiaTelegramBot.Other
+{
+    public class GiveAway
+    {
+        public static readonly Dictionary<int, GiveAway> OpenedGiveaways = new ();
+
+        private readonly int _id;
+        private readonly string _url;
+        private int _count;
+        private readonly List<long> _awardedIdList = new ();
+        private Roles _prize;
+        private long _chatId;
+        private int _messageId;
+        private string _buttonText = "";
+
+        public GiveAway(int count, Roles prize)
+        {
+            _id = Utilities.Rnd.Next();
+            _count = count;
+            _prize = prize;
+            _url = $"https://t.me/{AppSettings.Name}?start=giveaway_id={_id}";
+            OpenedGiveaways.Add(_id, this);
+        }
+
+        public async Task<Message> PostGiveAway(long channelId, string buttonText, string message = null, string imageUrl = null, string userName = null)
+        {
+            _chatId = channelId;
+            _buttonText = buttonText;
+            var keyboard = new InlineKeyboardMarkup(InlineKeyboardButton.WithUrl(_buttonText + $" ({_count})", _url));
+            var result = imageUrl == null
+                ? await Bot.SendWithMarkdown2(_chatId, message, keyboard)
+                : await Bot.Get().SendPhotoAsync(_chatId, new InputOnlineFile(imageUrl), message, replyMarkup: keyboard);
+            _messageId = result.MessageId;
+            if (userName == null) return result;
+            var adminId = await UserDao.GetIdByUsername(userName);
+            var admin = await UserDao.GetPlayerById(adminId);
+            await Bot.SendHyperLink(admin.ChatId, $"<a href='{_url}'>{strings.giveaway_link}</a>");
+            return result;
+        }
+
+        private async Task<bool> TryDecreaseCount(long id)
+        {
+            if (_awardedIdList.Contains(id)) return false;
+            _count--;
+            await UpdateGiveAwayMessageOrDelete();
+            _awardedIdList.Add(id);
+            return true;
+        }
+
+        public async Task<ResultCode> GivePrizeTo(long id)
+        {
+            if (!await TryDecreaseCount(id)) return ResultCode.NowYouGetPrizeFromThisGiveaway;
+            var player = await UserDao.GetPlayerById(id);
+            return ResultCode.CodeOk;
+        }
+
+        private async Task UpdateGiveAwayMessageOrDelete()
+        {
+            if (_count == 0)
+            {
+                await Bot.Get().DeleteMessageAsync(_chatId, _messageId);
+                OpenedGiveaways.Remove(_id);
+                _awardedIdList.Clear();
+            }
+            else
+            {
+                var keyboard = new InlineKeyboardMarkup(InlineKeyboardButton.WithUrl(_buttonText + $" ({_count})", _url));
+                await Bot.Get().EditMessageReplyMarkupAsync(_chatId, _messageId, keyboard);
+            }
+        }
+    }
+}

+ 2 - 0
MafiaTelegramBot/Resources/ResultCode.cs

@@ -13,6 +13,8 @@ namespace MafiaTelegramBot.Resources
         RolesNotEqualPlayers,
         NotEnoughMafia,
         TooMuchMafia,
+        NowYouHaveThisRole,
+        NowYouGetPrizeFromThisGiveaway,
         CodeOk,
     }
 }

+ 90 - 0
MafiaTelegramBot/Resources/keywords.Designer.cs

@@ -0,0 +1,90 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MafiaTelegramBot.Resources {
+    using System;
+    
+    
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class keywords {
+        
+        private static System.Resources.ResourceManager resourceMan;
+        
+        private static System.Globalization.CultureInfo resourceCulture;
+        
+        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal keywords() {
+        }
+        
+        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.Equals(null, resourceMan)) {
+                    System.Resources.ResourceManager temp = new System.Resources.ResourceManager("MafiaTelegramBot.Resources.keywords", typeof(keywords).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        internal static string giveaway {
+            get {
+                return ResourceManager.GetString("giveaway", resourceCulture);
+            }
+        }
+        
+        internal static string message {
+            get {
+                return ResourceManager.GetString("message", resourceCulture);
+            }
+        }
+        
+        internal static string picture {
+            get {
+                return ResourceManager.GetString("picture", resourceCulture);
+            }
+        }
+        
+        internal static string prize {
+            get {
+                return ResourceManager.GetString("prize", resourceCulture);
+            }
+        }
+        
+        internal static string count {
+            get {
+                return ResourceManager.GetString("count", resourceCulture);
+            }
+        }
+        
+        internal static string button {
+            get {
+                return ResourceManager.GetString("button", resourceCulture);
+            }
+        }
+        
+        internal static string to {
+            get {
+                return ResourceManager.GetString("to", resourceCulture);
+            }
+        }
+    }
+}

+ 42 - 0
MafiaTelegramBot/Resources/keywords.resx

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<root>
+    <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+        <xsd:element name="root" msdata:IsDataSet="true">
+            
+        </xsd:element>
+    </xsd:schema>
+    <resheader name="resmimetype">
+        <value>text/microsoft-resx</value>
+    </resheader>
+    <resheader name="version">
+        <value>1.3</value>
+    </resheader>
+    <resheader name="reader">
+        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <resheader name="writer">
+        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    </resheader>
+    <data name="giveaway" xml:space="preserve">
+        <value>!Раздача</value>
+    </data>
+    <data name="message" xml:space="preserve">
+        <value>Сообщение</value>
+    </data>
+    <data name="picture" xml:space="preserve">
+        <value>Изображение</value>
+    </data>
+    <data name="prize" xml:space="preserve">
+        <value>Приз</value>
+    </data>
+    <data name="count" xml:space="preserve">
+        <value>Количество</value>
+    </data>
+    <data name="button" xml:space="preserve">
+        <value>Кнопка</value>
+    </data>
+    <data name="to" xml:space="preserve">
+        <value>Кому</value>
+    </data>
+</root>

+ 42 - 0
MafiaTelegramBot/Resources/strings.Designer.cs

@@ -1244,5 +1244,47 @@ namespace MafiaTelegramBot {
                 return ResourceManager.GetString("role_successfully_issued_to", resourceCulture);
             }
         }
+        
+        internal static string message_could_contain_text_or_image {
+            get {
+                return ResourceManager.GetString("message_could_contain_text_or_image", resourceCulture);
+            }
+        }
+        
+        internal static string message_could_contain_prize {
+            get {
+                return ResourceManager.GetString("message_could_contain_prize", resourceCulture);
+            }
+        }
+        
+        internal static string message_could_contain_button_name {
+            get {
+                return ResourceManager.GetString("message_could_contain_button_name", resourceCulture);
+            }
+        }
+        
+        internal static string message_could_contain_count {
+            get {
+                return ResourceManager.GetString("message_could_contain_count", resourceCulture);
+            }
+        }
+        
+        internal static string count_of_prizes_must_be_int {
+            get {
+                return ResourceManager.GetString("count_of_prizes_must_be_int", resourceCulture);
+            }
+        }
+        
+        internal static string prize_name_must_be_an_english_keyword {
+            get {
+                return ResourceManager.GetString("prize_name_must_be_an_english_keyword", resourceCulture);
+            }
+        }
+        
+        internal static string giveaway_link {
+            get {
+                return ResourceManager.GetString("giveaway_link", resourceCulture);
+            }
+        }
     }
 }

+ 21 - 0
MafiaTelegramBot/Resources/strings.resx

@@ -618,4 +618,25 @@
     <data name="role_successfully_issued_to" xml:space="preserve">
         <value>Роль успешно выдана игроку</value>
     </data>
+    <data name="message_could_contain_text_or_image" xml:space="preserve">
+        <value>Сообщение должно содержать изображение или текст</value>
+    </data>
+    <data name="message_could_contain_prize" xml:space="preserve">
+        <value>Сообщение должно содержать приз</value>
+    </data>
+    <data name="message_could_contain_button_name" xml:space="preserve">
+        <value>Сообщение должно содержать название кнопки</value>
+    </data>
+    <data name="message_could_contain_count" xml:space="preserve">
+        <value>Сообщение должно содержать количество призов</value>
+    </data>
+    <data name="count_of_prizes_must_be_int" xml:space="preserve">
+        <value>Количество призов должно быть целым числом</value>
+    </data>
+    <data name="prize_name_must_be_an_english_keyword" xml:space="preserve">
+        <value>Наименование приза должно быть английским ключевым словом</value>
+    </data>
+    <data name="giveaway_link" xml:space="preserve">
+        <value>Ссылка на раздачу</value>
+    </data>
 </root>