From e885613c585a0779c4f8d4c9008c2833f9f3ab1e Mon Sep 17 00:00:00 2001 From: West14 <30056636+West14@users.noreply.github.com> Date: Mon, 14 Feb 2022 14:39:55 +0200 Subject: [PATCH] [reputation] Add rating. --- Core/Data/IReputationEntity.cs | 8 +++ Core/Service/IReputation.cs | 5 +- Core/Service/UserService.cs | 51 ++++++++++++++++++- modules/Reputation/Data/UserReputation.cs | 8 +-- modules/Reputation/Handler/Reputation.cs | 21 ++++++-- .../Reputation/Service/ReputationService.cs | 13 ++++- 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 Core/Data/IReputationEntity.cs diff --git a/Core/Data/IReputationEntity.cs b/Core/Data/IReputationEntity.cs new file mode 100644 index 0000000..282d3b3 --- /dev/null +++ b/Core/Data/IReputationEntity.cs @@ -0,0 +1,8 @@ +namespace Kruzya.TelegramBot.Core.Data; + +public interface IReputationEntity +{ + public long UserId { get; set; } + public long ChatId { get; set; } + public double Value { get; set; } +} \ No newline at end of file diff --git a/Core/Service/IReputation.cs b/Core/Service/IReputation.cs index de51f00..ab1472d 100644 --- a/Core/Service/IReputation.cs +++ b/Core/Service/IReputation.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; +using Kruzya.TelegramBot.Core.Data; using Telegram.Bot.Types; namespace Kruzya.TelegramBot.Core.Service @@ -9,5 +11,6 @@ namespace Kruzya.TelegramBot.Core.Service public Task SetUserReputationAsync(Chat chat, User user, double value); public Task GetReputationDiffAsync(Chat chat, User sender, User receiver); public Task IncrementReputationAsync(Chat chat, User user, double diff); + public Task> GetChatRatingAsync(Chat chat, int limit = 10, int offset = 0); } } diff --git a/Core/Service/UserService.cs b/Core/Service/UserService.cs index 251d02e..bf9368d 100644 --- a/Core/Service/UserService.cs +++ b/Core/Service/UserService.cs @@ -3,7 +3,12 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; +using BotFramework.Abstractions; +using Kruzya.TelegramBot.Core.Cache; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Telegram.Bot; using Telegram.Bot.Types; namespace Kruzya.TelegramBot.Core.Service @@ -11,10 +16,17 @@ namespace Kruzya.TelegramBot.Core.Service public class UserService { private readonly List _superUsers; - private readonly Dictionary _statusMap; + private readonly ICacheStorage _userCache; + private readonly ITelegramBotClient _bot; + private readonly ILogger _logger; - public UserService(IConfiguration configuration) + + public UserService( + IConfiguration configuration, + IBotInstance bot, + ICacheStorage userCache, + ILogger logger) { _superUsers = configuration.GetSection("SuperUsers") .GetChildren() @@ -24,6 +36,41 @@ namespace Kruzya.TelegramBot.Core.Service _statusMap = configuration.GetSection("CustomMemberStatus") .GetChildren() .ToDictionary(x => Convert.ToInt64(x.Key), x => x.Value); + + _userCache = userCache; + _bot = bot.BotClient; + _logger = logger; + } + + public async Task GetUser(long userId, long chatId, bool bypassCache = false) + { + if (bypassCache || !_userCache.TryGetValue(userId, out var user)) + { + if (bypassCache) + { + _logger.LogDebug("Bypassing cache."); + } + else + { + _logger.LogDebug("User {UserId} is not found in cache. Fetching from Telegram API.", userId); + } + + user = await GetUserByChat(chatId, userId); + CacheUser(user); + } + + return user; + } + + private void CacheUser(User user) + { + // TODO: config entry for TTL + _userCache.SetValue(user.Id, user, Convert.ToInt32(TimeSpan.FromHours(1).TotalSeconds)); + } + + private async Task GetUserByChat(long chatId, long userId) + { + return (await _bot.GetChatMemberAsync(chatId, userId)).User; } public bool IsUserSuper(User user) diff --git a/modules/Reputation/Data/UserReputation.cs b/modules/Reputation/Data/UserReputation.cs index 8326a9e..3b06cf8 100644 --- a/modules/Reputation/Data/UserReputation.cs +++ b/modules/Reputation/Data/UserReputation.cs @@ -1,10 +1,10 @@ -namespace West.TelegramBot.Reputation.Data; +using Kruzya.TelegramBot.Core.Data; -public class UserReputation +namespace West.TelegramBot.Reputation.Data; + +public class UserReputation : IReputationEntity { public long UserId { get; set; } - public long ChatId { get; set; } - public double Value { get; set; } } \ No newline at end of file diff --git a/modules/Reputation/Handler/Reputation.cs b/modules/Reputation/Handler/Reputation.cs index 71451a0..590076d 100644 --- a/modules/Reputation/Handler/Reputation.cs +++ b/modules/Reputation/Handler/Reputation.cs @@ -17,7 +17,7 @@ public class Reputation : CommonHandler private readonly UserService _userService; private readonly ILogger _logger; private readonly IReputation _reputationService; - + private static readonly List RepUpChars = new() { "+", @@ -43,8 +43,7 @@ public class Reputation : CommonHandler CoreContext db, UserService userService, IReputation reputationService, - ILogger logger - ) : base(db) + ILogger logger) : base(db) { _reputationService = reputationService; _userService = userService; @@ -129,6 +128,22 @@ public class Reputation : CommonHandler ); } + [Command(InChat.Public, "top", CommandParseMode.Both)] + public async Task HandleTop() + { + var msg = new HtmlString(); + msg.TextBr("Топ репутации чата: "); + var i = 1; + foreach (var rep in await _reputationService.GetChatRatingAsync(Chat)) + { + var user = await _userService.GetUser(rep.UserId, rep.ChatId); + msg.Text($"{i}. ").UserMention(user).Text($" ({rep.Value})").Br(); + i++; + } + + await Bot.SendHtmlStringAsync(Chat, msg); + } + private async Task GetUserReputation(User user) { return await _reputationService.GetUserReputationAsync(Chat, user); diff --git a/modules/Reputation/Service/ReputationService.cs b/modules/Reputation/Service/ReputationService.cs index 00bc57b..07e0a16 100644 --- a/modules/Reputation/Service/ReputationService.cs +++ b/modules/Reputation/Service/ReputationService.cs @@ -1,4 +1,5 @@ -using Kruzya.TelegramBot.Core.Extensions; +using Kruzya.TelegramBot.Core.Data; +using Kruzya.TelegramBot.Core.Extensions; using Kruzya.TelegramBot.Core.Service; using Microsoft.EntityFrameworkCore; using Telegram.Bot.Types; @@ -54,6 +55,16 @@ public class ReputationService : IReputation return Math.Round(senderValue == 0 ? 1 : Math.Sqrt(senderValue), 2); } + public async Task> GetChatRatingAsync(Chat chat, int limit = 10, int offset = 0) + { + return await _reputationContext.UserReputation + .Where(r => r.ChatId == chat.Id && r.Value != 0D) + .OrderByDescending(r => r.Value) + .Skip(offset) + .Take(limit) + .ToListAsync(); + } + private async Task FindUserReputation(Chat chat, User user) { return await _reputationContext.UserReputation.SingleOrDefaultAsync(