From e815deba580bafa434ac8a66e79e3745e14a9ee7 Mon Sep 17 00:00:00 2001
From: West14 <30056636+West14@users.noreply.github.com>
Date: Wed, 16 Feb 2022 17:07:30 +0200
Subject: [PATCH] [store] Basic content store implementation.
- Bump Telegram Bot Framework to 0.6.9-gf1e77653ff
---
Core/Core.csproj | 2 +-
Kruzya.TelegramBot.sln | 9 +-
modules/ContentStore/ContentStore.cs | 20 +++
modules/ContentStore/ContentStore.csproj | 20 +++
modules/ContentStore/Handler/Store.cs | 163 ++++++++++++++++++
modules/ContentStore/Model/CatImage.cs | 7 +
modules/ContentStore/Model/OBoobsItem.cs | 10 ++
modules/ContentStore/Model/RandomMedia.cs | 18 ++
modules/ContentStore/Model/StoreItem.cs | 25 +++
.../ContentStore/Service/AnimBoobsService.cs | 27 +++
.../ContentStore/Service/AnimalAsAService.cs | 24 +++
modules/ContentStore/Service/CatApiService.cs | 10 ++
modules/ContentStore/Service/DogApiService.cs | 6 +
.../Service/IRandomMediaService.cs | 9 +
modules/ContentStore/Service/OBoobsService.cs | 28 +++
15 files changed, 376 insertions(+), 2 deletions(-)
create mode 100644 modules/ContentStore/ContentStore.cs
create mode 100644 modules/ContentStore/ContentStore.csproj
create mode 100644 modules/ContentStore/Handler/Store.cs
create mode 100644 modules/ContentStore/Model/CatImage.cs
create mode 100644 modules/ContentStore/Model/OBoobsItem.cs
create mode 100644 modules/ContentStore/Model/RandomMedia.cs
create mode 100644 modules/ContentStore/Model/StoreItem.cs
create mode 100644 modules/ContentStore/Service/AnimBoobsService.cs
create mode 100644 modules/ContentStore/Service/AnimalAsAService.cs
create mode 100644 modules/ContentStore/Service/CatApiService.cs
create mode 100644 modules/ContentStore/Service/DogApiService.cs
create mode 100644 modules/ContentStore/Service/IRandomMediaService.cs
create mode 100644 modules/ContentStore/Service/OBoobsService.cs
diff --git a/Core/Core.csproj b/Core/Core.csproj
index bb41840..afda299 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -8,7 +8,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Kruzya.TelegramBot.sln b/Kruzya.TelegramBot.sln
index 0dcdad6..a995a9a 100644
--- a/Kruzya.TelegramBot.sln
+++ b/Kruzya.TelegramBot.sln
@@ -25,7 +25,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Entertainment", "modules\En
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatQuotes", "modules\ChatQuotes\ChatQuotes.csproj", "{04F16325-8F44-4250-9B2E-0F77E8F65CBF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reputation", "modules\Reputation\Reputation.csproj", "{03F3C7D5-6FEF-4A83-9191-501091BFC1AC}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Reputation", "modules\Reputation\Reputation.csproj", "{03F3C7D5-6FEF-4A83-9191-501091BFC1AC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContentStore", "modules\ContentStore\ContentStore.csproj", "{4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -77,6 +79,10 @@ Global
{03F3C7D5-6FEF-4A83-9191-501091BFC1AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03F3C7D5-6FEF-4A83-9191-501091BFC1AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03F3C7D5-6FEF-4A83-9191-501091BFC1AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -91,6 +97,7 @@ Global
{1D62101B-C2B1-4E79-8F7A-690E44E3EE81} = {C7821F15-DEDD-474F-A575-A296D4B58F10}
{04F16325-8F44-4250-9B2E-0F77E8F65CBF} = {C7821F15-DEDD-474F-A575-A296D4B58F10}
{03F3C7D5-6FEF-4A83-9191-501091BFC1AC} = {C7821F15-DEDD-474F-A575-A296D4B58F10}
+ {4F1E8FE8-640F-4671-87FC-0FFCCB6EDF5E} = {C7821F15-DEDD-474F-A575-A296D4B58F10}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5BA73C3B-D5FC-4942-9091-504325CDC308}
diff --git a/modules/ContentStore/ContentStore.cs b/modules/ContentStore/ContentStore.cs
new file mode 100644
index 0000000..df6745e
--- /dev/null
+++ b/modules/ContentStore/ContentStore.cs
@@ -0,0 +1,20 @@
+using Kruzya.TelegramBot.Core;
+using Microsoft.Extensions.DependencyInjection;
+using West.TelegramBot.ContentStore.Service;
+
+namespace West.TelegramBot.ContentStore;
+
+public class ContentStore : Module
+{
+ public ContentStore(Core core) : base(core)
+ {
+ }
+
+ public override void ConfigureServices(IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+}
\ No newline at end of file
diff --git a/modules/ContentStore/ContentStore.csproj b/modules/ContentStore/ContentStore.csproj
new file mode 100644
index 0000000..c76005f
--- /dev/null
+++ b/modules/ContentStore/ContentStore.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0
+ enable
+ enable
+ TelegramBot.ContentStore
+ West.TelegramBot.ContentStore
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/ContentStore/Handler/Store.cs b/modules/ContentStore/Handler/Store.cs
new file mode 100644
index 0000000..51b33b1
--- /dev/null
+++ b/modules/ContentStore/Handler/Store.cs
@@ -0,0 +1,163 @@
+#nullable enable
+
+using BotFramework;
+using BotFramework.Attributes;
+using BotFramework.Enums;
+using Kruzya.TelegramBot.Core.Extensions;
+using Kruzya.TelegramBot.Core.Service;
+using Microsoft.Extensions.DependencyInjection;
+using Telegram.Bot;
+using Telegram.Bot.Types.Enums;
+using Telegram.Bot.Types.InputFiles;
+using Telegram.Bot.Types.ReplyMarkups;
+using West.TelegramBot.ContentStore.Model;
+using West.TelegramBot.ContentStore.Service;
+
+namespace West.TelegramBot.ContentStore.Handler;
+
+public class Store : BotEventHandler
+{
+ private readonly IReputation? _reputation;
+ private readonly IServiceProvider _provider;
+
+ private readonly Dictionary _storeItemMap = new()
+ {
+ { "cat", new StoreItem("cat", "Котэ", 40) },
+ { "dog", new StoreItem("dog", "Пёсель", 40) },
+ { "boobs", new StoreItem("boobs", "Сиськи", 60) },
+ { "anim_boobs", new StoreItem("anim_boobs", "Сиськи движущиеся", 120) }
+ };
+
+ public Store(IServiceProvider provider)
+ {
+ _reputation = provider.GetService();
+ _provider = provider;
+ }
+
+ [Command(InChat.Public, "store", CommandParseMode.Both)]
+ public async Task HandleStore()
+ {
+ if (_reputation == null)
+ {
+ await Bot.SendTextMessageAsync(Chat.Id, "Reputation is unavailable.");
+ return;
+ }
+
+ var rowList = new List>();
+
+ var counter = 0;
+ var list = new List();
+ foreach (var item in _storeItemMap)
+ {
+ var btn = item.Value.ToButton(From.Id);
+ if ((counter & 1) == 0) // 0 - even, 1 - odd
+ {
+ list = new List
+ {
+ btn
+ };
+ }
+ else
+ {
+ list.Add(btn);
+ rowList.Add(list);
+ }
+
+ counter++;
+ }
+
+ await Bot.SendTextMessageAsync(Chat.Id, "Чего пожелаете?", replyMarkup: new InlineKeyboardMarkup(rowList));
+ }
+
+ [Update(InChat.Public, UpdateFlag.CallbackQuery)]
+ public async Task HandleStoreCallback()
+ {
+ var query = CallbackQuery;
+ var queryData = query.Data;
+ if (queryData == null || !queryData.StartsWith("store|") || _reputation == null)
+ {
+ return;
+ }
+
+ var paramList = queryData.Split('|');
+ if (!long.TryParse(paramList[1], out var senderId))
+ {
+ return;
+ }
+
+ if (senderId != From.Id)
+ {
+ await AnswerQuery(query.Id, "Keyboard called by another user.");
+ return;
+ }
+
+ var answer = "Unknown action.";
+ if (paramList[2] == "purchase")
+ {
+ var purchaseType = paramList[3];
+ answer = "Спасибо за покупку";
+
+ if (!_storeItemMap.TryGetValue(purchaseType, out var storeItem)
+ || !TryGetMediaService(purchaseType, out var mediaService))
+ {
+ await AnswerQuery(query.Id, "Unknown purchasable.");
+ return;
+ }
+
+ var messageId = query.Message!.MessageId;
+ if (await _reputation.GetUserReputationAsync(Chat, From) < storeItem.Price)
+ {
+ await Bot.EditMessageTextAsync(
+ Chat.Id,
+ messageId,
+ $"{From.ToHtml()}, продолжай работать и тебе обязательно хватит на покупку.",
+ ParseMode.Html);
+ await AnswerQuery(query.Id);
+ return;
+ }
+
+ await _reputation.IncrementReputationAsync(Chat, From, -storeItem.Price);
+ await Bot.EditMessageTextAsync(Chat.Id, messageId, $"{From.ToHtml()} купил \"{storeItem.Name}\".");
+
+ var randomMedia = await mediaService!.GetRandomMediaAsync();
+ var file = new InputOnlineFile(randomMedia.Url);
+ switch (randomMedia.Type)
+ {
+ case InputMediaType.Photo:
+ await Bot.SendPhotoAsync(Chat.Id, file, randomMedia.Caption, replyToMessageId: messageId);
+ break;
+ case InputMediaType.Video:
+ await Bot.SendVideoAsync(Chat.Id, file, caption: randomMedia.Caption, replyToMessageId: messageId);
+ break;
+ }
+ }
+
+ await AnswerQuery(query.Id, answer);
+ }
+
+ private bool TryGetMediaService(string name, out IRandomMediaService? mediaService)
+ {
+ var serviceType = name switch
+ {
+ "boobs" => typeof(OBoobsService),
+ "cat" => typeof(CatApiService),
+ "dog" => typeof(DogApiService),
+ "anim_boobs" => typeof(AnimBoobsService),
+ _ => null
+ };
+
+ if (serviceType == null)
+ {
+ mediaService = null;
+ return false;
+ }
+
+ mediaService = _provider.GetService(serviceType) as IRandomMediaService;
+ return mediaService != null;
+ }
+
+ private async Task AnswerQuery(string id, string? message = null)
+ {
+ await Bot.AnswerCallbackQueryAsync(id, message);
+ }
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Model/CatImage.cs b/modules/ContentStore/Model/CatImage.cs
new file mode 100644
index 0000000..4f3b619
--- /dev/null
+++ b/modules/ContentStore/Model/CatImage.cs
@@ -0,0 +1,7 @@
+namespace West.TelegramBot.ContentStore.Model;
+
+public class AnimalImage
+{
+ public string Id { get; set; } = null!;
+ public string Url { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Model/OBoobsItem.cs b/modules/ContentStore/Model/OBoobsItem.cs
new file mode 100644
index 0000000..947016f
--- /dev/null
+++ b/modules/ContentStore/Model/OBoobsItem.cs
@@ -0,0 +1,10 @@
+namespace West.TelegramBot.ContentStore.Model;
+
+public class OBoobsItem
+{
+ public int Id { get; set; }
+ public int Rank { get; set; }
+ public string? Author { get; set; }
+ public string? Model { get; set; }
+ public string Preview { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Model/RandomMedia.cs b/modules/ContentStore/Model/RandomMedia.cs
new file mode 100644
index 0000000..dedb55e
--- /dev/null
+++ b/modules/ContentStore/Model/RandomMedia.cs
@@ -0,0 +1,18 @@
+using Telegram.Bot.Types;
+using Telegram.Bot.Types.Enums;
+
+namespace West.TelegramBot.ContentStore.Model;
+
+public class RandomMedia
+{
+ public RandomMedia(string url, string? caption = null)
+ {
+ Url = url;
+ Caption = caption;
+ }
+
+ public string Url;
+ public string? Caption;
+
+ public InputMediaType Type { get; set; } = InputMediaType.Photo;
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Model/StoreItem.cs b/modules/ContentStore/Model/StoreItem.cs
new file mode 100644
index 0000000..b3250c4
--- /dev/null
+++ b/modules/ContentStore/Model/StoreItem.cs
@@ -0,0 +1,25 @@
+using Telegram.Bot.Types.ReplyMarkups;
+
+namespace West.TelegramBot.ContentStore.Model;
+
+class StoreItem
+{
+ public string Id;
+ public readonly string Name;
+ public readonly double Price;
+
+ public StoreItem(string id, string name, double price)
+ {
+ Id = id;
+ Name = name;
+ Price = price;
+ }
+
+ public InlineKeyboardButton ToButton(long userId)
+ {
+ return new InlineKeyboardButton($"{Name} ({Price})")
+ {
+ CallbackData = $"store|{userId}|purchase|{Id}"
+ };
+ }
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/AnimBoobsService.cs b/modules/ContentStore/Service/AnimBoobsService.cs
new file mode 100644
index 0000000..d2afda8
--- /dev/null
+++ b/modules/ContentStore/Service/AnimBoobsService.cs
@@ -0,0 +1,27 @@
+using Telegram.Bot.Types;
+using Telegram.Bot.Types.Enums;
+using West.TelegramBot.ContentStore.Model;
+
+namespace West.TelegramBot.ContentStore.Service;
+
+public class AnimBoobsService : IRandomMediaService
+{
+ private readonly HttpClient _httpClient;
+
+ public AnimBoobsService()
+ {
+ _httpClient = new HttpClient()
+ {
+ BaseAddress = new Uri("https://westdev.me/_boobs/")
+ };
+ }
+
+ public async Task GetRandomMediaAsync()
+ {
+ var fileName = await _httpClient.GetStringAsync("index.php");
+ return new RandomMedia($"https://westdev.me/_boobs/media/{fileName}")
+ {
+ Type = InputMediaType.Video
+ };
+ }
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/AnimalAsAService.cs b/modules/ContentStore/Service/AnimalAsAService.cs
new file mode 100644
index 0000000..e70e50c
--- /dev/null
+++ b/modules/ContentStore/Service/AnimalAsAService.cs
@@ -0,0 +1,24 @@
+using Newtonsoft.Json;
+using West.TelegramBot.ContentStore.Model;
+
+namespace West.TelegramBot.ContentStore.Service;
+
+public abstract class AnimalAsAService : IRandomMediaService
+{
+ private readonly HttpClient _httpClient;
+
+ protected AnimalAsAService(Uri baseAddress)
+ {
+ _httpClient = new HttpClient
+ {
+ BaseAddress = baseAddress
+ };
+ }
+
+ public async Task GetRandomMediaAsync()
+ {
+ var resp = await _httpClient.GetAsync("images/search");
+ var catImage = JsonConvert.DeserializeObject>(await resp.Content.ReadAsStringAsync())[0];
+ return new RandomMedia(catImage.Url);
+ }
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/CatApiService.cs b/modules/ContentStore/Service/CatApiService.cs
new file mode 100644
index 0000000..e340357
--- /dev/null
+++ b/modules/ContentStore/Service/CatApiService.cs
@@ -0,0 +1,10 @@
+using Newtonsoft.Json;
+using Telegram.Bot.Types;
+using West.TelegramBot.ContentStore.Model;
+
+namespace West.TelegramBot.ContentStore.Service;
+
+public class CatApiService : AnimalAsAService
+{
+ public CatApiService() : base(new Uri("https://api.thecatapi.com/v1/")) {}
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/DogApiService.cs b/modules/ContentStore/Service/DogApiService.cs
new file mode 100644
index 0000000..6bd9fb1
--- /dev/null
+++ b/modules/ContentStore/Service/DogApiService.cs
@@ -0,0 +1,6 @@
+namespace West.TelegramBot.ContentStore.Service;
+
+public class DogApiService : AnimalAsAService
+{
+ public DogApiService() : base(new Uri("https://api.thedogapi.com/v1/")) {}
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/IRandomMediaService.cs b/modules/ContentStore/Service/IRandomMediaService.cs
new file mode 100644
index 0000000..07c7077
--- /dev/null
+++ b/modules/ContentStore/Service/IRandomMediaService.cs
@@ -0,0 +1,9 @@
+using Telegram.Bot.Types;
+using West.TelegramBot.ContentStore.Model;
+
+namespace West.TelegramBot.ContentStore.Service;
+
+public interface IRandomMediaService
+{
+ public Task GetRandomMediaAsync();
+}
\ No newline at end of file
diff --git a/modules/ContentStore/Service/OBoobsService.cs b/modules/ContentStore/Service/OBoobsService.cs
new file mode 100644
index 0000000..d88727e
--- /dev/null
+++ b/modules/ContentStore/Service/OBoobsService.cs
@@ -0,0 +1,28 @@
+using Newtonsoft.Json;
+using Telegram.Bot.Types;
+using West.TelegramBot.ContentStore.Model;
+
+namespace West.TelegramBot.ContentStore.Service;
+
+public class OBoobsService : IRandomMediaService
+{
+ private readonly HttpClient _httpClient;
+
+ public OBoobsService()
+ {
+ _httpClient = new HttpClient
+ {
+ BaseAddress = new Uri("http://api.oboobs.ru")
+ };
+ }
+
+ public async Task GetRandomMediaAsync()
+ {
+ var httpResp = await _httpClient.GetAsync("boobs/1/1/random");
+ var boobsResponse = JsonConvert.DeserializeObject>(await httpResp.Content.ReadAsStringAsync());
+ var boobsItem = boobsResponse[0];
+ var boobsId = boobsItem.Id.ToString("D5");
+
+ return new RandomMedia($"https://media.oboobs.ru/boobs/{boobsId}.jpg", boobsItem.Model);
+ }
+}
\ No newline at end of file