Code cleanup

This commit is contained in:
2022-01-22 17:13:38 +03:00
parent 401f9fb529
commit ff63d6dfaa
13 changed files with 232 additions and 138 deletions
+7 -5
View File
@@ -1,4 +1,6 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -107,7 +109,7 @@ namespace Kruzya.TelegramBot.Core
/// </summary> /// </summary>
/// <param name="path">The full path to assembly file</param> /// <param name="path">The full path to assembly file</param>
/// <returns><see cref="IEnumerable{T}"/> if success, null otherwise.</returns> /// <returns><see cref="IEnumerable{T}"/> if success, null otherwise.</returns>
private IEnumerable<Type> LoadAssembly(string path) private IEnumerable<Type>? LoadAssembly(string path)
{ {
Assembly assembly; Assembly assembly;
try try
@@ -150,7 +152,7 @@ namespace Kruzya.TelegramBot.Core
var module = _modules.FirstOrDefault(module => module.GetType() == moduleType); var module = _modules.FirstOrDefault(module => module.GetType() == moduleType);
if (module == null) if (module == null)
{ {
module = (Module) Activator.CreateInstance(moduleType, this); module = (Module) Activator.CreateInstance(moduleType, this)!;
Console.WriteLine($"Started module {module.GetType().Name}"); Console.WriteLine($"Started module {module.GetType().Name}");
_modules.Add(module); _modules.Add(module);
} }
@@ -169,12 +171,12 @@ namespace Kruzya.TelegramBot.Core
var possiblePaths = new List<string>(); var possiblePaths = new List<string>();
if (args.RequestingAssembly != null) if (args.RequestingAssembly != null)
{ {
var modulePath = Path.GetDirectoryName(args.RequestingAssembly.Location); var modulePath = Path.GetDirectoryName(args.RequestingAssembly.Location)!;
possiblePaths.Add(modulePath); possiblePaths.Add(modulePath);
possiblePaths.Add(args.RequestingAssembly.Location.Replace(".dll", "")); possiblePaths.Add(args.RequestingAssembly.Location.Replace(".dll", ""));
} }
possiblePaths.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); possiblePaths.Add(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!);
possiblePaths.Add(Environment.CurrentDirectory); possiblePaths.Add(Environment.CurrentDirectory);
foreach (var basePath in possiblePaths) foreach (var basePath in possiblePaths)
+2 -1
View File
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
using System.Xml.Serialization; using System.Xml.Serialization;
namespace Kruzya.TelegramBot.Core.Data namespace Kruzya.TelegramBot.Core.Data
@@ -35,7 +36,7 @@ namespace Kruzya.TelegramBot.Core.Data
public void SetValue<T>(T value) public void SetValue<T>(T value)
{ {
Value = JsonSerializer.SerializeToUtf8Bytes(value, new JsonSerializerOptions { WriteIndented = false, Value = JsonSerializer.SerializeToUtf8Bytes(value, new JsonSerializerOptions { WriteIndented = false,
IgnoreNullValues = true }); DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
ValueType = value.GetType().FullName; ValueType = value.GetType().FullName;
} }
} }
+40
View File
@@ -0,0 +1,40 @@
using System;
using Microsoft.EntityFrameworkCore;
namespace Kruzya.TelegramBot.Core.Extensions;
public static class DbContextExtension
{
/// <summary>
/// Marks the entity as created.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as created.</param>
[Obsolete("DbContextExtension.MarkAsCreated is obsolete, use DbSet<T>.Add instead")]
public static void MarkAsCreated(this DbContext dbContext, object entity) =>
dbContext.Entry(entity).State = EntityState.Added;
/// <summary>
/// Marks the entity as deleted.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as deleted.</param>
[Obsolete("DbContextExtension.MarkAsDeleted is obsolete, use DbSet<T>.Remove instead")]
public static void MarkAsDeleted(this DbContext dbContext, object entity) =>
dbContext.Entry(entity).State = EntityState.Deleted;
/// <summary>
/// Marks the entity as modified.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as modified.</param>
[Obsolete("DbContextExtension.MarkAsModified is obsolete, use DbContext.Update instead")]
public static void MarkAsModified(this DbContext dbContext, object entity)
{
var entry = dbContext.Entry(entity);
if (entry.State == EntityState.Added)
return;
entry.State = EntityState.Modified;
}
}
@@ -0,0 +1,87 @@
using System.Threading.Tasks;
using Kruzya.TelegramBot.Core.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Kruzya.TelegramBot.Core.Extensions
{
public static partial class RepositoryExtension
{
#region BotUser
public static async Task<BotUser> FindOrCreate(this DbSet<BotUser> repository, long chatId, long userId)
{
var user = await repository.SingleOrDefaultAsync(e => e.ChatId == chatId && e.UserId == userId);
if (user == null)
{
user = repository.Create();
user.ChatId = chatId;
user.UserId = userId;
}
return user;
}
#endregion
#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, long 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,
long userId, string option)
{
var opt = await repository.FindOption(chatId, userId, option);
if (opt == null)
{
opt = repository.Create();
opt.Name = option;
opt.BotUser = await repository.GetService<CoreContext>().Users.FindOrCreate(chatId, userId);
}
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, long userId,
string option, T val)
{
var opt = await repository.FindOrCreateOption(chatId, userId, option);
opt.SetValue(val);
repository.Update(opt);
}
#endregion
#endregion
}
}
+1 -120
View File
@@ -5,44 +5,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Kruzya.TelegramBot.Core.Extensions namespace Kruzya.TelegramBot.Core.Extensions
{ {
public static class RepositoryExtension public static partial class RepositoryExtension
{ {
#region DbContext
/// <summary>
/// Marks the entity as created.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as created.</param>
public static void MarkAsCreated(this DbContext dbContext, object entity) =>
dbContext.Entry(entity).State = EntityState.Added;
/// <summary>
/// Marks the entity as deleted.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as deleted.</param>
public static void MarkAsDeleted(this DbContext dbContext, object entity) =>
dbContext.Entry(entity).State = EntityState.Deleted;
/// <summary>
/// Marks the entity as modified.
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity">Entity for marking as modified.</param>
public static void MarkAsModified(this DbContext dbContext, object entity)
{
var entry = dbContext.Entry(entity);
if (entry.State == EntityState.Added)
return;
entry.State = EntityState.Modified;
}
#endregion
#region Repository
public static TEntity Create<TEntity>(this DbSet<TEntity> repository) where TEntity : class, new() public static TEntity Create<TEntity>(this DbSet<TEntity> repository) where TEntity : class, new()
{ {
var entity = new TEntity(); var entity = new TEntity();
@@ -50,88 +14,5 @@ namespace Kruzya.TelegramBot.Core.Extensions
return entity; return entity;
} }
#endregion
#region Core-context repository extensions
#region BotUser
public static async Task<BotUser> FindOrCreate(this DbSet<BotUser> repository, long chatId, long userId)
{
var user = await repository.SingleOrDefaultAsync(e => e.ChatId == chatId && e.UserId == userId);
if (user == null)
{
user = repository.Create();
user.ChatId = chatId;
user.UserId = userId;
}
return user;
}
#endregion
#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, long 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,
long userId, string option)
{
var opt = await repository.FindOption(chatId, userId, option);
if (opt == null)
{
opt = repository.Create();
opt.Name = option;
opt.BotUser = await repository.GetService<CoreContext>().Users.FindOrCreate(chatId, userId);
}
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, long userId,
string option, T val)
{
var opt = await repository.FindOrCreateOption(chatId, userId, option);
opt.SetValue(val);
repository.Update(opt);
}
#endregion
#endregion
#endregion
} }
} }
+83
View File
@@ -0,0 +1,83 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
namespace Kruzya.TelegramBot.Core.Service;
internal class EntityFormatter
{
private static readonly Dictionary<MessageEntityType, string> HtmlMap = new()
{
{ MessageEntityType.Bold, "<b>{0}</b>" },
{ MessageEntityType.Code, "<code>{0}</code>" },
{ MessageEntityType.Italic, "<i>{0}</i>" },
{ MessageEntityType.TextMention, "<a href=\"tg://user?id={1}\">{0}</a>" },
{ MessageEntityType.Pre, "<pre>{0}</pre>" },
{ MessageEntityType.Underline, "<u>{0}</u>" },
{ MessageEntityType.TextLink, "<a href=\"{1}\">{0}</a>" }
};
private static readonly Dictionary<MessageEntityType, string> MarkdownMap = new()
{
{ MessageEntityType.Bold, "*{0}*" },
{ MessageEntityType.Code, "```{0}```" },
{ MessageEntityType.Italic, "_{0}_" },
{ MessageEntityType.TextMention, "[{0}](tg://user?id={1})" },
{ MessageEntityType.Pre, "```{0}```" },
{ MessageEntityType.Underline, "__{0}__" },
{ MessageEntityType.TextLink, "[{0}]({1})" }
};
/// <summary>
/// Performs the formatting a text representation of message from <see cref="Message"/> entity with
/// </summary>
/// <param name="msg"></param>
/// <param name="parseMode"></param>
/// <returns></returns>
public string? FormatMessage(Message msg, ParseMode parseMode = ParseMode.Html)
{
var text = "";
var entities = msg.Entities;
if (entities != null)
{
// Suppress the warning about possibility using empty ref (CS8602).
text = msg.Text!;
// TODO: Currently, this algo don't support inherited entities. This need thinking.
foreach (var entity in entities.Reverse())
{
var entityText = text.Substring(entity.Offset, entity.Length);
text = text.Replace(entityText, FormatEntity(entity, entityText, parseMode));
}
}
return text;
}
public string FormatEntity(MessageEntity entity, string text, ParseMode parseMode)
{
var dict = parseMode switch
{
ParseMode.Html => HtmlMap,
ParseMode.Markdown => MarkdownMap,
ParseMode.MarkdownV2 => MarkdownMap,
_ => throw new Exception("Unsupported parse mode")
};
var arg = entity.Type switch
{
MessageEntityType.TextMention => entity.User!.Id.ToString(),
MessageEntityType.TextLink => entity.Url!,
_ => ""
};
return dict[entity.Type].Replace("{0}", text)
.Replace("{1}", arg);
}
}
+2 -2
View File
@@ -114,7 +114,7 @@ namespace West.TelegramBot.ChatManagement.Handler
} }
receiverRepOption.SetValue(receiverRepCount); receiverRepOption.SetValue(receiverRepCount);
Db.MarkAsModified(receiverRepOption); Db.Update(receiverRepOption);
await Reply($"{From.ToHtml()}<code>({await GetUserReputation(From)}) " + await Reply($"{From.ToHtml()}<code>({await GetUserReputation(From)}) " +
$"{action} репутацию </code>{receiver.ToHtml()}<code>({Math.Round(receiverRepCount, 2)})</code>"); $"{action} репутацию </code>{receiver.ToHtml()}<code>({Math.Round(receiverRepCount, 2)})</code>");
@@ -138,7 +138,7 @@ namespace West.TelegramBot.ChatManagement.Handler
reputation = Math.Round(reputation, 2); reputation = Math.Round(reputation, 2);
var opt = await GetReputationOption(RepliedUser); var opt = await GetReputationOption(RepliedUser);
opt.SetValue(reputation); opt.SetValue(reputation);
Db.MarkAsModified(opt); Db.Update(opt);
await Reply( await Reply(
new HtmlString() new HtmlString()
+2 -2
View File
@@ -19,7 +19,7 @@ namespace West.TelegramBot.ChatManagement.Handler
var opt = await Db.UserValues.FindOrCreateOption(Chat.Id, "rulesMsgId"); var opt = await Db.UserValues.FindOrCreateOption(Chat.Id, "rulesMsgId");
opt.SetValue(replyToMessage.MessageId); opt.SetValue(replyToMessage.MessageId);
Db.MarkAsModified(opt); Db.Update(opt);
} }
[Command(InChat.Public, "rules", CommandParseMode.Both)] [Command(InChat.Public, "rules", CommandParseMode.Both)]
@@ -37,7 +37,7 @@ namespace West.TelegramBot.ChatManagement.Handler
} }
catch (ApiRequestException) catch (ApiRequestException)
{ {
Db.MarkAsDeleted(opt); Db.UserValues.Remove(opt);
throw; throw;
} }
} }
+2 -2
View File
@@ -24,7 +24,7 @@ namespace West.TelegramBot.ChatManagement.Handler
var warnOption = await GetWarnOption(warnUser); var warnOption = await GetWarnOption(warnUser);
var warnCount = warnOption!.GetValue<int>() + 1; var warnCount = warnOption!.GetValue<int>() + 1;
warnOption.SetValue(warnCount); warnOption.SetValue(warnCount);
Db.MarkAsModified(warnOption); Db.Update(warnOption);
await Bot.SendTextMessageAsync(Chat.Id, $"{warnUser.ToHtml()}<code>, Вам выдано предупреждение! " + await Bot.SendTextMessageAsync(Chat.Id, $"{warnUser.ToHtml()}<code>, Вам выдано предупреждение! " +
$"Текущее кол-во: {warnCount}/3</code>", $"Текущее кол-во: {warnCount}/3</code>",
@@ -49,7 +49,7 @@ namespace West.TelegramBot.ChatManagement.Handler
warnCount = Math.Max(warnCount - 1, 0); warnCount = Math.Max(warnCount - 1, 0);
warnOption.SetValue(warnCount); warnOption.SetValue(warnCount);
Db.MarkAsModified(warnOption); Db.Update(warnOption);
await Bot.SendTextMessageAsync(Chat.Id, await Bot.SendTextMessageAsync(Chat.Id,
$"{RepliedUser.ToHtml()}<code>, с Вас снято предупреждение! " + $"{RepliedUser.ToHtml()}<code>, с Вас снято предупреждение! " +
@@ -47,7 +47,7 @@ namespace West.Entertainment.Handler.Fun
var animationFileOption = await GetAnimationFileOption(); var animationFileOption = await GetAnimationFileOption();
animationFileOption.SetValue(animation.FileId); animationFileOption.SetValue(animation.FileId);
_db.MarkAsModified(animationFileOption); _db.Update(animationFileOption);
} }
// ReSharper disable once MemberCanBeProtected.Global // ReSharper disable once MemberCanBeProtected.Global
@@ -77,7 +77,7 @@ namespace West.Entertainment.Handler.Fun
replyToMessageId: GetMessageIdToReply() ?? Message?.MessageId); replyToMessageId: GetMessageIdToReply() ?? Message?.MessageId);
nextUseOption.SetValue(DateTime.Now + Cooldown); nextUseOption.SetValue(DateTime.Now + Cooldown);
_db.MarkAsModified(nextUseOption); _db.Update(nextUseOption);
return true; return true;
} }
+2 -2
View File
@@ -290,7 +290,7 @@ namespace Kruzya.TelegramBot.RichSiteSummary.Handler
.Where(subscriber => subscriber.Feed == feed && subscriber.SubscriberId == chat.Id) .Where(subscriber => subscriber.Feed == feed && subscriber.SubscriberId == chat.Id)
.Select(subscriber => subscriber.SubscriptionId).FirstAsync(); .Select(subscriber => subscriber.SubscriptionId).FirstAsync();
_dbContext.MarkAsDeleted(_dbContext.Find<Subscriber>(subId)); _dbContext.Subscriptions.Remove(_dbContext.Find<Subscriber>(subId));
} }
else else
{ {
@@ -298,7 +298,7 @@ namespace Kruzya.TelegramBot.RichSiteSummary.Handler
subscription.Feed = feed; subscription.Feed = feed;
subscription.SubscriberId = chat.Id; subscription.SubscriberId = chat.Id;
_dbContext.MarkAsCreated(subscription); _dbContext.Subscriptions.Add(subscription);
} }
await _dbContext.SaveChangesAsync(); await _dbContext.SaveChangesAsync();
+1 -1
View File
@@ -109,7 +109,7 @@ namespace Kruzya.TelegramBot.RichSiteSummary.Service
await ProcessFeed(feed, dbContext); await ProcessFeed(feed, dbContext);
feed.UpdatedAt = DateTime.Now; feed.UpdatedAt = DateTime.Now;
dbContext.MarkAsModified(feed); dbContext.Update(feed);
} }
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
+1 -1
View File
@@ -56,7 +56,7 @@ namespace UserGroupTag
tagDictionary[groupName] = memberList; tagDictionary[groupName] = memberList;
userGroupOption.SetValue(tagDictionary); userGroupOption.SetValue(tagDictionary);
_db.MarkAsModified(userGroupOption); _db.Update(userGroupOption);
_userCache.SetValue(repliedMessage.From.Id, repliedMessage.From, Int32.MaxValue); _userCache.SetValue(repliedMessage.From.Id, repliedMessage.From, Int32.MaxValue);
await Bot.SendTextMessageAsync(chatId, $"{from.ToHtml()} добавлен в группу {groupName}", await Bot.SendTextMessageAsync(chatId, $"{from.ToHtml()} добавлен в группу {groupName}",