#nullable enable using BotFramework.Attributes; using BotFramework.Enums; using BotFramework.Utils; using Kruzya.TelegramBot.Core.Data; using Kruzya.TelegramBot.Core.Extensions; using Kruzya.TelegramBot.Core.Handler; using Kruzya.TelegramBot.Core.Service; using Microsoft.Extensions.Logging; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; namespace West.TelegramBot.Reputation.Handler; public class Reputation : CommonHandler { private readonly UserService _userService; private readonly ILogger _logger; private readonly IReputation _reputationService; private readonly IAntiFlood _antiFlood; private static readonly List RepUpChars = new() { "+", "👍", "👍🏼", "👍🏽", "👍🏾", "👍🏿", "👍🏻" }; private static readonly List RepDownChars = new() { "-", "👎", "👎🏼", "👎🏽", "👎🏾", "👎🏿", "👎🏻" }; public Reputation( CoreContext db, UserService userService, IReputation reputationService, IAntiFlood antiFlood, ILogger logger) : base(db) { _reputationService = reputationService; _userService = userService; _antiFlood = antiFlood; _logger = logger; } [Message(InChat.Public, MessageFlag.HasText | MessageFlag.HasSticker)] public async Task HandleReputation() { var text = Message?.Text; if (string.IsNullOrEmpty(text)) { text = Message?.Sticker?.Emoji; } if (text == null) { return; } var receiver = RepliedUser; var canChangeRep = receiver is { IsBot: false } && !From.IsBot && receiver.Id != From.Id; if (canChangeRep && (RepUpChars.Contains(text) || RepDownChars.Contains(text))) { if (!_userService.IsUserSuper(From) && !await Bot.IsUserAdminAsync(Chat, From)) { if (_antiFlood.IsUserFlooding(Chat, From)) { return; } _antiFlood.RecordAction(Chat, From); if (_antiFlood.IsUserFlooding(Chat, From)) { await Reply(new HtmlString() .UserMention(From).Code(": пользователь отправлен в игнор.") .ToString()); return; } } var senderRepCount = await GetUserReputation(From); if (senderRepCount < 0) { await Reply(new HtmlString() .Code("Ты не можешь голосовать с отрицательной репутацией.") .ToString() ); return; } var diff = await _reputationService.GetReputationDiffAsync(Chat, From, receiver); _logger.LogDebug("Calculated diff: {Diff}", diff); string action; if (RepUpChars.Contains(text)) { action = "увеличил"; } else { diff *= -1; action = "уменьшил"; } await _reputationService.IncrementReputationAsync(Chat, receiver, diff); var receiverRepCount = await GetUserReputation(receiver!); _logger.LogDebug("Updated value: {Value}", receiverRepCount); await Reply($"{From.ToHtml()}({await GetUserReputation(From)}) " + $"{action} репутацию {receiver.ToHtml()}({Math.Round(receiverRepCount, 2)})"); } } [ParametrizedCommand(InChat.Public, "setrep", CommandParseMode.Both)] public async Task HandleSetRep(double reputation) { if (!CanModifyUserReputation(RepliedUser)) { return; } await SendReputationModifyResponse( await _reputationService.SetUserReputationAsync(Chat, RepliedUser, reputation) ); } [ParametrizedCommand(InChat.Public, "addrep", CommandParseMode.Both)] public async Task HandleAddRep(double reputation) { if (!CanModifyUserReputation(RepliedUser)) { return; } await SendReputationModifyResponse( await _reputationService.IncrementReputationAsync(Chat, RepliedUser, reputation) ); } [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)) { // TODO: there are should be more correct fix, but I want to fix this now, West, 18:04, 07.05.2022 User user; try { user = await _userService.GetUser(rep.UserId, rep.ChatId); } catch { continue; } msg.Text($"{i}. ") .Text($"{user.FirstName} {user.LastName}".Trim().HtmlEncode()) .Text($" ({rep.Value})").Br(); i++; } await Bot.SendTextMessageAsync(Chat!, msg.ToString(), parseMode: ParseMode.Html, disableNotification: true); } private async Task SendReputationModifyResponse(double reputation) { await Reply( new HtmlString() .Code("Пользователю ") .UserMention(RepliedUser) .Code($" установлена репутация: {reputation}") .ToString() ); } private bool CanModifyUserReputation(User? user) { if (!_userService.IsUserSuper(From)) { _logger.LogWarning("{User} attempted to modify reputation in {Chat}", From.ToLog(), Chat.ToLog() ); return false; } return user is {IsBot: false}; } private async Task GetUserReputation(User user) { return await _reputationService.GetUserReputationAsync(Chat, user); } }