mirror of
https://github.com/Bubuni-Team/telegram-bot.git
synced 2026-07-31 00:29:24 +03:00
initial chat options implementation
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#nullable enable
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json;
|
||||
using System;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Data;
|
||||
|
||||
[PrimaryKey(nameof(ChatId), nameof(OptionId))]
|
||||
public class ChatOptionValue
|
||||
{
|
||||
public long ChatId { get; set; }
|
||||
public string OptionId { get; set; }
|
||||
public byte[] Value { get; set; }
|
||||
|
||||
|
||||
public T GetValue<T>(T? defVal = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
return JsonSerializer.Deserialize<T>(new ReadOnlySpan<byte>(Value));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return defVal;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetValue<T>(T value)
|
||||
{
|
||||
Value = JsonSerializer.SerializeToUtf8Bytes(value, new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = false,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ namespace Kruzya.TelegramBot.Core.Data
|
||||
/// </summary>
|
||||
public DbSet<BotUserValue> UserValues { get; set; }
|
||||
|
||||
public DbSet<ChatOptionValue> ChatOptionValues { get; set; }
|
||||
|
||||
public CoreContext(DbContextOptions<CoreContext> ctx) : base(ctx)
|
||||
{
|
||||
Database.Migrate();
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Threading.Tasks;
|
||||
using Kruzya.TelegramBot.Core.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Extensions;
|
||||
|
||||
public partial class RepositoryExtension
|
||||
{
|
||||
public static async Task<ChatOptionValue> FindOption(this DbSet<ChatOptionValue> repository, long chatId,
|
||||
string optionId)
|
||||
{
|
||||
return await repository.SingleOrDefaultAsync(x => x.ChatId == chatId && x.OptionId == optionId);
|
||||
}
|
||||
|
||||
public static async Task<ChatOptionValue> FindOrCreateOption(this DbSet<ChatOptionValue> repository, long chatId,
|
||||
string optionId)
|
||||
{
|
||||
var opt = await repository.FindOption(chatId, optionId) ?? new ChatOptionValue
|
||||
{
|
||||
ChatId = chatId,
|
||||
OptionId = optionId
|
||||
};
|
||||
|
||||
return opt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Kruzya.TelegramBot.Core.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Migrations
|
||||
{
|
||||
[DbContext(typeof(CoreContext))]
|
||||
[Migration("20230720171645_AddChatOptions")]
|
||||
partial class AddChatOptions
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.BotUser", b =>
|
||||
{
|
||||
b.Property<Guid>("BotUserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<long>("ChatId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("BotUserId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.BotUserValue", b =>
|
||||
{
|
||||
b.Property<Guid>("BotUserValueId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid?>("BotUserId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<byte[]>("Value")
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.Property<string>("ValueType")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("BotUserValueId");
|
||||
|
||||
b.HasIndex("BotUserId");
|
||||
|
||||
b.ToTable("UserValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.ChatOptionValue", b =>
|
||||
{
|
||||
b.Property<long>("ChatId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("OptionId")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<byte[]>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.HasKey("ChatId", "OptionId");
|
||||
|
||||
b.ToTable("ChatOptionValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.BotUserValue", b =>
|
||||
{
|
||||
b.HasOne("Kruzya.TelegramBot.Core.Data.BotUser", "BotUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("BotUserId");
|
||||
|
||||
b.Navigation("BotUser");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddChatOptions : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ChatOptionValues",
|
||||
columns: table => new
|
||||
{
|
||||
ChatId = table.Column<long>(type: "bigint", nullable: false),
|
||||
OptionId = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Value = table.Column<byte[]>(type: "longblob", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ChatOptionValues", x => new { x.ChatId, x.OptionId });
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ChatOptionValues");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "ValueType",
|
||||
table: "UserValues",
|
||||
type: "longtext CHARACTER SET utf8mb4",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext",
|
||||
oldNullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Name",
|
||||
table: "UserValues",
|
||||
type: "longtext CHARACTER SET utf8mb4",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext",
|
||||
oldNullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Migrations
|
||||
{
|
||||
[DbContext(typeof(CoreContext))]
|
||||
@@ -14,7 +16,7 @@ namespace Kruzya.TelegramBot.Core.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.1.2")
|
||||
.HasAnnotation("ProductVersion", "7.0.1")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.BotUser", b =>
|
||||
@@ -44,13 +46,13 @@ namespace Kruzya.TelegramBot.Core.Migrations
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<byte[]>("Value")
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.Property<string>("ValueType")
|
||||
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("BotUserValueId");
|
||||
|
||||
@@ -59,11 +61,30 @@ namespace Kruzya.TelegramBot.Core.Migrations
|
||||
b.ToTable("UserValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.ChatOptionValue", b =>
|
||||
{
|
||||
b.Property<long>("ChatId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("OptionId")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<byte[]>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("longblob");
|
||||
|
||||
b.HasKey("ChatId", "OptionId");
|
||||
|
||||
b.ToTable("ChatOptionValues");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Kruzya.TelegramBot.Core.Data.BotUserValue", b =>
|
||||
{
|
||||
b.HasOne("Kruzya.TelegramBot.Core.Data.BotUser", "BotUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("BotUserId");
|
||||
|
||||
b.Navigation("BotUser");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
public abstract class AbstractOption<TOption, TValue> : IOption<TValue>
|
||||
where TOption: AbstractOption<TOption, TValue>
|
||||
{
|
||||
private readonly IOptionProvider _optionProvider;
|
||||
|
||||
protected AbstractOption(IOptionProvider optionProvider)
|
||||
{
|
||||
_optionProvider = optionProvider;
|
||||
}
|
||||
|
||||
public async Task<TValue> GetValueAsync(long chatId)
|
||||
{
|
||||
return await _optionProvider.GetValueAsync<TOption, TValue>(chatId);
|
||||
}
|
||||
|
||||
public async Task SetValueAsync(long chatId, TValue value)
|
||||
{
|
||||
await _optionProvider.SetValueAsync<TOption, TValue>(chatId, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Kruzya.TelegramBot.Core.Data;
|
||||
using Kruzya.TelegramBot.Core.Extensions;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
public class DbOptionProvider : IOptionProvider
|
||||
{
|
||||
private readonly CoreContext _db;
|
||||
|
||||
public DbOptionProvider(CoreContext db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<TValue> GetValueAsync<TOption, TValue>(long chatId)
|
||||
{
|
||||
return await GetValueAsync(
|
||||
chatId,
|
||||
GetOptionId<TOption>(),
|
||||
GetDefaultValue<TOption, TValue>()
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<TValue> GetValueAsync<TValue>(long chatId, string optionId, TValue defVal)
|
||||
{
|
||||
return (await _db.ChatOptionValues.FindOrCreateOption(chatId, optionId)).GetValue(defVal);
|
||||
}
|
||||
|
||||
public async Task SetValueAsync<TOption, TValue>(long chatId, TValue value)
|
||||
{
|
||||
var chatOption = await _db.ChatOptionValues.FindOrCreateOption(chatId, GetOptionId<TOption>());
|
||||
chatOption.SetValue(value);
|
||||
_db.AddOrUpdate(chatOption);
|
||||
}
|
||||
|
||||
protected OptionAttribute GetOptionAttribute<TOption>()
|
||||
{
|
||||
return typeof(TOption).GetCustomAttribute<OptionAttribute>();
|
||||
}
|
||||
|
||||
protected string GetOptionId<TOption>()
|
||||
{
|
||||
var optionId = GetOptionAttribute<TOption>()?.OptionId;
|
||||
if (optionId == null)
|
||||
{
|
||||
throw new ArgumentException("Option must implement OptionAttribute");
|
||||
}
|
||||
|
||||
return optionId;
|
||||
}
|
||||
|
||||
protected TValue GetDefaultValue<TOption, TValue>()
|
||||
{
|
||||
return (TValue) GetOptionAttribute<TOption>().DefaultValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
public interface IOption<TValue>
|
||||
{
|
||||
public Task<TValue> GetValueAsync(long chatId);
|
||||
public Task SetValueAsync(long chatId, TValue value);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
public interface IOptionProvider
|
||||
{
|
||||
public Task<TValue> GetValueAsync<TOption, TValue>(long chatId);
|
||||
public Task SetValueAsync<TOption, TValue>(long chatId, TValue value);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class OptionAttribute : Attribute
|
||||
{
|
||||
public string OptionId { get; }
|
||||
public object DefaultValue { get; }
|
||||
|
||||
public OptionAttribute(string optionId, object defaultValue = default)
|
||||
{
|
||||
OptionId = optionId;
|
||||
DefaultValue = defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Concurrent;
|
||||
using Kruzya.TelegramBot.Core.Options;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core
|
||||
@@ -53,6 +54,8 @@ namespace Kruzya.TelegramBot.Core
|
||||
services.AddSingleton<ConcurrentBag<DeleteRequest>>();
|
||||
services.AddHostedService<DeleteService>();
|
||||
|
||||
services.AddScoped<IOptionProvider, DbOptionProvider>();
|
||||
|
||||
// Trigger module handlers.
|
||||
_core.Modules.ConfigureServices(services);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Threading.Tasks;
|
||||
using BotFramework;
|
||||
using BotFramework.Attributes;
|
||||
using BotFramework.Enums;
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core;
|
||||
|
||||
public class Test : BotEventHandler
|
||||
{
|
||||
public uint Counter { get; set; } = 5;
|
||||
|
||||
|
||||
[Command(InChat.All, "test_state")]
|
||||
public async Task TestState()
|
||||
{
|
||||
Counter++;
|
||||
await Bot.SendTextMessageAsync(Chat.Id, Counter.ToString());
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ global using GuessCache = Kruzya.TelegramBot.Core.Cache.MemoryCache<Telegram.Bot
|
||||
|
||||
|
||||
using Kruzya.TelegramBot.Core;
|
||||
using Kruzya.TelegramBot.Core.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using West.Entertainment.Options;
|
||||
|
||||
|
||||
namespace West.Entertainment
|
||||
@@ -15,6 +17,7 @@ namespace West.Entertainment
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IGuessCache, GuessCache>();
|
||||
services.AddScoped<NsfwOption>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,20 +12,23 @@ using Kruzya.TelegramBot.Core.Service;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using West.Entertainment.Options;
|
||||
|
||||
namespace West.Entertainment.Handler
|
||||
{
|
||||
public class Common : BotEventHandler
|
||||
{
|
||||
private readonly UserService _userService;
|
||||
private readonly NsfwOption _nsfwOption;
|
||||
private readonly ILogger _logger;
|
||||
private readonly CoreContext _db;
|
||||
|
||||
public Common(CoreContext db, ILogger<Common> logger, UserService userService)
|
||||
public Common(CoreContext db, ILogger<Common> logger, UserService userService, NsfwOption nsfwOption)
|
||||
{
|
||||
_db = db;
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
_nsfwOption = nsfwOption;
|
||||
}
|
||||
|
||||
[Command(InChat.Public, "cooldowns", CommandParseMode.Both)]
|
||||
@@ -59,5 +62,20 @@ namespace West.Entertainment.Handler
|
||||
|
||||
await Bot.SendTextMessageAsync(Chat.Id, msg.ToString(), parseMode: ParseMode.Html);
|
||||
}
|
||||
|
||||
[Command("test_option_get")]
|
||||
public async Task HandleTestOptionGet()
|
||||
{
|
||||
await Bot.SendTextMessageAsync(Chat.Id, $"nsfw option is: {await _nsfwOption.GetValueAsync(Chat.Id)}");
|
||||
}
|
||||
|
||||
[Command("test_option_set")]
|
||||
public async Task HandleTestOptionSet()
|
||||
{
|
||||
var value = await _nsfwOption.GetValueAsync(Chat.Id);
|
||||
await _nsfwOption.SetValueAsync(Chat.Id, !value);
|
||||
|
||||
await Bot.SendTextMessageAsync(Chat.Id, $"nsfw option is: {await _nsfwOption.GetValueAsync(Chat.Id)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Kruzya.TelegramBot.Core.Options;
|
||||
|
||||
namespace West.Entertainment.Options;
|
||||
|
||||
[Option("allowNSFW", false)]
|
||||
public class NsfwOption : AbstractOption<NsfwOption, bool>
|
||||
{
|
||||
public NsfwOption(IOptionProvider optionProvider) : base(optionProvider)
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user