Migrate to database storage in UrlLimitations

This commit is contained in:
2020-03-08 12:38:00 +04:00
parent 3fd5042367
commit 73cfe51312
7 changed files with 151 additions and 48 deletions
+65 -1
View File
@@ -1,4 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using Kruzya.TelegramBot.Core.Data;
using Microsoft.EntityFrameworkCore;
namespace Kruzya.TelegramBot.Core.Extensions
{
@@ -43,5 +45,67 @@ namespace Kruzya.TelegramBot.Core.Extensions
}
#endregion
#region Core-context repository extensions
#region BotUserValue
#region FindOption
public static async Task<BotUserValue> FindOption(this DbSet<BotUserValue> repository, long chatId,
string option) => await repository.FindOption(chatId, 0, option);
public static async Task<BotUserValue> FindOption(this DbSet<BotUserValue> repository, BotUser user,
string option) => await repository.FindOption(user.ChatId, user.UserId, option);
public static async Task<BotUserValue> FindOption(this DbSet<BotUserValue> repository, long chatId, int userId,
string option) => await repository.SingleOrDefaultAsync(e =>
e.BotUser.ChatId == chatId && e.BotUser.UserId == userId && e.Name == option);
#endregion
#region FindOrCreateOption
public static async Task<BotUserValue> FindOrCreateOption(this DbSet<BotUserValue> repository, long chatId,
string option) => await repository.FindOrCreateOption(chatId, 0, option);
public static async Task<BotUserValue> FindOrCreateOption(this DbSet<BotUserValue> repository, BotUser user,
string option) => await repository.FindOrCreateOption(user.ChatId, user.UserId, option);
public static async Task<BotUserValue> FindOrCreateOption(this DbSet<BotUserValue> repository, long chatId,
int userId, string option)
{
var opt = await repository.FindOption(chatId, userId, option);
if (opt == null)
{
opt = repository.Create();
}
return opt;
}
#endregion
#region SetOptionValue
public static async Task SetOptionValue<T>(this DbSet<BotUserValue> repository, long chatId, string option,
T val) => await repository.SetOptionValue(chatId, 0, option, val);
public static async Task SetOptionValue<T>(this DbSet<BotUserValue> repository, BotUser user, string option,
T val) => await repository.SetOptionValue(user.ChatId, user.UserId, option, val);
public static async Task SetOptionValue<T>(this DbSet<BotUserValue> repository, long chatId, int userId,
string option, T val)
{
var opt = await repository.FindOrCreateOption(chatId, userId, option);
opt.SetValue(val);
repository.Update(opt);
}
#endregion
#endregion
#endregion
}
}
-19
View File
@@ -1,19 +0,0 @@
using Telegram.Bot.Types;
namespace Kruzya.TelegramBot.UrlLimitations
{
public struct ChatMember
{
public long Chat;
public long User;
public static ChatMember From(long chatId, long userId)
{
return new ChatMember()
{
Chat = chatId,
User = userId
};
}
}
}
@@ -1,7 +0,0 @@
namespace Kruzya.TelegramBot.UrlLimitations
{
public class UrlLimitationsContext
{
}
}
@@ -0,0 +1,64 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BotFramework;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
namespace Kruzya.TelegramBot.UrlLimitations
{
public static class MessageExtension
{
public static async Task<bool> HasUnknownMention(this Message message, ITelegramBotClient bot)
{
foreach (var mention in message.Entities.Where(e =>
e.Type == MessageEntityType.Mention || e.Type == MessageEntityType.TextMention))
{
var userId = 0;
if (mention.Type == MessageEntityType.TextMention)
{
userId = mention.User.Id;
}
else
{
try
{
var chat = await bot.GetChatAsync(
new ChatId(message.Text.Substring(mention.Offset, mention.Length)));
if (chat != null)
{
if (chat.Type != ChatType.Private)
{
return true;
}
userId = Convert.ToInt32(chat.Id);
}
}
catch (Exception e)
{
return true;
}
}
var status = (await bot.GetChatMemberAsync(message.Chat, userId)).Status;
if ((new ChatMemberStatus[]
{
ChatMemberStatus.Administrator, ChatMemberStatus.Creator, ChatMemberStatus.Member,
ChatMemberStatus.Restricted
// i'm not sure about "Restricted"
// maybe leaved members with some restrictions also can be "Restricted".
}).Any(e => e == status) == false)
{
return true;
}
}
return false;
}
}
}
+11 -11
View File
@@ -5,6 +5,7 @@ using BotFramework;
using BotFramework.Attributes;
using BotFramework.Setup;
using Kruzya.TelegramBot.Core.Cache;
using Kruzya.TelegramBot.Core.Data;
using Kruzya.TelegramBot.Core.Extensions;
using Microsoft.Extensions.Logging;
using Telegram.Bot.Types;
@@ -15,35 +16,34 @@ namespace Kruzya.TelegramBot.UrlLimitations
public class MessageHandler : BotEventHandler
{
protected ILogger Logger;
protected MemoryCache<ChatMember, UInt16> ChatMembersCache;
protected readonly CoreContext dbCtx;
public MessageHandler(ILogger<MessageHandler> logger, MemoryCache<ChatMember, UInt16> chatMembersCache)
public MessageHandler(ILogger<MessageHandler> logger, CoreContext coreContext)
{
Logger = logger;
ChatMembersCache = chatMembersCache;
dbCtx = coreContext;
}
[TextMessage(InChat.Public)]
public void OnMessageReceived()
public async Task OnMessageReceived()
{
UInt16 messageCount;
var chatMember = ChatMember.From(Chat.Id, From.Id);
if (!ChatMembersCache.TryGetValue(chatMember, out messageCount))
var option = await dbCtx.UserValues.FindOption(Chat.Id, From.Id, "urlLimitations.messagesAfterJoin");
if (option == null)
{
return;
}
var messageCount = option.GetValue<UInt16>();
if (messageCount > 10)
{
ChatMembersCache.SetValue(chatMember, 0, 0);
dbCtx.UserValues.Remove(option);
return;
}
messageCount++;
ChatMembersCache.SetValue(chatMember, messageCount);
option.SetValue(messageCount + 1);
var message = RawUpdate.Message;
if (message.Entities.Count(e => e.Type == MessageEntityType.Url || e.Type == MessageEntityType.TextLink) >
0)
0 || await message.HasUnknownMention(Bot))
{
var targetChat = new ChatId(Chat.Id);
Task.WaitAll(new Task[] {
+1 -5
View File
@@ -1,5 +1,6 @@
using System;
using Kruzya.TelegramBot.Core;
using Kruzya.TelegramBot.Core.Data;
using Kruzya.TelegramBot.Core.Extensions;
using Microsoft.Extensions.DependencyInjection;
@@ -10,10 +11,5 @@ namespace Kruzya.TelegramBot.UrlLimitations
public UrlLimitations(Core.Core core) : base(core)
{
}
public override void ConfigureServices(IServiceCollection services)
{
services.AddMemoryCache<ChatMember, UInt16>();
}
}
}
+10 -5
View File
@@ -1,25 +1,30 @@
using System;
using System.Threading.Tasks;
using BotFramework;
using BotFramework.Attributes;
using BotFramework.Setup;
using Kruzya.TelegramBot.Core.Cache;
using Kruzya.TelegramBot.Core.Data;
using Kruzya.TelegramBot.Core.Extensions;
using Telegram.Bot.Types.Enums;
namespace Kruzya.TelegramBot.UrlLimitations
{
public class UserJoinHandler : BotEventHandler
{
protected MemoryCache<ChatMember, UInt16> ChatMembersCache;
protected readonly CoreContext dbCtx;
public UserJoinHandler(MemoryCache<ChatMember, UInt16> chatMembersCache)
public UserJoinHandler(CoreContext coreContext)
{
ChatMembersCache = chatMembersCache;
dbCtx = coreContext;
}
[Message(MessageType.ChatMembersAdded, InChat.Public)]
public void OnChatMembersAdded()
public async Task OnChatMembersAdded()
{
ChatMembersCache.SetValue(ChatMember.From(Chat.Id, From.Id), 0);
foreach (var member in RawUpdate.Message.NewChatMembers)
await dbCtx.UserValues.SetOptionValue<UInt16>(Chat.Id, member.Id, "urlLimitations.messagesAfterJoin",
0);
}
}
}