[store] Basic content store implementation.

- Bump Telegram Bot Framework to 0.6.9-gf1e77653ff
This commit is contained in:
West14
2022-02-16 17:07:30 +02:00
parent 67d0e81953
commit e815deba58
15 changed files with 376 additions and 2 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Core' " />
<ItemGroup>
<PackageReference Include="AleXr64.BotFramework" Version="0.6.8-g0882b76d16" />
<PackageReference Include="AleXr64.BotFramework" Version="0.6.9-gf1e77653ff" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+8 -1
View File
@@ -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}
+20
View File
@@ -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<OBoobsService>();
services.AddSingleton<CatApiService>();
services.AddSingleton<DogApiService>();
services.AddSingleton<AnimBoobsService>();
}
}
+20
View File
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>TelegramBot.ContentStore</AssemblyName>
<RootNamespace>West.TelegramBot.ContentStore</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\Core.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Handler\" />
<Folder Include="Model\" />
</ItemGroup>
</Project>
+163
View File
@@ -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<string, StoreItem> _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<IReputation>();
_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<List<InlineKeyboardButton>>();
var counter = 0;
var list = new List<InlineKeyboardButton>();
foreach (var item in _storeItemMap)
{
var btn = item.Value.ToButton(From.Id);
if ((counter & 1) == 0) // 0 - even, 1 - odd
{
list = new List<InlineKeyboardButton>
{
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);
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace West.TelegramBot.ContentStore.Model;
public class AnimalImage
{
public string Id { get; set; } = null!;
public string Url { get; set; } = null!;
}
+10
View File
@@ -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;
}
+18
View File
@@ -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;
}
+25
View File
@@ -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}"
};
}
}
@@ -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<RandomMedia> GetRandomMediaAsync()
{
var fileName = await _httpClient.GetStringAsync("index.php");
return new RandomMedia($"https://westdev.me/_boobs/media/{fileName}")
{
Type = InputMediaType.Video
};
}
}
@@ -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<RandomMedia> GetRandomMediaAsync()
{
var resp = await _httpClient.GetAsync("images/search");
var catImage = JsonConvert.DeserializeObject<List<AnimalImage>>(await resp.Content.ReadAsStringAsync())[0];
return new RandomMedia(catImage.Url);
}
}
@@ -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/")) {}
}
@@ -0,0 +1,6 @@
namespace West.TelegramBot.ContentStore.Service;
public class DogApiService : AnimalAsAService
{
public DogApiService() : base(new Uri("https://api.thedogapi.com/v1/")) {}
}
@@ -0,0 +1,9 @@
using Telegram.Bot.Types;
using West.TelegramBot.ContentStore.Model;
namespace West.TelegramBot.ContentStore.Service;
public interface IRandomMediaService
{
public Task<RandomMedia> GetRandomMediaAsync();
}
@@ -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<RandomMedia> GetRandomMediaAsync()
{
var httpResp = await _httpClient.GetAsync("boobs/1/1/random");
var boobsResponse = JsonConvert.DeserializeObject<List<OBoobsItem>>(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);
}
}