diff --git a/Docs/BotFramework.puml b/Docs/BotFramework.puml new file mode 100644 index 0000000..5a74951 --- /dev/null +++ b/Docs/BotFramework.puml @@ -0,0 +1,26 @@ +@startuml Modules + +package Framework { + package BF.Abstractions + package BF.Analyzer + package BF.Core +} + +package Plugins { + package BF.Providers.Telegram + package BF.Providers.Discord +} + +BF.Analyzer --> BF.Abstractions +BF.Core --> BF.Abstractions +BF.Core --> BF.Analyzer + +BF.Providers.Telegram --> BF.Abstractions +BF.Providers.Discord --> BF.Abstractions + +package Bot + +Bot --> BF.Core +Bot --> BF.Providers.Telegram + +@enduml \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDialogContext.cs b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDialogContext.cs index 80adc3e..2e0458a 100644 --- a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDialogContext.cs +++ b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDialogContext.cs @@ -2,7 +2,5 @@ public interface IDialogContext { - ISenderInfo SenderInfo { get; } - int State { get; set; } } \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDiscordSenderInfo.cs b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDiscordSenderInfo.cs new file mode 100644 index 0000000..a9f3cd0 --- /dev/null +++ b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/IDiscordSenderInfo.cs @@ -0,0 +1,6 @@ +namespace Kysect.BotFramework.Abstractions.Contexts; + +public interface IDiscordSenderInfo : ISenderInfo +{ + ulong GuildId { get; } +} \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ISenderInfo.cs b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ISenderInfo.cs index 072c621..8f54543 100644 --- a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ISenderInfo.cs +++ b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ISenderInfo.cs @@ -1,4 +1,6 @@ -namespace Kysect.BotFramework.Abstractions.Contexts; +using Kysect.BotFramework.Abstractions.Visitors; + +namespace Kysect.BotFramework.Abstractions.Contexts; public interface ISenderInfo { @@ -6,4 +8,6 @@ public interface ISenderInfo long UserSenderId { get; } string UserSenderUsername { get; } bool IsAdmin { get; } + + TContext Accept(ISenderInfoVisitor visitor); } \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ITelegramSenderInfo.cs b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ITelegramSenderInfo.cs new file mode 100644 index 0000000..b76b1f2 --- /dev/null +++ b/Kysect.BotFramework.Abstractions/Abstractions/Contexts/ITelegramSenderInfo.cs @@ -0,0 +1,5 @@ +namespace Kysect.BotFramework.Abstractions.Contexts; + +public interface ITelegramSenderInfo : ISenderInfo +{ +} \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Services/IDialogContextProvider.cs b/Kysect.BotFramework.Abstractions/Abstractions/Services/IDialogContextProvider.cs index 9b34a38..1ac01bb 100644 --- a/Kysect.BotFramework.Abstractions/Abstractions/Services/IDialogContextProvider.cs +++ b/Kysect.BotFramework.Abstractions/Abstractions/Services/IDialogContextProvider.cs @@ -4,5 +4,5 @@ namespace Kysect.BotFramework.Abstactions.Services; public interface IDialogContextProvider { - public IDialogContext GetDialogContext(ISenderInfo senderInfo); + IDialogContext GetDialogContext(ISenderInfo senderInfo); } \ No newline at end of file diff --git a/Kysect.BotFramework.Abstractions/Abstractions/Visitors/ISenderInfoVisitor.cs b/Kysect.BotFramework.Abstractions/Abstractions/Visitors/ISenderInfoVisitor.cs new file mode 100644 index 0000000..ee2d887 --- /dev/null +++ b/Kysect.BotFramework.Abstractions/Abstractions/Visitors/ISenderInfoVisitor.cs @@ -0,0 +1,10 @@ +using Kysect.BotFramework.Abstractions.Contexts; + +namespace Kysect.BotFramework.Abstractions.Visitors; + +public interface ISenderInfoVisitor +{ + TContext Visit(IDiscordSenderInfo senderInfo); + + TContext Visit(ITelegramSenderInfo senderInfo); +} \ No newline at end of file diff --git a/Kysect.BotFramework/ApiProviders/Discord/DiscordSenderInfo.cs b/Kysect.BotFramework/ApiProviders/Discord/DiscordSenderInfo.cs index 3acccd8..22a398b 100644 --- a/Kysect.BotFramework/ApiProviders/Discord/DiscordSenderInfo.cs +++ b/Kysect.BotFramework/ApiProviders/Discord/DiscordSenderInfo.cs @@ -1,39 +1,35 @@ -using Kysect.BotFramework.Abstractions.Contexts; -using Kysect.BotFramework.Core.Contexts; -using Kysect.BotFramework.Data; -using Kysect.BotFramework.Data.Entities; +using System; +using Kysect.BotFramework.Abstractions.Contexts; +using Kysect.BotFramework.Abstractions.Visitors; -namespace Kysect.BotFramework.ApiProviders.Discord +namespace Kysect.BotFramework.ApiProviders.Discord; + +public class DiscordSenderInfo : IDiscordSenderInfo { - public class DiscordSenderInfo : SenderInfo + public DiscordSenderInfo(long chatId, long userSenderId, string userSenderUsername, bool isAdmin, ulong guildId) + { + GuildId = guildId; + ChatId = chatId; + UserSenderId = userSenderId; + UserSenderUsername = userSenderUsername; + IsAdmin = isAdmin; + } + + public long ChatId { get; } + + public long UserSenderId { get; } + + public string UserSenderUsername { get; } + + public bool IsAdmin { get; } + + public ulong GuildId { get; } + + public TContext Accept(ISenderInfoVisitor visitor) { - public ulong GuildId { get; } - - internal override ContextType ContextType => ContextType.Discord; - - public DiscordSenderInfo(long chatId, long userSenderId, string userSenderUsername, bool isAdmin, ulong guildId) - : base(chatId, userSenderId, userSenderUsername, isAdmin) - { - GuildId = guildId; - } - - private DiscordSenderInfoEntity ToEntity() - { - var entity = new DiscordSenderInfoEntity - { - GuildId = GuildId, - ChatId = ChatId, - UserSenderId = UserSenderId - }; - return entity; - } - - internal override IDialogContext GetOrCreateDialogContext(BotFrameworkDbContext dbContext) - { - var contextSenderInfo = DiscordSenderInfoEntity.GetOrCreate(this, dbContext); - var contextModel = DialogContextEntity.GetOrCreate(contextSenderInfo, ContextType, dbContext); - - return new DialogContext(contextModel.State, contextModel.SenderInfoId, this, ContextType, dbContext); - } + if (visitor is null) + throw new ArgumentNullException(nameof(visitor)); + + return visitor.Visit(this); } } \ No newline at end of file diff --git a/Kysect.BotFramework/ApiProviders/Telegram/TelegramSenderInfo.cs b/Kysect.BotFramework/ApiProviders/Telegram/TelegramSenderInfo.cs index b6ad066..59f7c9e 100644 --- a/Kysect.BotFramework/ApiProviders/Telegram/TelegramSenderInfo.cs +++ b/Kysect.BotFramework/ApiProviders/Telegram/TelegramSenderInfo.cs @@ -1,34 +1,32 @@ using Kysect.BotFramework.Abstractions.Contexts; -using Kysect.BotFramework.Core.Contexts; -using Kysect.BotFramework.Data; -using Kysect.BotFramework.Data.Entities; +using Kysect.BotFramework.Abstractions.Visitors; +using System; -namespace Kysect.BotFramework.ApiProviders.Telegram +namespace Kysect.BotFramework.ApiProviders.Telegram; + +public class TelegramSenderInfo : ITelegramSenderInfo { - public class TelegramSenderInfo : SenderInfo + public TelegramSenderInfo(long chatId, long userSenderId, string userSenderUsername, bool isAdmin) { - internal override ContextType ContextType => ContextType.Telegram; + ChatId = chatId; + UserSenderId = userSenderId; + UserSenderUsername = userSenderUsername; + IsAdmin = isAdmin; + } - public TelegramSenderInfo(long chatId, long userSenderId, string userSenderUsername, bool isAdmin) - : base(chatId, userSenderId, userSenderUsername, isAdmin) - { } - - private TelegramSenderInfoEntity ToEntity() - { - var entity = new TelegramSenderInfoEntity() - { - ChatId = ChatId, - UserSenderId = UserSenderId - }; - return entity; - } + public long ChatId { get; } + + public long UserSenderId { get; } - internal override IDialogContext GetOrCreateDialogContext(BotFrameworkDbContext dbContext) - { - var contextSenderInfo = TelegramSenderInfoEntity.GetOrCreate(this, dbContext); - var contextModel = DialogContextEntity.GetOrCreate(contextSenderInfo, ContextType, dbContext); - - return new DialogContext(contextModel.State, contextModel.SenderInfoId, this, ContextType, dbContext); - } + public string UserSenderUsername { get; } + + public bool IsAdmin { get; } + + public TContext Accept(ISenderInfoVisitor visitor) + { + if (visitor is null) + throw new ArgumentNullException(nameof(visitor)); + + return visitor.Visit(this); } } \ No newline at end of file diff --git a/Kysect.BotFramework/Core/BotManagerBuilder.cs b/Kysect.BotFramework/Core/BotManagerBuilder.cs index a1b4cc9..6cfcf95 100644 --- a/Kysect.BotFramework/Core/BotManagerBuilder.cs +++ b/Kysect.BotFramework/Core/BotManagerBuilder.cs @@ -4,6 +4,8 @@ using FluentScanning; using Kysect.BotFramework.Abstactions.Services; using Kysect.BotFramework.Abstractions.Commands; +using Kysect.BotFramework.Abstractions.Contexts; +using Kysect.BotFramework.Abstractions.Visitors; using Kysect.BotFramework.ApiProviders; using Kysect.BotFramework.Attributes; using Kysect.BotFramework.Core.Contexts.Providers; @@ -11,6 +13,7 @@ using Kysect.BotFramework.Core.Tools; using Kysect.BotFramework.Core.Tools.Extensions; using Kysect.BotFramework.Core.Tools.Loggers; +using Kysect.BotFramework.Core.Visitors; using Kysect.BotFramework.Data; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; @@ -95,7 +98,8 @@ public BotManagerBuilder SetDatabaseOptions(Action opti { ServiceCollection .AddDbContext(optionsAction) - .AddScoped(); + .AddScoped() + .AddScoped, DialogSenderInfoVisitor>(); return this; } diff --git a/Kysect.BotFramework/Core/Contexts/DialogContext.cs b/Kysect.BotFramework/Core/Contexts/DialogContext.cs index b615bb4..b5f83ed 100644 --- a/Kysect.BotFramework/Core/Contexts/DialogContext.cs +++ b/Kysect.BotFramework/Core/Contexts/DialogContext.cs @@ -3,53 +3,48 @@ using Kysect.BotFramework.Data; using Kysect.BotFramework.Data.Entities; -namespace Kysect.BotFramework.Core.Contexts +namespace Kysect.BotFramework.Core.Contexts; + +public class DialogContext : IDialogContext { - public class DialogContext : IDialogContext - { - private readonly BotFrameworkDbContext _dbContext; + private readonly BotFrameworkDbContext _dbContext; - private readonly long _senderInfoId; - private readonly ContextType _contextType; - - private int _state; + private readonly long _senderInfoId; + private readonly ContextType _contextType; - public ISenderInfo SenderInfo { get; } + private int _state; - public int State + public int State + { + get => _state; + set { - get => _state; - set - { - _state = value; - SaveChanges(); - } + _state = value; + SaveChanges(); } + } - public DialogContext( - int state, - long senderInfoId, - SenderInfo senderInfo, - ContextType contextType, - BotFrameworkDbContext dbContext) - { - SenderInfo = senderInfo; - _senderInfoId = senderInfoId; - _state = state; - _contextType = contextType; - _dbContext = dbContext; - } + public DialogContext( + int state, + long senderInfoId, + ContextType contextType, + BotFrameworkDbContext dbContext) + { + _senderInfoId = senderInfoId; + _state = state; + _contextType = contextType; + _dbContext = dbContext; + } - private void SaveChanges() - { - DialogContextEntity context = _dbContext.DialogContexts.FirstOrDefault( - x => - x.SenderInfoId == _senderInfoId - && x.ContextType == _contextType); + private void SaveChanges() + { + DialogContextEntity context = _dbContext.DialogContexts.FirstOrDefault( + x => + x.SenderInfoId == _senderInfoId + && x.ContextType == _contextType); - context!.State = State; - _dbContext.DialogContexts.Update(context); - _dbContext.SaveChanges(); - } + context!.State = State; + _dbContext.DialogContexts.Update(context); + _dbContext.SaveChanges(); } } \ No newline at end of file diff --git a/Kysect.BotFramework/Core/Contexts/Providers/StorageDialogContextProvider.cs b/Kysect.BotFramework/Core/Contexts/Providers/StorageDialogContextProvider.cs index 322c50f..d8bc418 100644 --- a/Kysect.BotFramework/Core/Contexts/Providers/StorageDialogContextProvider.cs +++ b/Kysect.BotFramework/Core/Contexts/Providers/StorageDialogContextProvider.cs @@ -1,16 +1,24 @@ -using Kysect.BotFramework.Abstactions.Services; +using System; +using Kysect.BotFramework.Abstactions.Services; using Kysect.BotFramework.Abstractions.Contexts; -using Kysect.BotFramework.Data; +using Kysect.BotFramework.Abstractions.Visitors; namespace Kysect.BotFramework.Core.Contexts.Providers; public class StorageDialogContextProvider : IDialogContextProvider { - private readonly BotFrameworkDbContext _dbContext; + private readonly ISenderInfoVisitor _dialogSenderInfoVisitor; - public StorageDialogContextProvider(BotFrameworkDbContext dbContext) - => _dbContext = dbContext; + public StorageDialogContextProvider(ISenderInfoVisitor dialogSenderInfoVisitor) + { + _dialogSenderInfoVisitor = dialogSenderInfoVisitor; + } public IDialogContext GetDialogContext(ISenderInfo senderInfo) - => (senderInfo as SenderInfo).GetOrCreateDialogContext(_dbContext); + { + if (senderInfo is null) + throw new ArgumentNullException(nameof(senderInfo)); + + return senderInfo.Accept(_dialogSenderInfoVisitor); + } } \ No newline at end of file diff --git a/Kysect.BotFramework/Core/Contexts/SenderInfo.cs b/Kysect.BotFramework/Core/Contexts/SenderInfo.cs deleted file mode 100644 index fc68b30..0000000 --- a/Kysect.BotFramework/Core/Contexts/SenderInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Kysect.BotFramework.Abstractions.Contexts; -using Kysect.BotFramework.Data; - -namespace Kysect.BotFramework.Core.Contexts -{ - public abstract class SenderInfo : ISenderInfo - { - public long ChatId { get; internal set; } - public long UserSenderId { get; internal set; } - public string UserSenderUsername { get; internal set; } - public bool IsAdmin { get; internal set; } - - internal abstract ContextType ContextType { get; } - - protected SenderInfo(long chatId, long userSenderId, string userSenderUsername, bool isAdmin) - { - ChatId = chatId; - UserSenderId = userSenderId; - UserSenderUsername = userSenderUsername; - IsAdmin = isAdmin; - } - - internal abstract IDialogContext GetOrCreateDialogContext(BotFrameworkDbContext dbContext); - } -} \ No newline at end of file diff --git a/Kysect.BotFramework/Core/Visitors/DialogSenderInfoVisitor.cs b/Kysect.BotFramework/Core/Visitors/DialogSenderInfoVisitor.cs new file mode 100644 index 0000000..d157c4e --- /dev/null +++ b/Kysect.BotFramework/Core/Visitors/DialogSenderInfoVisitor.cs @@ -0,0 +1,33 @@ +using Kysect.BotFramework.Abstractions.Contexts; +using Kysect.BotFramework.Abstractions.Visitors; +using Kysect.BotFramework.Core.Contexts; +using Kysect.BotFramework.Data; +using Kysect.BotFramework.Data.Entities; + +namespace Kysect.BotFramework.Core.Visitors; + +public class DialogSenderInfoVisitor : ISenderInfoVisitor +{ + private readonly BotFrameworkDbContext _dbContext; + + public DialogSenderInfoVisitor(BotFrameworkDbContext dbContext) + { + _dbContext = dbContext; + } + + public IDialogContext Visit(IDiscordSenderInfo senderInfo) + { + var contextSenderInfo = DiscordSenderInfoEntity.GetOrCreate(senderInfo, _dbContext); + var contextModel = DialogContextEntity.GetOrCreate(contextSenderInfo, ContextType.Discord, _dbContext); + + return new DialogContext(contextModel.State, contextModel.SenderInfoId, ContextType.Discord, _dbContext); + } + + public IDialogContext Visit(ITelegramSenderInfo senderInfo) + { + var contextSenderInfo = TelegramSenderInfoEntity.GetOrCreate(senderInfo, _dbContext); + var contextModel = DialogContextEntity.GetOrCreate(contextSenderInfo, ContextType.Telegram, _dbContext); + + return new DialogContext(contextModel.State, contextModel.SenderInfoId, ContextType.Telegram, _dbContext); + } +} \ No newline at end of file diff --git a/Kysect.BotFramework/Data/Entities/DiscordSenderInfoEntity.cs b/Kysect.BotFramework/Data/Entities/DiscordSenderInfoEntity.cs index b1c0d84..95eb6e3 100644 --- a/Kysect.BotFramework/Data/Entities/DiscordSenderInfoEntity.cs +++ b/Kysect.BotFramework/Data/Entities/DiscordSenderInfoEntity.cs @@ -1,5 +1,5 @@ using System.Linq; -using Kysect.BotFramework.ApiProviders.Discord; +using Kysect.BotFramework.Abstractions.Contexts; namespace Kysect.BotFramework.Data.Entities { @@ -7,7 +7,7 @@ public class DiscordSenderInfoEntity : SenderInfoEntity { public ulong GuildId { get; set; } - public static DiscordSenderInfoEntity GetOrCreate(DiscordSenderInfo senderInfo, BotFrameworkDbContext dbContext) + public static DiscordSenderInfoEntity GetOrCreate(IDiscordSenderInfo senderInfo, BotFrameworkDbContext dbContext) { var senderInfoEntity = dbContext.DiscordSenderInfos.FirstOrDefault( si => diff --git a/Kysect.BotFramework/Data/Entities/TelegramSenderInfoEntity.cs b/Kysect.BotFramework/Data/Entities/TelegramSenderInfoEntity.cs index 9084cc3..01440cd 100644 --- a/Kysect.BotFramework/Data/Entities/TelegramSenderInfoEntity.cs +++ b/Kysect.BotFramework/Data/Entities/TelegramSenderInfoEntity.cs @@ -1,11 +1,11 @@ using System.Linq; -using Kysect.BotFramework.ApiProviders.Telegram; +using Kysect.BotFramework.Abstractions.Contexts; namespace Kysect.BotFramework.Data.Entities { public class TelegramSenderInfoEntity : SenderInfoEntity { - public static TelegramSenderInfoEntity GetOrCreate(TelegramSenderInfo senderInfo, BotFrameworkDbContext dbContext) + public static TelegramSenderInfoEntity GetOrCreate(ITelegramSenderInfo senderInfo, BotFrameworkDbContext dbContext) { var senderInfoEntity = dbContext.TelegramSenderInfos.FirstOrDefault( si =>