From 957790a85b7d031186f2494776aef5f65b3e5068 Mon Sep 17 00:00:00 2001 From: Toastie Date: Sun, 12 May 2024 19:30:05 +1200 Subject: [PATCH] Removed a bunch of things out of EllieBot --- src/EllieBot/Bot.cs | 404 ++++++++ src/EllieBot/Common/Attributes/Aliases.cs | 12 - .../Attributes/CommandNameLoadHelper.cs | 31 - .../DontAddToIocContainerAttribute.cs | 11 - .../Common/Attributes/EllieCommand.cs | 18 - .../Common/Attributes/EllieOptions.cs | 10 - .../Attributes/NoPublicBotPrecondition.cs | 38 - .../Common/Attributes/OwnerOnlyAttribute.cs | 19 - src/EllieBot/Common/Attributes/Ratelimit.cs | 38 - src/EllieBot/Common/Attributes/UserPerm.cs | 30 - .../Common/Cache/BotCacheExtensions.cs | 46 - src/EllieBot/Common/Cache/IBotCache.cs | 47 - src/EllieBot/Common/Cache/MemoryBotCache.cs | 71 -- src/EllieBot/Common/Cache/RedisBotCache.cs | 119 --- src/EllieBot/Common/Configs/BotConfig.cs | 185 ---- src/EllieBot/Common/Configs/IConfigSeria.cs | 18 - .../Common/Interaction/EllieInteraction.cs | 82 -- .../Interaction/EllieInteractionData.cs | 8 - .../Interaction/EllieInteractionService.cs | 20 - .../Interaction/IEllieInteractionService.cs | 8 - .../Common/Interaction/SimpleInteraction.cs | 20 - .../JsonConverters/CultureInfoConverter.cs | 14 - .../Common/JsonConverters/Rgba32Converter.cs | 14 - .../Marmalade/Adapters/BehaviorAdapter.cs | 76 -- .../Adapters/ContextAdapterFactory.cs | 7 - .../Marmalade/Adapters/DmContextAdapter.cs | 49 - .../Marmalade/Adapters/FilterAdapter.cs | 31 - .../Marmalade/Adapters/GuildContextAdapter.cs | 53 - .../Marmalade/Adapters/ParamParserAdapter.cs | 32 - .../Common/Marmalade/CommandContextType.cs | 27 - .../Config/IMarmaladeConfigService.cs | 8 - .../Marmalade/Config/MarmaladeConfig.cs | 20 - .../Config/MarmaladeConfigService.cs | 45 - .../Marmalade/IMarmaladeLoaderService.cs | 23 - .../Marmalade/MarmaladeAssemblyLoadContext.cs | 36 - .../Marmalade/MarmaladeLoaderService.cs | 917 ------------------ .../Marmalade/MarmaladeServiceProvider.cs | 24 - .../Marmalade/Models/CanaryCommandData.cs | 46 - .../Common/Marmalade/Models/CanaryData.cs | 11 - .../Common/Marmalade/Models/ParamData.cs | 10 - .../Marmalade/Models/ResolvedMarmalade.cs | 14 - .../Common/ModuleBehaviors/IExecNoCommand.cs | 19 - .../Common/ModuleBehaviors/IExecOnMessage.cs | 21 - .../ModuleBehaviors/IExecPostCommand.cs | 22 - .../Common/ModuleBehaviors/IExecPreCommand.cs | 25 - .../ModuleBehaviors/IInputTransformer.cs | 25 - .../Common/ModuleBehaviors/IReadyExecutor.cs | 13 - src/EllieBot/Common/PubSub/EventPubSub.cs | 80 -- src/EllieBot/Common/PubSub/IPubSub.cs | 10 - src/EllieBot/Common/PubSub/ISeria.cs | 7 - src/EllieBot/Common/PubSub/JsonSeria.cs | 27 - src/EllieBot/Common/PubSub/RedisPubSub.cs | 52 - src/EllieBot/Common/PubSub/TypedKey.cs | 30 - src/EllieBot/Common/PubSub/YamlSeria.cs | 39 - src/EllieBot/Common/Yml/CommentAttribute.cs | 11 - .../Yml/CommentGatheringTypeInspector.cs | 65 -- .../Common/Yml/CommentsObjectDescriptor.cs | 30 - .../Common/Yml/CommentsObjectGraphVisitor.cs | 29 - .../Yml/MultilineScalarFlowStyleEmitter.cs | 35 - src/EllieBot/Common/Yml/Rgba32Converter.cs | 47 - src/EllieBot/Common/Yml/UriConverter.cs | 25 - src/EllieBot/Common/Yml/Yaml.cs | 28 - src/EllieBot/Common/Yml/YamlHelper.cs | 48 - src/EllieBot/Db/EllieContext.cs | 491 ---------- src/EllieBot/Db/Extensions/ClubExtensions.cs | 34 - .../CurrencyTransactionExtensions.cs | 20 - src/EllieBot/Db/Extensions/DbExtensions.cs | 12 - .../Db/Extensions/DiscordUserExtensions.cs | 179 ---- .../Extensions/EllieExpressionExtensions.cs | 15 - .../Db/Extensions/GuildConfigExtensions.cs | 227 ----- .../MusicPlayerSettingsExtensions.cs | 27 - .../Db/Extensions/MusicPlaylistExtensions.cs | 19 - src/EllieBot/Db/Extensions/PollExtensions.cs | 34 - src/EllieBot/Db/Extensions/QuoteExtensions.cs | 57 -- .../Db/Extensions/ReminderExtensions.cs | 23 - .../SelfAssignableRolesExtensions.cs | 22 - .../Db/Extensions/UserXpExtensions.cs | 63 -- src/EllieBot/Db/Extensions/WaifuExtensions.cs | 145 --- .../Db/Extensions/WarningExtensions.cs | 60 -- src/EllieBot/Db/Models/AntiProtection.cs | 65 -- src/EllieBot/Db/Models/AutoCommand.cs | 14 - src/EllieBot/Db/Models/AutoPublishChannel.cs | 9 - .../Db/Models/AutoTranslateChannel.cs | 10 - src/EllieBot/Db/Models/AutoTranslateUser.cs | 11 - src/EllieBot/Db/Models/BanTemplate.cs | 9 - src/EllieBot/Db/Models/BankUser.cs | 9 - src/EllieBot/Db/Models/BlacklistEntry.cs | 15 - src/EllieBot/Db/Models/ClubInfo.cs | 42 - src/EllieBot/Db/Models/CommandAlias.cs | 8 - src/EllieBot/Db/Models/CommandCooldown.cs | 8 - src/EllieBot/Db/Models/CurrencyTransaction.cs | 12 - src/EllieBot/Db/Models/DbEntity.cs | 12 - src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs | 14 - src/EllieBot/Db/Models/DiscordPemOverride.cs | 10 - src/EllieBot/Db/Models/DiscordUser.cs | 31 - src/EllieBot/Db/Models/EllieExpression.cs | 27 - src/EllieBot/Db/Models/Event.cs | 49 - src/EllieBot/Db/Models/FeedSub.cs | 19 - src/EllieBot/Db/Models/FilterChannelId.cs | 30 - .../Db/Models/FilterLinksChannelId.cs | 13 - src/EllieBot/Db/Models/FilteredWord.cs | 7 - src/EllieBot/Db/Models/FollowedStream.cs | 37 - src/EllieBot/Db/Models/GCChannelId.cs | 14 - src/EllieBot/Db/Models/GamblingStats.cs | 9 - src/EllieBot/Db/Models/GroupName.cs | 11 - src/EllieBot/Db/Models/GuildConfig.cs | 108 --- src/EllieBot/Db/Models/IgnoredLogItem.cs | 16 - .../Db/Models/IgnoredVoicePresenceChannel.cs | 8 - src/EllieBot/Db/Models/ImageOnlyChannel.cs | 15 - src/EllieBot/Db/Models/LogSetting.cs | 37 - src/EllieBot/Db/Models/MusicPlaylist.cs | 10 - src/EllieBot/Db/Models/MusicSettings.cs | 61 -- src/EllieBot/Db/Models/MutedUserId.cs | 13 - src/EllieBot/Db/Models/NsfwBlacklistedTag.cs | 14 - src/EllieBot/Db/Models/PatronQuota.cs | 48 - src/EllieBot/Db/Models/Permission.cs | 55 -- src/EllieBot/Db/Models/PlantedCurrency.cs | 12 - src/EllieBot/Db/Models/PlaylistSong.cs | 19 - src/EllieBot/Db/Models/Poll.cs | 17 - src/EllieBot/Db/Models/PollVote.cs | 14 - src/EllieBot/Db/Models/Quote.cs | 26 - src/EllieBot/Db/Models/ReactionRole.cs | 18 - src/EllieBot/Db/Models/Reminder.cs | 12 - src/EllieBot/Db/Models/Repeater.cs | 15 - src/EllieBot/Db/Models/RewardedUser.cs | 10 - .../Db/Models/RotatingPlayingStatus.cs | 8 - src/EllieBot/Db/Models/SelfAssignableRole.cs | 11 - src/EllieBot/Db/Models/ShopEntry.cs | 43 - src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs | 20 - src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs | 20 - src/EllieBot/Db/Models/StreamOnlineMessage.cs | 13 - src/EllieBot/Db/Models/StreamRoleSettings.cs | 68 -- src/EllieBot/Db/Models/UnbanTimer.cs | 14 - src/EllieBot/Db/Models/UnmuteTimer.cs | 14 - src/EllieBot/Db/Models/UnroleTimer.cs | 15 - src/EllieBot/Db/Models/UserXpStats.cs | 13 - src/EllieBot/Db/Models/VcRoleInfo.cs | 8 - src/EllieBot/Db/Models/Waifu.cs | 75 -- src/EllieBot/Db/Models/WaifuItem.cs | 10 - src/EllieBot/Db/Models/WaifuUpdate.cs | 23 - src/EllieBot/Db/Models/WarnExpireAction.cs | 8 - src/EllieBot/Db/Models/Warning.cs | 13 - src/EllieBot/Db/Models/WarningPunishment.cs | 10 - src/EllieBot/Db/Models/XpSettings.cs | 62 -- src/EllieBot/Db/Models/XpShopOwnedItem.cs | 18 - src/EllieBot/Db/MysqlContext.cs | 38 - src/EllieBot/Db/PostgreSqlContext.cs | 26 - src/EllieBot/Db/SqliteContext.cs | 26 - src/EllieBot/EllieBot.csproj | 1 - src/EllieBot/GlobalUsings.cs | 31 + 150 files changed, 435 insertions(+), 5984 deletions(-) create mode 100644 src/EllieBot/Bot.cs delete mode 100644 src/EllieBot/Common/Attributes/Aliases.cs delete mode 100644 src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs delete mode 100644 src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs delete mode 100644 src/EllieBot/Common/Attributes/EllieCommand.cs delete mode 100644 src/EllieBot/Common/Attributes/EllieOptions.cs delete mode 100644 src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs delete mode 100644 src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs delete mode 100644 src/EllieBot/Common/Attributes/Ratelimit.cs delete mode 100644 src/EllieBot/Common/Attributes/UserPerm.cs delete mode 100644 src/EllieBot/Common/Cache/BotCacheExtensions.cs delete mode 100644 src/EllieBot/Common/Cache/IBotCache.cs delete mode 100644 src/EllieBot/Common/Cache/MemoryBotCache.cs delete mode 100644 src/EllieBot/Common/Cache/RedisBotCache.cs delete mode 100644 src/EllieBot/Common/Configs/BotConfig.cs delete mode 100644 src/EllieBot/Common/Configs/IConfigSeria.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteraction.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteractionData.cs delete mode 100644 src/EllieBot/Common/Interaction/EllieInteractionService.cs delete mode 100644 src/EllieBot/Common/Interaction/IEllieInteractionService.cs delete mode 100644 src/EllieBot/Common/Interaction/SimpleInteraction.cs delete mode 100644 src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs delete mode 100644 src/EllieBot/Common/JsonConverters/Rgba32Converter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs delete mode 100644 src/EllieBot/Common/Marmalade/CommandContextType.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs delete mode 100644 src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs delete mode 100644 src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs delete mode 100644 src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/CanaryData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/ParamData.cs delete mode 100644 src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs delete mode 100644 src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs delete mode 100644 src/EllieBot/Common/PubSub/EventPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/IPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/ISeria.cs delete mode 100644 src/EllieBot/Common/PubSub/JsonSeria.cs delete mode 100644 src/EllieBot/Common/PubSub/RedisPubSub.cs delete mode 100644 src/EllieBot/Common/PubSub/TypedKey.cs delete mode 100644 src/EllieBot/Common/PubSub/YamlSeria.cs delete mode 100644 src/EllieBot/Common/Yml/CommentAttribute.cs delete mode 100644 src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs delete mode 100644 src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs delete mode 100644 src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs delete mode 100644 src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs delete mode 100644 src/EllieBot/Common/Yml/Rgba32Converter.cs delete mode 100644 src/EllieBot/Common/Yml/UriConverter.cs delete mode 100644 src/EllieBot/Common/Yml/Yaml.cs delete mode 100644 src/EllieBot/Common/Yml/YamlHelper.cs delete mode 100644 src/EllieBot/Db/EllieContext.cs delete mode 100644 src/EllieBot/Db/Extensions/ClubExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/DbExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/DiscordUserExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/GuildConfigExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/PollExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/QuoteExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/ReminderExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/UserXpExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/WaifuExtensions.cs delete mode 100644 src/EllieBot/Db/Extensions/WarningExtensions.cs delete mode 100644 src/EllieBot/Db/Models/AntiProtection.cs delete mode 100644 src/EllieBot/Db/Models/AutoCommand.cs delete mode 100644 src/EllieBot/Db/Models/AutoPublishChannel.cs delete mode 100644 src/EllieBot/Db/Models/AutoTranslateChannel.cs delete mode 100644 src/EllieBot/Db/Models/AutoTranslateUser.cs delete mode 100644 src/EllieBot/Db/Models/BanTemplate.cs delete mode 100644 src/EllieBot/Db/Models/BankUser.cs delete mode 100644 src/EllieBot/Db/Models/BlacklistEntry.cs delete mode 100644 src/EllieBot/Db/Models/ClubInfo.cs delete mode 100644 src/EllieBot/Db/Models/CommandAlias.cs delete mode 100644 src/EllieBot/Db/Models/CommandCooldown.cs delete mode 100644 src/EllieBot/Db/Models/CurrencyTransaction.cs delete mode 100644 src/EllieBot/Db/Models/DbEntity.cs delete mode 100644 src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs delete mode 100644 src/EllieBot/Db/Models/DiscordPemOverride.cs delete mode 100644 src/EllieBot/Db/Models/DiscordUser.cs delete mode 100644 src/EllieBot/Db/Models/EllieExpression.cs delete mode 100644 src/EllieBot/Db/Models/Event.cs delete mode 100644 src/EllieBot/Db/Models/FeedSub.cs delete mode 100644 src/EllieBot/Db/Models/FilterChannelId.cs delete mode 100644 src/EllieBot/Db/Models/FilterLinksChannelId.cs delete mode 100644 src/EllieBot/Db/Models/FilteredWord.cs delete mode 100644 src/EllieBot/Db/Models/FollowedStream.cs delete mode 100644 src/EllieBot/Db/Models/GCChannelId.cs delete mode 100644 src/EllieBot/Db/Models/GamblingStats.cs delete mode 100644 src/EllieBot/Db/Models/GroupName.cs delete mode 100644 src/EllieBot/Db/Models/GuildConfig.cs delete mode 100644 src/EllieBot/Db/Models/IgnoredLogItem.cs delete mode 100644 src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs delete mode 100644 src/EllieBot/Db/Models/ImageOnlyChannel.cs delete mode 100644 src/EllieBot/Db/Models/LogSetting.cs delete mode 100644 src/EllieBot/Db/Models/MusicPlaylist.cs delete mode 100644 src/EllieBot/Db/Models/MusicSettings.cs delete mode 100644 src/EllieBot/Db/Models/MutedUserId.cs delete mode 100644 src/EllieBot/Db/Models/NsfwBlacklistedTag.cs delete mode 100644 src/EllieBot/Db/Models/PatronQuota.cs delete mode 100644 src/EllieBot/Db/Models/Permission.cs delete mode 100644 src/EllieBot/Db/Models/PlantedCurrency.cs delete mode 100644 src/EllieBot/Db/Models/PlaylistSong.cs delete mode 100644 src/EllieBot/Db/Models/Poll.cs delete mode 100644 src/EllieBot/Db/Models/PollVote.cs delete mode 100644 src/EllieBot/Db/Models/Quote.cs delete mode 100644 src/EllieBot/Db/Models/ReactionRole.cs delete mode 100644 src/EllieBot/Db/Models/Reminder.cs delete mode 100644 src/EllieBot/Db/Models/Repeater.cs delete mode 100644 src/EllieBot/Db/Models/RewardedUser.cs delete mode 100644 src/EllieBot/Db/Models/RotatingPlayingStatus.cs delete mode 100644 src/EllieBot/Db/Models/SelfAssignableRole.cs delete mode 100644 src/EllieBot/Db/Models/ShopEntry.cs delete mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs delete mode 100644 src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs delete mode 100644 src/EllieBot/Db/Models/StreamOnlineMessage.cs delete mode 100644 src/EllieBot/Db/Models/StreamRoleSettings.cs delete mode 100644 src/EllieBot/Db/Models/UnbanTimer.cs delete mode 100644 src/EllieBot/Db/Models/UnmuteTimer.cs delete mode 100644 src/EllieBot/Db/Models/UnroleTimer.cs delete mode 100644 src/EllieBot/Db/Models/UserXpStats.cs delete mode 100644 src/EllieBot/Db/Models/VcRoleInfo.cs delete mode 100644 src/EllieBot/Db/Models/Waifu.cs delete mode 100644 src/EllieBot/Db/Models/WaifuItem.cs delete mode 100644 src/EllieBot/Db/Models/WaifuUpdate.cs delete mode 100644 src/EllieBot/Db/Models/WarnExpireAction.cs delete mode 100644 src/EllieBot/Db/Models/Warning.cs delete mode 100644 src/EllieBot/Db/Models/WarningPunishment.cs delete mode 100644 src/EllieBot/Db/Models/XpSettings.cs delete mode 100644 src/EllieBot/Db/Models/XpShopOwnedItem.cs delete mode 100644 src/EllieBot/Db/MysqlContext.cs delete mode 100644 src/EllieBot/Db/PostgreSqlContext.cs delete mode 100644 src/EllieBot/Db/SqliteContext.cs create mode 100644 src/EllieBot/GlobalUsings.cs diff --git a/src/EllieBot/Bot.cs b/src/EllieBot/Bot.cs new file mode 100644 index 0000000..d6ab91a --- /dev/null +++ b/src/EllieBot/Bot.cs @@ -0,0 +1,404 @@ +#nullable disable +using Microsoft.Extensions.DependencyInjection; +using EllieBot.Common.Configs; +using EllieBot.Common.ModuleBehaviors; +using EllieBot.Db; +using EllieBot.Modules.Utility; +using EllieBot.Services.Database.Models; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Net; +using System.Reflection; +using RunMode = Discord.Commands.RunMode; + +namespace EllieBot; + +public sealed class Bot +{ + public event Func JoinedGuild = delegate { return Task.CompletedTask; }; + + public DiscordSocketClient Client { get; } + public ImmutableArray AllGuildConfigs { get; private set; } + + private IServiceProvider Services { get; set; } + + public string Mention { get; private set; } + public bool IsReady { get; private set; } + public int ShardId { get; set; } + + private readonly IBotCredentials _creds; + private readonly CommandService _commandService; + private readonly DbService _db; + + private readonly IBotCredsProvider _credsProvider; + // private readonly InteractionService _interactionService; + + public Bot(int shardId, int? totalShards, string credPath = null) + { + if (shardId < 0) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + ShardId = shardId; + _credsProvider = new BotCredsProvider(totalShards, credPath); + _creds = _credsProvider.GetCreds(); + + _db = new(_credsProvider); + + var messageCacheSize = +#if GLOBAL_ELLIE + 0; +#else + 50; +#endif + + if(!_creds.UsePrivilegedIntents) + Log.Warning("You are not using privileged intents. Some features will not work properly"); + + Client = new(new() + { + MessageCacheSize = messageCacheSize, + LogLevel = LogSeverity.Warning, + ConnectionTimeout = int.MaxValue, + TotalShards = _creds.TotalShards, + ShardId = shardId, + AlwaysDownloadUsers = false, + AlwaysResolveStickers = false, + AlwaysDownloadDefaultStickers = false, + GatewayIntents = _creds.UsePrivilegedIntents + ? GatewayIntents.All + : GatewayIntents.AllUnprivileged, + LogGatewayIntentWarnings = false, + FormatUsersInBidirectionalUnicode = false, + DefaultRetryMode = RetryMode.Retry502 + }); + + _commandService = new(new() + { + CaseSensitiveCommands = false, + DefaultRunMode = RunMode.Sync, + }); + + // _interactionService = new(Client.Rest); + + Client.Log += Client_Log; + } + + + public List GetCurrentGuildIds() + => Client.Guilds.Select(x => x.Id).ToList(); + + private void AddServices() + { + var startingGuildIdList = GetCurrentGuildIds(); + var sw = Stopwatch.StartNew(); + var bot = Client.CurrentUser; + + using (var uow = _db.GetDbContext()) + { + uow.EnsureUserCreated(bot.Id, bot.Username, bot.Discriminator, bot.AvatarId); + AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); + } + + var svcs = new ServiceCollection().AddTransient(_ => _credsProvider.GetCreds()) // bot creds + .AddSingleton(_credsProvider) + .AddSingleton(_db) // database + .AddSingleton(Client) // discord socket client + .AddSingleton(_commandService) + // .AddSingleton(_interactionService) + .AddSingleton(this) + .AddSingleton() + .AddSingleton() + .AddConfigServices() + .AddConfigMigrators() + .AddMemoryCache() + // music + .AddMusic() + // cache + .AddCache(_creds); + + + svcs.AddHttpClient(); + svcs.AddHttpClient("memelist") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler + { + AllowAutoRedirect = false + }); + + svcs.AddHttpClient("google:search") + .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler() + { + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate + }); + + if (Environment.GetEnvironmentVariable("ELLIE_IS_COORDINATED") != "1") + svcs.AddSingleton(); + else + { + svcs.AddSingleton() + .AddSingleton(x => x.GetRequiredService()) + .AddSingleton(x => x.GetRequiredService()); + } + + svcs.Scan(scan => scan.FromAssemblyOf() + .AddClasses(classes => classes.AssignableToAny( + // services + typeof(IEService), + + // behaviours + typeof(IExecOnMessage), + typeof(IInputTransformer), + typeof(IExecPreCommand), + typeof(IExecPostCommand), + typeof(IExecNoCommand)) + .WithoutAttribute() +#if GLOBAL_ELLIE + .WithoutAttribute() +#endif + ) + .AsSelfWithInterfaces() + .WithSingletonLifetime()); + + //initialize Services + Services = svcs.BuildServiceProvider(); + Services.GetRequiredService().Initialize(); + Services.GetRequiredService(); + + if (Client.ShardId == 0) + ApplyConfigMigrations(); + + _ = LoadTypeReaders(typeof(Bot).Assembly); + + sw.Stop(); + Log.Information( "All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds); + } + + private void ApplyConfigMigrations() + { + // execute all migrators + var migrators = Services.GetServices(); + foreach (var migrator in migrators) + migrator.EnsureMigrated(); + } + + private IEnumerable LoadTypeReaders(Assembly assembly) + { + Type[] allTypes; + try + { + allTypes = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + Log.Warning(ex.LoaderExceptions[0], "Error getting types"); + return Enumerable.Empty(); + } + + var filteredTypes = allTypes.Where(x => x.IsSubclassOf(typeof(TypeReader)) + && x.BaseType?.GetGenericArguments().Length > 0 + && !x.IsAbstract); + + var toReturn = new List(); + foreach (var ft in filteredTypes) + { + var x = (TypeReader)ActivatorUtilities.CreateInstance(Services, ft); + var baseType = ft.BaseType; + if (baseType is null) + continue; + var typeArgs = baseType.GetGenericArguments(); + _commandService.AddTypeReader(typeArgs[0], x); + toReturn.Add(x); + } + + return toReturn; + } + + private async Task LoginAsync(string token) + { + var clientReady = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + async Task SetClientReady() + { + clientReady.TrySetResult(true); + try + { + foreach (var chan in await Client.GetDMChannelsAsync()) + await chan.CloseAsync(); + } + catch + { + // ignored + } + } + + //connect + Log.Information("Shard {ShardId} logging in ...", Client.ShardId); + try + { + Client.Ready += SetClientReady; + + await Client.LoginAsync(TokenType.Bot, token); + await Client.StartAsync(); + } + catch (HttpException ex) + { + LoginErrorHandler.Handle(ex); + Helpers.ReadErrorAndExit(3); + } + catch (Exception ex) + { + LoginErrorHandler.Handle(ex); + Helpers.ReadErrorAndExit(4); + } + + await clientReady.Task.ConfigureAwait(false); + Client.Ready -= SetClientReady; + + Client.JoinedGuild += Client_JoinedGuild; + Client.LeftGuild += Client_LeftGuild; + + // _ = Client.SetStatusAsync(UserStatus.Online); + Log.Information("Shard {ShardId} logged in", Client.ShardId); + } + + private Task Client_LeftGuild(SocketGuild arg) + { + Log.Information("Left server: {GuildName} [{GuildId}]", arg?.Name, arg?.Id); + return Task.CompletedTask; + } + + private Task Client_JoinedGuild(SocketGuild arg) + { + Log.Information("Joined server: {GuildName} [{GuildId}]", arg.Name, arg.Id); + _ = Task.Run(async () => + { + GuildConfig gc; + await using (var uow = _db.GetDbContext()) + { + gc = uow.GuildConfigsForId(arg.Id, null); + } + + await JoinedGuild.Invoke(gc); + }); + return Task.CompletedTask; + } + + public async Task RunAsync() + { + if (ShardId == 0) + await _db.SetupAsync(); + + var sw = Stopwatch.StartNew(); + + await LoginAsync(_creds.Token); + + Mention = Client.CurrentUser.Mention; + Log.Information("Shard {ShardId} loading services...", Client.ShardId); + try + { + AddServices(); + } + catch (Exception ex) + { + Log.Error(ex, "Error adding services"); + Helpers.ReadErrorAndExit(9); + } + + sw.Stop(); + Log.Information("Shard {ShardId} connected in {Elapsed:F2}s", Client.ShardId, sw.Elapsed.TotalSeconds); + var commandHandler = Services.GetRequiredService(); + + // start handling messages received in commandhandler + await commandHandler.StartHandling(); + + await _commandService.AddModulesAsync(typeof(Bot).Assembly, Services); + // await _interactionService.AddModulesAsync(typeof(Bot).Assembly, Services); + IsReady = true; + + await EnsureBotOwnershipAsync(); + _ = Task.Run(ExecuteReadySubscriptions); + Log.Information("Shard {ShardId} ready", Client.ShardId); + } + + private async ValueTask EnsureBotOwnershipAsync() + { + try + { + if (_creds.OwnerIds.Count != 0) + return; + + Log.Information("Initializing Owner Id..."); + var info = await Client.GetApplicationInfoAsync(); + _credsProvider.ModifyCredsFile(x => x.OwnerIds = new[] { info.Owner.Id }); + } + catch (Exception ex) + { + Log.Warning("Getting application info failed: {ErrorMessage}", ex.Message); + } + } + + private Task ExecuteReadySubscriptions() + { + var readyExecutors = Services.GetServices(); + var tasks = readyExecutors.Select(async toExec => + { + try + { + await toExec.OnReadyAsync(); + } + catch (Exception ex) + { + Log.Error(ex, + "Failed running OnReadyAsync method on {Type} type: {Message}", + toExec.GetType().Name, + ex.Message); + } + }); + + return tasks.WhenAll(); + } + + private Task Client_Log(LogMessage arg) + { + if (arg.Message?.Contains("unknown dispatch", StringComparison.InvariantCultureIgnoreCase) ?? false) + return Task.CompletedTask; + + if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } }) + { + Log.Error(@" +Login failed. + +*** Please enable privileged intents *** + +Certain Ellie features require Discord's privileged gateway intents. +These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding. + +How to enable privileged intents: +1. Head over to the Discord Developer Portal https://discord.com/developers/applications/ +2. Select your Application. +3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section. +4. Enable all intents. +5. Restart your bot. + +Read this only if your bot is in 100 or more servers: + +You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal. +Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before. +While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the ellie's features"); + return Task.CompletedTask; + } + +#if GLOBAL_ELLIE || DEBUG + if (arg.Exception is not null) + Log.Warning(arg.Exception, "{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message); + else + Log.Warning("{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message); +#endif + return Task.CompletedTask; + } + + public async Task RunAndBlockAsync() + { + await RunAsync(); + await Task.Delay(-1); + } +} \ No newline at end of file diff --git a/src/EllieBot/Common/Attributes/Aliases.cs b/src/EllieBot/Common/Attributes/Aliases.cs deleted file mode 100644 index 14df34a..0000000 --- a/src/EllieBot/Common/Attributes/Aliases.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class AliasesAttribute : AliasAttribute -{ - public AliasesAttribute([CallerMemberName] string memberName = "") - : base(CommandNameLoadHelper.GetAliasesFor(memberName)) - { - } -} diff --git a/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs b/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs deleted file mode 100644 index e77533d..0000000 --- a/src/EllieBot/Common/Attributes/CommandNameLoadHelper.cs +++ /dev/null @@ -1,31 +0,0 @@ -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Attributes; - -public static class CommandNameLoadHelper -{ - private static readonly IDeserializer _deserializer = new Deserializer(); - - private static readonly Lazy> _lazyCommandAliases - = new(() => LoadAliases()); - - public static Dictionary LoadAliases(string aliasesFilePath = "data/aliases.yml") - { - var text = File.ReadAllText(aliasesFilePath); - return _deserializer.Deserialize>(text); - } - - public static string[] GetAliasesFor(string methodName) - => _lazyCommandAliases.Value.TryGetValue(methodName.ToLowerInvariant(), out var aliases) && aliases.Length > 1 - ? aliases.Skip(1).ToArray() - : Array.Empty(); - - public static string GetCommandNameFor(string methodName) - { - methodName = methodName.ToLowerInvariant(); - var toReturn = _lazyCommandAliases.Value.TryGetValue(methodName, out var aliases) && aliases.Length > 0 - ? aliases[0] - : methodName; - return toReturn; - } -} diff --git a/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs b/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs deleted file mode 100644 index 666ebbe..0000000 --- a/src/EllieBot/Common/Attributes/DontAddToIocContainerAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Common; - -/// -/// Classed marked with this attribute will not be added to the service provider -/// -[AttributeUsage(AttributeTargets.Class)] -public class DontAddToIocContainerAttribute : Attribute -{ - -} diff --git a/src/EllieBot/Common/Attributes/EllieCommand.cs b/src/EllieBot/Common/Attributes/EllieCommand.cs deleted file mode 100644 index 109c1c5..0000000 --- a/src/EllieBot/Common/Attributes/EllieCommand.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class CmdAttribute : CommandAttribute -{ - public string MethodName { get; } - - public CmdAttribute([CallerMemberName] string memberName = "") - : base(CommandNameLoadHelper.GetCommandNameFor(memberName)) - { - MethodName = memberName.ToLowerInvariant(); - Aliases = CommandNameLoadHelper.GetAliasesFor(memberName); - Remarks = memberName.ToLowerInvariant(); - Summary = memberName.ToLowerInvariant(); - } -} diff --git a/src/EllieBot/Common/Attributes/EllieOptions.cs b/src/EllieBot/Common/Attributes/EllieOptions.cs deleted file mode 100644 index 32f91df..0000000 --- a/src/EllieBot/Common/Attributes/EllieOptions.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class EllieOptionsAttribute : Attribute -{ - public Type OptionType { get; set; } - - public EllieOptionsAttribute(Type t) - => OptionType = t; -} \ No newline at end of file diff --git a/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs b/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs deleted file mode 100644 index d380a92..0000000 --- a/src/EllieBot/Common/Attributes/NoPublicBotPrecondition.cs +++ /dev/null @@ -1,38 +0,0 @@ -#nullable disable -using System.Diagnostics.CodeAnalysis; - -namespace EllieBot.Common; - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -[SuppressMessage("Style", "IDE0022:Use expression body for methods")] -public sealed class NoPublicBotAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { -#if GLOBAL_ELLIE - return Task.FromResult(PreconditionResult.FromError("Not available on the public bot. To learn how to selfhost a private bot, click [here](https://docs.elliebot.net/v4/).")); -#else - return Task.FromResult(PreconditionResult.FromSuccess()); -#endif - } -} - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -[SuppressMessage("Style", "IDE0022:Use expression body for methods")] -public sealed class OnlyPublicBotAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { -#if GLOBAL_ELLIE || DEBUG - return Task.FromResult(PreconditionResult.FromSuccess()); -#else - return Task.FromResult(PreconditionResult.FromError("Only available on the public bot.")); -#endif - } -} diff --git a/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs b/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs deleted file mode 100644 index 7aa9317..0000000 --- a/src/EllieBot/Common/Attributes/OwnerOnlyAttribute.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -public sealed class OwnerOnlyAttribute : PreconditionAttribute -{ - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var creds = services.GetRequiredService().GetCreds(); - - return Task.FromResult(creds.IsOwner(context.User) || context.Client.CurrentUser.Id == context.User.Id - ? PreconditionResult.FromSuccess() - : PreconditionResult.FromError("Not owner")); - } -} diff --git a/src/EllieBot/Common/Attributes/Ratelimit.cs b/src/EllieBot/Common/Attributes/Ratelimit.cs deleted file mode 100644 index 9a8c887..0000000 --- a/src/EllieBot/Common/Attributes/Ratelimit.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace EllieBot.Common.Attributes; - -[AttributeUsage(AttributeTargets.Method)] -public sealed class RatelimitAttribute : PreconditionAttribute -{ - public int Seconds { get; } - - public RatelimitAttribute(int seconds) - { - if (seconds <= 0) - throw new ArgumentOutOfRangeException(nameof(seconds)); - - Seconds = seconds; - } - - public override async Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - if (Seconds == 0) - return PreconditionResult.FromSuccess(); - - var cache = services.GetRequiredService(); - var rem = await cache.GetRatelimitAsync( - new($"precondition:{context.User.Id}:{command.Name}"), - Seconds.Seconds()); - - if (rem is null) - return PreconditionResult.FromSuccess(); - - var msgContent = $"You can use this command again in {rem.Value.TotalSeconds:F1}s."; - - return PreconditionResult.FromError(msgContent); - } -} diff --git a/src/EllieBot/Common/Attributes/UserPerm.cs b/src/EllieBot/Common/Attributes/UserPerm.cs deleted file mode 100644 index dd2e7b5..0000000 --- a/src/EllieBot/Common/Attributes/UserPerm.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using EllieBot.Modules.Administration.Services; - -namespace Discord; - -[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] -public class UserPermAttribute : RequireUserPermissionAttribute -{ - public UserPermAttribute(GuildPerm permission) - : base(permission) - { - } - - public UserPermAttribute(ChannelPerm permission) - : base(permission) - { - } - - public override Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var permService = services.GetRequiredService(); - if (permService.TryGetOverrides(context.Guild?.Id ?? 0, command.Name.ToUpperInvariant(), out _)) - return Task.FromResult(PreconditionResult.FromSuccess()); - - return base.CheckPermissionsAsync(context, command, services); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/BotCacheExtensions.cs b/src/EllieBot/Common/Cache/BotCacheExtensions.cs deleted file mode 100644 index 41c6066..0000000 --- a/src/EllieBot/Common/Cache/BotCacheExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using OneOf; -using OneOf.Types; - -namespace EllieBot.Common; - -public static class BotCacheExtensions -{ - public static async ValueTask GetOrDefaultAsync(this IBotCache cache, TypedKey key) - { - var result = await cache.GetAsync(key); - if (result.TryGetValue(out var val)) - return val; - - return default; - } - - private static TypedKey GetImgKey(Uri uri) - => new($"image:{uri}"); - - public static ValueTask SetImageDataAsync(this IBotCache c, string key, byte[] data) - => c.SetImageDataAsync(new Uri(key), data); - public static async ValueTask SetImageDataAsync(this IBotCache c, Uri key, byte[] data) - => await c.AddAsync(GetImgKey(key), data, expiry: TimeSpan.FromHours(48)); - - public static async ValueTask> GetImageDataAsync(this IBotCache c, Uri key) - => await c.GetAsync(GetImgKey(key)); - - public static async Task GetRatelimitAsync( - this IBotCache c, - TypedKey key, - TimeSpan length) - { - var now = DateTime.UtcNow; - var nowB = now.ToBinary(); - - var cachedValue = await c.GetOrAddAsync(key, - () => Task.FromResult(now.ToBinary()), - expiry: length); - - if (cachedValue == nowB) - return null; - - var diff = now - DateTime.FromBinary(cachedValue); - return length - diff; - } -} diff --git a/src/EllieBot/Common/Cache/IBotCache.cs b/src/EllieBot/Common/Cache/IBotCache.cs deleted file mode 100644 index e1ea2c9..0000000 --- a/src/EllieBot/Common/Cache/IBotCache.cs +++ /dev/null @@ -1,47 +0,0 @@ -using OneOf; -using OneOf.Types; - -namespace EllieBot.Common; - -public interface IBotCache -{ - /// - /// Adds an item to the cache - /// - /// Key to add - /// Value to add to the cache - /// Optional expiry - /// Whether old value should be overwritten - /// Type of the value - /// Returns whether add was sucessful. Always true unless ovewrite = false - ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true); - - /// - /// Get an element from the cache - /// - /// Key - /// Type of the value - /// Either a value or - ValueTask> GetAsync(TypedKey key); - - /// - /// Remove a key from the cache - /// - /// Key to remove - /// Type of the value - /// Whether there was item - ValueTask RemoveAsync(TypedKey key); - - /// - /// Get the key if it exists or add a new one - /// - /// Key to get and potentially add - /// Value creation factory - /// Optional expiry - /// Type of the value - /// The retrieved or newly added value - ValueTask GetOrAddAsync( - TypedKey key, - Func> createFactory, - TimeSpan? expiry = null); -} diff --git a/src/EllieBot/Common/Cache/MemoryBotCache.cs b/src/EllieBot/Common/Cache/MemoryBotCache.cs deleted file mode 100644 index d0b7e68..0000000 --- a/src/EllieBot/Common/Cache/MemoryBotCache.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.Extensions.Caching.Memory; -using OneOf; -using OneOf.Types; - -// ReSharper disable InconsistentlySynchronizedField - -namespace EllieBot.Common; - -public sealed class MemoryBotCache : IBotCache -{ - // needed for overwrites and Delete return value - private readonly object _cacheLock = new object(); - private readonly MemoryCache _cache; - - public MemoryBotCache() - { - _cache = new MemoryCache(new MemoryCacheOptions()); - } - - public ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) - { - if (overwrite) - { - using var item = _cache.CreateEntry(key.Key); - item.Value = value; - item.AbsoluteExpirationRelativeToNow = expiry; - return new(true); - } - - lock (_cacheLock) - { - if (_cache.TryGetValue(key.Key, out var old) && old is not null) - return new(false); - - using var item = _cache.CreateEntry(key.Key); - item.Value = value; - item.AbsoluteExpirationRelativeToNow = expiry; - return new(true); - } - } - - public async ValueTask GetOrAddAsync( - TypedKey key, - Func> createFactory, - TimeSpan? expiry = null) - => await _cache.GetOrCreateAsync(key.Key, - async ce => - { - ce.AbsoluteExpirationRelativeToNow = expiry; - var val = await createFactory(); - return val; - }); - - public ValueTask> GetAsync(TypedKey key) - { - if (!_cache.TryGetValue(key.Key, out var val) || val is null) - return new(new None()); - - return new((T)val); - } - - public ValueTask RemoveAsync(TypedKey key) - { - lock (_cacheLock) - { - var toReturn = _cache.TryGetValue(key.Key, out var old) && old is not null; - _cache.Remove(key.Key); - return new(toReturn); - } - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Cache/RedisBotCache.cs b/src/EllieBot/Common/Cache/RedisBotCache.cs deleted file mode 100644 index 8de00fe..0000000 --- a/src/EllieBot/Common/Cache/RedisBotCache.cs +++ /dev/null @@ -1,119 +0,0 @@ -using OneOf; -using OneOf.Types; -using StackExchange.Redis; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common; - -public sealed class RedisBotCache : IBotCache -{ - private static readonly Type[] _supportedTypes = new[] - { - typeof(bool), typeof(int), typeof(uint), typeof(long), - typeof(ulong), typeof(float), typeof(double), - typeof(string), typeof(byte[]), typeof(ReadOnlyMemory), typeof(Memory), - typeof(RedisValue), - }; - - private static readonly JsonSerializerOptions _opts = new() - { - PropertyNameCaseInsensitive = true, - NumberHandling = JsonNumberHandling.AllowReadingFromString, - AllowTrailingCommas = true, - IgnoreReadOnlyProperties = false, - }; - private readonly ConnectionMultiplexer _conn; - - public RedisBotCache(ConnectionMultiplexer conn) - { - _conn = conn; - } - - public async ValueTask AddAsync(TypedKey key, T value, TimeSpan? expiry = null, bool overwrite = true) - { - // if a null value is passed, remove the key - if (value is null) - { - await RemoveAsync(key); - return false; - } - - var db = _conn.GetDatabase(); - RedisValue val = IsSupportedType(typeof(T)) - ? RedisValue.Unbox(value) - : JsonSerializer.Serialize(value, _opts); - - var success = await db.StringSetAsync(key.Key, - val, - expiry: expiry, - when: overwrite ? When.Always : When.NotExists); - - return success; - } - - public bool IsSupportedType(Type type) - { - if (type.IsGenericType) - { - var typeDef = type.GetGenericTypeDefinition(); - if (typeDef == typeof(Nullable<>)) - return IsSupportedType(type.GenericTypeArguments[0]); - } - - foreach (var t in _supportedTypes) - { - if (type == t) - return true; - } - - return false; - } - - public async ValueTask> GetAsync(TypedKey key) - { - var db = _conn.GetDatabase(); - var val = await db.StringGetAsync(key.Key); - if (val == default) - return new None(); - - if (IsSupportedType(typeof(T))) - return (T)((IConvertible)val).ToType(typeof(T), null); - - return JsonSerializer.Deserialize(val.ToString(), _opts)!; - } - - public async ValueTask RemoveAsync(TypedKey key) - { - var db = _conn.GetDatabase(); - - return await db.KeyDeleteAsync(key.Key); - } - - public async ValueTask GetOrAddAsync(TypedKey key, Func> createFactory, TimeSpan? expiry = null) - { - var result = await GetAsync(key); - - return await result.Match>( - v => Task.FromResult(v), - async _ => - { - var factoryValue = await createFactory(); - - if (factoryValue is null) - return default; - - await AddAsync(key, factoryValue, expiry); - - // get again to make sure it's the cached value - // and not the late factory value, in case there's a race condition - - var newResult = await GetAsync(key); - - // it's fine to do this, it should blow up if something went wrong. - return newResult.Match( - v => v, - _ => default); - }); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/BotConfig.cs b/src/EllieBot/Common/Configs/BotConfig.cs deleted file mode 100644 index 80186a9..0000000 --- a/src/EllieBot/Common/Configs/BotConfig.cs +++ /dev/null @@ -1,185 +0,0 @@ -#nullable disable -using Cloneable; -using EllieBot.Common.Yml; -using SixLabors.ImageSharp.PixelFormats; -using System.Globalization; -using YamlDotNet.Core; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Configs; - -[Cloneable] -public sealed partial class BotConfig : ICloneable -{ - [Comment(@"DO NOT CHANGE")] - public int Version { get; set; } = 5; - - [Comment(@"Most commands, when executed, have a small colored line -next to the response. The color depends whether the command -is completed, errored or in progress (pending) -Color settings below are for the color of those lines. -To get color's hex, you can go here https://htmlcolorcodes.com/ -and copy the hex code fo your selected color (marked as #)")] - public ColorConfig Color { get; set; } - - [Comment("Default bot language. It has to be in the list of supported languages (.langli)")] - public CultureInfo DefaultLocale { get; set; } - - [Comment(@"Style in which executed commands will show up in the console. -Allowed values: Simple, Normal, None")] - public ConsoleOutputType ConsoleOutputType { get; set; } - - [Comment(@"Whether the bot will check for new releases every hour")] - public bool CheckForUpdates { get; set; } = true; - - [Comment(@"Do you want any messages sent by users in Bot's DM to be forwarded to the owner(s)?")] - public bool ForwardMessages { get; set; } - - [Comment( - @"Do you want the message to be forwarded only to the first owner specified in the list of owners (in creds.yml), -or all owners? (this might cause the bot to lag if there's a lot of owners specified)")] - public bool ForwardToAllOwners { get; set; } - - [Comment(@"Any messages sent by users in Bot's DM to be forwarded to the specified channel. -This option will only work when ForwardToAllOwners is set to false")] - public ulong? ForwardToChannel { get; set; } - - [Comment(@"When a user DMs the bot with a message which is not a command -they will receive this message. Leave empty for no response. The string which will be sent whenever someone DMs the bot. -Supports embeds. How it looks: https://puu.sh/B0BLV.png")] - [YamlMember(ScalarStyle = ScalarStyle.Literal)] - public string DmHelpText { get; set; } - - [Comment(@"Only users who send a DM to the bot containing one of the specified words will get a DmHelpText response. -Case insensitive. -Leave empty to reply with DmHelpText to every DM.")] - public List DmHelpTextKeywords { get; set; } - - [Comment(@"This is the response for the .h command")] - [YamlMember(ScalarStyle = ScalarStyle.Literal)] - public string HelpText { get; set; } - - [Comment(@"List of modules and commands completely blocked on the bot")] - public BlockedConfig Blocked { get; set; } - - [Comment(@"Which string will be used to recognize the commands")] - public string Prefix { get; set; } - - [Comment(@"Toggles whether your bot will group greet/bye messages into a single message every 5 seconds. -1st user who joins will get greeted immediately -If more users join within the next 5 seconds, they will be greeted in groups of 5. -This will cause %user.mention% and other placeholders to be replaced with multiple users. -Keep in mind this might break some of your embeds - for example if you have %user.avatar% in the thumbnail, -it will become invalid, as it will resolve to a list of avatars of grouped users. -note: This setting is primarily used if you're afraid of raids, or you're running medium/large bots where some - servers might get hundreds of people join at once. This is used to prevent the bot from getting ratelimited, - and (slightly) reduce the greet spam in those servers.")] - public bool GroupGreets { get; set; } - - [Comment(@"Whether the bot will rotate through all specified statuses. -This setting can be changed via .ropl command. -See RotatingStatuses submodule in Administration.")] - public bool RotateStatuses { get; set; } - - public BotConfig() - { - var color = new ColorConfig(); - Color = color; - DefaultLocale = new("en-US"); - ConsoleOutputType = ConsoleOutputType.Normal; - ForwardMessages = false; - ForwardToAllOwners = false; - DmHelpText = @"{""description"": ""Type `%prefix%h` for help.""}"; - HelpText = @"{ - ""title"": ""To invite me to your server, use this link"", - ""description"": ""https://discordapp.com/oauth2/authorize?client_id={0}&scope=bot&permissions=66186303"", - ""color"": 53380, - ""thumbnail"": ""https://cdn.elliebot.net/Ellie.png"", - ""fields"": [ - { - ""name"": ""Useful help commands"", - ""value"": ""`%bot.prefix%modules` Lists all bot modules. -`%prefix%h CommandName` Shows some help about a specific command. -`%prefix%commands ModuleName` Lists all commands in a module."", - ""inline"": false - }, - { - ""name"": ""List of all Commands"", - ""value"": ""https://commands.elliebot.net"", - ""inline"": false - }, - { - ""name"": ""Ellie Support Server"", - ""value"": ""https://discord.gg/etQdZxSyEH"", - ""inline"": true - } - ] -}"; - var blocked = new BlockedConfig(); - Blocked = blocked; - Prefix = "."; - RotateStatuses = false; - GroupGreets = false; - DmHelpTextKeywords = new() - { - "help", - "commands", - "cmds", - "module", - "can you do" - }; - } - - // [Comment(@"Whether the prefix will be a suffix, or prefix. - // For example, if your prefix is ! you will run a command called 'cash' by typing either - // '!cash @Someone' if your prefixIsSuffix: false or - // 'cash @Someone!' if your prefixIsSuffix: true")] - // public bool PrefixIsSuffix { get; set; } - - // public string Prefixed(string text) => PrefixIsSuffix - // ? text + Prefix - // : Prefix + text; - - public string Prefixed(string text) - => Prefix + text; -} - -[Cloneable] -public sealed partial class BlockedConfig -{ - public HashSet Commands { get; set; } - public HashSet Modules { get; set; } - - public BlockedConfig() - { - Modules = new(); - Commands = new(); - } -} - -[Cloneable] -public partial class ColorConfig -{ - [Comment(@"Color used for embed responses when command successfully executes")] - public Rgba32 Ok { get; set; } - - [Comment(@"Color used for embed responses when command has an error")] - public Rgba32 Error { get; set; } - - [Comment(@"Color used for embed responses while command is doing work or is in progress")] - public Rgba32 Pending { get; set; } - - public ColorConfig() - { - Ok = Rgba32.ParseHex("00e584"); - Error = Rgba32.ParseHex("ee281f"); - Pending = Rgba32.ParseHex("faa61a"); - } -} - -public enum ConsoleOutputType -{ - Normal = 0, - Simple = 1, - None = 2 -} \ No newline at end of file diff --git a/src/EllieBot/Common/Configs/IConfigSeria.cs b/src/EllieBot/Common/Configs/IConfigSeria.cs deleted file mode 100644 index cced324..0000000 --- a/src/EllieBot/Common/Configs/IConfigSeria.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace EllieBot.Common.Configs; - -/// -/// Base interface for available config serializers -/// -public interface IConfigSeria -{ - /// - /// Serialize the object to string - /// - public string Serialize(T obj) - where T : notnull; - - /// - /// Deserialize string data into an object of the specified type - /// - public T Deserialize(string data); -} diff --git a/src/EllieBot/Common/Interaction/EllieInteraction.cs b/src/EllieBot/Common/Interaction/EllieInteraction.cs deleted file mode 100644 index e77fede..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteraction.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace EllieBot; - -public sealed class EllieInteraction -{ - private readonly ulong _authorId; - private readonly ButtonBuilder _button; - private readonly Func _onClick; - private readonly bool _onlyAuthor; - public DiscordSocketClient Client { get; } - - private readonly TaskCompletionSource _interactionCompletedSource; - - private IUserMessage message = null!; - - public EllieInteraction(DiscordSocketClient client, - ulong authorId, - ButtonBuilder button, - Func onClick, - bool onlyAuthor) - { - _authorId = authorId; - _button = button; - _onClick = onClick; - _onlyAuthor = onlyAuthor; - _interactionCompletedSource = new(TaskCreationOptions.RunContinuationsAsynchronously); - - Client = client; - } - - public async Task RunAsync(IUserMessage msg) - { - message = msg; - - Client.InteractionCreated += OnInteraction; - await Task.WhenAny(Task.Delay(15_000), _interactionCompletedSource.Task); - Client.InteractionCreated -= OnInteraction; - - await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build()); - } - - private Task OnInteraction(SocketInteraction arg) - { - if (arg is not SocketMessageComponent smc) - return Task.CompletedTask; - - if (smc.Message.Id != message.Id) - return Task.CompletedTask; - - if (_onlyAuthor && smc.User.Id != _authorId) - return Task.CompletedTask; - - if (smc.Data.CustomId != _button.CustomId) - return Task.CompletedTask; - - _ = Task.Run(async () => - { - await ExecuteOnActionAsync(smc); - - // this should only be a thing on single-response buttons - _interactionCompletedSource.TrySetResult(true); - - if (!smc.HasResponded) - { - await smc.DeferAsync(); - } - }); - - return Task.CompletedTask; - } - - - public MessageComponent CreateComponent() - { - var comp = new ComponentBuilder() - .WithButton(_button); - - return comp.Build(); - } - - public Task ExecuteOnActionAsync(SocketMessageComponent smc) - => _onClick(smc); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionData.cs b/src/EllieBot/Common/Interaction/EllieInteractionData.cs deleted file mode 100644 index 3e25606..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteractionData.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EllieBot; - -/// -/// Represents essential interacation data -/// -/// Emote which will show on a button -/// Custom interaction id -public record EllieInteractionData(IEmote Emote, string CustomId, string? Text = null); \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/EllieInteractionService.cs b/src/EllieBot/Common/Interaction/EllieInteractionService.cs deleted file mode 100644 index 3e97ec1..0000000 --- a/src/EllieBot/Common/Interaction/EllieInteractionService.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace EllieBot; - -public class EllieInteractionService : IEllieInteractionService, IEService -{ - private readonly DiscordSocketClient _client; - - public EllieInteractionService(DiscordSocketClient client) - { - _client = client; - } - - public EllieInteraction Create( - ulong userId, - SimpleInteraction inter) - => new EllieInteraction(_client, - userId, - inter.Button, - inter.TriggerAsync, - onlyAuthor: true); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs b/src/EllieBot/Common/Interaction/IEllieInteractionService.cs deleted file mode 100644 index 03a3ba1..0000000 --- a/src/EllieBot/Common/Interaction/IEllieInteractionService.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace EllieBot; - -public interface IEllieInteractionService -{ - public EllieInteraction Create( - ulong userId, - SimpleInteraction inter); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Interaction/SimpleInteraction.cs b/src/EllieBot/Common/Interaction/SimpleInteraction.cs deleted file mode 100644 index 045d4fc..0000000 --- a/src/EllieBot/Common/Interaction/SimpleInteraction.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace EllieBot; - -public class SimpleInteraction -{ - public ButtonBuilder Button { get; } - private readonly Func _onClick; - private readonly T? _state; - - public SimpleInteraction(ButtonBuilder button, Func onClick, T? state = default) - { - Button = button; - _onClick = onClick; - _state = state; - } - - public async Task TriggerAsync(SocketMessageComponent smc) - { - await _onClick(smc, _state!); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs b/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs deleted file mode 100644 index 0c26f15..0000000 --- a/src/EllieBot/Common/JsonConverters/CultureInfoConverter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common.JsonConverters; - -public class CultureInfoConverter : JsonConverter -{ - public override CultureInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => new(reader.GetString() ?? "en-US"); - - public override void Write(Utf8JsonWriter writer, CultureInfo value, JsonSerializerOptions options) - => writer.WriteStringValue(value.Name); -} \ No newline at end of file diff --git a/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs b/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs deleted file mode 100644 index ef619a6..0000000 --- a/src/EllieBot/Common/JsonConverters/Rgba32Converter.cs +++ /dev/null @@ -1,14 +0,0 @@ -using SixLabors.ImageSharp.PixelFormats; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace EllieBot.Common.JsonConverters; - -public class Rgba32Converter : JsonConverter -{ - public override Rgba32 Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => Rgba32.ParseHex(reader.GetString()); - - public override void Write(Utf8JsonWriter writer, Rgba32 value, JsonSerializerOptions options) - => writer.WriteStringValue(value.ToHex()); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs deleted file mode 100644 index 935d27a..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/BehaviorAdapter.cs +++ /dev/null @@ -1,76 +0,0 @@ -#nullable disable - -[DontAddToIocContainer] -public sealed class BehaviorAdapter : ICustomBehavior -{ - private readonly WeakReference _canaryWr; - private readonly IMarmaladeStrings _strings; - private readonly IServiceProvider _services; - private readonly string _name; - - // unused - public int Priority - => 0; - - public BehaviorAdapter(WeakReference canaryWr, IMarmaladeStrings strings, IServiceProvider services) - { - _canaryWr = canaryWr; - _strings = strings; - _services = services; - - _name = canaryWr.TryGetTarget(out var canary) - ? $"canary/{canary.GetType().Name}" - : "unknown"; - } - - public async Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return false; - - return await canary.ExecPreCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), - moduleName, - command.Name); - } - - public async Task ExecOnMessageAsync(IGuild? guild, IUserMessage msg) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return false; - - return await canary.ExecOnMessageAsync(guild, msg); - } - - public async Task TransformInput( - IGuild guild, - IMessageChannel channel, - IUser user, - string input) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return null; - - return await canary.ExecInputTransformAsync(guild, channel, user, input); - } - - public async Task ExecOnNoCommandAsync(IGuild? guild, IUserMessage msg) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return; - - await canary.ExecOnNoCommandAsync(guild, msg); - } - - public async ValueTask ExecPostCommandAsync(ICommandContext context, string moduleName, string commandName) - { - if (!_canaryWr.TryGetTarget(out var canary)) - return; - - await canary.ExecPostCommandAsync(ContextAdapterFactory.CreateNew(context, _strings, _services), - moduleName, - commandName); - } - - public override string ToString() - => _name; -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs b/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs deleted file mode 100644 index 212e8ee..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/ContextAdapterFactory.cs +++ /dev/null @@ -1,7 +0,0 @@ -internal class ContextFactory -{ - public static AnyContext CreateNew(ICommandContext context, IMarmaladeStrings strings, IServiceProvider services) - => context.Guild is null - ? new DmContextAdapter(context, strings, services) - : new GuildContextAdapter(context, strings, services); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs deleted file mode 100644 index d0aaabc..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/DmContextAdapter.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -public sealed class DmContextAdapter : DmContext -{ - public override IMarmaladeStrings Strings { get; } - public override IDMChannel Channel { get; } - public override IUserMessage Message { get; } - public override ISelfUser Bot { get; } - public override IUser User - => Message.Author; - - private readonly IServiceProvider _services; - private readonly Lazy _ebs; - private readonly Lazy _botStrings; - private readonly Lazy _localization; - - public DmContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) - { - if (ctx is not { Channel: IDMChannel ch}) - { - throw new ArgumentException("Can't use non-dm context to create DmContextAdapter", nameof(ctx)); - } - - Strings = strings; - - _services = services; - - Channel = ch; - Message = ctx.Message; - Bot = ctx.Client.CurrentUser; - - _ebs = new(_services.GetRequiredService()); - _botStrings = new(_services.GetRequiredService); - _localization = new(_services.GetRequiredService()); - } - - public override IEmbedBuilder Embed() - => _ebs.Value.Create(); - - public override string GetText(string key, object[]? args = null) - { - var cultureInfo = _localization.Value.GetCultureInfo(default(ulong?)); - var output = Strings.GetText(key, cultureInfo, args ?? Array.Empty()); - if (!string.IsNullOrEmpty(output)) - return output; - - return _botStrings.Value.GetText(key, cultureInfo, args); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs deleted file mode 100644 index 1934e38..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/FilterAdapter.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Ellie.Marmalade.Adapters; - -public class FilterAdapter : PreconditionAttribute -{ - private readonly FilterAttribute _filterAttribute; - private readonly IMarmaladeStrings _strings; - - public FilterAdapter(FilterAttribute filterAttribute, - IMarmaladeStrings strings) - { - _filterAttribute = filterAttribute; - _strings = strings; - } - - public override async Task CheckPermissionsAsync( - ICommandContext context, - CommandInfo command, - IServiceProvider services) - { - var marmaladeContext = ContextAdapterFactory.CreateNew(context, - _strings, - services); - - var result = await _filterAttribute.CheckAsync(marmaladeContext); - - if (!result) - return PreconditionResult.FromError($"Precondition '{_filterAttribute.GetType().Name}' failed."); - - return PreconditionResult.FromSuccess(); - } -} diff --git a/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs deleted file mode 100644 index f5f0a2b..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/GuildContextAdapter.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -public sealed class GuildContextAdapter : GuildContext -{ - private readonly IServiceProvider _services; - private readonly ICommandContext _ctx; - private readonly Lazy _ebs; - private readonly Lazy _botStrings; - private readonly Lazy _localization; - - public override IMarmaladeStrings Strings { get; } - public override IGuild Guild { get; } - public override ITextChannel Channel { get; } - public override ISelfUser Bot { get; } - public override IUserMessage Message - => _ctx.Message; - - public override IGuildUser User { get; } - - public override IEmbedBuilder Embed() - => _ebs.Value.Create(); - - public GuildContextAdapter(ICommandContext ctx, IMarmaladeStrings strings, IServiceProvider services) - { - if (ctx.Guild is not IGuild guild || ctx.Channel is not ITextChannel channel) - { - throw new ArgumentException("Can't use non-guild context to create GuildContextAdapter", nameof(ctx)); - } - - Strings = strings; - User = (IGuildUser)ctx.User; - Bot = ctx.Client.CurrentUser; - - _services = services; - _ebs = new(_services.GetRequiredService()); - _botStrings = new(_services.GetRequiredService); - _localization = new(_services.GetRequiredService()); - - (_ctx, Guild, Channel) = (ctx, guild, channel); - } - - public override string GetText(string key, object[]? args = null) - { - args ??= Array.Empty(); - - var cultureInfo = _localization.Value.GetCultureInfo(_ctx.Guild.Id); - var output = Strings.GetText(key, cultureInfo, args); - if (!string.IsNullOrWhiteSpace(output)) - return output; - - return _botStrings.Value.GetText(key, cultureInfo, args); - } -} diff --git a/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs b/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs deleted file mode 100644 index 1d3b948..0000000 --- a/src/EllieBot/Common/Marmalade/Adapters/ParamParserAdapter.cs +++ /dev/null @@ -1,32 +0,0 @@ -public sealed class ParamParserAdapter : TypeReader -{ - private readonly ParamParser _parser; - private readonly IMarmaladeStrings _strings; - private readonly IServiceProvider _services; - - public ParamParserAdapter(ParamParser parser, - IMarmaladeStrings strings, - IServiceProvider services) - { - _parser = parser; - _strings = strings; - _services = services; - } - - public override async Task ReadAsync( - ICommandContext context, - string input, - IServiceProvider services) - { - var marmaladeContext = ContextAdapterFactory.CreateNew(context, - _strings, - _services); - - var result = await _parser.TryParseAsync(marmaladeContext, input); - - if (result.IsSuccess) - return Discord.Commands.TypeReaderResult.FromSuccess(result.Data); - - return Discord.Commands.TypeReaderResult.FromError(CommandError.Unsuccessful, "Invalid input"); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/CommandContextType.cs b/src/EllieBot/Common/Marmalade/CommandContextType.cs deleted file mode 100644 index 9f9459c..0000000 --- a/src/EllieBot/Common/Marmalade/CommandContextType.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ellie.Marmalade; - -/// -/// Enum specifying in which context the command can be executed -/// -public enum CommandContextType -{ - /// - /// Command can only be executed in a guild - /// - Guild, - - /// - /// Command can only be executed in DMs - /// - Dm, - - /// - /// Command can be executed anywhere - /// - Any, - - /// - /// Command can be executed anywhere, and it doesn't require context to be passed to it - /// - Unspecified -} diff --git a/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs deleted file mode 100644 index f3e6f6a..0000000 --- a/src/EllieBot/Common/Marmalade/Config/IMarmaladeConfigService.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ellie.Marmalade; - -public interface IMarmaladeConfigService -{ - IReadOnlyCollection GetLoadedMarmalades(); - void AddLoadedMarmalade(string name); - void RemoveLoadedMarmalade(string name); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs deleted file mode 100644 index 82ec302..0000000 --- a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfig.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -using Cloneable; -using EllieBot.Common.Yml; - -namespace Ellie.Marmalade; - -[Cloneable] -public sealed partial class MarmaladeConfig : ICloneable -{ - [Comment(@"DO NOT CHANGE")] - public int Version { get; set; } = 1; - - [Comment("List of marmalades automatically loaded at startup")] - public List? Loaded { get; set; } - - public MarmaladeConfig() - { - Loaded = new(); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs b/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs deleted file mode 100644 index fe475e8..0000000 --- a/src/EllieBot/Common/Marmalade/Config/MarmaladeConfigService.cs +++ /dev/null @@ -1,45 +0,0 @@ -using EllieBot.Common.Configs; - -namespace Ellie.Marmalade; - -public sealed class MarmaladeConfigService : ConfigServiceBase, IMarmaladeConfigService -{ - private const string FILE_PATH = "data/marmalades/marmalade.yml"; - private static readonly TypedKey _changeKey = new("config.marmalade.updated"); - - public override string Name - => "marmalade"; - - public MarmaladeConfigService( - IConfigSeria serializer, - IPubSub pubSub) - : base(FILE_PATH, serializer, pubSub, _changeKey) - { - } - - public IReadOnlyCollection GetLoadedMarmalades() - => Data.Loaded?.ToList() ?? new List(); - - public void AddLoadedMarmalade(string name) - { - ModifyConfig(conf => - { - if (conf.Loaded is null) - conf.Loaded = new(); - - if (!conf.Loaded.Contains(name)) - conf.Loaded.Add(name); - }); - } - - public void RemoveLoadedMarmalade(string name) - { - ModifyConfig(conf => - { - if (conf.Loaded is null) - conf.Loaded = new(); - - conf.Loaded.Remove(name); - }); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs deleted file mode 100644 index 7064f5c..0000000 --- a/src/EllieBot/Common/Marmalade/IMarmaladeLoaderService.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Globalization; - -namespace Ellie.Marmalade; - -public interface IMarmaladeLoaderService -{ - Task LoadMarmaladeAsync(string marmaladeName); - Task UnloadMarmaladeAsync(string marmaladeName); - string GetCommandDescription(string marmamaleName, string commandName, CultureInfo culture); - string[] GetCommandExampleArgs(string marmamaleName, string commandName, CultureInfo culture); - Task ReloadStrings(); - IReadOnlyCollection GetAllMarmalades(); - IReadOnlyCollection GetLoadedMarmalades(CultureInfo? cultureInfo = null); -} - -public sealed record MarmaladeStats(string Name, - string? Description, - IReadOnlyCollection Canaries); - -public sealed record CanaryStats(string Name, - IReadOnlyCollection Commands); - -public sealed record CanaryCommandStats(string Name); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs b/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs deleted file mode 100644 index 2e30d81..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeAssemblyLoadContext.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.Loader; - -namespace Ellie.Marmalade; - -public sealed class MarmaladeAssemblyLoadContext : AssemblyLoadContext -{ - private readonly AssemblyDependencyResolver _depResolver; - - public MarmaladeAssemblyLoadContext(string pluginPath) : base(isCollectible: true) - { - _depResolver = new(pluginPath); - } - - protected override Assembly? Load(AssemblyName assemblyName) - { - var assemblyPath = _depResolver.ResolveAssemblyToPath(assemblyName); - if (assemblyPath != null) - { - return LoadFromAssemblyPath(assemblyPath); - } - - return null; - } - - protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) - { - var libraryPath = _depResolver.ResolveUnmanagedDllToPath(unmanagedDllName); - if (libraryPath != null) - { - return LoadUnmanagedDllFromPath(libraryPath); - } - - return IntPtr.Zero; - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs b/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs deleted file mode 100644 index d31fc51..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeLoaderService.cs +++ /dev/null @@ -1,917 +0,0 @@ -using Discord.Commands.Builders; -using Microsoft.Extensions.DependencyInjection; -using Ellie.Marmalade.Adapters; -using EllieBot.Common.ModuleBehaviors; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Ellie.Marmalade; - -// ReSharper disable RedundantAssignment -public sealed class MarmaladeLoaderService : IMarmaladeLoaderService, IReadyExecutor, IEService -{ - private readonly CommandService _cmdService; - private readonly IServiceProvider _botServices; - private readonly IBehaviorHandler _behHandler; - private readonly IPubSub _pubSub; - private readonly IMarmaladeConfigService _marmaladeConfig; - - private readonly ConcurrentDictionary _resolved = new(); -#pragma warning disable IDE0090 // Use 'new(...)' - private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1); -#pragma warning restore IDE0090 // Use 'new(...)' - - private readonly TypedKey _loadKey = new("marmalade:load"); - private readonly TypedKey _unloadKey = new("marmalade:unload"); - - private readonly TypedKey _stringsReload = new("marmalade:reload_strings"); - - private const string BASE_DIR = "data/marmalades"; - - public MarmaladeLoaderService(CommandService cmdService, - IServiceProvider botServices, - IBehaviorHandler behHandler, - IPubSub pubSub, - IMarmaladeConfigService marmaladeConfig) - { - _cmdService = cmdService; - _botServices = botServices; - _behHandler = behHandler; - _pubSub = pubSub; - _marmaladeConfig = marmaladeConfig; - - // has to be done this way to support this feature on sharded bots - _pubSub.Sub(_loadKey, async name => await InternalLoadAsync(name)); - _pubSub.Sub(_unloadKey, async name => await InternalUnloadAsync(name)); - - _pubSub.Sub(_stringsReload, async _ => await ReloadStringsInternal()); - } - - public IReadOnlyCollection GetAllMarmalades() - { - if (!Directory.Exists(BASE_DIR)) - return Array.Empty(); - - return Directory.GetDirectories(BASE_DIR) - .Select(x => Path.GetRelativePath(BASE_DIR, x)) - .ToArray(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public IReadOnlyCollection GetLoadedMarmalades(CultureInfo? culture) - { - var toReturn = new List(_resolved.Count); - foreach (var (name, resolvedData) in _resolved) - { - var canaries = new List(resolvedData.CanaryInfos.Count); - - foreach (var canaryInfos in resolvedData.CanaryInfos.Concat(resolvedData.CanaryInfos.SelectMany(x => x.Subcanaries))) - { - var commands = new List(); - - foreach (var command in canaryInfos.Commands) - { - commands.Add(new CanaryCommandStats(command.Aliases.First())); - } - - canaries.Add(new CanaryStats(canaryInfos.Name, commands)); - } - - toReturn.Add(new MarmaladeStats(name, resolvedData.Strings.GetDescription(culture), canaries)); - } - return toReturn; - } - - public async Task OnReadyAsync() - { - foreach (var name in _marmaladeConfig.GetLoadedMarmalades()) - { - var result = await InternalLoadAsync(name); - if (result != MarmaladeLoadResult.Success) - Log.Warning("Unable to load '{MarmaladeName}' marmalade", name); - else - Log.Warning("Loaded marmalade '{MarmaladeName}'", name); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public async Task LoadMarmaladeAsync(string marmaladeName) - { - // try loading on this shard first to see if it works - var res = await InternalLoadAsync(marmaladeName); - if (res == MarmaladeLoadResult.Success) - { - // if it does publish it so that other shards can load the medusa too - // this method will be ran twice on this shard but it doesn't matter as - // the second attempt will be ignored - await _pubSub.Pub(_loadKey, marmaladeName); - } - - return res; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public async Task UnloadMarmaladeAsync(string marmaladeName) - { - var res = await InternalUnloadAsync(marmaladeName); - if (res == MarmaladeUnloadResult.Success) - { - await _pubSub.Pub(_unloadKey, marmaladeName); - } - - return res; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public string[] GetCommandExampleArgs(string marmaladeName, string commandName, CultureInfo culture) - { - if (!_resolved.TryGetValue(marmaladeName, out var data)) - return Array.Empty(); - - return data.Strings.GetCommandStrings(commandName, culture).Args - ?? data.CanaryInfos - .SelectMany(x => x.Commands) - .FirstOrDefault(x => x.Aliases.Any(alias - => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) - ?.OptionalStrings - .Args - ?? new[] { string.Empty }; - } - - public Task ReloadStrings() - => _pubSub.Pub(_stringsReload, true); - - [MethodImpl(MethodImplOptions.NoInlining)] - private void ReloadStringsSync() - { - foreach (var resolved in _resolved.Values) - { - resolved.Strings.Reload(); - } - } - - private async Task ReloadStringsInternal() - { - await _lock.WaitAsync(); - try - { - ReloadStringsSync(); - } - finally - { - _lock.Release(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public string GetCommandDescription(string marmaladeName, string commandName, CultureInfo culture) - { - if (!_resolved.TryGetValue(marmaladeName, out var data)) - return string.Empty; - - return data.Strings.GetCommandStrings(commandName, culture).Desc - ?? data.CanaryInfos - .SelectMany(x => x.Commands) - .FirstOrDefault(x => x.Aliases.Any(alias - => alias.Equals(commandName, StringComparison.InvariantCultureIgnoreCase))) - ?.OptionalStrings - .Desc - ?? string.Empty; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async ValueTask InternalLoadAsync(string name) - { - if (_resolved.ContainsKey(name)) - return MarmaladeLoadResult.AlreadyLoaded; - - var safeName = Uri.EscapeDataString(name); - - await _lock.WaitAsync(); - try - { - if (LoadAssemblyInternal(safeName, - out var ctx, - out var canaryData, - out var services, - out var strings, - out var typeReaders)) - { - var moduleInfos = new List(); - - LoadTypeReadersInternal(typeReaders); - - foreach (var point in canaryData) - { - try - { - // initialize canary and subcanaries - await point.Instance.InitializeAsync(); - foreach (var sub in point.Subcanaries) - { - await sub.Instance.InitializeAsync(); - } - - var module = await LoadModuleInternalAsync(name, point, strings, services); - moduleInfos.Add(module); - } - catch (Exception ex) - { - Log.Warning(ex, - "Error loading canary {CanaryName}", - point.Name); - } - } - - var execs = GetExecsInternal(canaryData, strings, services); - await _behHandler.AddRangeAsync(execs); - - _resolved[name] = new(LoadContext: ctx, - ModuleInfos: moduleInfos.ToImmutableArray(), - CanaryInfos: canaryData.ToImmutableArray(), - strings, - typeReaders, - execs) - { - Services = services - }; - - - services = null; - _marmaladeConfig.AddLoadedMarmalade(safeName); - return MarmaladeLoadResult.Success; - } - - return MarmaladeLoadResult.Empty; - } - catch (Exception ex) when (ex is FileNotFoundException or BadImageFormatException) - { - return MarmaladeLoadResult.NotFound; - } - catch (Exception ex) - { - Log.Error(ex, "An error occurred loading a marmalade"); - return MarmaladeLoadResult.UnknownError; - } - finally - { - _lock.Release(); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private IReadOnlyCollection GetExecsInternal(IReadOnlyCollection canaryData, IMarmaladeStrings strings, IServiceProvider services) - { - var behs = new List(); - foreach (var canary in canaryData) - { - behs.Add(new BehaviorAdapter(new(canary.Instance), strings, services)); - - foreach (var sub in canary.Subcanaries) - { - behs.Add(new BehaviorAdapter(new(sub.Instance), strings, services)); - } - } - - return behs; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void LoadTypeReadersInternal(Dictionary typeReaders) - { - var notAddedTypeReaders = new List(); - foreach (var (type, typeReader) in typeReaders) - { - // if type reader for this type already exists, it will not be replaced - if (_cmdService.TypeReaders.Contains(type)) - { - notAddedTypeReaders.Add(type); - continue; - } - - _cmdService.AddTypeReader(type, typeReader); - } - - // remove the ones that were not added - // to prevent them from being unloaded later - // as they didn't come from this marmalade - foreach (var toRemove in notAddedTypeReaders) - { - typeReaders.Remove(toRemove); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private bool LoadAssemblyInternal( - string safeName, - [NotNullWhen(true)] out WeakReference? ctxWr, - [NotNullWhen(true)] out IReadOnlyCollection? canaryData, - out IServiceProvider services, - out IMarmaladeStrings strings, - out Dictionary typeReaders) - { - ctxWr = null; - canaryData = null; - - var path = $"{BASE_DIR}/{safeName}/{safeName}.dll"; - strings = MarmaladeStrings.CreateDefault($"{BASE_DIR}/{safeName}"); - var ctx = new MarmaladeAssemblyLoadContext(Path.GetDirectoryName(path)); - var a = ctx.LoadFromAssemblyPath(Path.GetFullPath(path)); - var sis = LoadCanariesFromAssembly(a, out services); - typeReaders = LoadTypeReadersFromAssembly(a, strings, services); - - if (sis.Count == 0) - { - return false; - } - - ctxWr = new(ctx); - canaryData = sis; - - return true; - } - - - private static readonly Type _paramParserType = typeof(ParamParser<>); - - [MethodImpl(MethodImplOptions.NoInlining)] - private Dictionary LoadTypeReadersFromAssembly( - Assembly assembly, - IMarmaladeStrings strings, - IServiceProvider services) - { - var paramParsers = assembly.GetExportedTypes() - .Where(x => x.IsClass - && !x.IsAbstract - && x.BaseType is not null - && x.BaseType.IsGenericType - && x.BaseType.GetGenericTypeDefinition() == _paramParserType); - - var typeReaders = new Dictionary(); - foreach (var parserType in paramParsers) - { - var parserObj = ActivatorUtilities.CreateInstance(services, parserType); - - var targetType = parserType.BaseType!.GetGenericArguments()[0]; - var typeReaderInstance = (TypeReader)Activator.CreateInstance( - typeof(ParamParserAdapter<>).MakeGenericType(targetType), - args: new[] { parserObj, strings, services })!; - - typeReaders.Add(targetType, typeReaderInstance); - } - - return typeReaders; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task LoadModuleInternalAsync(string marmaladeName, CanaryInfo canaryInfo, IMarmaladeStrings strings, IServiceProvider services) - { - var module = await _cmdService.CreateModuleAsync(canaryInfo.Instance.Prefix, - CreateModuleFactory(marmaladeName, canaryInfo, strings, services)); - - return module; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private Action CreateModuleFactory( - string marmaladeName, - CanaryInfo canaryInfo, - IMarmaladeStrings strings, - IServiceProvider marmaladeServices) - => mb => - { - var m = mb.WithName(canaryInfo.Name); - - foreach (var f in canaryInfo.Filters) - { - m.AddPrecondition(new FilterAdapter(f, strings)); - } - - foreach (var cmd in canaryInfo.Commands) - { - m.AddCommand(cmd.Aliases.First(), - CreateCallback(cmd.ContextType, - new(canaryInfo), - new(cmd), - new(marmaladeServices), - strings), - CreateCommandFactory(marmaladeName, cmd, strings)); - } - - foreach (var subInfo in canaryInfo.Subcanaries) - m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(marmaladeName, subInfo, strings, marmaladeServices)); - }; - -#pragma warning disable IDE0090 // Use 'new(...)' - private static readonly RequireContextAttribute _reqGuild = new RequireContextAttribute(ContextType.Guild); - private static readonly RequireContextAttribute _reqDm = new RequireContextAttribute(ContextType.DM); -#pragma warning restore IDE0090 // Use 'new(...)' - private Action CreateCommandFactory(string marmaladeName, CanaryCommandData cmd, IMarmaladeStrings strings) - => (cb) => - { - cb.AddAliases(cmd.Aliases.Skip(1).ToArray()); - - if (cmd.ContextType == CommandContextType.Guild) - cb.AddPrecondition(_reqGuild); - else if (cmd.ContextType == CommandContextType.Dm) - cb.AddPrecondition(_reqDm); - - foreach (var f in cmd.Filters) - cb.AddPrecondition(new FilterAdapter(f, strings)); - - foreach (var ubp in cmd.UserAndBotPerms) - { - if (ubp is user_permAttribute up) - { - if (up.GuildPerm is { } gp) - cb.AddPrecondition(new UserPermAttribute(gp)); - else if (up.ChannelPerm is { } cp) - cb.AddPrecondition(new UserPermAttribute(cp)); - } - else if (ubp is bot_permAttribute bp) - { - if (bp.GuildPerm is { } gp) - cb.AddPrecondition(new BotPermAttribute(gp)); - else if (bp.ChannelPerm is { } cp) - cb.AddPrecondition(new BotPermAttribute(cp)); - } - else if (ubp is bot_owner_onlyAttribute) - { - cb.AddPrecondition(new OwnerOnlyAttribute()); - } - } - - cb.WithPriority(cmd.Priority); - - // using summary to save method name - // method name is used to retrieve desc/usages - cb.WithRemarks($"marmalade///{marmaladeName}"); - cb.WithSummary(cmd.MethodInfo.Name.ToLowerInvariant()); - - foreach (var param in cmd.Parameters) - { - cb.AddParameter(param.Name, param.Type, CreateParamFactory(param)); - } - }; - - private Action CreateParamFactory(ParamData paramData) - => (pb) => - { - pb.WithIsMultiple(paramData.IsParams) - .WithIsOptional(paramData.IsOptional) - .WithIsRemainder(paramData.IsLeftover); - - if (paramData.IsOptional) - pb.WithDefault(paramData.DefaultValue); - }; - - [MethodImpl(MethodImplOptions.NoInlining)] - private Func CreateCallback( - CommandContextType contextType, - WeakReference canaryDataWr, - WeakReference canaryCommandDataWr, - WeakReference marmaladeServicesWr, - IMarmaladeStrings strings) - => async (context, parameters, svcs, _) => - { - if (!canaryCommandDataWr.TryGetTarget(out var cmdData) - || !canaryDataWr.TryGetTarget(out var canaryData) - || !marmaladeServicesWr.TryGetTarget(out var marmaladeServices)) - { - Log.Warning("Attempted to run an unloaded canary's command"); - return; - } - - var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, marmaladeServices, strings); - - try - { - var methodInfo = cmdData.MethodInfo; - if (methodInfo.ReturnType == typeof(Task) - || (methodInfo.ReturnType.IsGenericType - && methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))) - { - await (Task)methodInfo.Invoke(canaryData.Instance, paramObjs)!; - } - else if (methodInfo.ReturnType == typeof(ValueTask)) - { - await ((ValueTask)methodInfo.Invoke(canaryData.Instance, paramObjs)!).AsTask(); - } - else // if (methodInfo.ReturnType == typeof(void)) - { - methodInfo.Invoke(canaryData.Instance, paramObjs); - } - } - finally - { - paramObjs = null; - cmdData = null; - - canaryData = null; - marmaladeServices = null; - } - }; - - [MethodImpl(MethodImplOptions.NoInlining)] - private static object[] ParamObjs( - CommandContextType contextType, - CanaryCommandData cmdData, - object[] parameters, - ICommandContext context, - IServiceProvider svcs, - IServiceProvider svcProvider, - IMarmaladeStrings strings) - { - var extraParams = contextType == CommandContextType.Unspecified ? 0 : 1; - extraParams += cmdData.InjectedParams.Count; - - var paramObjs = new object[parameters.Length + extraParams]; - - var startAt = 0; - if (contextType != CommandContextType.Unspecified) - { - paramObjs[0] = ContextAdapterFactory.CreateNew(context, strings, svcs); - - startAt = 1; - } - - for (var i = 0; i < cmdData.InjectedParams.Count; i++) - { - var svc = svcProvider.GetService(cmdData.InjectedParams[i]); - if (svc is null) - { - throw new ArgumentException($"Cannot inject a service of type {cmdData.InjectedParams[i]}"); - } - - paramObjs[i + startAt] = svc; - - svc = null; - } - - startAt += cmdData.InjectedParams.Count; - - for (var i = 0; i < parameters.Length; i++) - paramObjs[startAt + i] = parameters[i]; - - return paramObjs; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task InternalUnloadAsync(string name) - { - if (!_resolved.Remove(name, out var lsi)) - return MarmaladeUnloadResult.NotLoaded; - - await _lock.WaitAsync(); - try - { - UnloadTypeReaders(lsi.TypeReaders); - - foreach (var mi in lsi.ModuleInfos) - { - await _cmdService.RemoveModuleAsync(mi); - } - - await _behHandler.RemoveRangeAsync(lsi.Execs); - - await DisposeCanaryInstances(lsi); - - var lc = lsi.LoadContext; - - // removing this line will prevent assembly from being unloaded quickly - // as this local variable will be held for a long time potentially - // due to how async works - lsi.Services = null!; - lsi = null; - - _marmaladeConfig.RemoveLoadedMarmalade(name); - return UnloadInternal(lc) - ? MarmaladeUnloadResult.Success - : MarmaladeUnloadResult.PossiblyUnable; - } - finally - { - _lock.Release(); - } - } - - private void UnloadTypeReaders(Dictionary valueTypeReaders) - { - foreach (var tr in valueTypeReaders) - { - _cmdService.TryRemoveTypeReader(tr.Key, false, out _); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private async Task DisposeCanaryInstances(ResolvedMarmalade marmalade) - { - foreach (var si in marmalade.CanaryInfos) - { - try - { - await si.Instance.DisposeAsync(); - foreach (var sub in si.Subcanaries) - { - await sub.Instance.DisposeAsync(); - } - } - catch (Exception ex) - { - Log.Warning(ex, - "Failed cleanup of Canary {CanaryName}. This marmalade might not unload correctly", - si.Instance.Name); - } - } - - // marmalades = null; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private bool UnloadInternal(WeakReference lsi) - { - UnloadContext(lsi); - GcCleanup(); - - return !lsi.TryGetTarget(out _); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void UnloadContext(WeakReference lsiLoadContext) - { - if (lsiLoadContext.TryGetTarget(out var ctx)) - ctx.Unload(); - } - - private void GcCleanup() - { - // cleanup - for (var i = 0; i < 10; i++) - { - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.WaitForFullGCComplete(); - GC.Collect(); - } - } - - private static readonly Type _canaryType = typeof(Canary); - - [MethodImpl(MethodImplOptions.NoInlining)] - private IServiceProvider LoadMarmaladeServicesInternal(Assembly a) - => new ServiceCollection() - .Scan(x => x.FromAssemblies(a) - .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Transient)) - .AsSelfWithInterfaces() - .WithTransientLifetime() - .AddClasses(static x => x.WithAttribute(x => x.Lifetime == Lifetime.Singleton)) - .AsSelfWithInterfaces() - .WithSingletonLifetime()) - .BuildServiceProvider(); - - - [MethodImpl(MethodImplOptions.NoInlining)] - public IReadOnlyCollection LoadCanariesFromAssembly(Assembly a, out IServiceProvider services) - { - var marmaladeServices = LoadMarmaladeServicesInternal(a); - services = new MarmaladeServiceProvider(_botServices, marmaladeServices); - - // find all types in teh assembly - var types = a.GetExportedTypes(); - // snek is always a public non abstract class - var classes = types.Where(static x => x.IsClass - && (x.IsNestedPublic || x.IsPublic) - && !x.IsAbstract - && x.BaseType == _canaryType - && (x.DeclaringType is null || x.DeclaringType.IsAssignableTo(_canaryType))) - .ToList(); - - var topModules = new Dictionary(); - - foreach (var cl in classes) - { - if (cl.DeclaringType is not null) - continue; - - // get module data, and add it to the topModules dictionary - var module = GetModuleData(cl, services); - topModules.Add(cl, module); - } - - foreach (var c in classes) - { - if (c.DeclaringType is not Type dt) - continue; - - // if there is no top level module which this module is a child of - // just print a warning and skip it - if (!topModules.TryGetValue(dt, out var parentData)) - { - Log.Warning("Can't load submodule {SubName} because parent module {Name} does not exist", - c.Name, - dt.Name); - continue; - } - - GetModuleData(c, services, parentData); - } - - return topModules.Values.ToArray(); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private CanaryInfo GetModuleData(Type type, IServiceProvider services, CanaryInfo? parentData = null) - { - var filters = type.GetCustomAttributes(true) - .ToArray(); - - var instance = (Canary)ActivatorUtilities.CreateInstance(services, type); - - var module = new CanaryInfo(instance.Name, - parentData, - instance, - GetCommands(instance, type), - filters); - - if (parentData is not null) - parentData.Subcanaries.Add(module); - - return module; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private IReadOnlyCollection GetCommands(Canary instance, Type type) - { - var methodInfos = type - .GetMethods(BindingFlags.Instance - | BindingFlags.DeclaredOnly - | BindingFlags.Public) - .Where(static x => - { - if (x.GetCustomAttribute(true) is null) - return false; - - if (x.ReturnType.IsGenericType) - { - var genericType = x.ReturnType.GetGenericTypeDefinition(); - if (genericType == typeof(Task<>)) - return true; - - // if (genericType == typeof(ValueTask<>)) - // return true; - - Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", - x.Name, - x.ReturnType); - - return false; - } - - var succ = x.ReturnType == typeof(Task) - || x.ReturnType == typeof(ValueTask) - || x.ReturnType == typeof(void); - - if (!succ) - { - Log.Warning("Method {MethodName} has an invalid return type: {ReturnType}", - x.Name, - x.ReturnType); - } - - return succ; - }); - - - var cmds = new List(); - foreach (var method in methodInfos) - { - var filters = method.GetCustomAttributes(true).ToArray(); - var userAndBotPerms = method.GetCustomAttributes(true) - .ToArray(); - var prio = method.GetCustomAttribute(true)?.Priority ?? 0; - - var paramInfos = method.GetParameters(); - var cmdParams = new List(); - var diParams = new List(); - var cmdContext = CommandContextType.Unspecified; - var canInject = false; - for (var paramCounter = 0; paramCounter < paramInfos.Length; paramCounter++) - { - var pi = paramInfos[paramCounter]; - - var paramName = pi.Name ?? "unnamed"; - var isContext = paramCounter == 0 && pi.ParameterType.IsAssignableTo(typeof(AnyContext)); - - var leftoverAttribute = pi.GetCustomAttribute(true); - var hasDefaultValue = pi.HasDefaultValue; - var defaultValue = pi.DefaultValue; - var isLeftover = leftoverAttribute != null; - var isParams = pi.GetCustomAttribute() is not null; - var paramType = pi.ParameterType; - var isInjected = pi.GetCustomAttribute(true) is not null; - - if (isContext) - { - if (hasDefaultValue || leftoverAttribute != null || isParams) - throw new ArgumentException("IContext parameter cannot be optional, leftover, constant or params. " + GetErrorPath(method, pi)); - - if (paramCounter != 0) - throw new ArgumentException($"IContext parameter has to be first. {GetErrorPath(method, pi)}"); - - canInject = true; - - if (paramType.IsAssignableTo(typeof(GuildContext))) - cmdContext = CommandContextType.Guild; - else if (paramType.IsAssignableTo(typeof(DmContext))) - cmdContext = CommandContextType.Dm; - else - cmdContext = CommandContextType.Any; - - continue; - } - - if (isInjected) - { - if (!canInject && paramCounter != 0) - throw new ArgumentException($"Parameters marked as [Injected] have to come after IContext"); - - canInject = true; - - diParams.Add(paramType); - continue; - } - - canInject = false; - - if (isParams) - { - if (hasDefaultValue) - throw new NotSupportedException("Params can't have const values at the moment. " - + GetErrorPath(method, pi)); - // if it's params, it means it's an array, and i only need a parser for the actual type, - // as the parser will run on each array element, it can't be null - paramType = paramType.GetElementType()!; - } - - // leftover can only be the last parameter. - if (isLeftover && paramCounter != paramInfos.Length - 1) - { - var path = GetErrorPath(method, pi); - Log.Error("Only one parameter can be marked [Leftover] and it has to be the last one. {Path} ", - path); - throw new ArgumentException("Leftover attribute error."); - } - - cmdParams.Add(new ParamData(paramType, paramName, hasDefaultValue, defaultValue, isLeftover, isParams)); - } - - - var cmdAttribute = method.GetCustomAttribute(true)!; - var aliases = cmdAttribute.Aliases; - if (aliases.Length == 0) - aliases = new[] { method.Name.ToLowerInvariant() }; - - cmds.Add(new( - aliases, - method, - instance, - filters, - userAndBotPerms, - cmdContext, - diParams, - cmdParams, - new(cmdAttribute.desc, cmdAttribute.args), - prio - )); - } - - return cmds; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private string GetErrorPath(MethodInfo m, System.Reflection.ParameterInfo pi) - => $@"Module: {m.DeclaringType?.Name} -Command: {m.Name} -ParamName: {pi.Name} -ParamType: {pi.ParameterType.Name}"; -} - -public enum MarmaladeLoadResult -{ - Success, - NotFound, - AlreadyLoaded, - Empty, - UnknownError, -} - -public enum MarmaladeUnloadResult -{ - Success, - NotLoaded, - PossiblyUnable, - NotFound, -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs b/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs deleted file mode 100644 index c2f3c76..0000000 --- a/src/EllieBot/Common/Marmalade/MarmaladeServiceProvider.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace Ellie.Marmalade; - -public class MarmaladeServiceProvider : IServiceProvider -{ - private readonly IServiceProvider _ellieServices; - private readonly IServiceProvider _marmaladeServices; - - public MarmaladeServiceProvider(IServiceProvider ellieServices, IServiceProvider marmaladeServices) - { - _ellieServices = ellieServices; - _marmaladeServices = marmaladeServices; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - public object? GetService(Type serviceType) - { - if (!serviceType.Assembly.IsCollectible) - return _ellieServices.GetService(serviceType); - - return _marmaladeServices.GetService(serviceType); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs deleted file mode 100644 index 412243d..0000000 --- a/src/EllieBot/Common/Marmalade/Models/CanaryCommandData.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.VisualBasic; -using System.Reflection; -using CommandStrings = Ellie.Marmalade.CommandStrings; - -namespace Ellie.Marmalade; - -public sealed class CanaryCommandData -{ - public CanaryCommandData( - IReadOnlyCollection aliases, - MethodInfo methodInfo, - Canary module, - FilterAttribute[] filters, - MarmaladePermAttribute[] userAndBotPerms, - CommandContextType contextType, - IReadOnlyList injectedParams, - IReadOnlyList parameters, - CommandStrings strings, - int priority) - { - Aliases = aliases; - MethodInfo = methodInfo; - Module = module; - Filters = filters; - UserAndBotPerms = userAndBotPerms; - ContextType = contextType; - InjectedParams = injectedParams; - Parameters = parameters; - Priority = priority; - OptionalStrings = strings; - } - - public MarmaladePermAttribute[] UserAndBotPerms { get; set; } - - public CommandStrings OptionalStrings { get; set; } - - public IReadOnlyCollection Aliases { get; } - public MethodInfo MethodInfo { get; set; } - public Canary Module { get; set; } - public FilterAttribute[] Filters { get; set; } - public CommandContextType ContextType { get; } - public IReadOnlyList InjectedParams { get; } - public IReadOnlyList Parameters { get; } - public int Priority { get; } - -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/CanaryData.cs b/src/EllieBot/Common/Marmalade/Models/CanaryData.cs deleted file mode 100644 index b3938e7..0000000 --- a/src/EllieBot/Common/Marmalade/Models/CanaryData.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ellie.Marmalade; - -public sealed record CanaryInfo( - string Name, - CanaryInfo? Parent, - Canary Instance, - IReadOnlyCollection Commands, - IReadOnlyCollection Filters) -{ - public List Subcanaries { get; set; } = new(); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ParamData.cs b/src/EllieBot/Common/Marmalade/Models/ParamData.cs deleted file mode 100644 index e329958..0000000 --- a/src/EllieBot/Common/Marmalade/Models/ParamData.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ellie.Marmalade; - -public sealed record ParamData( - Type Type, - string Name, - bool IsOptional, - object? DefaultValue, - bool IsLeftover, - bool IsParams -); \ No newline at end of file diff --git a/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs b/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs deleted file mode 100644 index bf40d7a..0000000 --- a/src/EllieBot/Common/Marmalade/Models/ResolvedMarmalade.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections.Immutable; - -namespace Ellie.Marmalade; - -public sealed record ResolvedMarmalade( - WeakReference LoadContext, - IImmutableList ModuleInfos, - IImmutableList CanaryInfos, - IMarmaladeStrings Strings, - Dictionary TypeReaders, - IReadOnlyCollection Execs) -{ - public IServiceProvider Services { get; set; } = null!; -} \ No newline at end of file diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs deleted file mode 100644 index a73a7a7..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecNoCommand.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Executed if no command was found for this message -/// -public interface IExecNoCommand -{ - /// - /// Executed at the end of the lifecycle if no command was found - /// → - /// → - /// → - /// [ | **] - /// - /// - /// - /// A task representing completion - Task ExecOnNoCommandAsync(IGuild guild, IUserMessage msg); -} \ No newline at end of file diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs b/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs deleted file mode 100644 index eade8d5..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecOnMessage.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Implemented by modules to handle non-bot messages received -/// -public interface IExecOnMessage -{ - int Priority { get; } - - /// - /// Ran after a non-bot message was received - /// ** → - /// → - /// → - /// [ | ] - /// - /// Guild where the message was sent - /// The message that was received - /// Whether further processing of this message should be blocked - Task ExecOnMessageAsync(IGuild guild, IUserMessage msg); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs deleted file mode 100644 index 4f79c31..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecPostCommand.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// This interface's method is executed after the command successfully finished execution. -/// ***There is no support for this method in EllieBot services.*** -/// It is only meant to be used in marmalade system -/// -public interface IExecPostCommand -{ - /// - /// Executed after a command was successfully executed - /// → - /// → - /// → - /// [** | ] - /// - /// Command context - /// Module name - /// Command name - /// A task representing completion - ValueTask ExecPostCommandAsync(ICommandContext ctx, string moduleName, string commandName); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs b/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs deleted file mode 100644 index dc14cdd..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IExecPreCommand.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// This interface's method is executed after a command was found but before it was executed. -/// Able to block further processing of a command -/// -public interface IExecPreCommand -{ - public int Priority { get; } - - /// - /// - /// Ran after a command was found but before execution. - /// - /// → - /// → - /// ** → - /// [ | ] - /// - /// Command context - /// Name of the module - /// Command info - /// Whether further processing of the command is blocked - Task ExecPreCommandAsync(ICommandContext context, string moduleName, CommandInfo command); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs b/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs deleted file mode 100644 index 90ae000..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IInputTransformer.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// Implemented by services which may transform input before a command is searched for -/// -public interface IInputTransformer -{ - /// - /// Ran after a non-bot message was received - /// -> - /// ** -> - /// -> - /// [ OR ] - /// - /// Guild - /// Channel in which the message was sent - /// User who sent the message - /// Content of the message - /// New input, if any, otherwise null - Task TransformInput( - IGuild guild, - IMessageChannel channel, - IUser user, - string input); -} diff --git a/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs b/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs deleted file mode 100644 index 9ae8211..0000000 --- a/src/EllieBot/Common/ModuleBehaviors/IReadyExecutor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace EllieBot.Common.ModuleBehaviors; - -/// -/// All services which need to execute something after -/// the bot is ready should implement this interface -/// -public interface IReadyExecutor -{ - /// - /// Executed when bot is ready - /// - public Task OnReadyAsync(); -} diff --git a/src/EllieBot/Common/PubSub/EventPubSub.cs b/src/EllieBot/Common/PubSub/EventPubSub.cs deleted file mode 100644 index 0e45ed8..0000000 --- a/src/EllieBot/Common/PubSub/EventPubSub.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace EllieBot.Common; - -public class EventPubSub : IPubSub -{ - private readonly Dictionary>>> _actions = new(); - private readonly object _locker = new(); - - public Task Sub(in TypedKey key, Func action) - where TData : notnull - { - Func localAction = obj => action((TData)obj); - lock (_locker) - { - if (!_actions.TryGetValue(key.Key, out var keyActions)) - { - keyActions = new(); - _actions[key.Key] = keyActions; - } - - if (!keyActions.TryGetValue(action, out var sameActions)) - { - sameActions = new(); - keyActions[action] = sameActions; - } - - sameActions.Add(localAction); - - return Task.CompletedTask; - } - } - - public Task Pub(in TypedKey key, TData data) - where TData : notnull - { - lock (_locker) - { - if (_actions.TryGetValue(key.Key, out var actions)) - // if this class ever gets used, this needs to be properly implemented - // 1. ignore all valuetasks which are completed - // 2. run all other tasks in parallel - return actions.SelectMany(kvp => kvp.Value).Select(action => action(data).AsTask()).WhenAll(); - - return Task.CompletedTask; - } - } - - public Task Unsub(in TypedKey key, Func action) - { - lock (_locker) - { - // get subscriptions for this action - if (_actions.TryGetValue(key.Key, out var actions)) - // get subscriptions which have the same action hash code - // note: having this as a list allows for multiple subscriptions of - // the same insance's/static method - { - if (actions.TryGetValue(action, out var sameActions)) - { - // remove last subscription - sameActions.RemoveAt(sameActions.Count - 1); - - // if the last subscription was the only subscription - // we can safely remove this action's dictionary entry - if (sameActions.Count == 0) - { - actions.Remove(action); - - // if our dictionary has no more elements after - // removing the entry - // it's safe to remove it from the key's subscriptions - if (actions.Count == 0) - _actions.Remove(key.Key); - } - } - } - - return Task.CompletedTask; - } - } -} diff --git a/src/EllieBot/Common/PubSub/IPubSub.cs b/src/EllieBot/Common/PubSub/IPubSub.cs deleted file mode 100644 index 0d52156..0000000 --- a/src/EllieBot/Common/PubSub/IPubSub.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EllieBot.Common; - -public interface IPubSub -{ - public Task Pub(in TypedKey key, TData data) - where TData : notnull; - - public Task Sub(in TypedKey key, Func action) - where TData : notnull; -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/ISeria.cs b/src/EllieBot/Common/PubSub/ISeria.cs deleted file mode 100644 index 0eb9706..0000000 --- a/src/EllieBot/Common/PubSub/ISeria.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EllieBot.Common; - -public interface ISeria -{ - byte[] Serialize(T data); - T? Deserialize(byte[]? data); -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/JsonSeria.cs b/src/EllieBot/Common/PubSub/JsonSeria.cs deleted file mode 100644 index b8f8033..0000000 --- a/src/EllieBot/Common/PubSub/JsonSeria.cs +++ /dev/null @@ -1,27 +0,0 @@ -using EllieBot.Common.JsonConverters; -using System.Text.Json; - -namespace EllieBot.Common; - -public class JsonSeria : ISeria -{ - private readonly JsonSerializerOptions _serializerOptions = new() - { - Converters = - { - new Rgba32Converter(), - new CultureInfoConverter() - } - }; - - public byte[] Serialize(T data) - => JsonSerializer.SerializeToUtf8Bytes(data, _serializerOptions); - - public T? Deserialize(byte[]? data) - { - if (data is null) - return default; - - return JsonSerializer.Deserialize(data, _serializerOptions); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/RedisPubSub.cs b/src/EllieBot/Common/PubSub/RedisPubSub.cs deleted file mode 100644 index 82d8a99..0000000 --- a/src/EllieBot/Common/PubSub/RedisPubSub.cs +++ /dev/null @@ -1,52 +0,0 @@ -using StackExchange.Redis; - -namespace EllieBot.Common; - -public sealed class RedisPubSub : IPubSub -{ - private readonly IBotCredentials _creds; - private readonly ConnectionMultiplexer _multi; - private readonly ISeria _serializer; - - public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds) - { - _multi = multi; - _serializer = serializer; - _creds = creds; - } - - public Task Pub(in TypedKey key, TData data) - where TData : notnull - { - var serialized = _serializer.Serialize(data); - return _multi.GetSubscriber() - .PublishAsync($"{_creds.RedisKey()}:{key.Key}", serialized, CommandFlags.FireAndForget); - } - - public Task Sub(in TypedKey key, Func action) - where TData : notnull - { - var eventName = key.Key; - - async void OnSubscribeHandler(RedisChannel _, RedisValue data) - { - try - { - var dataObj = _serializer.Deserialize(data); - if (dataObj is not null) - await action(dataObj); - else - { - Log.Warning("Publishing event {EventName} with a null value. This is not allowed", - eventName); - } - } - catch (Exception ex) - { - Log.Error("Error handling the event {EventName}: {ErrorMessage}", eventName, ex.Message); - } - } - - return _multi.GetSubscriber().SubscribeAsync($"{_creds.RedisKey()}:{eventName}", OnSubscribeHandler); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/TypedKey.cs b/src/EllieBot/Common/PubSub/TypedKey.cs deleted file mode 100644 index e637707..0000000 --- a/src/EllieBot/Common/PubSub/TypedKey.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EllieBot.Common; - -public readonly struct TypedKey -{ - public string Key { get; } - - public TypedKey(in string key) - => Key = key; - - public static implicit operator TypedKey(in string input) - => new(input); - - public static implicit operator string(in TypedKey input) - => input.Key; - - public static bool operator ==(in TypedKey left, in TypedKey right) - => left.Key == right.Key; - - public static bool operator !=(in TypedKey left, in TypedKey right) - => !(left == right); - - public override bool Equals(object? obj) - => obj is TypedKey o && o == this; - - public override int GetHashCode() - => Key?.GetHashCode() ?? 0; - - public override string ToString() - => Key; -} \ No newline at end of file diff --git a/src/EllieBot/Common/PubSub/YamlSeria.cs b/src/EllieBot/Common/PubSub/YamlSeria.cs deleted file mode 100644 index 2feb5c8..0000000 --- a/src/EllieBot/Common/PubSub/YamlSeria.cs +++ /dev/null @@ -1,39 +0,0 @@ -using EllieBot.Common.Configs; -using EllieBot.Common.Yml; -using System.Text.RegularExpressions; -using YamlDotNet.Serialization; - -namespace EllieBot.Common; - -public class YamlSeria : IConfigSeria -{ - private static readonly Regex _codePointRegex = - new(@"(\\U(?[a-zA-Z0-9]{8})|\\u(?[a-zA-Z0-9]{4})|\\x(?[a-zA-Z0-9]{2}))", - RegexOptions.Compiled); - - private readonly IDeserializer _deserializer; - private readonly ISerializer _serializer; - - public YamlSeria() - { - _serializer = Yaml.Serializer; - _deserializer = Yaml.Deserializer; - } - - public string Serialize(T obj) - where T : notnull - { - var escapedOutput = _serializer.Serialize(obj); - var output = _codePointRegex.Replace(escapedOutput, - me => - { - var str = me.Groups["code"].Value; - var newString = YamlHelper.UnescapeUnicodeCodePoint(str); - return newString; - }); - return output; - } - - public T Deserialize(string data) - => _deserializer.Deserialize(data); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/CommentAttribute.cs b/src/EllieBot/Common/Yml/CommentAttribute.cs deleted file mode 100644 index 9d3d7ec..0000000 --- a/src/EllieBot/Common/Yml/CommentAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Common.Yml; - -[AttributeUsage(AttributeTargets.Property)] -public class CommentAttribute : Attribute -{ - public string Comment { get; } - - public CommentAttribute(string comment) - => Comment = comment; -} diff --git a/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs b/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs deleted file mode 100644 index 1a81978..0000000 --- a/src/EllieBot/Common/Yml/CommentGatheringTypeInspector.cs +++ /dev/null @@ -1,65 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.TypeInspectors; - -namespace EllieBot.Common.Yml; - -public class CommentGatheringTypeInspector : TypeInspectorSkeleton -{ - private readonly ITypeInspector _innerTypeDescriptor; - - public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor) - => _innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor)); - - public override IEnumerable GetProperties(Type type, object container) - => _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d)); - - private sealed class CommentsPropertyDescriptor : IPropertyDescriptor - { - public string Name { get; } - - public Type Type - => _baseDescriptor.Type; - - public Type TypeOverride - { - get => _baseDescriptor.TypeOverride; - set => _baseDescriptor.TypeOverride = value; - } - - public int Order { get; set; } - - public ScalarStyle ScalarStyle - { - get => _baseDescriptor.ScalarStyle; - set => _baseDescriptor.ScalarStyle = value; - } - - public bool CanWrite - => _baseDescriptor.CanWrite; - - private readonly IPropertyDescriptor _baseDescriptor; - - public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor) - { - _baseDescriptor = baseDescriptor; - Name = baseDescriptor.Name; - } - - public void Write(object target, object value) - => _baseDescriptor.Write(target, value); - - public T GetCustomAttribute() - where T : Attribute - => _baseDescriptor.GetCustomAttribute(); - - public IObjectDescriptor Read(object target) - { - var comment = _baseDescriptor.GetCustomAttribute(); - return comment is not null - ? new CommentsObjectDescriptor(_baseDescriptor.Read(target), comment.Comment) - : _baseDescriptor.Read(target); - } - } -} diff --git a/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs b/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs deleted file mode 100644 index 9dc61f9..0000000 --- a/src/EllieBot/Common/Yml/CommentsObjectDescriptor.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public sealed class CommentsObjectDescriptor : IObjectDescriptor -{ - public string Comment { get; } - - public object Value - => _innerDescriptor.Value; - - public Type Type - => _innerDescriptor.Type; - - public Type StaticType - => _innerDescriptor.StaticType; - - public ScalarStyle ScalarStyle - => _innerDescriptor.ScalarStyle; - - private readonly IObjectDescriptor _innerDescriptor; - - public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment) - { - _innerDescriptor = innerDescriptor; - Comment = comment; - } -} diff --git a/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs b/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs deleted file mode 100644 index 1c89a95..0000000 --- a/src/EllieBot/Common/Yml/CommentsObjectGraphVisitor.cs +++ /dev/null @@ -1,29 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.ObjectGraphVisitors; - -namespace EllieBot.Common.Yml; - -public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor -{ - public CommentsObjectGraphVisitor(IObjectGraphVisitor nextVisitor) - : base(nextVisitor) - { - } - - public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context) - { - if (value is CommentsObjectDescriptor commentsDescriptor - && !string.IsNullOrWhiteSpace(commentsDescriptor.Comment)) - { - var parts = commentsDescriptor.Comment.Split('\n'); - - foreach (var part in parts) - context.Emit(new Comment(part.Trim(), false)); - } - - return base.EnterMapping(key, value, context); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs b/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs deleted file mode 100644 index cf9e15f..0000000 --- a/src/EllieBot/Common/Yml/MultilineScalarFlowStyleEmitter.cs +++ /dev/null @@ -1,35 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.EventEmitters; - -namespace EllieBot.Common.Yml; - -public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter -{ - public MultilineScalarFlowStyleEmitter(IEventEmitter nextEmitter) - : base(nextEmitter) - { - } - - public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter) - { - if (typeof(string).IsAssignableFrom(eventInfo.Source.Type)) - { - var value = eventInfo.Source.Value as string; - if (!string.IsNullOrEmpty(value)) - { - var isMultiLine = value.IndexOfAny(new[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0; - if (isMultiLine) - { - eventInfo = new(eventInfo.Source) - { - Style = ScalarStyle.Literal - }; - } - } - } - - nextEmitter.Emit(eventInfo, emitter); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Rgba32Converter.cs b/src/EllieBot/Common/Yml/Rgba32Converter.cs deleted file mode 100644 index 12f6cf9..0000000 --- a/src/EllieBot/Common/Yml/Rgba32Converter.cs +++ /dev/null @@ -1,47 +0,0 @@ -#nullable disable -using SixLabors.ImageSharp.PixelFormats; -using System.Globalization; -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public class Rgba32Converter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(Rgba32); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = Rgba32.ParseHex(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var color = (Rgba32)value; - var val = (uint)((color.B << 0) | (color.G << 8) | (color.R << 16)); - emitter.Emit(new Scalar(val.ToString("X6").ToLower())); - } -} - -public class CultureInfoConverter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(CultureInfo); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = new CultureInfo(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var ci = (CultureInfo)value; - emitter.Emit(new Scalar(ci.Name)); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/UriConverter.cs b/src/EllieBot/Common/Yml/UriConverter.cs deleted file mode 100644 index 66e2ca0..0000000 --- a/src/EllieBot/Common/Yml/UriConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -#nullable disable -using YamlDotNet.Core; -using YamlDotNet.Core.Events; -using YamlDotNet.Serialization; - -namespace EllieBot.Common.Yml; - -public class UriConverter : IYamlTypeConverter -{ - public bool Accepts(Type type) - => type == typeof(Uri); - - public object ReadYaml(IParser parser, Type type) - { - var scalar = parser.Consume(); - var result = new Uri(scalar.Value); - return result; - } - - public void WriteYaml(IEmitter emitter, object value, Type type) - { - var uri = (Uri)value; - emitter.Emit(new Scalar(uri.ToString())); - } -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/Yaml.cs b/src/EllieBot/Common/Yml/Yaml.cs deleted file mode 100644 index 2c65698..0000000 --- a/src/EllieBot/Common/Yml/Yaml.cs +++ /dev/null @@ -1,28 +0,0 @@ -#nullable disable -using YamlDotNet.Serialization; -using YamlDotNet.Serialization.NamingConventions; - -namespace EllieBot.Common.Yml; - -public class Yaml -{ - public static ISerializer Serializer - => new SerializerBuilder().WithTypeInspector(inner => new CommentGatheringTypeInspector(inner)) - .WithEmissionPhaseObjectGraphVisitor(args - => new CommentsObjectGraphVisitor(args.InnerVisitor)) - .WithEventEmitter(args => new MultilineScalarFlowStyleEmitter(args)) - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithIndentedSequences() - .WithTypeConverter(new Rgba32Converter()) - .WithTypeConverter(new CultureInfoConverter()) - .WithTypeConverter(new UriConverter()) - .Build(); - - public static IDeserializer Deserializer - => new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithTypeConverter(new Rgba32Converter()) - .WithTypeConverter(new CultureInfoConverter()) - .WithTypeConverter(new UriConverter()) - .IgnoreUnmatchedProperties() - .Build(); -} \ No newline at end of file diff --git a/src/EllieBot/Common/Yml/YamlHelper.cs b/src/EllieBot/Common/Yml/YamlHelper.cs deleted file mode 100644 index 25dbfd6..0000000 --- a/src/EllieBot/Common/Yml/YamlHelper.cs +++ /dev/null @@ -1,48 +0,0 @@ -#nullable disable -namespace EllieBot.Common.Yml; - -public class YamlHelper -{ - // https://github.com/aaubry/YamlDotNet/blob/0f4cc205e8b2dd8ef6589d96de32bf608a687c6f/YamlDotNet/Core/Scanner.cs#L1687 - /// - /// This is modified code from yamldotnet's repo which handles parsing unicode code points - /// it is needed as yamldotnet doesn't support unescaped unicode characters - /// - /// Unicode code point - /// Actual character - public static string UnescapeUnicodeCodePoint(string point) - { - var character = 0; - - // Scan the character value. - - foreach (var c in point) - { - if (!IsHex(c)) - return point; - - character = (character << 4) + AsHex(c); - } - - // Check the value and write the character. - - if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF) - return point; - - return char.ConvertFromUtf32(character); - } - - public static bool IsHex(char c) - => c is (>= '0' and <= '9') or (>= 'A' and <= 'F') or (>= 'a' and <= 'f'); - - public static int AsHex(char c) - { - if (c <= '9') - return c - '0'; - - if (c <= 'F') - return c - 'A' + 10; - - return c - 'a' + 10; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/EllieContext.cs b/src/EllieBot/Db/EllieContext.cs deleted file mode 100644 index b5fffda..0000000 --- a/src/EllieBot/Db/EllieContext.cs +++ /dev/null @@ -1,491 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; -using EllieBot.Db.Models; -using EllieBot.Services.Database.Models; - -// ReSharper disable UnusedAutoPropertyAccessor.Global - -namespace EllieBot.Services.Database; - -public abstract class EllieContext : DbContext -{ - public DbSet GuildConfigs { get; set; } - - public DbSet Quotes { get; set; } - public DbSet Reminders { get; set; } - public DbSet SelfAssignableRoles { get; set; } - public DbSet MusicPlaylists { get; set; } - public DbSet Expressions { get; set; } - public DbSet CurrencyTransactions { get; set; } - public DbSet WaifuUpdates { get; set; } - public DbSet WaifuItem { get; set; } - public DbSet Warnings { get; set; } - public DbSet UserXpStats { get; set; } - public DbSet Clubs { get; set; } - public DbSet ClubBans { get; set; } - public DbSet ClubApplicants { get; set; } - - - //logging - public DbSet LogSettings { get; set; } - public DbSet IgnoredVoicePresenceCHannels { get; set; } - public DbSet IgnoredLogChannels { get; set; } - - public DbSet RotatingStatus { get; set; } - public DbSet Blacklist { get; set; } - public DbSet AutoCommands { get; set; } - public DbSet RewardedUsers { get; set; } - public DbSet PlantedCurrency { get; set; } - public DbSet BanTemplates { get; set; } - public DbSet DiscordPermOverrides { get; set; } - public DbSet DiscordUser { get; set; } - public DbSet MusicPlayerSettings { get; set; } - public DbSet Repeaters { get; set; } - public DbSet Poll { get; set; } - public DbSet WaifuInfo { get; set; } - public DbSet ImageOnlyChannels { get; set; } - public DbSet NsfwBlacklistedTags { get; set; } - public DbSet AutoTranslateChannels { get; set; } - public DbSet AutoTranslateUsers { get; set; } - - public DbSet Permissions { get; set; } - - public DbSet BankUsers { get; set; } - - public DbSet ReactionRoles { get; set; } - - public DbSet Patrons { get; set; } - - public DbSet PatronQuotas { get; set; } - - public DbSet StreamOnlineMessages { get; set; } - - - #region Mandatory Provider-Specific Values - - protected abstract string CurrencyTransactionOtherIdDefaultValue { get; } - - #endregion - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - #region QUOTES - - var quoteEntity = modelBuilder.Entity(); - quoteEntity.HasIndex(x => x.GuildId); - quoteEntity.HasIndex(x => x.Keyword); - - #endregion - - #region GuildConfig - - var configEntity = modelBuilder.Entity(); - configEntity.HasIndex(c => c.GuildId) - .IsUnique(); - - configEntity.Property(x => x.VerboseErrors) - .HasDefaultValue(true); - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiSpamSetting); - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.AntiRaidSetting); - - modelBuilder.Entity() - .HasOne(x => x.AntiAltSetting) - .WithOne() - .HasForeignKey(x => x.GuildConfigId) - .OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity() - .HasAlternateKey(x => new - { - x.GuildConfigId, - x.Url - }); - - modelBuilder.Entity().HasIndex(x => x.MessageId).IsUnique(); - - modelBuilder.Entity().HasIndex(x => x.ChannelId); - - configEntity.HasIndex(x => x.WarnExpireHours).IsUnique(false); - - #endregion - - #region streamrole - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.StreamRole); - - #endregion - - #region Self Assignable Roles - - var selfassignableRolesEntity = modelBuilder.Entity(); - - selfassignableRolesEntity.HasIndex(s => new - { - s.GuildId, - s.RoleId - }) - .IsUnique(); - - selfassignableRolesEntity.Property(x => x.Group).HasDefaultValue(0); - - #endregion - - #region MusicPlaylists - - var musicPlaylistEntity = modelBuilder.Entity(); - - musicPlaylistEntity.HasMany(p => p.Songs).WithOne().OnDelete(DeleteBehavior.Cascade); - - #endregion - - #region Waifus - - var wi = modelBuilder.Entity(); - wi.HasOne(x => x.Waifu).WithOne(); - - wi.HasIndex(x => x.Price); - wi.HasIndex(x => x.ClaimerId); - // wi.HasMany(x => x.Items) - // .WithOne() - // .OnDelete(DeleteBehavior.Cascade); - - #endregion - - #region DiscordUser - - modelBuilder.Entity(du => - { - du.Property(x => x.IsClubAdmin) - .HasDefaultValue(false); - - du.Property(x => x.NotifyOnLevelUp) - .HasDefaultValue(XpNotificationLocation.None); - - du.Property(x => x.TotalXp) - .HasDefaultValue(0); - - du.Property(x => x.CurrencyAmount) - .HasDefaultValue(0); - - du.HasAlternateKey(w => w.UserId); - du.HasOne(x => x.Club) - .WithMany(x => x.Members) - .IsRequired(false) - .OnDelete(DeleteBehavior.NoAction); - - du.HasIndex(x => x.TotalXp); - du.HasIndex(x => x.CurrencyAmount); - du.HasIndex(x => x.UserId); - }); - - #endregion - - #region Warnings - - modelBuilder.Entity(warn => - { - warn.HasIndex(x => x.GuildId); - warn.HasIndex(x => x.UserId); - warn.HasIndex(x => x.DateAdded); - warn.Property(x => x.Weight).HasDefaultValue(1); - }); - - #endregion - - #region XpStats - - var xps = modelBuilder.Entity(); - xps.HasIndex(x => new - { - x.UserId, - x.GuildId - }) - .IsUnique(); - - xps.HasIndex(x => x.UserId); - xps.HasIndex(x => x.GuildId); - xps.HasIndex(x => x.Xp); - xps.HasIndex(x => x.AwardedXp); - - #endregion - - #region XpSettings - - modelBuilder.Entity().HasOne(x => x.GuildConfig).WithOne(x => x.XpSettings); - - #endregion - - #region XpRoleReward - - modelBuilder.Entity() - .HasIndex(x => new - { - x.XpSettingsId, - x.Level - }) - .IsUnique(); - - #endregion - - #region Club - - var ci = modelBuilder.Entity(); - ci.HasOne(x => x.Owner) - .WithOne() - .HasForeignKey(x => x.OwnerId) - .OnDelete(DeleteBehavior.SetNull); - - ci.HasAlternateKey(x => new - { - x.Name - }); - - #endregion - - #region ClubManytoMany - - modelBuilder.Entity() - .HasKey(t => new - { - t.ClubId, - t.UserId - }); - - modelBuilder.Entity() - .HasOne(pt => pt.User) - .WithMany(); - - modelBuilder.Entity() - .HasOne(pt => pt.Club) - .WithMany(x => x.Applicants); - - modelBuilder.Entity() - .HasKey(t => new - { - t.ClubId, - t.UserId - }); - - modelBuilder.Entity() - .HasOne(pt => pt.User) - .WithMany(); - - modelBuilder.Entity() - .HasOne(pt => pt.Club) - .WithMany(x => x.Bans); - - #endregion - - #region Polls - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - - #endregion - - #region CurrencyTransactions - - modelBuilder.Entity(e => - { - e.HasIndex(x => x.UserId) - .IsUnique(false); - - e.Property(x => x.OtherId) - .HasDefaultValueSql(CurrencyTransactionOtherIdDefaultValue); - - e.Property(x => x.Type) - .IsRequired(); - - e.Property(x => x.Extra) - .IsRequired(); - }); - - #endregion - - #region Reminders - - modelBuilder.Entity().HasIndex(x => x.When); - - #endregion - - #region GroupName - - modelBuilder.Entity() - .HasIndex(x => new - { - x.GuildConfigId, - x.Number - }) - .IsUnique(); - - modelBuilder.Entity() - .HasOne(x => x.GuildConfig) - .WithMany(x => x.SelfAssignableRoleGroupNames) - .IsRequired(); - - #endregion - - #region BanTemplate - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - modelBuilder.Entity() - .Property(x => x.PruneDays) - .HasDefaultValue(null) - .IsRequired(false); - - #endregion - - #region Perm Override - - modelBuilder.Entity() - .HasIndex(x => new - { - x.GuildId, - x.Command - }) - .IsUnique(); - - #endregion - - #region Music - - modelBuilder.Entity().HasIndex(x => x.GuildId).IsUnique(); - - modelBuilder.Entity().Property(x => x.Volume).HasDefaultValue(100); - - #endregion - - #region Reaction roles - - modelBuilder.Entity(rr2 => - { - rr2.HasIndex(x => x.GuildId) - .IsUnique(false); - - rr2.HasIndex(x => new - { - x.MessageId, - x.Emote - }) - .IsUnique(); - }); - - #endregion - - #region LogSettings - - modelBuilder.Entity(ls => ls.HasIndex(x => x.GuildId).IsUnique()); - - modelBuilder.Entity(ls => ls - .HasMany(x => x.LogIgnores) - .WithOne(x => x.LogSetting) - .OnDelete(DeleteBehavior.Cascade)); - - modelBuilder.Entity(ili => ili - .HasIndex(x => new - { - x.LogSettingId, - x.LogItemId, - x.ItemType - }) - .IsUnique()); - - #endregion - - modelBuilder.Entity(ioc => ioc.HasIndex(x => x.ChannelId).IsUnique()); - - modelBuilder.Entity(nbt => nbt.HasIndex(x => x.GuildId).IsUnique(false)); - - var atch = modelBuilder.Entity(); - atch.HasIndex(x => x.GuildId).IsUnique(false); - - atch.HasIndex(x => x.ChannelId).IsUnique(); - - atch.HasMany(x => x.Users).WithOne(x => x.Channel).OnDelete(DeleteBehavior.Cascade); - - modelBuilder.Entity(atu => atu.HasAlternateKey(x => new - { - x.ChannelId, - x.UserId - })); - - #region BANK - - modelBuilder.Entity(bu => bu.HasIndex(x => x.UserId).IsUnique()); - - #endregion - - - #region Patron - - // currency rewards - var pr = modelBuilder.Entity(); - pr.HasIndex(x => x.PlatformUserId).IsUnique(); - - // patrons - // patrons are not identified by their user id, but by their platform user id - // as multiple accounts (even maybe on different platforms) could have - // the same account connected to them - modelBuilder.Entity(pu => - { - pu.HasIndex(x => x.UniquePlatformUserId).IsUnique(); - pu.HasKey(x => x.UserId); - }); - - // quotes are per user id - modelBuilder.Entity(pq => - { - pq.HasIndex(x => x.UserId).IsUnique(false); - pq.HasKey(x => new - { - x.UserId, - x.FeatureType, - x.Feature - }); - }); - - #endregion - - #region Xp Item Shop - - modelBuilder.Entity( - x => - { - // user can own only one of each item - x.HasIndex(model => new - { - model.UserId, - model.ItemType, - model.ItemKey - }) - .IsUnique(); - }); - - #endregion - - #region AutoPublish - - modelBuilder.Entity(apc => apc - .HasIndex(x => x.GuildId) - .IsUnique()); - - #endregion - - #region GamblingStats - - modelBuilder.Entity(gs => gs - .HasIndex(x => x.Feature) - .IsUnique()); - - #endregion - } - -#if DEBUG - private static readonly ILoggerFactory _debugLoggerFactory = LoggerFactory.Create(x => x.AddConsole()); - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseLoggerFactory(_debugLoggerFactory); -#endif -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ClubExtensions.cs b/src/EllieBot/Db/Extensions/ClubExtensions.cs deleted file mode 100644 index 88a851b..0000000 --- a/src/EllieBot/Db/Extensions/ClubExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; - -namespace EllieBot.Db; - -public static class ClubExtensions -{ - private static IQueryable Include(this DbSet clubs) - => clubs.Include(x => x.Owner) - .Include(x => x.Applicants) - .ThenInclude(x => x.User) - .Include(x => x.Bans) - .ThenInclude(x => x.User) - .Include(x => x.Members) - .AsQueryable(); - - public static ClubInfo GetByOwner(this DbSet clubs, ulong userId) - => Include(clubs).FirstOrDefault(c => c.Owner.UserId == userId); - - public static ClubInfo GetByOwnerOrAdmin(this DbSet clubs, ulong userId) - => Include(clubs) - .FirstOrDefault(c => c.Owner.UserId == userId || c.Members.Any(u => u.UserId == userId && u.IsClubAdmin)); - - public static ClubInfo GetByMember(this DbSet clubs, ulong userId) - => Include(clubs).FirstOrDefault(c => c.Members.Any(u => u.UserId == userId)); - - public static ClubInfo GetByName(this DbSet clubs, string name) - => Include(clubs) - .FirstOrDefault(c => c.Name == name); - - public static List GetClubLeaderboardPage(this DbSet clubs, int page) - => clubs.AsNoTracking().OrderByDescending(x => x.Xp).Skip(page * 9).Take(9).ToList(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs b/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs deleted file mode 100644 index 4bd2439..0000000 --- a/src/EllieBot/Db/Extensions/CurrencyTransactionExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class CurrencyTransactionExtensions -{ - public static Task> GetPageFor( - this DbSet set, - ulong userId, - int page) - => set.ToLinqToDBTable() - .Where(x => x.UserId == userId) - .OrderByDescending(x => x.DateAdded) - .Skip(15 * page) - .Take(15) - .ToListAsyncLinqToDB(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DbExtensions.cs b/src/EllieBot/Db/Extensions/DbExtensions.cs deleted file mode 100644 index 568643b..0000000 --- a/src/EllieBot/Db/Extensions/DbExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class DbExtensions -{ - public static T GetById(this DbSet set, int id) - where T : DbEntity - => set.FirstOrDefault(x => x.Id == id); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs b/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs deleted file mode 100644 index 8d94814..0000000 --- a/src/EllieBot/Db/Extensions/DiscordUserExtensions.cs +++ /dev/null @@ -1,179 +0,0 @@ -#nullable disable -using LinqToDB; -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using System.Collections.Immutable; - -namespace EllieBot.Db; - -public static class DiscordUserExtensions -{ - /// - /// Adds the specified to the database. If a database user with placeholder name - /// and discriminator is present in , their name and discriminator get updated accordingly. - /// - /// This database context. - /// The users to add or update in the database. - /// A tuple with the amount of new users added and old users updated. - public static async Task<(long UsersAdded, long UsersUpdated)> RefreshUsersAsync(this EllieContext ctx, List users) - { - var presentDbUsers = await ctx.DiscordUser - .Select(x => new { x.UserId, x.Username, x.Discriminator }) - .Where(x => users.Select(y => y.Id).Contains(x.UserId)) - .ToArrayAsyncEF(); - - var usersToAdd = users - .Where(x => !presentDbUsers.Select(x => x.UserId).Contains(x.Id)) - .Select(x => new DiscordUser() - { - UserId = x.Id, - AvatarId = x.AvatarId, - Username = x.Username, - Discriminator = x.Discriminator - }); - - var added = (await ctx.BulkCopyAsync(usersToAdd)).RowsCopied; - var toUpdateUserIds = presentDbUsers - .Where(x => x.Username == "Unknown" && x.Discriminator == "????") - .Select(x => x.UserId) - .ToArray(); - - foreach (var user in users.Where(x => toUpdateUserIds.Contains(x.Id))) - { - await ctx.DiscordUser - .Where(x => x.UserId == user.Id) - .UpdateAsync(x => new DiscordUser() - { - Username = user.Username, - Discriminator = user.Discriminator, - - // .award tends to set AvatarId and DateAdded to NULL, so account for that. - AvatarId = user.AvatarId, - DateAdded = x.DateAdded ?? DateTime.UtcNow - }); - } - - return (added, toUpdateUserIds.Length); - } - - public static Task GetByUserIdAsync( - this IQueryable set, - ulong userId) - => set.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId); - - public static void EnsureUserCreated( - this EllieContext ctx, - ulong userId, - string username, - string discrim, - string avatarId) - => ctx.DiscordUser.ToLinqToDBTable() - .InsertOrUpdate( - () => new() - { - UserId = userId, - Username = username, - Discriminator = discrim, - AvatarId = avatarId, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - Username = username, - Discriminator = discrim, - AvatarId = avatarId - }, - () => new() - { - UserId = userId - }); - - public static Task EnsureUserCreatedAsync( - this EllieContext ctx, - ulong userId) - => ctx.DiscordUser - .ToLinqToDBTable() - .InsertOrUpdateAsync( - () => new() - { - UserId = userId, - Username = "Unknown", - Discriminator = "????", - AvatarId = string.Empty, - TotalXp = 0, - CurrencyAmount = 0 - }, - old => new() - { - - }, - () => new() - { - UserId = userId - }); - - //temp is only used in updatecurrencystate, so that i don't overwrite real usernames/discrims with Unknown - public static DiscordUser GetOrCreateUser( - this EllieContext ctx, - ulong userId, - string username, - string discrim, - string avatarId, - Func, IQueryable> includes = null) - { - ctx.EnsureUserCreated(userId, username, discrim, avatarId); - - IQueryable queryable = ctx.DiscordUser; - if (includes is not null) - queryable = includes(queryable); - return queryable.First(u => u.UserId == userId); - } - - public static DiscordUser GetOrCreateUser(this EllieContext ctx, IUser original, Func, IQueryable> includes = null) - => ctx.GetOrCreateUser(original.Id, original.Username, original.Discriminator, original.AvatarId, includes); - - public static int GetUserGlobalRank(this DbSet users, ulong id) - => users.AsQueryable() - .Where(x => x.TotalXp - > users.AsQueryable().Where(y => y.UserId == id).Select(y => y.TotalXp).FirstOrDefault()) - .Count() - + 1; - - public static DiscordUser[] GetUsersXpLeaderboardFor(this DbSet users, int page) - => users.AsQueryable().OrderByDescending(x => x.TotalXp).Skip(page * 9).Take(9).AsEnumerable().ToArray(); - - public static List GetTopRichest( - this DbSet users, - ulong botId, - int count, - int page = 0) - => users.AsQueryable() - .Where(c => c.CurrencyAmount > 0 && botId != c.UserId) - .OrderByDescending(c => c.CurrencyAmount) - .Skip(page * 9) - .Take(count) - .ToList(); - - public static async Task GetUserCurrencyAsync(this DbSet users, ulong userId) - => (await users.FirstOrDefaultAsyncLinqToDB(x => x.UserId == userId))?.CurrencyAmount ?? 0; - - public static void RemoveFromMany(this DbSet users, IEnumerable ids) - { - var items = users.AsQueryable().Where(x => ids.Contains(x.UserId)); - foreach (var item in items) - item.CurrencyAmount = 0; - } - - public static decimal GetTotalCurrency(this DbSet users) - => users.Sum((Func)(x => x.CurrencyAmount)); - - public static decimal GetTopOnePercentCurrency(this DbSet users, ulong botId) - => users.AsQueryable() - .Where(x => x.UserId != botId) - .OrderByDescending(x => x.CurrencyAmount) - .Take(users.Count() / 100 == 0 ? 1 : users.Count() / 100) - .Sum(x => x.CurrencyAmount); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs b/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs deleted file mode 100644 index 658a631..0000000 --- a/src/EllieBot/Db/Extensions/EllieExpressionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -using LinqToDB; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class EllieExpressionExtensions -{ - public static int ClearFromGuild(this DbSet exprs, ulong guildId) - => exprs.Delete(x => x.GuildId == guildId); - - public static IEnumerable ForId(this DbSet exprs, ulong id) - => exprs.AsNoTracking().AsQueryable().Where(x => x.GuildId == id).ToList(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs b/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs deleted file mode 100644 index 2b6272a..0000000 --- a/src/EllieBot/Db/Extensions/GuildConfigExtensions.cs +++ /dev/null @@ -1,227 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class GuildConfigExtensions -{ - private static List DefaultWarnPunishments - => new() - { - new() - { - Count = 3, - Punishment = PunishmentAction.Kick - }, - new() - { - Count = 5, - Punishment = PunishmentAction.Ban - } - }; - - /// - /// Gets full stream role settings for the guild with the specified id. - /// - /// Db Context - /// Id of the guild to get stream role settings for. - /// Guild'p stream role settings - public static StreamRoleSettings GetStreamRoleSettings(this EllieContext ctx, ulong guildId) - { - var conf = ctx.GuildConfigsForId(guildId, - set => set.Include(y => y.StreamRole) - .Include(y => y.StreamRole.Whitelist) - .Include(y => y.StreamRole.Blacklist)); - - if (conf.StreamRole is null) - conf.StreamRole = new(); - - return conf.StreamRole; - } - - private static IQueryable IncludeEverything(this DbSet configs) - => configs.AsQueryable() - .AsSplitQuery() - .Include(gc => gc.CommandCooldowns) - .Include(gc => gc.FollowedStreams) - .Include(gc => gc.StreamRole) - .Include(gc => gc.XpSettings) - .ThenInclude(x => x.ExclusionList) - .Include(gc => gc.DelMsgOnCmdChannels); - - public static IEnumerable GetAllGuildConfigs( - this DbSet configs, - List availableGuilds) - => configs.IncludeEverything().AsNoTracking().Where(x => availableGuilds.Contains(x.GuildId)).ToList(); - - /// - /// Gets and creates if it doesn't exist a config for a guild. - /// - /// Context - /// Id of the guide - /// Use to manipulate the set however you want. Pass null to include everything - /// Config for the guild - public static GuildConfig GuildConfigsForId( - this EllieContext ctx, - ulong guildId, - Func, IQueryable> includes) - { - GuildConfig config; - - if (includes is null) - config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId); - else - { - var set = includes(ctx.GuildConfigs); - config = set.FirstOrDefault(c => c.GuildId == guildId); - } - - if (config is null) - { - ctx.GuildConfigs.Add(config = new() - { - GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist, - WarningsInitialized = true, - WarnPunishments = DefaultWarnPunishments - }); - ctx.SaveChanges(); - } - - if (!config.WarningsInitialized) - { - config.WarningsInitialized = true; - config.WarnPunishments = DefaultWarnPunishments; - } - - return config; - - // ctx.GuildConfigs - // .ToLinqToDBTable() - // .InsertOrUpdate(() => new() - // { - // GuildId = guildId, - // Permissions = Permissionv2.GetDefaultPermlist, - // WarningsInitialized = true, - // WarnPunishments = DefaultWarnPunishments - // }, - // _ => new(), - // () => new() - // { - // GuildId = guildId - // }); - // - // if(includes is null) - // return ctx.GuildConfigs - // .ToLinqToDBTable() - // .First(x => x.GuildId == guildId); - } - - public static LogSetting LogSettingsFor(this EllieContext ctx, ulong guildId) - { - var logSetting = ctx.LogSettings.AsQueryable() - .Include(x => x.LogIgnores) - .Where(x => x.GuildId == guildId) - .FirstOrDefault(); - - if (logSetting is null) - { - ctx.LogSettings.Add(logSetting = new() - { - GuildId = guildId - }); - ctx.SaveChanges(); - } - - return logSetting; - } - - public static IEnumerable PermissionsForAll(this DbSet configs, List include) - { - var query = configs.AsQueryable().Where(x => include.Contains(x.GuildId)).Include(gc => gc.Permissions); - - return query.ToList(); - } - - public static GuildConfig GcWithPermissionsFor(this EllieContext ctx, ulong guildId) - { - var config = ctx.GuildConfigs.AsQueryable() - .Where(gc => gc.GuildId == guildId) - .Include(gc => gc.Permissions) - .FirstOrDefault(); - - if (config is null) // if there is no guildconfig, create new one - { - ctx.GuildConfigs.Add(config = new() - { - GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist - }); - ctx.SaveChanges(); - } - else if (config.Permissions is null || !config.Permissions.Any()) // if no perms, add default ones - { - config.Permissions = Permissionv2.GetDefaultPermlist; - ctx.SaveChanges(); - } - - return config; - } - - public static IEnumerable GetFollowedStreams(this DbSet configs) - => configs.AsQueryable().Include(x => x.FollowedStreams).SelectMany(gc => gc.FollowedStreams).ToArray(); - - public static IEnumerable GetFollowedStreams(this DbSet configs, List included) - => configs.AsQueryable() - .Where(gc => included.Contains(gc.GuildId)) - .Include(gc => gc.FollowedStreams) - .SelectMany(gc => gc.FollowedStreams) - .ToList(); - - public static void SetCleverbotEnabled(this DbSet configs, ulong id, bool cleverbotEnabled) - { - var conf = configs.FirstOrDefault(gc => gc.GuildId == id); - - if (conf is null) - return; - - conf.CleverbotEnabled = cleverbotEnabled; - } - - public static XpSettings XpSettingsFor(this EllieContext ctx, ulong guildId) - { - var gc = ctx.GuildConfigsForId(guildId, - set => set.Include(x => x.XpSettings) - .ThenInclude(x => x.RoleRewards) - .Include(x => x.XpSettings) - .ThenInclude(x => x.CurrencyRewards) - .Include(x => x.XpSettings) - .ThenInclude(x => x.ExclusionList)); - - if (gc.XpSettings is null) - gc.XpSettings = new(); - - return gc.XpSettings; - } - - public static IEnumerable GetGeneratingChannels(this DbSet configs) - => configs.AsQueryable() - .Include(x => x.GenerateCurrencyChannelIds) - .Where(x => x.GenerateCurrencyChannelIds.Any()) - .SelectMany(x => x.GenerateCurrencyChannelIds) - .Select(x => new GeneratingChannel - { - ChannelId = x.ChannelId, - GuildId = x.GuildConfig.GuildId - }) - .ToArray(); - - public class GeneratingChannel - { - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs deleted file mode 100644 index d8a3d12..0000000 --- a/src/EllieBot/Db/Extensions/MusicPlayerSettingsExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class MusicPlayerSettingsExtensions -{ - public static async Task ForGuildAsync(this DbSet settings, ulong guildId) - { - var toReturn = await settings.AsQueryable().FirstOrDefaultAsync(x => x.GuildId == guildId); - - if (toReturn is null) - { - var newSettings = new MusicPlayerSettings - { - GuildId = guildId, - PlayerRepeat = PlayerRepeatType.Queue - }; - - await settings.AddAsync(newSettings); - return newSettings; - } - - return toReturn; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs b/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs deleted file mode 100644 index e7ac6aa..0000000 --- a/src/EllieBot/Db/Extensions/MusicPlaylistExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class MusicPlaylistExtensions -{ - public static List GetPlaylistsOnPage(this DbSet playlists, int num) - { - if (num < 1) - throw new ArgumentOutOfRangeException(nameof(num)); - - return playlists.AsQueryable().Skip((num - 1) * 20).Take(20).Include(pl => pl.Songs).ToList(); - } - - public static MusicPlaylist GetWithSongs(this DbSet playlists, int id) - => playlists.Include(mpl => mpl.Songs).FirstOrDefault(mpl => mpl.Id == id); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/PollExtensions.cs b/src/EllieBot/Db/Extensions/PollExtensions.cs deleted file mode 100644 index 8491d65..0000000 --- a/src/EllieBot/Db/Extensions/PollExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class PollExtensions -{ - public static IEnumerable GetAllPolls(this DbSet polls) - => polls.Include(x => x.Answers).Include(x => x.Votes).ToArray(); - - public static void RemovePoll(this EllieContext ctx, int id) - { - var p = ctx.Poll.Include(x => x.Answers).Include(x => x.Votes).FirstOrDefault(x => x.Id == id); - - if (p is null) - return; - - if (p.Votes is not null) - { - ctx.RemoveRange(p.Votes); - p.Votes.Clear(); - } - - if (p.Answers is not null) - { - ctx.RemoveRange(p.Answers); - p.Answers.Clear(); - } - - ctx.Poll.Remove(p); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/QuoteExtensions.cs b/src/EllieBot/Db/Extensions/QuoteExtensions.cs deleted file mode 100644 index 59cae90..0000000 --- a/src/EllieBot/Db/Extensions/QuoteExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class QuoteExtensions -{ - public static IEnumerable GetForGuild(this DbSet quotes, ulong guildId) - => quotes.AsQueryable().Where(x => x.GuildId == guildId); - - public static IReadOnlyCollection GetGroup( - this DbSet quotes, - ulong guildId, - int page, - OrderType order) - { - var q = quotes.AsQueryable().Where(x => x.GuildId == guildId); - if (order == OrderType.Keyword) - q = q.OrderBy(x => x.Keyword); - else - q = q.OrderBy(x => x.Id); - - return q.Skip(15 * page).Take(15).ToArray(); - } - - public static async Task GetRandomQuoteByKeywordAsync( - this DbSet quotes, - ulong guildId, - string keyword) - { - var rng = new EllieRandom(); - return (await quotes.AsQueryable().Where(q => q.GuildId == guildId && q.Keyword == keyword).ToListAsync()) - .OrderBy(_ => rng.Next()) - .FirstOrDefault(); - } - - public static async Task SearchQuoteKeywordTextAsync( - this DbSet quotes, - ulong guildId, - string keyword, - string text) - { - var rngk = new EllieRandom(); - return (await quotes.AsQueryable() - .Where(q => q.GuildId == guildId - && (keyword == null || q.Keyword == keyword) - && (EF.Functions.Like(q.Text.ToUpper(), $"%{text.ToUpper()}%") - || EF.Functions.Like(q.AuthorName, text))) - .ToListAsync()) - .OrderBy(_ => rngk.Next()) - .FirstOrDefault(); - } - - public static void RemoveAllByKeyword(this DbSet quotes, ulong guildId, string keyword) - => quotes.RemoveRange(quotes.AsQueryable().Where(x => x.GuildId == guildId && x.Keyword.ToUpper() == keyword)); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/ReminderExtensions.cs b/src/EllieBot/Db/Extensions/ReminderExtensions.cs deleted file mode 100644 index 1fd519f..0000000 --- a/src/EllieBot/Db/Extensions/ReminderExtensions.cs +++ /dev/null @@ -1,23 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class ReminderExtensions -{ - public static IEnumerable GetIncludedReminders( - this DbSet reminders, - IEnumerable guildIds) - => reminders.AsQueryable().Where(x => guildIds.Contains(x.ServerId) || x.ServerId == 0).ToList(); - - public static IEnumerable RemindersFor(this DbSet reminders, ulong userId, int page) - => reminders.AsQueryable().Where(x => x.UserId == userId).OrderBy(x => x.DateAdded).Skip(page * 10).Take(10); - - public static IEnumerable RemindersForServer(this DbSet reminders, ulong serverId, int page) - => reminders.AsQueryable() - .Where(x => x.ServerId == serverId) - .OrderBy(x => x.DateAdded) - .Skip(page * 10) - .Take(10); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs b/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs deleted file mode 100644 index b2e3e39..0000000 --- a/src/EllieBot/Db/Extensions/SelfAssignableRolesExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class SelfAssignableRolesExtensions -{ - public static bool DeleteByGuildAndRoleId(this DbSet roles, ulong guildId, ulong roleId) - { - var role = roles.FirstOrDefault(s => s.GuildId == guildId && s.RoleId == roleId); - - if (role is null) - return false; - - roles.Remove(role); - return true; - } - - public static IReadOnlyCollection GetFromGuild(this DbSet roles, ulong guildId) - => roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/UserXpExtensions.cs b/src/EllieBot/Db/Extensions/UserXpExtensions.cs deleted file mode 100644 index a20071b..0000000 --- a/src/EllieBot/Db/Extensions/UserXpExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -#nullable disable -using LinqToDB; -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class UserXpExtensions -{ - public static UserXpStats GetOrCreateUserXpStats(this EllieContext ctx, ulong guildId, ulong userId) - { - var usr = ctx.UserXpStats.FirstOrDefault(x => x.UserId == userId && x.GuildId == guildId); - - if (usr is null) - { - ctx.Add(usr = new() - { - Xp = 0, - UserId = userId, - NotifyOnLevelUp = XpNotificationLocation.None, - GuildId = guildId - }); - } - - return usr; - } - - public static List GetUsersFor(this DbSet xps, ulong guildId, int page) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Skip(page * 9) - .Take(9) - .ToList(); - - public static List GetTopUserXps(this DbSet xps, ulong guildId, int count) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId) - .OrderByDescending(x => x.Xp + x.AwardedXp) - .Take(count) - .ToList(); - - public static int GetUserGuildRanking(this DbSet xps, ulong userId, ulong guildId) - => xps.AsQueryable() - .AsNoTracking() - .Where(x => x.GuildId == guildId - && x.Xp + x.AwardedXp - > xps.AsQueryable() - .Where(y => y.UserId == userId && y.GuildId == guildId) - .Select(y => y.Xp + y.AwardedXp) - .FirstOrDefault()) - .Count() - + 1; - - public static void ResetGuildUserXp(this DbSet xps, ulong userId, ulong guildId) - => xps.Delete(x => x.UserId == userId && x.GuildId == guildId); - - public static void ResetGuildXp(this DbSet xps, ulong guildId) - => xps.Delete(x => x.GuildId == guildId); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WaifuExtensions.cs b/src/EllieBot/Db/Extensions/WaifuExtensions.cs deleted file mode 100644 index 97d9cf4..0000000 --- a/src/EllieBot/Db/Extensions/WaifuExtensions.cs +++ /dev/null @@ -1,145 +0,0 @@ -#nullable disable -using LinqToDB; -using LinqToDB.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; -using EllieBot.Services.Database; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public class WaifuInfoStats -{ - public int WaifuId { get; init; } - public string FullName { get; init; } - public long Price { get; init; } - public string ClaimerName { get; init; } - public string AffinityName { get; init; } - public int AffinityCount { get; init; } - public int DivorceCount { get; init; } - public int ClaimCount { get; init; } -} - -public static class WaifuExtensions -{ - public static WaifuInfo ByWaifuUserId( - this DbSet waifus, - ulong userId, - Func, IQueryable> includes = null) - { - if (includes is null) - { - return waifus.Include(wi => wi.Waifu) - .Include(wi => wi.Affinity) - .Include(wi => wi.Claimer) - .Include(wi => wi.Items) - .FirstOrDefault(wi => wi.Waifu.UserId == userId); - } - - return includes(waifus).AsQueryable().FirstOrDefault(wi => wi.Waifu.UserId == userId); - } - - public static IEnumerable GetTop(this DbSet waifus, int count, int skip = 0) - { - if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count)); - if (count == 0) - return new List(); - - return waifus.Include(wi => wi.Waifu) - .Include(wi => wi.Affinity) - .Include(wi => wi.Claimer) - .OrderByDescending(wi => wi.Price) - .Skip(skip) - .Take(count) - .Select(x => new WaifuLbResult - { - Affinity = x.Affinity == null ? null : x.Affinity.Username, - AffinityDiscrim = x.Affinity == null ? null : x.Affinity.Discriminator, - Claimer = x.Claimer == null ? null : x.Claimer.Username, - ClaimerDiscrim = x.Claimer == null ? null : x.Claimer.Discriminator, - Username = x.Waifu.Username, - Discrim = x.Waifu.Discriminator, - Price = x.Price - }) - .ToList(); - } - - public static decimal GetTotalValue(this DbSet waifus) - => waifus.AsQueryable().Where(x => x.ClaimerId != null).Sum(x => x.Price); - - public static ulong GetWaifuUserId(this DbSet waifus, ulong ownerId, string name) - => waifus.AsQueryable() - .AsNoTracking() - .Where(x => x.Claimer.UserId == ownerId && x.Waifu.Username + "#" + x.Waifu.Discriminator == name) - .Select(x => x.Waifu.UserId) - .FirstOrDefault(); - - public static async Task GetWaifuInfoAsync(this EllieContext ctx, ulong userId) - { - await ctx.WaifuInfo - .ToLinqToDBTable() - .InsertOrUpdateAsync(() => new() - { - AffinityId = null, - ClaimerId = null, - Price = 1, - WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() - }, - _ => new(), - () => new() - { - WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First() - }); - - var toReturn = ctx.WaifuInfo.AsQueryable() - .Where(w => w.WaifuId - == ctx.Set() - .AsQueryable() - .Where(u => u.UserId == userId) - .Select(u => u.Id) - .FirstOrDefault()) - .Select(w => new WaifuInfoStats - { - WaifuId = w.WaifuId, - FullName = - ctx.Set() - .AsQueryable() - .Where(u => u.UserId == userId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - AffinityCount = - ctx.Set() - .AsQueryable() - .Count(x => x.UserId == w.WaifuId - && x.UpdateType == WaifuUpdateType.AffinityChanged - && x.NewId != null), - AffinityName = - ctx.Set() - .AsQueryable() - .Where(u => u.Id == w.AffinityId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - ClaimCount = ctx.WaifuInfo.AsQueryable().Count(x => x.ClaimerId == w.WaifuId), - ClaimerName = - ctx.Set() - .AsQueryable() - .Where(u => u.Id == w.ClaimerId) - .Select(u => u.Username + "#" + u.Discriminator) - .FirstOrDefault(), - DivorceCount = - ctx.Set() - .AsQueryable() - .Count(x => x.OldId == w.WaifuId - && x.NewId == null - && x.UpdateType == WaifuUpdateType.Claimed), - Price = w.Price, - }) - .FirstOrDefault(); - - if (toReturn is null) - return null; - - return toReturn; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Extensions/WarningExtensions.cs b/src/EllieBot/Db/Extensions/WarningExtensions.cs deleted file mode 100644 index 76d0815..0000000 --- a/src/EllieBot/Db/Extensions/WarningExtensions.cs +++ /dev/null @@ -1,60 +0,0 @@ -#nullable disable -using Microsoft.EntityFrameworkCore; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db; - -public static class WarningExtensions -{ - public static Warning[] ForId(this DbSet warnings, ulong guildId, ulong userId) - { - var query = warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .OrderByDescending(x => x.DateAdded); - - return query.ToArray(); - } - - public static bool Forgive( - this DbSet warnings, - ulong guildId, - ulong userId, - string mod, - int index) - { - if (index < 0) - throw new ArgumentOutOfRangeException(nameof(index)); - - var warn = warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .OrderByDescending(x => x.DateAdded) - .Skip(index) - .FirstOrDefault(); - - if (warn is null || warn.Forgiven) - return false; - - warn.Forgiven = true; - warn.ForgivenBy = mod; - return true; - } - - public static async Task ForgiveAll( - this DbSet warnings, - ulong guildId, - ulong userId, - string mod) - => await warnings.AsQueryable() - .Where(x => x.GuildId == guildId && x.UserId == userId) - .ForEachAsync(x => - { - if (x.Forgiven != true) - { - x.Forgiven = true; - x.ForgivenBy = mod; - } - }); - - public static Warning[] GetForGuild(this DbSet warnings, ulong id) - => warnings.AsQueryable().Where(x => x.GuildId == id).ToArray(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AntiProtection.cs b/src/EllieBot/Db/Models/AntiProtection.cs deleted file mode 100644 index 8539496..0000000 --- a/src/EllieBot/Db/Models/AntiProtection.cs +++ /dev/null @@ -1,65 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AntiRaidSetting : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public int UserThreshold { get; set; } - public int Seconds { get; set; } - public PunishmentAction Action { get; set; } - - /// - /// Duration of the punishment, in minutes. This works only for supported Actions, like: - /// Mute, Chatmute, Voicemute, etc... - /// - public int PunishDuration { get; set; } -} - -public class AntiSpamSetting : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public PunishmentAction Action { get; set; } - public int MessageThreshold { get; set; } = 3; - public int MuteTime { get; set; } - public ulong? RoleId { get; set; } - public HashSet IgnoredChannels { get; set; } = new(); -} - -public class AntiAltSetting -{ - public int Id { get; set; } - public int GuildConfigId { get; set; } - public TimeSpan MinAge { get; set; } - public PunishmentAction Action { get; set; } - public int ActionDurationMinutes { get; set; } - public ulong? RoleId { get; set; } -} - -public enum PunishmentAction -{ - Mute, - Kick, - Ban, - Softban, - RemoveRoles, - ChatMute, - VoiceMute, - AddRole, - Warn, - TimeOut -} - -public class AntiSpamIgnore : DbEntity -{ - public ulong ChannelId { get; set; } - - public override int GetHashCode() - => ChannelId.GetHashCode(); - - public override bool Equals(object obj) - => obj is AntiSpamIgnore inst ? inst.ChannelId == ChannelId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoCommand.cs b/src/EllieBot/Db/Models/AutoCommand.cs deleted file mode 100644 index 8bcae05..0000000 --- a/src/EllieBot/Db/Models/AutoCommand.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoCommand : DbEntity -{ - public string CommandText { get; set; } - public ulong ChannelId { get; set; } - public string ChannelName { get; set; } - public ulong? GuildId { get; set; } - public string GuildName { get; set; } - public ulong? VoiceChannelId { get; set; } - public string VoiceChannelName { get; set; } - public int Interval { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoPublishChannel.cs b/src/EllieBot/Db/Models/AutoPublishChannel.cs deleted file mode 100644 index a19fd28..0000000 --- a/src/EllieBot/Db/Models/AutoPublishChannel.cs +++ /dev/null @@ -1,9 +0,0 @@ -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class AutoPublishChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateChannel.cs b/src/EllieBot/Db/Models/AutoTranslateChannel.cs deleted file mode 100644 index 6f6ef58..0000000 --- a/src/EllieBot/Db/Models/AutoTranslateChannel.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoTranslateChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public bool AutoDelete { get; set; } - public IList Users { get; set; } = new List(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/AutoTranslateUser.cs b/src/EllieBot/Db/Models/AutoTranslateUser.cs deleted file mode 100644 index 6e36404..0000000 --- a/src/EllieBot/Db/Models/AutoTranslateUser.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class AutoTranslateUser : DbEntity -{ - public int ChannelId { get; set; } - public AutoTranslateChannel Channel { get; set; } - public ulong UserId { get; set; } - public string Source { get; set; } - public string Target { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BanTemplate.cs b/src/EllieBot/Db/Models/BanTemplate.cs deleted file mode 100644 index d32f4c7..0000000 --- a/src/EllieBot/Db/Models/BanTemplate.cs +++ /dev/null @@ -1,9 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class BanTemplate : DbEntity -{ - public ulong GuildId { get; set; } - public string Text { get; set; } - public int? PruneDays { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BankUser.cs b/src/EllieBot/Db/Models/BankUser.cs deleted file mode 100644 index 7fa6418..0000000 --- a/src/EllieBot/Db/Models/BankUser.cs +++ /dev/null @@ -1,9 +0,0 @@ -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class BankUser : DbEntity -{ - public ulong UserId { get; set; } - public long Balance { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/BlacklistEntry.cs b/src/EllieBot/Db/Models/BlacklistEntry.cs deleted file mode 100644 index 3ecf999..0000000 --- a/src/EllieBot/Db/Models/BlacklistEntry.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class BlacklistEntry : DbEntity -{ - public ulong ItemId { get; set; } - public BlacklistType Type { get; set; } -} - -public enum BlacklistType -{ - Server, - Channel, - User -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ClubInfo.cs b/src/EllieBot/Db/Models/ClubInfo.cs deleted file mode 100644 index 8c8f85c..0000000 --- a/src/EllieBot/Db/Models/ClubInfo.cs +++ /dev/null @@ -1,42 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Db.Models; - -public class ClubInfo : DbEntity -{ - [MaxLength(20)] - public string Name { get; set; } - public string Description { get; set; } - public string ImageUrl { get; set; } = string.Empty; - - public int Xp { get; set; } = 0; - public int? OwnerId { get; set; } - public DiscordUser Owner { get; set; } - - public List Members { get; set; } = new(); - public List Applicants { get; set; } = new(); - public List Bans { get; set; } = new(); - - public override string ToString() - => Name; -} - -public class ClubApplicants -{ - public int ClubId { get; set; } - public ClubInfo Club { get; set; } - - public int UserId { get; set; } - public DiscordUser User { get; set; } -} - -public class ClubBans -{ - public int ClubId { get; set; } - public ClubInfo Club { get; set; } - - public int UserId { get; set; } - public DiscordUser User { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandAlias.cs b/src/EllieBot/Db/Models/CommandAlias.cs deleted file mode 100644 index b3d6fc4..0000000 --- a/src/EllieBot/Db/Models/CommandAlias.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CommandAlias : DbEntity -{ - public string Trigger { get; set; } - public string Mapping { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CommandCooldown.cs b/src/EllieBot/Db/Models/CommandCooldown.cs deleted file mode 100644 index f25cd08..0000000 --- a/src/EllieBot/Db/Models/CommandCooldown.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CommandCooldown : DbEntity -{ - public int Seconds { get; set; } - public string CommandName { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/CurrencyTransaction.cs b/src/EllieBot/Db/Models/CurrencyTransaction.cs deleted file mode 100644 index 9153520..0000000 --- a/src/EllieBot/Db/Models/CurrencyTransaction.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CurrencyTransaction : DbEntity -{ - public long Amount { get; set; } - public string Note { get; set; } - public ulong UserId { get; set; } - public string Type { get; set; } - public string Extra { get; set; } - public ulong? OtherId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DbEntity.cs b/src/EllieBot/Db/Models/DbEntity.cs deleted file mode 100644 index 035ff76..0000000 --- a/src/EllieBot/Db/Models/DbEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class DbEntity -{ - [Key] - public int Id { get; set; } - - public DateTime? DateAdded { get; set; } = DateTime.UtcNow; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs b/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs deleted file mode 100644 index 6a24297..0000000 --- a/src/EllieBot/Db/Models/DelMsgOnCmdChannel.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class DelMsgOnCmdChannel : DbEntity -{ - public ulong ChannelId { get; set; } - public bool State { get; set; } - - public override int GetHashCode() - => ChannelId.GetHashCode(); - - public override bool Equals(object obj) - => obj is DelMsgOnCmdChannel x && x.ChannelId == ChannelId; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordPemOverride.cs b/src/EllieBot/Db/Models/DiscordPemOverride.cs deleted file mode 100644 index 461dcc4..0000000 --- a/src/EllieBot/Db/Models/DiscordPemOverride.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class DiscordPermOverride : DbEntity -{ - public GuildPerm Perm { get; set; } - - public ulong? GuildId { get; set; } - public string Command { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/DiscordUser.cs b/src/EllieBot/Db/Models/DiscordUser.cs deleted file mode 100644 index 5f8cc7b..0000000 --- a/src/EllieBot/Db/Models/DiscordUser.cs +++ /dev/null @@ -1,31 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -// FUTURE remove LastLevelUp from here and UserXpStats -public class DiscordUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - public string Discriminator { get; set; } - public string AvatarId { get; set; } - - public int? ClubId { get; set; } - public ClubInfo Club { get; set; } - public bool IsClubAdmin { get; set; } - - public long TotalXp { get; set; } - public XpNotificationLocation NotifyOnLevelUp { get; set; } - - public long CurrencyAmount { get; set; } - - public override bool Equals(object obj) - => obj is DiscordUser du ? du.UserId == UserId : false; - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override string ToString() - => Username + "#" + Discriminator; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/EllieExpression.cs b/src/EllieBot/Db/Models/EllieExpression.cs deleted file mode 100644 index 28c75f1..0000000 --- a/src/EllieBot/Db/Models/EllieExpression.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class EllieExpression : DbEntity -{ - public ulong? GuildId { get; set; } - public string Response { get; set; } - public string Trigger { get; set; } - - public bool AutoDeleteTrigger { get; set; } - public bool DmResponse { get; set; } - public bool ContainsAnywhere { get; set; } - public bool AllowTarget { get; set; } - public string Reactions { get; set; } - - public string[] GetReactions() - => string.IsNullOrWhiteSpace(Reactions) ? Array.Empty() : Reactions.Split("@@@"); - - public bool IsGlobal() - => GuildId is null or 0; -} - -public class ReactionResponse : DbEntity -{ - public bool OwnerOnly { get; set; } - public string Text { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Event.cs b/src/EllieBot/Db/Models/Event.cs deleted file mode 100644 index bface52..0000000 --- a/src/EllieBot/Db/Models/Event.cs +++ /dev/null @@ -1,49 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class CurrencyEvent -{ - public enum Type - { - Reaction, - - GameStatus - //NotRaid, - } - - public ulong ServerId { get; set; } - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - public Type EventType { get; set; } - - /// - /// Amount of currency that the user will be rewarded. - /// - public long Amount { get; set; } - - /// - /// Maximum amount of currency that can be handed out. - /// - public long PotSize { get; set; } - - public List AwardedUsers { get; set; } - - /// - /// Used as extra data storage for events which need it. - /// - public ulong ExtraId { get; set; } - - /// - /// May be used for some future event. - /// - public ulong ExtraId2 { get; set; } - - /// - /// May be used for some future event. - /// - public string ExtraString { get; set; } -} - -public class AwardedUser -{ -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FeedSub.cs b/src/EllieBot/Db/Models/FeedSub.cs deleted file mode 100644 index f5fccc6..0000000 --- a/src/EllieBot/Db/Models/FeedSub.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FeedSub : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public ulong ChannelId { get; set; } - public string Url { get; set; } - - public string Message { get; set; } - - public override int GetHashCode() - => Url.GetHashCode(StringComparison.InvariantCulture) ^ GuildConfigId.GetHashCode(); - - public override bool Equals(object obj) - => obj is FeedSub s && s.Url.ToLower() == Url.ToLower() && s.GuildConfigId == GuildConfigId; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterChannelId.cs b/src/EllieBot/Db/Models/FilterChannelId.cs deleted file mode 100644 index 9eaf8fa..0000000 --- a/src/EllieBot/Db/Models/FilterChannelId.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilterChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public bool Equals(FilterChannelId other) - => ChannelId == other.ChannelId; - - public override bool Equals(object obj) - => obj is FilterChannelId fci && Equals(fci); - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} - -public class FilterWordsChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public bool Equals(FilterWordsChannelId other) - => ChannelId == other.ChannelId; - - public override bool Equals(object obj) - => obj is FilterWordsChannelId fci && Equals(fci); - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilterLinksChannelId.cs b/src/EllieBot/Db/Models/FilterLinksChannelId.cs deleted file mode 100644 index f48d9b4..0000000 --- a/src/EllieBot/Db/Models/FilterLinksChannelId.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilterLinksChannelId : DbEntity -{ - public ulong ChannelId { get; set; } - - public override bool Equals(object obj) - => obj is FilterLinksChannelId f && f.ChannelId == ChannelId; - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FilteredWord.cs b/src/EllieBot/Db/Models/FilteredWord.cs deleted file mode 100644 index 4ff32f7..0000000 --- a/src/EllieBot/Db/Models/FilteredWord.cs +++ /dev/null @@ -1,7 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class FilteredWord : DbEntity -{ - public string Word { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/FollowedStream.cs b/src/EllieBot/Db/Models/FollowedStream.cs deleted file mode 100644 index ca119b4..0000000 --- a/src/EllieBot/Db/Models/FollowedStream.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable disable -using EllieBot.Modules.Searches.Common; -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class FollowedStream : DbEntity -{ - public enum FType - { - Twitch = 0, - Picarto = 3, - Youtube = 4, - Facebook = 5, - Trovo = 6 - } - - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public string Username { get; set; } - public FType Type { get; set; } - public string Message { get; set; } - - protected bool Equals(FollowedStream other) - => ChannelId == other.ChannelId - && Username.Trim().ToUpperInvariant() == other.Username.Trim().ToUpperInvariant() - && Type == other.Type; - - public override int GetHashCode() - => HashCode.Combine(ChannelId, Username, (int)Type); - - public override bool Equals(object obj) - => obj is FollowedStream fs && Equals(fs); - - public StreamDataKey CreateKey() - => new(Type, Username.ToLower()); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GCChannelId.cs b/src/EllieBot/Db/Models/GCChannelId.cs deleted file mode 100644 index 1f265d7..0000000 --- a/src/EllieBot/Db/Models/GCChannelId.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GCChannelId : DbEntity -{ - public GuildConfig GuildConfig { get; set; } - public ulong ChannelId { get; set; } - - public override bool Equals(object obj) - => obj is GCChannelId gc && gc.ChannelId == ChannelId; - - public override int GetHashCode() - => ChannelId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GamblingStats.cs b/src/EllieBot/Db/Models/GamblingStats.cs deleted file mode 100644 index 8a4654e..0000000 --- a/src/EllieBot/Db/Models/GamblingStats.cs +++ /dev/null @@ -1,9 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GamblingStats : DbEntity -{ - public string Feature { get; set; } - public decimal Bet { get; set; } - public decimal PaidOut { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GroupName.cs b/src/EllieBot/Db/Models/GroupName.cs deleted file mode 100644 index de88717..0000000 --- a/src/EllieBot/Db/Models/GroupName.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class GroupName : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public int Number { get; set; } - public string Name { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/GuildConfig.cs b/src/EllieBot/Db/Models/GuildConfig.cs deleted file mode 100644 index b05df52..0000000 --- a/src/EllieBot/Db/Models/GuildConfig.cs +++ /dev/null @@ -1,108 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class GuildConfig : DbEntity -{ - public ulong GuildId { get; set; } - - public string Prefix { get; set; } - - public bool DeleteMessageOnCommand { get; set; } - public HashSet DelMsgOnCmdChannels { get; set; } = new(); - - public string AutoAssignRoleIds { get; set; } - - //greet stuff - public int AutoDeleteGreetMessagesTimer { get; set; } = 30; - public int AutoDeleteByeMessagesTimer { get; set; } = 30; - - public ulong GreetMessageChannelId { get; set; } - public ulong ByeMessageChannelId { get; set; } - - public bool SendDmGreetMessage { get; set; } - public string DmGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; - - public bool SendChannelGreetMessage { get; set; } - public string ChannelGreetMessageText { get; set; } = "Welcome to the %server% server, %user%!"; - - public bool SendChannelByeMessage { get; set; } - public string ChannelByeMessageText { get; set; } = "%user% has left!"; - - //self assignable roles - public bool ExclusiveSelfAssignedRoles { get; set; } - public bool AutoDeleteSelfAssignedRoleMessages { get; set; } - - //stream notifications - public HashSet FollowedStreams { get; set; } = new(); - - //currencyGeneration - public HashSet GenerateCurrencyChannelIds { get; set; } = new(); - - public List Permissions { get; set; } - public bool VerbosePermissions { get; set; } = true; - public string PermissionRole { get; set; } - - public HashSet CommandCooldowns { get; set; } = new(); - - //filtering - public bool FilterInvites { get; set; } - public bool FilterLinks { get; set; } - public HashSet FilterInvitesChannelIds { get; set; } = new(); - public HashSet FilterLinksChannelIds { get; set; } = new(); - - //public bool FilterLinks { get; set; } - //public HashSet FilterLinksChannels { get; set; } = new HashSet(); - - public bool FilterWords { get; set; } - public HashSet FilteredWords { get; set; } = new(); - public HashSet FilterWordsChannelIds { get; set; } = new(); - - public HashSet MutedUsers { get; set; } = new(); - - public string MuteRoleName { get; set; } - public bool CleverbotEnabled { get; set; } - - public AntiRaidSetting AntiRaidSetting { get; set; } - public AntiSpamSetting AntiSpamSetting { get; set; } - public AntiAltSetting AntiAltSetting { get; set; } - - public string Locale { get; set; } - public string TimeZoneId { get; set; } - - public HashSet UnmuteTimers { get; set; } = new(); - public HashSet UnbanTimer { get; set; } = new(); - public HashSet UnroleTimer { get; set; } = new(); - public HashSet VcRoleInfos { get; set; } - public HashSet CommandAliases { get; set; } = new(); - public List WarnPunishments { get; set; } = new(); - public bool WarningsInitialized { get; set; } - public HashSet SlowmodeIgnoredUsers { get; set; } - public HashSet SlowmodeIgnoredRoles { get; set; } - - public List ShopEntries { get; set; } - public ulong? GameVoiceChannel { get; set; } - public bool VerboseErrors { get; set; } = true; - - public StreamRoleSettings StreamRole { get; set; } - - public XpSettings XpSettings { get; set; } - public List FeedSubs { get; set; } = new(); - public bool NotifyStreamOffline { get; set; } - public bool DeleteStreamOnlineMessage { get; set; } - public List SelfAssignableRoleGroupNames { get; set; } - public int WarnExpireHours { get; set; } - public WarnExpireAction WarnExpireAction { get; set; } = WarnExpireAction.Clear; - - public bool DisableGlobalExpressions { get; set; } = false; - - #region Boost Message - - public bool SendBoostMessage { get; set; } - public string BoostMessage { get; set; } = "%user% just boosted this server!"; - public ulong BoostMessageChannelId { get; set; } - public int BoostMessageDeleteAfter { get; set; } - - #endregion -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredLogItem.cs b/src/EllieBot/Db/Models/IgnoredLogItem.cs deleted file mode 100644 index 060ef32..0000000 --- a/src/EllieBot/Db/Models/IgnoredLogItem.cs +++ /dev/null @@ -1,16 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class IgnoredLogItem : DbEntity -{ - public int LogSettingId { get; set; } - public LogSetting LogSetting { get; set; } - public ulong LogItemId { get; set; } - public IgnoredItemType ItemType { get; set; } -} - -public enum IgnoredItemType -{ - Channel, - User -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs b/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs deleted file mode 100644 index e25c38a..0000000 --- a/src/EllieBot/Db/Models/IgnoredVoicePresenceChannel.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class IgnoredVoicePresenceChannel : DbEntity -{ - public LogSetting LogSetting { get; set; } - public ulong ChannelId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ImageOnlyChannel.cs b/src/EllieBot/Db/Models/ImageOnlyChannel.cs deleted file mode 100644 index 2fce8d1..0000000 --- a/src/EllieBot/Db/Models/ImageOnlyChannel.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class ImageOnlyChannel : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public OnlyChannelType Type { get; set; } -} - -public enum OnlyChannelType -{ - Image, - Link -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/LogSetting.cs b/src/EllieBot/Db/Models/LogSetting.cs deleted file mode 100644 index 93228ca..0000000 --- a/src/EllieBot/Db/Models/LogSetting.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class LogSetting : DbEntity -{ - public List LogIgnores { get; set; } = new(); - - public ulong GuildId { get; set; } - public ulong? LogOtherId { get; set; } - public ulong? MessageUpdatedId { get; set; } - public ulong? MessageDeletedId { get; set; } - - public ulong? UserJoinedId { get; set; } - public ulong? UserLeftId { get; set; } - public ulong? UserBannedId { get; set; } - public ulong? UserUnbannedId { get; set; } - public ulong? UserUpdatedId { get; set; } - - public ulong? ChannelCreatedId { get; set; } - public ulong? ChannelDestroyedId { get; set; } - public ulong? ChannelUpdatedId { get; set; } - - - public ulong? ThreadDeletedId { get; set; } - public ulong? ThreadCreatedId { get; set; } - - public ulong? UserMutedId { get; set; } - - //userpresence - public ulong? LogUserPresenceId { get; set; } - - //voicepresence - - public ulong? LogVoicePresenceId { get; set; } - public ulong? LogVoicePresenceTTSId { get; set; } - public ulong? LogWarnsId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicPlaylist.cs b/src/EllieBot/Db/Models/MusicPlaylist.cs deleted file mode 100644 index 3f96d05..0000000 --- a/src/EllieBot/Db/Models/MusicPlaylist.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MusicPlaylist : DbEntity -{ - public string Name { get; set; } - public string Author { get; set; } - public ulong AuthorId { get; set; } - public List Songs { get; set; } = new(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MusicSettings.cs b/src/EllieBot/Db/Models/MusicSettings.cs deleted file mode 100644 index b81d433..0000000 --- a/src/EllieBot/Db/Models/MusicSettings.cs +++ /dev/null @@ -1,61 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MusicPlayerSettings -{ - /// - /// Auto generated Id - /// - public int Id { get; set; } - - /// - /// Id of the guild - /// - public ulong GuildId { get; set; } - - /// - /// Queue repeat type - /// - public PlayerRepeatType PlayerRepeat { get; set; } = PlayerRepeatType.Queue; - - /// - /// Channel id the bot will always try to send track related messages to - /// - public ulong? MusicChannelId { get; set; } - - /// - /// Default volume player will be created with - /// - public int Volume { get; set; } = 100; - - /// - /// Whether the bot should auto disconnect from the voice channel once the queue is done - /// This only has effect if - /// - public bool AutoDisconnect { get; set; } - - /// - /// Selected quality preset for the music player - /// - public QualityPreset QualityPreset { get; set; } - - /// - /// Whether the bot will automatically queue related songs - /// - public bool AutoPlay { get; set; } -} - -public enum QualityPreset -{ - Highest, - High, - Medium, - Low -} - -public enum PlayerRepeatType -{ - None, - Track, - Queue -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/MutedUserId.cs b/src/EllieBot/Db/Models/MutedUserId.cs deleted file mode 100644 index 78fc9f3..0000000 --- a/src/EllieBot/Db/Models/MutedUserId.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class MutedUserId : DbEntity -{ - public ulong UserId { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is MutedUserId mui ? mui.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs b/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs deleted file mode 100644 index 3617132..0000000 --- a/src/EllieBot/Db/Models/NsfwBlacklistedTag.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class NsfwBlacklistedTag : DbEntity -{ - public ulong GuildId { get; set; } - public string Tag { get; set; } - - public override int GetHashCode() - => Tag.GetHashCode(StringComparison.InvariantCulture); - - public override bool Equals(object obj) - => obj is NsfwBlacklistedTag x && x.Tag == Tag; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PatronQuota.cs b/src/EllieBot/Db/Models/PatronQuota.cs deleted file mode 100644 index 1ebd2fd..0000000 --- a/src/EllieBot/Db/Models/PatronQuota.cs +++ /dev/null @@ -1,48 +0,0 @@ -#nullable disable -namespace EllieBot.Db.Models; - -/// -/// Contains data about usage of Patron-Only commands per user -/// in order to provide support for quota limitations -/// (allow user x who is pledging amount y to use the specified command only -/// x amount of times in the specified time period) -/// -public class PatronQuota -{ - public ulong UserId { get; set; } - public FeatureType FeatureType { get; set; } - public string Feature { get; set; } - public uint HourlyCount { get; set; } - public uint DailyCount { get; set; } - public uint MonthlyCount { get; set; } -} - -public enum FeatureType -{ - Command, - Group, - Module, - Limit -} - -public class PatronUser -{ - public string UniquePlatformUserId { get; set; } - public ulong UserId { get; set; } - public int AmountCents { get; set; } - - public DateTime LastCharge { get; set; } - - // Date Only component - public DateTime ValidThru { get; set; } - - public PatronUser Clone() - => new PatronUser() - { - UniquePlatformUserId = this.UniquePlatformUserId, - UserId = this.UserId, - AmountCents = this.AmountCents, - LastCharge = this.LastCharge, - ValidThru = this.ValidThru - }; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Permission.cs b/src/EllieBot/Db/Models/Permission.cs deleted file mode 100644 index 24a8186..0000000 --- a/src/EllieBot/Db/Models/Permission.cs +++ /dev/null @@ -1,55 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations.Schema; -using System.Diagnostics; - -namespace EllieBot.Services.Database.Models; - -[DebuggerDisplay("{PrimaryTarget}{SecondaryTarget} {SecondaryTargetName} {State} {PrimaryTargetId}")] -public class Permissionv2 : DbEntity, IIndexed -{ - public int? GuildConfigId { get; set; } - public int Index { get; set; } - - public PrimaryPermissionType PrimaryTarget { get; set; } - public ulong PrimaryTargetId { get; set; } - - public SecondaryPermissionType SecondaryTarget { get; set; } - public string SecondaryTargetName { get; set; } - - public bool IsCustomCommand { get; set; } - - public bool State { get; set; } - - [NotMapped] - public static Permissionv2 AllowAllPerm - => new() - { - PrimaryTarget = PrimaryPermissionType.Server, - PrimaryTargetId = 0, - SecondaryTarget = SecondaryPermissionType.AllModules, - SecondaryTargetName = "*", - State = true, - Index = 0 - }; - - public static List GetDefaultPermlist - => new() - { - AllowAllPerm - }; -} - -public enum PrimaryPermissionType -{ - User, - Channel, - Role, - Server -} - -public enum SecondaryPermissionType -{ - Module, - Command, - AllModules -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlantedCurrency.cs b/src/EllieBot/Db/Models/PlantedCurrency.cs deleted file mode 100644 index 3741530..0000000 --- a/src/EllieBot/Db/Models/PlantedCurrency.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PlantedCurrency : DbEntity -{ - public long Amount { get; set; } - public string Password { get; set; } - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public ulong UserId { get; set; } - public ulong MessageId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PlaylistSong.cs b/src/EllieBot/Db/Models/PlaylistSong.cs deleted file mode 100644 index 7a2078d..0000000 --- a/src/EllieBot/Db/Models/PlaylistSong.cs +++ /dev/null @@ -1,19 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PlaylistSong : DbEntity -{ - public string Provider { get; set; } - public MusicType ProviderType { get; set; } - public string Title { get; set; } - public string Uri { get; set; } - public string Query { get; set; } -} - -public enum MusicType -{ - Radio, - YouTube, - Local, - Soundcloud -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Poll.cs b/src/EllieBot/Db/Models/Poll.cs deleted file mode 100644 index 10e988c..0000000 --- a/src/EllieBot/Db/Models/Poll.cs +++ /dev/null @@ -1,17 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Poll : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public string Question { get; set; } - public IndexedCollection Answers { get; set; } - public HashSet Votes { get; set; } = new(); -} - -public class PollAnswer : DbEntity, IIndexed -{ - public int Index { get; set; } - public string Text { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/PollVote.cs b/src/EllieBot/Db/Models/PollVote.cs deleted file mode 100644 index e78dadf..0000000 --- a/src/EllieBot/Db/Models/PollVote.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class PollVote : DbEntity -{ - public ulong UserId { get; set; } - public int VoteIndex { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is PollVote p ? p.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Quote.cs b/src/EllieBot/Db/Models/Quote.cs deleted file mode 100644 index 529dc46..0000000 --- a/src/EllieBot/Db/Models/Quote.cs +++ /dev/null @@ -1,26 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class Quote : DbEntity -{ - public ulong GuildId { get; set; } - - [Required] - public string Keyword { get; set; } - - [Required] - public string AuthorName { get; set; } - - public ulong AuthorId { get; set; } - - [Required] - public string Text { get; set; } -} - -public enum OrderType -{ - Id = -1, - Keyword = -2 -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ReactionRole.cs b/src/EllieBot/Db/Models/ReactionRole.cs deleted file mode 100644 index 4e1e4f6..0000000 --- a/src/EllieBot/Db/Models/ReactionRole.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable -using System.ComponentModel.DataAnnotations; - -namespace EllieBot.Services.Database.Models; - -public class ReactionRoleV2 : DbEntity -{ - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - - public ulong MessageId { get; set; } - - [MaxLength(100)] - public string Emote { get; set; } - public ulong RoleId { get; set; } - public int Group { get; set; } - public int LevelReq { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Reminder.cs b/src/EllieBot/Db/Models/Reminder.cs deleted file mode 100644 index df51f6d..0000000 --- a/src/EllieBot/Db/Models/Reminder.cs +++ /dev/null @@ -1,12 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Reminder : DbEntity -{ - public DateTime When { get; set; } - public ulong ChannelId { get; set; } - public ulong ServerId { get; set; } - public ulong UserId { get; set; } - public string Message { get; set; } - public bool IsPrivate { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Repeater.cs b/src/EllieBot/Db/Models/Repeater.cs deleted file mode 100644 index 7ac971e..0000000 --- a/src/EllieBot/Db/Models/Repeater.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Repeater -{ - public int Id { get; set; } - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public ulong? LastMessageId { get; set; } - public string Message { get; set; } - public TimeSpan Interval { get; set; } - public TimeSpan? StartTimeOfDay { get; set; } - public bool NoRedundant { get; set; } - public DateTime DateAdded { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RewardedUser.cs b/src/EllieBot/Db/Models/RewardedUser.cs deleted file mode 100644 index 9ac6e78..0000000 --- a/src/EllieBot/Db/Models/RewardedUser.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class RewardedUser : DbEntity -{ - public ulong UserId { get; set; } - public string PlatformUserId { get; set; } - public long AmountRewardedThisMonth { get; set; } - public DateTime LastReward { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs b/src/EllieBot/Db/Models/RotatingPlayingStatus.cs deleted file mode 100644 index a76c38f..0000000 --- a/src/EllieBot/Db/Models/RotatingPlayingStatus.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class RotatingPlayingStatus : DbEntity -{ - public string Status { get; set; } - public ActivityType Type { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SelfAssignableRole.cs b/src/EllieBot/Db/Models/SelfAssignableRole.cs deleted file mode 100644 index c68fd32..0000000 --- a/src/EllieBot/Db/Models/SelfAssignableRole.cs +++ /dev/null @@ -1,11 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SelfAssignedRole : DbEntity -{ - public ulong GuildId { get; set; } - public ulong RoleId { get; set; } - - public int Group { get; set; } - public int LevelRequirement { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/ShopEntry.cs b/src/EllieBot/Db/Models/ShopEntry.cs deleted file mode 100644 index 6d08ab3..0000000 --- a/src/EllieBot/Db/Models/ShopEntry.cs +++ /dev/null @@ -1,43 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public enum ShopEntryType -{ - Role, - - List - //Infinite_List, -} - -public class ShopEntry : DbEntity, IIndexed -{ - public int Index { get; set; } - public int Price { get; set; } - public string Name { get; set; } - public ulong AuthorId { get; set; } - - public ShopEntryType Type { get; set; } - - //role - public string RoleName { get; set; } - public ulong RoleId { get; set; } - - //list - public HashSet Items { get; set; } = new(); - public ulong? RoleRequirement { get; set; } -} - -public class ShopEntryItem : DbEntity -{ - public string Text { get; set; } - - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - return ((ShopEntryItem)obj).Text == Text; - } - - public override int GetHashCode() - => Text.GetHashCode(StringComparison.InvariantCulture); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs deleted file mode 100644 index 4e55546..0000000 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredRole.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SlowmodeIgnoredRole : DbEntity -{ - public ulong RoleId { get; set; } - - // override object.Equals - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - - return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; - } - - // override object.GetHashCode - public override int GetHashCode() - => RoleId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs b/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs deleted file mode 100644 index c6a62f2..0000000 --- a/src/EllieBot/Db/Models/SlowmodeIgnoredUser.cs +++ /dev/null @@ -1,20 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class SlowmodeIgnoredUser : DbEntity -{ - public ulong UserId { get; set; } - - // override object.Equals - public override bool Equals(object obj) - { - if (obj is null || GetType() != obj.GetType()) - return false; - - return ((SlowmodeIgnoredUser)obj).UserId == UserId; - } - - // override object.GetHashCode - public override int GetHashCode() - => UserId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamOnlineMessage.cs b/src/EllieBot/Db/Models/StreamOnlineMessage.cs deleted file mode 100644 index 2f8c821..0000000 --- a/src/EllieBot/Db/Models/StreamOnlineMessage.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class StreamOnlineMessage : DbEntity -{ - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - - public FollowedStream.FType Type { get; set; } - public string Name { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/StreamRoleSettings.cs b/src/EllieBot/Db/Models/StreamRoleSettings.cs deleted file mode 100644 index 8b9b379..0000000 --- a/src/EllieBot/Db/Models/StreamRoleSettings.cs +++ /dev/null @@ -1,68 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class StreamRoleSettings : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - /// - /// Whether the feature is enabled in the guild. - /// - public bool Enabled { get; set; } - - /// - /// Id of the role to give to the users in the role 'FromRole' when they start streaming - /// - public ulong AddRoleId { get; set; } - - /// - /// Id of the role whose users are eligible to get the 'AddRole' - /// - public ulong FromRoleId { get; set; } - - /// - /// If set, feature will only apply to users who have this keyword in their streaming status. - /// - public string Keyword { get; set; } - - /// - /// A collection of whitelisted users' IDs. Whitelisted users don't require 'keyword' in - /// order to get the stream role. - /// - public HashSet Whitelist { get; set; } = new(); - - /// - /// A collection of blacklisted users' IDs. Blacklisted useres will never get the stream role. - /// - public HashSet Blacklist { get; set; } = new(); -} - -public class StreamRoleBlacklistedUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - - public override bool Equals(object obj) - { - if (obj is not StreamRoleBlacklistedUser x) - return false; - - return x.UserId == UserId; - } - - public override int GetHashCode() - => UserId.GetHashCode(); -} - -public class StreamRoleWhitelistedUser : DbEntity -{ - public ulong UserId { get; set; } - public string Username { get; set; } - - public override bool Equals(object obj) - => obj is StreamRoleWhitelistedUser x ? x.UserId == UserId : false; - - public override int GetHashCode() - => UserId.GetHashCode(); -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnbanTimer.cs b/src/EllieBot/Db/Models/UnbanTimer.cs deleted file mode 100644 index 6878b00..0000000 --- a/src/EllieBot/Db/Models/UnbanTimer.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnbanTimer : DbEntity -{ - public ulong UserId { get; set; } - public DateTime UnbanAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnbanTimer ut ? ut.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnmuteTimer.cs b/src/EllieBot/Db/Models/UnmuteTimer.cs deleted file mode 100644 index 54638ad..0000000 --- a/src/EllieBot/Db/Models/UnmuteTimer.cs +++ /dev/null @@ -1,14 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnmuteTimer : DbEntity -{ - public ulong UserId { get; set; } - public DateTime UnmuteAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnmuteTimer ut ? ut.UserId == UserId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UnroleTimer.cs b/src/EllieBot/Db/Models/UnroleTimer.cs deleted file mode 100644 index ceb0d4c..0000000 --- a/src/EllieBot/Db/Models/UnroleTimer.cs +++ /dev/null @@ -1,15 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UnroleTimer : DbEntity -{ - public ulong UserId { get; set; } - public ulong RoleId { get; set; } - public DateTime UnbanAt { get; set; } - - public override int GetHashCode() - => UserId.GetHashCode() ^ RoleId.GetHashCode(); - - public override bool Equals(object obj) - => obj is UnroleTimer ut ? ut.UserId == UserId && ut.RoleId == RoleId : false; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/UserXpStats.cs b/src/EllieBot/Db/Models/UserXpStats.cs deleted file mode 100644 index e79f735..0000000 --- a/src/EllieBot/Db/Models/UserXpStats.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class UserXpStats : DbEntity -{ - public ulong UserId { get; set; } - public ulong GuildId { get; set; } - public long Xp { get; set; } - public long AwardedXp { get; set; } - public XpNotificationLocation NotifyOnLevelUp { get; set; } -} - -public enum XpNotificationLocation { None, Dm, Channel } \ No newline at end of file diff --git a/src/EllieBot/Db/Models/VcRoleInfo.cs b/src/EllieBot/Db/Models/VcRoleInfo.cs deleted file mode 100644 index 3f6155e..0000000 --- a/src/EllieBot/Db/Models/VcRoleInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class VcRoleInfo : DbEntity -{ - public ulong VoiceChannelId { get; set; } - public ulong RoleId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Waifu.cs b/src/EllieBot/Db/Models/Waifu.cs deleted file mode 100644 index a140be5..0000000 --- a/src/EllieBot/Db/Models/Waifu.cs +++ /dev/null @@ -1,75 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class WaifuInfo : DbEntity -{ - public int WaifuId { get; set; } - public DiscordUser Waifu { get; set; } - - public int? ClaimerId { get; set; } - public DiscordUser Claimer { get; set; } - - public int? AffinityId { get; set; } - public DiscordUser Affinity { get; set; } - - public long Price { get; set; } - public List Items { get; set; } = new(); - - public override string ToString() - { - var claimer = "no one"; - var status = string.Empty; - - var waifuUsername = Waifu.Username.TrimTo(20); - var claimerUsername = Claimer?.Username.TrimTo(20); - - if (ClaimerId is not null) - claimer = $"{claimerUsername}#{Claimer.Discriminator}"; - if (AffinityId is null) - status = $"... but {waifuUsername}'s heart is empty"; - else if (AffinityId == ClaimerId) - status = $"... and {waifuUsername} likes {claimerUsername} too <3"; - else - { - status = - $"... but {waifuUsername}'s heart belongs to {Affinity.Username.TrimTo(20)}#{Affinity.Discriminator}"; - } - - return $"**{waifuUsername}#{Waifu.Discriminator}** - claimed by **{claimer}**\n\t{status}"; - } -} - -public class WaifuLbResult -{ - public string Username { get; set; } - public string Discrim { get; set; } - - public string Claimer { get; set; } - public string ClaimerDiscrim { get; set; } - - public string Affinity { get; set; } - public string AffinityDiscrim { get; set; } - - public long Price { get; set; } - - public override string ToString() - { - var claimer = "no one"; - var status = string.Empty; - - var waifuUsername = Username.TrimTo(20); - var claimerUsername = Claimer?.TrimTo(20); - - if (Claimer is not null) - claimer = $"{claimerUsername}#{ClaimerDiscrim}"; - if (Affinity is null) - status = $"... but {waifuUsername}'s heart is empty"; - else if (Affinity + AffinityDiscrim == Claimer + ClaimerDiscrim) - status = $"... and {waifuUsername} likes {claimerUsername} too <3"; - else - status = $"... but {waifuUsername}'s heart belongs to {Affinity.TrimTo(20)}#{AffinityDiscrim}"; - return $"**{waifuUsername}#{Discrim}** - claimed by **{claimer}**\n\t{status}"; - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WaifuItem.cs b/src/EllieBot/Db/Models/WaifuItem.cs deleted file mode 100644 index 53b8f8e..0000000 --- a/src/EllieBot/Db/Models/WaifuItem.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class WaifuItem : DbEntity -{ - public WaifuInfo WaifuInfo { get; set; } - public int? WaifuInfoId { get; set; } - public string ItemEmoji { get; set; } - public string Name { get; set; } -} diff --git a/src/EllieBot/Db/Models/WaifuUpdate.cs b/src/EllieBot/Db/Models/WaifuUpdate.cs deleted file mode 100644 index 70e8960..0000000 --- a/src/EllieBot/Db/Models/WaifuUpdate.cs +++ /dev/null @@ -1,23 +0,0 @@ -#nullable disable -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database.Models; - -public class WaifuUpdate : DbEntity -{ - public int UserId { get; set; } - public DiscordUser User { get; set; } - public WaifuUpdateType UpdateType { get; set; } - - public int? OldId { get; set; } - public DiscordUser Old { get; set; } - - public int? NewId { get; set; } - public DiscordUser New { get; set; } -} - -public enum WaifuUpdateType -{ - AffinityChanged, - Claimed -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarnExpireAction.cs b/src/EllieBot/Db/Models/WarnExpireAction.cs deleted file mode 100644 index 69d90b8..0000000 --- a/src/EllieBot/Db/Models/WarnExpireAction.cs +++ /dev/null @@ -1,8 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public enum WarnExpireAction -{ - Clear, - Delete -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/Warning.cs b/src/EllieBot/Db/Models/Warning.cs deleted file mode 100644 index 9bd9b41..0000000 --- a/src/EllieBot/Db/Models/Warning.cs +++ /dev/null @@ -1,13 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class Warning : DbEntity -{ - public ulong GuildId { get; set; } - public ulong UserId { get; set; } - public string Reason { get; set; } - public bool Forgiven { get; set; } - public string ForgivenBy { get; set; } - public string Moderator { get; set; } - public long Weight { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/WarningPunishment.cs b/src/EllieBot/Db/Models/WarningPunishment.cs deleted file mode 100644 index a0aa731..0000000 --- a/src/EllieBot/Db/Models/WarningPunishment.cs +++ /dev/null @@ -1,10 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class WarningPunishment : DbEntity -{ - public int Count { get; set; } - public PunishmentAction Punishment { get; set; } - public int Time { get; set; } - public ulong? RoleId { get; set; } -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpSettings.cs b/src/EllieBot/Db/Models/XpSettings.cs deleted file mode 100644 index a0cae1e..0000000 --- a/src/EllieBot/Db/Models/XpSettings.cs +++ /dev/null @@ -1,62 +0,0 @@ -#nullable disable -namespace EllieBot.Services.Database.Models; - -public class XpSettings : DbEntity -{ - public int GuildConfigId { get; set; } - public GuildConfig GuildConfig { get; set; } - - public HashSet RoleRewards { get; set; } = new(); - public HashSet CurrencyRewards { get; set; } = new(); - public HashSet ExclusionList { get; set; } = new(); - public bool ServerExcluded { get; set; } -} - -public enum ExcludedItemType { Channel, Role } - -public class XpRoleReward : DbEntity -{ - public int XpSettingsId { get; set; } - public XpSettings XpSettings { get; set; } - - public int Level { get; set; } - public ulong RoleId { get; set; } - - /// - /// Whether the role should be removed (true) or added (false) - /// - public bool Remove { get; set; } - - public override int GetHashCode() - => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); - - public override bool Equals(object obj) - => obj is XpRoleReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; -} - -public class XpCurrencyReward : DbEntity -{ - public int XpSettingsId { get; set; } - public XpSettings XpSettings { get; set; } - - public int Level { get; set; } - public int Amount { get; set; } - - public override int GetHashCode() - => Level.GetHashCode() ^ XpSettingsId.GetHashCode(); - - public override bool Equals(object obj) - => obj is XpCurrencyReward xrr && xrr.Level == Level && xrr.XpSettingsId == XpSettingsId; -} - -public class ExcludedItem : DbEntity -{ - public ulong ItemId { get; set; } - public ExcludedItemType ItemType { get; set; } - - public override int GetHashCode() - => ItemId.GetHashCode() ^ ItemType.GetHashCode(); - - public override bool Equals(object obj) - => obj is ExcludedItem ei && ei.ItemId == ItemId && ei.ItemType == ItemType; -} \ No newline at end of file diff --git a/src/EllieBot/Db/Models/XpShopOwnedItem.cs b/src/EllieBot/Db/Models/XpShopOwnedItem.cs deleted file mode 100644 index dc0f641..0000000 --- a/src/EllieBot/Db/Models/XpShopOwnedItem.cs +++ /dev/null @@ -1,18 +0,0 @@ -#nullable disable warnings -using EllieBot.Services.Database.Models; - -namespace EllieBot.Db.Models; - -public class XpShopOwnedItem : DbEntity -{ - public ulong UserId { get; set; } - public XpShopItemType ItemType { get; set; } - public bool IsUsing { get; set; } - public string ItemKey { get; set; } -} - -public enum XpShopItemType -{ - Background = 0, - Frame = 1, -} \ No newline at end of file diff --git a/src/EllieBot/Db/MysqlContext.cs b/src/EllieBot/Db/MysqlContext.cs deleted file mode 100644 index 1474b30..0000000 --- a/src/EllieBot/Db/MysqlContext.cs +++ /dev/null @@ -1,38 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using EllieBot.Db.Models; - -namespace EllieBot.Services.Database; - -public sealed class MysqlContext : EllieContext -{ - private readonly string _connStr; - private readonly string _version; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public MysqlContext(string connStr = "Server=localhost", string version = "8.0") - { - _connStr = connStr; - _version = version; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - optionsBuilder - .UseLowerCaseNamingConvention() - .UseMySql(_connStr, ServerVersion.Parse(_version)); - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - // mysql is case insensitive by default - // we can set binary collation to change that - modelBuilder.Entity() - .Property(x => x.Name) - .UseCollation("utf8mb4_bin"); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/PostgreSqlContext.cs b/src/EllieBot/Db/PostgreSqlContext.cs deleted file mode 100644 index dba46f6..0000000 --- a/src/EllieBot/Db/PostgreSqlContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace EllieBot.Services.Database; - -public sealed class PostgreSqlContext : EllieContext -{ - private readonly string _connStr; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public PostgreSqlContext(string connStr = "Host=localhost") - { - _connStr = connStr; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); - - base.OnConfiguring(optionsBuilder); - optionsBuilder - .UseLowerCaseNamingConvention() - .UseNpgsql(_connStr); - } -} \ No newline at end of file diff --git a/src/EllieBot/Db/SqliteContext.cs b/src/EllieBot/Db/SqliteContext.cs deleted file mode 100644 index 530bfb4..0000000 --- a/src/EllieBot/Db/SqliteContext.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; - -namespace EllieBot.Services.Database; - -public sealed class SqliteContext : EllieContext -{ - private readonly string _connectionString; - - protected override string CurrencyTransactionOtherIdDefaultValue - => "NULL"; - - public SqliteContext(string connectionString = "Data Source=data/EllieBot.db", int commandTimeout = 60) - { - _connectionString = connectionString; - Database.SetCommandTimeout(commandTimeout); - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - base.OnConfiguring(optionsBuilder); - var builder = new SqliteConnectionStringBuilder(_connectionString); - builder.DataSource = Path.Combine(AppContext.BaseDirectory, builder.DataSource); - optionsBuilder.UseSqlite(builder.ToString()); - } -} \ No newline at end of file diff --git a/src/EllieBot/EllieBot.csproj b/src/EllieBot/EllieBot.csproj index 42d6327..5f4dbb0 100644 --- a/src/EllieBot/EllieBot.csproj +++ b/src/EllieBot/EllieBot.csproj @@ -99,7 +99,6 @@ - diff --git a/src/EllieBot/GlobalUsings.cs b/src/EllieBot/GlobalUsings.cs new file mode 100644 index 0000000..7984372 --- /dev/null +++ b/src/EllieBot/GlobalUsings.cs @@ -0,0 +1,31 @@ +// global using System.Collections.Concurrent +global using NonBlocking; + +// packages +global using Serilog; +global using Humanizer; + +// elliebot +global using EllieBot; +global using EllieBot.Services; +global using Ellie.Common; // new project +global using EllieBot.Common; // old + elliebot specific things +global using EllieBot.Common.Attributes; +global using EllieBot.Extensions; +global using Ellie.Marmalade; + +// discord +global using Discord; +global using Discord.Commands; +global using Discord.Net; +global using Discord.WebSocket; + +// aliases +global using GuildPerm = Discord.GuildPermission; +global using ChannelPerm = Discord.ChannelPermission; +global using BotPermAttribute = Discord.Commands.RequireBotPermissionAttribute; +global using LeftoverAttribute = Discord.Commands.RemainderAttribute; +global using TypeReaderResult = EllieBot.Common.TypeReaders.TypeReaderResult; + +// non-essential +global using JetBrains.Annotations; \ No newline at end of file