diff --git a/.deploy.yml b/.deploy.yml index 5fb394d..cf0e485 100644 --- a/.deploy.yml +++ b/.deploy.yml @@ -7,13 +7,13 @@ ansible_python_interpreter: /usr/bin/python3 tasks: - name: Login to Gitlab Docker Registry - 'community.docker.docker_login': + docker_login: registry_url: "{{ lookup('env', 'CI_REGISTRY') }}" username: "{{ lookup('env', 'CI_REGISTRY_USER') }}" password: "{{ lookup('env', 'CI_REGISTRY_PASSWORD') }}" reauthorize: yes - name: Replace Prod Container - 'community.docker.docker_container': + docker_container: name: GeekbotProd image: "{{ lookup('env', 'IMAGE_TAG') }}" recreate: yes @@ -34,5 +34,5 @@ GEEKBOT_SENTRY: "{{ lookup('env', 'GEEKBOT_SENTRY') }}" GEEKBOT_DB_REDSHIFT_COMPAT: "true" - name: Cleanup Old Container - 'community.docker.docker_prune': + docker_prune: images: yes diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a774f5e..c4d8b15 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,12 +5,12 @@ stages: - ops variables: - VERSION: 4.4.0-V$CI_COMMIT_SHORT_SHA + VERSION: 4.3.0-$CI_COMMIT_SHORT_SHA IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG Build: stage: build - image: mcr.microsoft.com/dotnet/sdk:6.0 + image: mcr.microsoft.com/dotnet/sdk:5.0 artifacts: expire_in: 1h paths: @@ -18,7 +18,7 @@ Build: script: - dotnet restore - dotnet test tests - - dotnet publish --version-suffix "$VERSION" -r linux-x64 -c Release -p:DebugType=embedded --no-self-contained -o ./app ./src/Startup/ + - dotnet publish --version-suffix $VERSION -r linux-x64 -c Release -o ./app ./src/Bot/ Package: stage: docker @@ -34,7 +34,7 @@ Package: Deploy: stage: deploy - image: quay.io/ansible/ansible-runner:stable-2.12-latest + image: ansible/ansible-runner only: - master variables: @@ -46,7 +46,6 @@ Deploy: - chmod -R 600 /root/.ssh - ssh-keyscan -p 65432 $PROD_IP > /root/.ssh/known_hosts script: - - ansible-galaxy collection install -r ansible-requirements.yml - ansible-playbook -i $PROD_IP, .deploy.yml Sentry: diff --git a/Dockerfile b/Dockerfile index 39529ff..245e06b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0 +FROM mcr.microsoft.com/dotnet/aspnet:5.0 COPY ./app /app/ diff --git a/Geekbot.net.sln b/Geekbot.net.sln index f33d887..4a5b912 100644 --- a/Geekbot.net.sln +++ b/Geekbot.net.sln @@ -11,12 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot", "src\Bot\Bot.csproj", "{DBF79896-9F7F-443D-B336-155E276DFF16}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands", "src\Commands\Commands.csproj", "{7C771DFE-912A-4276-B0A6-047E09603F1E}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interactions", "src\Interactions\Interactions.csproj", "{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startup", "src\Startup\Startup.csproj", "{A691B018-4B19-4A7A-A0F6-DBB17641254F}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,18 +33,6 @@ Global {DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.Build.0 = Debug|Any CPU {DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.ActiveCfg = Release|Any CPU {DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.Build.0 = Release|Any CPU - {7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.Build.0 = Release|Any CPU - {FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.Build.0 = Release|Any CPU - {A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ansible-requirements.yml b/ansible-requirements.yml deleted file mode 100644 index 90d8fb4..0000000 --- a/ansible-requirements.yml +++ /dev/null @@ -1,3 +0,0 @@ -collections: - - name: community.docker - version: 2.7.0 \ No newline at end of file diff --git a/src/Bot/Bot.csproj b/src/Bot/Bot.csproj index 2219b32..4cd5b39 100644 --- a/src/Bot/Bot.csproj +++ b/src/Bot/Bot.csproj @@ -1,25 +1,34 @@ - net6.0 + Exe + net5.0 + win-x64;linux-x64 + derp.ico $(VersionSuffix) Geekbot.Bot - Geekbot.Bot - $(VersionSuffix) + Geekbot + $(VersionSuffix) 0.0.0-DEV + Pizza and Coffee Studios + Pizza and Coffee Studios + A Discord bot + https://github.com/pizzaandcoffee/Geekbot.net NU1701 - enable - True - Library + git + https://geekbot.pizzaandcoffee.rocks + + + true - - - + + + - + @@ -27,7 +36,113 @@ - + + + + + ResXFileCodeGenerator + Ship.Designer.cs + + + ResXFileCodeGenerator + Rank.Designer.cs + + + ResXFileCodeGenerator + Karma.Designer.cs + + + ResXFileCodeGenerator + Internal.Designer.cs + + + ResXFileCodeGenerator + Cookies.Designer.cs + + + ResXFileCodeGenerator + Roll.Designer.cs + + + ResXFileCodeGenerator + Choose.Designer.cs + + + ResXFileCodeGenerator + Admin.Designer.cs + + + ResXFileCodeGenerator + Quote.Designer.cs + + + ResXFileCodeGenerator + Role.Designer.cs + + + ResXFileCodeGenerator + Stats.Designer.cs + + + + + True + True + ship.resx + + + True + True + Rank.resx + + + Ship.resx + + + True + True + Karma.resx + + + True + True + Internal.resx + + + True + True + Cookies.resx + + + True + True + Roll.resx + + + True + True + Choose.resx + + + True + True + Admin.resx + + + True + True + Quote.resx + + + True + True + Role.resx + + + True + True + Stats.resx + diff --git a/src/Bot/BotStartup.cs b/src/Bot/BotStartup.cs deleted file mode 100644 index afb1a8a..0000000 --- a/src/Bot/BotStartup.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System.Reflection; -using Discord; -using Discord.Commands; -using Discord.WebSocket; -using Geekbot.Bot.Handlers; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.GlobalSettings; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.Logger; -using Geekbot.Core.Logger.Adapters; -using Geekbot.Core.ReactionListener; -using Geekbot.Core.UserRepository; -using Microsoft.Extensions.DependencyInjection; - -namespace Geekbot.Bot; - -public class BotStartup -{ - private readonly IServiceCollection _serviceCollection; - private readonly GeekbotLogger _logger; - private readonly RunParameters _runParameters; - private readonly IGlobalSettings _globalSettings; - private DiscordSocketClient _client; - - public BotStartup(IServiceCollection serviceCollection, GeekbotLogger logger, RunParameters runParameters, IGlobalSettings globalSettings) - { - _serviceCollection = serviceCollection; - _logger = logger; - _runParameters = runParameters; - _globalSettings = globalSettings; - } - - public async Task Start() - { - _logger.Information(LogSource.Geekbot, "Connecting to Discord"); - SetupDiscordClient(); - await Login(); - await _client.SetGameAsync(_globalSettings.GetKey("Game")); - _logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers"); - - _logger.Information(LogSource.Geekbot, "Registering Gateway Handlers"); - await RegisterHandlers(); - - _logger.Information(LogSource.Geekbot, "Done and ready for use"); - await Task.Delay(-1); - } - - private void SetupDiscordClient() - { - _client = new DiscordSocketClient(new DiscordSocketConfig - { - GatewayIntents = GatewayIntents.DirectMessageReactions | - GatewayIntents.DirectMessages | - GatewayIntents.GuildMessageReactions | - GatewayIntents.GuildMessages | - GatewayIntents.GuildWebhooks | - GatewayIntents.GuildIntegrations | - GatewayIntents.GuildEmojis | - GatewayIntents.GuildBans | - GatewayIntents.Guilds | - GatewayIntents.GuildMembers, - LogLevel = LogSeverity.Verbose, - MessageCacheSize = 1000, - }); - - var discordLogger = new DiscordLogger(_logger); - _client.Log += discordLogger.Log; - } - - private async Task Login() - { - try - { - var token = await GetToken(); - await _client.LoginAsync(TokenType.Bot, token); - await _client.StartAsync(); - while (!_client.ConnectionState.Equals(ConnectionState.Connected)) await Task.Delay(25); - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Could not connect to Discord", e); - Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode()); - } - } - - private async Task GetToken() - { - var token = _runParameters.Token ?? _globalSettings.GetKey("DiscordToken"); - if (string.IsNullOrEmpty(token)) - { - Console.Write("Your bot Token: "); - var newToken = Console.ReadLine(); - await _globalSettings.SetKey("DiscordToken", newToken); - await _globalSettings.SetKey("Game", "Ping Pong"); - token = newToken; - } - - return token; - } - - private async Task RegisterHandlers() - { - var applicationInfo = await _client.GetApplicationInfoAsync(); - - _serviceCollection.AddSingleton(_client); - var serviceProvider = _serviceCollection.BuildServiceProvider(); - - var commands = new CommandService(); - await commands.AddModulesAsync(Assembly.GetAssembly(typeof(BotStartup)), serviceProvider); - - var commandHandler = new CommandHandler(_client, _logger, serviceProvider, commands, applicationInfo, serviceProvider.GetService()); - var userHandler = new UserHandler(serviceProvider.GetService(), _logger, serviceProvider.GetService(), _client); - var reactionHandler = new ReactionHandler(serviceProvider.GetService()); - var statsHandler = new StatsHandler(_logger, serviceProvider.GetService()); - var messageDeletedHandler = new MessageDeletedHandler(serviceProvider.GetService(), _logger, _client); - - _client.MessageReceived += commandHandler.RunCommand; - _client.MessageDeleted += messageDeletedHandler.HandleMessageDeleted; - _client.UserJoined += userHandler.Joined; - _client.UserUpdated += userHandler.Updated; - _client.UserLeft += userHandler.Left; - _client.ReactionAdded += reactionHandler.Added; - _client.ReactionRemoved += reactionHandler.Removed; - if (!_runParameters.InMemory) _client.MessageReceived += statsHandler.UpdateStats; - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Admin/Admin.cs b/src/Bot/Commands/Admin/Admin.cs index 43fb3c4..60ba8ac 100644 --- a/src/Bot/Commands/Admin/Admin.cs +++ b/src/Bot/Commands/Admin/Admin.cs @@ -9,12 +9,11 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; using Discord.WebSocket; -using Geekbot.Bot.CommandPreconditions; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Admin { diff --git a/src/Bot/Commands/Admin/Mod.cs b/src/Bot/Commands/Admin/Mod.cs new file mode 100644 index 0000000..b642680 --- /dev/null +++ b/src/Bot/Commands/Admin/Mod.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.Core.CommandPreconditions; +using Geekbot.Core.ErrorHandling; + +namespace Geekbot.Bot.Commands.Admin +{ + [Group("mod")] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireUserPermission(GuildPermission.ManageRoles)] + [DisableInDirectMessage] + public class Mod : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Mod(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("namehistory", RunMode = RunMode.Async)] + [Summary("See past usernames of an user")] + public async Task UsernameHistory([Summary("@someone")] IUser user) + { + try + { + await Context.Channel.SendMessageAsync("This command has been removed due to low usage and excessively high database usage"); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Admin/Role.cs b/src/Bot/Commands/Admin/Role.cs index fb8ef68..efec7bd 100644 --- a/src/Bot/Commands/Admin/Role.cs +++ b/src/Bot/Commands/Admin/Role.cs @@ -6,15 +6,14 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; using Discord.Net; -using Geekbot.Bot.CommandPreconditions; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.ReactionListener; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Admin { diff --git a/src/Bot/Commands/Games/Pokedex.cs b/src/Bot/Commands/Games/Pokedex.cs index 325ee8c..426761c 100644 --- a/src/Bot/Commands/Games/Pokedex.cs +++ b/src/Bot/Commands/Games/Pokedex.cs @@ -3,14 +3,13 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using PokeAPI; namespace Geekbot.Bot.Commands.Games { - public class Pokedex : TransactionModuleBase + public class Pokedex : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Games/Roll/Roll.cs b/src/Bot/Commands/Games/Roll/Roll.cs index e9ed9e9..6ef9322 100644 --- a/src/Bot/Commands/Games/Roll/Roll.cs +++ b/src/Bot/Commands/Games/Roll/Roll.cs @@ -1,13 +1,16 @@ using System; +using System.Linq; using System.Threading.Tasks; using Discord.Commands; +using Geekbot.Bot.Utils; using Geekbot.Core; using Geekbot.Core.Database; +using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; +using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.KvInMemoryStore; using Geekbot.Core.RandomNumberGenerator; -using Sentry; namespace Geekbot.Bot.Commands.Games.Roll { @@ -31,20 +34,63 @@ namespace Geekbot.Bot.Commands.Games.Roll { try { - var res = await new Geekbot.Commands.Roll.Roll(_kvInMemoryStore, _database, _randomNumberGenerator) - .RunFromGateway( - Context.Guild.Id, - Context.User.Id, - Context.User.Username, - stuff ?? "0" - ); - await ReplyAsync(res); + var number = _randomNumberGenerator.Next(1, 100); + int.TryParse(stuff, out var guess); + if (guess <= 100 && guess > 0) + { + var kvKey = $"{Context?.Guild?.Id ?? 0}:{Context.User.Id}:RollsPrevious"; + + var prevRoll = _kvInMemoryStore.Get(kvKey); + + if (prevRoll?.LastGuess == guess && prevRoll?.GuessedOn.AddDays(1) > DateTime.Now) + { + await ReplyAsync(string.Format( + Localization.Roll.NoPrevGuess, + Context.Message.Author.Mention, + DateLocalization.FormatDateTimeAsRemaining(prevRoll.GuessedOn.AddDays(1)))); + return; + } + + _kvInMemoryStore.Set(kvKey, new RollTimeout {LastGuess = guess, GuessedOn = DateTime.Now}); + + await ReplyAsync(string.Format(Localization.Roll.Rolled, Context.Message.Author.Mention, number, guess)); + if (guess == number) + { + await ReplyAsync(string.Format(Localization.Roll.Gratz, Context.Message.Author)); + var user = await GetUser(Context.User.Id); + user.Rolls += 1; + _database.Rolls.Update(user); + await _database.SaveChangesAsync(); + } + } + else + { + await ReplyAsync(string.Format(Localization.Roll.RolledNoGuess, Context.Message.Author.Mention, number)); + } } catch (Exception e) { await ErrorHandler.HandleCommandException(e, Context); - Transaction.Status = SpanStatus.InternalError; } } + + private async Task GetUser(ulong userId) + { + var user = _database.Rolls.FirstOrDefault(u => u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId); + return user; + } + + private async Task CreateNewRow(ulong userId) + { + var user = new RollsModel() + { + GuildId = Context.Guild.Id.AsLong(), + UserId = userId.AsLong(), + Rolls = 0 + }; + var newUser = _database.Rolls.Add(user).Entity; + await _database.SaveChangesAsync(); + return newUser; + } } } \ No newline at end of file diff --git a/src/Commands/Roll/RollTimeout.cs b/src/Bot/Commands/Games/Roll/RollTimeout.cs similarity index 57% rename from src/Commands/Roll/RollTimeout.cs rename to src/Bot/Commands/Games/Roll/RollTimeout.cs index d296c45..c53101a 100644 --- a/src/Commands/Roll/RollTimeout.cs +++ b/src/Bot/Commands/Games/Roll/RollTimeout.cs @@ -1,10 +1,10 @@ -using System; - -namespace Geekbot.Commands.Roll -{ - public record RollTimeout - { - public int LastGuess { get; set; } - public DateTime GuessedOn { get; set; } - } +using System; + +namespace Geekbot.Bot.Commands.Games.Roll +{ + public class RollTimeout + { + public int LastGuess { get; set; } + public DateTime GuessedOn { get; set; } + } } \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs b/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs index 511d7b8..4e75034 100644 --- a/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs +++ b/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs @@ -10,7 +10,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Integrations.LolMmr { - public class LolMmr : TransactionModuleBase + public class LolMmr : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -46,9 +46,9 @@ namespace Geekbot.Bot.Commands.Integrations.LolMmr var sb = new StringBuilder(); sb.AppendLine($"**MMR for {summonerName}**"); - sb.AppendLine($"Normal: {data.Normal?.Avg ?? 0}"); - sb.AppendLine($"Ranked: {data.Ranked?.Avg ?? 0}"); - sb.AppendLine($"ARAM: {data.ARAM?.Avg ?? 0}"); + sb.AppendLine($"Normal: {data.Normal.Avg}"); + sb.AppendLine($"Ranked: {data.Ranked.Avg}"); + sb.AppendLine($"ARAM: {data.ARAM.Avg}"); await Context.Channel.SendMessageAsync(sb.ToString()); } diff --git a/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs b/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs index 233bcfc..51d4c85 100644 --- a/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs +++ b/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs @@ -1,16 +1,9 @@ -using System.Text.Json.Serialization; - namespace Geekbot.Bot.Commands.Integrations.LolMmr { public class LolMmrDto { - [JsonPropertyName("ranked")] public LolMrrInfoDto Ranked { get; set; } - - [JsonPropertyName("normal")] public LolMrrInfoDto Normal { get; set; } - - [JsonPropertyName("aram")] public LolMrrInfoDto ARAM { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs b/src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs index fbcc49a..18b096a 100644 --- a/src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs +++ b/src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs @@ -1,10 +1,10 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace Geekbot.Bot.Commands.Integrations.LolMmr { public class LolMrrInfoDto { - [JsonPropertyName("avg")] - public decimal? Avg { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public decimal Avg { get; set; } = 0; } } \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/MagicTheGathering.cs b/src/Bot/Commands/Integrations/MagicTheGathering.cs index 359b41e..b179d6e 100644 --- a/src/Bot/Commands/Integrations/MagicTheGathering.cs +++ b/src/Bot/Commands/Integrations/MagicTheGathering.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.Converters; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; @@ -12,7 +11,7 @@ using MtgApiManager.Lib.Service; namespace Geekbot.Bot.Commands.Integrations { - public class MagicTheGathering : TransactionModuleBase + public class MagicTheGathering : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly IMtgManaConverter _manaConverter; diff --git a/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs new file mode 100644 index 0000000..0aee35f --- /dev/null +++ b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs @@ -0,0 +1,12 @@ +namespace Geekbot.Bot.Commands.Integrations.UbranDictionary +{ + internal class UrbanListItemDto + { + public string Definition { get; set; } + public string Permalink { get; set; } + public string ThumbsUp { get; set; } + public string Word { get; set; } + public string Example { get; set; } + public string ThumbsDown { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs new file mode 100644 index 0000000..1846601 --- /dev/null +++ b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Geekbot.Bot.Commands.Integrations.UbranDictionary +{ + internal class UrbanResponseDto + { + public string[] Tags { get; set; } + public List List { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictionary.cs b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictionary.cs new file mode 100644 index 0000000..72bc8cd --- /dev/null +++ b/src/Bot/Commands/Integrations/UbranDictionary/UrbanDictionary.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.Core; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.Extensions; + +namespace Geekbot.Bot.Commands.Integrations.UbranDictionary +{ + public class UrbanDictionary : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public UrbanDictionary(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("urban", RunMode = RunMode.Async)] + [Summary("Lookup something on urban dictionary")] + public async Task UrbanDefine([Remainder] [Summary("word")] string word) + { + try + { + var definitions = await HttpAbstractions.Get(new Uri($"https://api.urbandictionary.com/v0/define?term={word}")); + if (definitions.List.Count == 0) + { + await ReplyAsync("That word hasn't been defined..."); + return; + } + + var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example)); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder + { + Name = definition.Word, + Url = definition.Permalink + }); + eb.WithColor(new Color(239, 255, 0)); + + static string ShortenIfToLong(string str, int maxLength) => str.Length > maxLength ? $"{str.Substring(0, maxLength - 5)}[...]" : str; + + if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = ShortenIfToLong(definition.Definition, 1800); + if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", ShortenIfToLong(definition.Example, 1024)); + if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp); + if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown); + if (definitions.Tags?.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags)); + + await ReplyAsync("", false, eb.Build()); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/UrbanDictionary.cs b/src/Bot/Commands/Integrations/UrbanDictionary.cs deleted file mode 100644 index 44fe868..0000000 --- a/src/Bot/Commands/Integrations/UrbanDictionary.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Integrations -{ - public class UrbanDictionary : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public UrbanDictionary(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("urban", RunMode = RunMode.Async)] - [Summary("Lookup something on urban dictionary")] - public async Task UrbanDefine([Remainder] [Summary("word")] string word) - { - try - { - var eb = await Geekbot.Commands.UrbanDictionary.UrbanDictionary.Run(word); - if (eb == null) - { - await ReplyAsync("That word hasn't been defined..."); - return; - } - - await ReplyAsync(string.Empty, false, eb.ToDiscordNetEmbed().Build()); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/Wikipedia.cs b/src/Bot/Commands/Integrations/Wikipedia.cs index 82f42a0..709f974 100644 --- a/src/Bot/Commands/Integrations/Wikipedia.cs +++ b/src/Bot/Commands/Integrations/Wikipedia.cs @@ -5,7 +5,6 @@ using System.Text; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.Database; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; @@ -15,7 +14,7 @@ using HtmlAgilityPack; namespace Geekbot.Bot.Commands.Integrations { - public class Wikipedia : TransactionModuleBase + public class Wikipedia : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly IWikipediaClient _wikipediaClient; diff --git a/src/Bot/Commands/Integrations/Youtube.cs b/src/Bot/Commands/Integrations/Youtube.cs index 50e9519..60ebdaa 100644 --- a/src/Bot/Commands/Integrations/Youtube.cs +++ b/src/Bot/Commands/Integrations/Youtube.cs @@ -1,59 +1,58 @@ -using Discord.Commands; -using Geekbot.Core; -// using Geekbot.Core.ErrorHandling; -// using Geekbot.Core.GlobalSettings; -// using Google.Apis.Services; -// using Google.Apis.YouTube.v3; +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.GlobalSettings; +using Google.Apis.Services; +using Google.Apis.YouTube.v3; namespace Geekbot.Bot.Commands.Integrations { - public class Youtube : TransactionModuleBase + public class Youtube : ModuleBase { - // private readonly IGlobalSettings _globalSettings; - // private readonly IErrorHandler _errorHandler; + private readonly IGlobalSettings _globalSettings; + private readonly IErrorHandler _errorHandler; - // public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler) - // { - // _globalSettings = globalSettings; - // _errorHandler = errorHandler; - // } + public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler) + { + _globalSettings = globalSettings; + _errorHandler = errorHandler; + } [Command("yt", RunMode = RunMode.Async)] [Summary("Search for something on youtube.")] public async Task Yt([Remainder] [Summary("title")] string searchQuery) { - await ReplyAsync("The youtube command is temporarily disabled"); - - // var key = _globalSettings.GetKey("YoutubeKey"); - // if (string.IsNullOrEmpty(key)) - // { - // await ReplyAsync("No youtube key set, please tell my senpai to set one"); - // return; - // } - // - // try - // { - // var youtubeService = new YouTubeService(new BaseClientService.Initializer - // { - // ApiKey = key, - // ApplicationName = GetType().ToString() - // }); - // - // var searchListRequest = youtubeService.Search.List("snippet"); - // searchListRequest.Q = searchQuery; - // searchListRequest.MaxResults = 2; - // - // var searchListResponse = await searchListRequest.ExecuteAsync(); - // - // var result = searchListResponse.Items[0]; - // - // await ReplyAsync( - // $"\"{result.Snippet.Title}\" from \"{result.Snippet.ChannelTitle}\" https://youtu.be/{result.Id.VideoId}"); - // } - // catch (Exception e) - // { - // await _errorHandler.HandleCommandException(e, Context); - // } + var key = _globalSettings.GetKey("YoutubeKey"); + if (string.IsNullOrEmpty(key)) + { + await ReplyAsync("No youtube key set, please tell my senpai to set one"); + return; + } + + try + { + var youtubeService = new YouTubeService(new BaseClientService.Initializer + { + ApiKey = key, + ApplicationName = GetType().ToString() + }); + + var searchListRequest = youtubeService.Search.List("snippet"); + searchListRequest.Q = searchQuery; + searchListRequest.MaxResults = 2; + + var searchListResponse = await searchListRequest.ExecuteAsync(); + + var result = searchListResponse.Items[0]; + + await ReplyAsync( + $"\"{result.Snippet.Title}\" from \"{result.Snippet.ChannelTitle}\" https://youtu.be/{result.Id.VideoId}"); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs b/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs index 23187bd..995c921 100644 --- a/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs +++ b/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs @@ -2,13 +2,12 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; using Geekbot.Core.RandomNumberGenerator; namespace Geekbot.Bot.Commands.Randomness { - public class BenedictCumberbatchNameGenerator : TransactionModuleBase + public class BenedictCumberbatchNameGenerator : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly IRandomNumberGenerator _randomNumberGenerator; diff --git a/src/Bot/Commands/Randomness/Cat/Cat.cs b/src/Bot/Commands/Randomness/Cat/Cat.cs index 1198113..7bd7e57 100644 --- a/src/Bot/Commands/Randomness/Cat/Cat.cs +++ b/src/Bot/Commands/Randomness/Cat/Cat.cs @@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Randomness.Cat { - public class Cat : TransactionModuleBase + public class Cat : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs b/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs index 523613b..febb66f 100644 --- a/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs +++ b/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs @@ -1,10 +1,7 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Randomness.Cat +namespace Geekbot.Bot.Commands.Randomness.Cat { internal class CatResponseDto { - [JsonPropertyName("file")] public string File { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs b/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs index 7c0aefa..99d9493 100644 --- a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs +++ b/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs @@ -1,10 +1,7 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Randomness.Chuck +namespace Geekbot.Bot.Commands.Randomness.Chuck { internal class ChuckNorrisJokeResponseDto { - [JsonPropertyName("value")] public string Value { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs b/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs index e2b1f16..be328b4 100644 --- a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs +++ b/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs @@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Randomness.Chuck { - public class ChuckNorrisJokes : TransactionModuleBase + public class ChuckNorrisJokes : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs b/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs index 012f9e9..2d72bdd 100644 --- a/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs +++ b/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs @@ -1,10 +1,7 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Randomness.Dad +namespace Geekbot.Bot.Commands.Randomness.Dad { internal class DadJokeResponseDto { - [JsonPropertyName("joke")] public string Joke { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Dad/DadJokes.cs b/src/Bot/Commands/Randomness/Dad/DadJokes.cs index 67f9679..136650c 100644 --- a/src/Bot/Commands/Randomness/Dad/DadJokes.cs +++ b/src/Bot/Commands/Randomness/Dad/DadJokes.cs @@ -6,7 +6,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Randomness.Dad { - public class DadJokes : TransactionModuleBase + public class DadJokes : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Randomness/Dog/Dog.cs b/src/Bot/Commands/Randomness/Dog/Dog.cs index 39e57c7..051dbf3 100644 --- a/src/Bot/Commands/Randomness/Dog/Dog.cs +++ b/src/Bot/Commands/Randomness/Dog/Dog.cs @@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Randomness.Dog { - public class Dog : TransactionModuleBase + public class Dog : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs b/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs index 9f0dfce..473c1ce 100644 --- a/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs +++ b/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs @@ -1,10 +1,7 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Randomness.Dog +namespace Geekbot.Bot.Commands.Randomness.Dog { internal class DogResponseDto { - [JsonPropertyName("url")] public string Url { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/EightBall.cs b/src/Bot/Commands/Randomness/EightBall.cs index b5f0c3a..e1a3a71 100644 --- a/src/Bot/Commands/Randomness/EightBall.cs +++ b/src/Bot/Commands/Randomness/EightBall.cs @@ -1,19 +1,18 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GuildSettingsManager; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Randomness { - public class EightBall : GeekbotCommandBase + public class EightBall : ModuleBase { - public EightBall(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) + private readonly IErrorHandler _errorHandler; + + public EightBall(IErrorHandler errorHandler) { + _errorHandler = errorHandler; } [Command("8ball", RunMode = RunMode.Async)] @@ -22,19 +21,36 @@ namespace Geekbot.Bot.Commands.Randomness { try { - var enumerator = Localization.EightBall.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true).GetEnumerator(); - var replies = new List(); - while (enumerator.MoveNext()) + var replies = new List { - replies.Add(enumerator.Value?.ToString()); - } - + "It is certain", + "It is decidedly so", + "Without a doubt", + "Yes, definitely", + "You may rely on it", + "As I see it, yes", + "Most likely", + "Outlook good", + "Yes", + "Signs point to yes", + "Reply hazy try again", + "Ask again later", + "Better not tell you now", + "Cannot predict now", + "Concentrate and ask again", + "Don't count on it", + "My reply is no", + "My sources say no", + "Outlook not so good", + "Very doubtful" + }; + var answer = new Random().Next(replies.Count); await ReplyAsync(replies[answer]); } catch (Exception e) { - await ErrorHandler.HandleCommandException(e, Context); + await _errorHandler.HandleCommandException(e, Context); } } } diff --git a/src/Bot/Commands/Randomness/Fortune.cs b/src/Bot/Commands/Randomness/Fortune.cs index 1157603..cc31536 100644 --- a/src/Bot/Commands/Randomness/Fortune.cs +++ b/src/Bot/Commands/Randomness/Fortune.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.Media; namespace Geekbot.Bot.Commands.Randomness { - public class Fortune : TransactionModuleBase + public class Fortune : ModuleBase { private readonly IFortunesProvider _fortunes; diff --git a/src/Bot/Commands/Randomness/Gdq.cs b/src/Bot/Commands/Randomness/Gdq.cs new file mode 100644 index 0000000..c6d9fa8 --- /dev/null +++ b/src/Bot/Commands/Randomness/Gdq.cs @@ -0,0 +1,36 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.Core.ErrorHandling; + +namespace Geekbot.Bot.Commands.Randomness +{ + public class Gdq : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Gdq(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("gdq", RunMode = RunMode.Async)] + [Summary("Get a quote from the GDQ donation generator.")] + public async Task GetQuote() + { + try + { + using var client = new WebClient(); + var url = new Uri("http://taskinoz.com/gdq/api/"); + var response = client.DownloadString(url); + + await ReplyAsync(response); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Greetings/GreetingBaseDto.cs b/src/Bot/Commands/Randomness/Greetings/GreetingBaseDto.cs new file mode 100644 index 0000000..ae0274b --- /dev/null +++ b/src/Bot/Commands/Randomness/Greetings/GreetingBaseDto.cs @@ -0,0 +1,11 @@ +namespace Geekbot.Bot.Commands.Randomness.Greetings +{ + public class GreetingBaseDto + { + public string Language { get; set; } + public string LanguageNative { get; set; } + public string LanguageCode { get; set; } + public string Script { get; set; } + public GreetingDto Primary { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Greetings/GreetingDto.cs b/src/Bot/Commands/Randomness/Greetings/GreetingDto.cs new file mode 100644 index 0000000..679e544 --- /dev/null +++ b/src/Bot/Commands/Randomness/Greetings/GreetingDto.cs @@ -0,0 +1,10 @@ +namespace Geekbot.Bot.Commands.Randomness.Greetings +{ + public class GreetingDto + { + public string Text { get; set; } + public string Dialect { get; set; } + public string Romanization { get; set; } + public string[] Use { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Greetings/Greetings.cs b/src/Bot/Commands/Randomness/Greetings/Greetings.cs new file mode 100644 index 0000000..cd69010 --- /dev/null +++ b/src/Bot/Commands/Randomness/Greetings/Greetings.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.Core; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.Extensions; + +namespace Geekbot.Bot.Commands.Randomness.Greetings +{ + public class Greetings : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Greetings(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("hello", RunMode = RunMode.Async)] + [Alias("greeting", "hi", "hallo")] + [Summary("Say hello to the bot and get a reply in a random language")] + public async Task GetGreeting() + { + try + { + var greeting = await HttpAbstractions.Get(new Uri("https://api.greetings.dev/v1/greeting")); + + var eb = new EmbedBuilder(); + eb.Title = greeting.Primary.Text; + eb.AddInlineField("Language", greeting.Language); + + if (greeting.Primary.Dialect != null) + { + eb.AddInlineField("Dialect", greeting.Primary.Dialect); + } + + if (greeting.Primary.Romanization != null) + { + eb.AddInlineField("Roman", greeting.Primary.Romanization); + } + + await ReplyAsync(string.Empty, false, eb.Build()); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Kanye/Kanye.cs b/src/Bot/Commands/Randomness/Kanye/Kanye.cs index e5d2e95..6ad67cb 100644 --- a/src/Bot/Commands/Randomness/Kanye/Kanye.cs +++ b/src/Bot/Commands/Randomness/Kanye/Kanye.cs @@ -6,7 +6,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Randomness.Kanye { - public class Kanye : TransactionModuleBase + public class Kanye : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs b/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs index ab8c06f..8ca248e 100644 --- a/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs +++ b/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs @@ -1,10 +1,8 @@ -using System.Text.Json.Serialization; - namespace Geekbot.Bot.Commands.Randomness.Kanye { public class KanyeResponseDto { - [JsonPropertyName("quote")] + public string Id { get; set; } public string Quote { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/RandomAnimals.cs b/src/Bot/Commands/Randomness/RandomAnimals.cs index 5493485..b9c1bdd 100644 --- a/src/Bot/Commands/Randomness/RandomAnimals.cs +++ b/src/Bot/Commands/Randomness/RandomAnimals.cs @@ -1,12 +1,11 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.Media; namespace Geekbot.Bot.Commands.Randomness { - public class RandomAnimals : TransactionModuleBase + public class RandomAnimals : ModuleBase { private readonly IMediaProvider _mediaProvider; diff --git a/src/Bot/Commands/Randomness/Ship.cs b/src/Bot/Commands/Randomness/Ship.cs index 55e55c5..f48713e 100644 --- a/src/Bot/Commands/Randomness/Ship.cs +++ b/src/Bot/Commands/Randomness/Ship.cs @@ -10,7 +10,6 @@ using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.RandomNumberGenerator; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Randomness { diff --git a/src/Bot/Commands/Randomness/Slap.cs b/src/Bot/Commands/Randomness/Slap.cs index c99c325..b512e73 100644 --- a/src/Bot/Commands/Randomness/Slap.cs +++ b/src/Bot/Commands/Randomness/Slap.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; @@ -12,7 +11,7 @@ using Geekbot.Core.Extensions; namespace Geekbot.Bot.Commands.Randomness { - public class Slap : TransactionModuleBase + public class Slap : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly DatabaseContext _database; @@ -77,14 +76,10 @@ namespace Geekbot.Bot.Commands.Randomness "teapot", "candle", "dictionary", - "powerless banhammer", - "piece of low fat mozzarella", - // For some reason it never picks the last one - // Adding this workaround, because i'm to lazy to actually fix it at the time of writing this - "padding" + "powerless banhammer" }; - await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[new Random().Next(0, things.Count - 1)]}"); + await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[new Random().Next(things.Count - 1)]}"); await UpdateRecieved(user.Id); await UpdateGiven(Context.User.Id); @@ -132,4 +127,4 @@ namespace Geekbot.Bot.Commands.Randomness e.UserId.Equals(userId.AsLong())); } } -} +} \ No newline at end of file diff --git a/src/Bot/Commands/Rpg/Cookies.cs b/src/Bot/Commands/Rpg/Cookies.cs index 66d845f..a51d652 100644 --- a/src/Bot/Commands/Rpg/Cookies.cs +++ b/src/Bot/Commands/Rpg/Cookies.cs @@ -3,15 +3,15 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; +using Geekbot.Bot.Utils; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.RandomNumberGenerator; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Rpg { @@ -37,16 +37,14 @@ namespace Geekbot.Bot.Commands.Rpg try { var actor = await GetUser(Context.User.Id); - var timeoutDays = 1; - if (actor.LastPayout?.AddDays(timeoutDays) > DateTime.Now.ToUniversalTime()) + if (actor.LastPayout.Value.AddDays(1).Date > DateTime.Now.Date) { - var remaining = actor.LastPayout.Value.AddDays(timeoutDays) - DateTimeOffset.Now.ToUniversalTime(); - var formattedWaitTime = DateLocalization.FormatDateTimeAsRemaining(remaining); + var formattedWaitTime = DateLocalization.FormatDateTimeAsRemaining(DateTimeOffset.Now.AddDays(1).Date); await ReplyAsync(string.Format(Localization.Cookies.WaitForMoreCookies, formattedWaitTime)); return; } actor.Cookies += 10; - actor.LastPayout = DateTimeOffset.Now.ToUniversalTime(); + actor.LastPayout = DateTimeOffset.Now; await SetUser(actor); await ReplyAsync(string.Format(Localization.Cookies.GetCookies, 10, actor.Cookies)); @@ -80,12 +78,6 @@ namespace Geekbot.Bot.Commands.Rpg { var giver = await GetUser(Context.User.Id); - if (amount < 1) - { - await ReplyAsync(Localization.Cookies.CantTakeCookies); - return; - } - if (giver.Cookies < amount) { await ReplyAsync(Localization.Cookies.NotEnoughToGive); @@ -154,7 +146,7 @@ namespace Geekbot.Bot.Commands.Rpg GuildId = Context.Guild.Id.AsLong(), UserId = userId.AsLong(), Cookies = 0, - LastPayout = DateTimeOffset.MinValue.ToUniversalTime() + LastPayout = DateTimeOffset.MinValue }; var newUser = _database.Cookies.Add(user).Entity; await _database.SaveChangesAsync(); diff --git a/src/Bot/Commands/User/GuildInfo.cs b/src/Bot/Commands/User/GuildInfo.cs index c063d89..c596186 100644 --- a/src/Bot/Commands/User/GuildInfo.cs +++ b/src/Bot/Commands/User/GuildInfo.cs @@ -3,8 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; @@ -12,7 +11,7 @@ using Geekbot.Core.Levels; namespace Geekbot.Bot.Commands.User { - public class GuildInfo : TransactionModuleBase + public class GuildInfo : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly DatabaseContext _database; diff --git a/src/Bot/Commands/User/Karma.cs b/src/Bot/Commands/User/Karma.cs index 469c371..4778bce 100644 --- a/src/Bot/Commands/User/Karma.cs +++ b/src/Bot/Commands/User/Karma.cs @@ -1,11 +1,13 @@ using System; +using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Commands.Karma; +using Geekbot.Bot.Utils; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; +using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; @@ -25,52 +27,123 @@ namespace Geekbot.Bot.Commands.User [Command("good", RunMode = RunMode.Async)] [Summary("Increase Someones Karma")] public async Task Good([Summary("@someone")] IUser user) - { - await ChangeKarma(user, KarmaChange.Up); - } - - [Command("bad", RunMode = RunMode.Async)] - [Summary("Decrease Someones Karma")] - public async Task Bad([Summary("@someone")] IUser user) - { - await ChangeKarma(user, KarmaChange.Down); - } - - [Command("neutral", RunMode = RunMode.Async)] - [Summary("Do nothing to someones Karma")] - public async Task Neutral([Summary("@someone")] IUser user) - { - await ChangeKarma(user, KarmaChange.Same); - } - - private async Task ChangeKarma(IUser user, KarmaChange change) { try { - var author = new Interactions.Resolved.User() + var actor = await GetUser(Context.User.Id); + if (user.Id == Context.User.Id) { - Id = Context.User.Id.ToString(), - Username = Context.User.Username, - Discriminator = Context.User.Discriminator, - Avatar = Context.User.AvatarId, - }; - var targetUser = new Interactions.Resolved.User() + await ReplyAsync(string.Format(Localization.Karma.CannotChangeOwnUp, Context.User.Username)); + } + else if (TimeoutFinished(actor.TimeOut)) { - Id = user.Id.ToString(), - Username = user.Username, - Discriminator = user.Discriminator, - Avatar = user.AvatarId, - }; - - var karma = new Geekbot.Commands.Karma.Karma(_database, Context.Guild.Id.AsLong()); - var res = await karma.ChangeKarma(author, targetUser, change); + var formatedWaitTime = DateLocalization.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3)); + await ReplyAsync(string.Format(Localization.Karma.WaitUntill, Context.User.Username, formatedWaitTime)); + } + else + { + var target = await GetUser(user.Id); + target.Karma += 1; + SetUser(target); + + actor.TimeOut = DateTimeOffset.Now; + SetUser(actor); - await ReplyAsync(string.Empty, false, res.ToDiscordNetEmbed().Build()); + await _database.SaveChangesAsync(); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(user.GetAvatarUrl()) + .WithName(user.Username)); + + eb.WithColor(new Color(138, 219, 146)); + eb.Title = Localization.Karma.Increased; + eb.AddInlineField(Localization.Karma.By, Context.User.Username); + eb.AddInlineField(Localization.Karma.Amount, "+1"); + eb.AddInlineField(Localization.Karma.Current, target.Karma); + await ReplyAsync("", false, eb.Build()); + } } catch (Exception e) { await ErrorHandler.HandleCommandException(e, Context); } } + + [Command("bad", RunMode = RunMode.Async)] + [Summary("Decrease Someones Karma")] + public async Task Bad([Summary("@someone")] IUser user) + { + try + { + var actor = await GetUser(Context.User.Id); + if (user.Id == Context.User.Id) + { + await ReplyAsync(string.Format(Localization.Karma.CannotChangeOwnDown, Context.User.Username)); + } + else if (TimeoutFinished(actor.TimeOut)) + { + var formatedWaitTime = DateLocalization.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3)); + await ReplyAsync(string.Format(Localization.Karma.WaitUntill, Context.User.Username, formatedWaitTime)); + } + else + { + var target = await GetUser(user.Id); + target.Karma -= 1; + SetUser(target); + + actor.TimeOut = DateTimeOffset.Now; + SetUser(actor); + + await _database.SaveChangesAsync(); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(user.GetAvatarUrl()) + .WithName(user.Username)); + + eb.WithColor(new Color(138, 219, 146)); + eb.Title = Localization.Karma.Decreased; + eb.AddInlineField(Localization.Karma.By, Context.User.Username); + eb.AddInlineField(Localization.Karma.Amount, "-1"); + eb.AddInlineField(Localization.Karma.Current, target.Karma); + await ReplyAsync("", false, eb.Build()); + } + } + catch (Exception e) + { + await ErrorHandler.HandleCommandException(e, Context); + } + } + + private bool TimeoutFinished(DateTimeOffset lastKarma) + { + return lastKarma.AddMinutes(3) > DateTimeOffset.Now; + } + + private async Task GetUser(ulong userId) + { + var user = _database.Karma.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId); + return user; + } + + private void SetUser(KarmaModel user) + { + _database.Karma.Update(user); + } + + private async Task CreateNewRow(ulong userId) + { + var user = new KarmaModel() + { + GuildId = Context.Guild.Id.AsLong(), + UserId = userId.AsLong(), + Karma = 0, + TimeOut = DateTimeOffset.MinValue + }; + var newUser = _database.Karma.Add(user).Entity; + await _database.SaveChangesAsync(); + return newUser; + } } } \ No newline at end of file diff --git a/src/Bot/Commands/User/Rank.cs b/src/Bot/Commands/User/Rank.cs deleted file mode 100644 index 639469f..0000000 --- a/src/Bot/Commands/User/Rank.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.Highscores; - -namespace Geekbot.Bot.Commands.User -{ - public class Rank : GeekbotCommandBase - { - private readonly IHighscoreManager _highscoreManager; - private readonly DatabaseContext _database; - - public Rank(DatabaseContext database, IErrorHandler errorHandler, IHighscoreManager highscoreManager, IGuildSettingsManager guildSettingsManager) - : base(errorHandler, guildSettingsManager) - { - _database = database; - _highscoreManager = highscoreManager; - } - - [Command("rank", RunMode = RunMode.Async)] - [Summary("Get the highscore for various stats like message count, karma, correctly guessed roles, etc...")] - [DisableInDirectMessage] - public async Task RankCmd( - [Summary("type")] string typeUnformated = "messages", - [Summary("amount")] int amount = 10, - [Summary("season")] string season = null) - { - try - { - var res = new Geekbot.Commands.Rank(_database, _highscoreManager) - .Run(typeUnformated, amount, season, Context.Guild.Id, Context.Guild.Name); - await ReplyAsync(res); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/User/Ranking/Rank.cs b/src/Bot/Commands/User/Ranking/Rank.cs new file mode 100644 index 0000000..20749a8 --- /dev/null +++ b/src/Bot/Commands/User/Ranking/Rank.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; +using Geekbot.Core.Converters; +using Geekbot.Core.Database; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.Extensions; +using Geekbot.Core.GuildSettingsManager; +using Geekbot.Core.Highscores; + +namespace Geekbot.Bot.Commands.User.Ranking +{ + public class Rank : GeekbotCommandBase + { + private readonly IEmojiConverter _emojiConverter; + private readonly IHighscoreManager _highscoreManager; + private readonly DatabaseContext _database; + + public Rank(DatabaseContext database, IErrorHandler errorHandler, IEmojiConverter emojiConverter, IHighscoreManager highscoreManager, IGuildSettingsManager guildSettingsManager) + : base(errorHandler, guildSettingsManager) + { + _database = database; + _emojiConverter = emojiConverter; + _highscoreManager = highscoreManager; + } + + [Command("rank", RunMode = RunMode.Async)] + [Summary("get user top 10 in messages or karma")] + [DisableInDirectMessage] + public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10) + { + try + { + HighscoreTypes type; + try + { + type = Enum.Parse(typeUnformated, true); + if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception(); + } + catch + { + await ReplyAsync(Localization.Rank.InvalidType); + return; + } + + var replyBuilder = new StringBuilder(); + if (amount > 20) + { + await ReplyAsync(Localization.Rank.LimitingTo20Warning); + amount = 20; + } + + var guildId = Context.Guild.Id; + Dictionary highscoreUsers; + try + { + highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount); + } + catch (HighscoreListEmptyException) + { + await ReplyAsync(string.Format(Localization.Rank.NoTypeFoundForServer, type)); + return; + } + + var guildMessages = 0; + if (type == HighscoreTypes.messages) + { + guildMessages = _database.Messages + .Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())) + .Select(e => e.MessageCount) + .Sum(); + } + + var failedToRetrieveUser = highscoreUsers.Any(e => string.IsNullOrEmpty(e.Key.Username)); + + if (failedToRetrieveUser) replyBuilder.AppendLine(Localization.Rank.FailedToResolveAllUsernames).AppendLine(); + + replyBuilder.AppendLine(string.Format(Localization.Rank.HighscoresFor, type.ToString().CapitalizeFirst(), Context.Guild.Name)); + + var highscorePlace = 1; + foreach (var (user, value) in highscoreUsers) + { + replyBuilder.Append(highscorePlace < 11 + ? $"{_emojiConverter.NumberToEmoji(highscorePlace)} " + : $"`{highscorePlace}.` "); + + replyBuilder.Append(user.Username != null + ? $"**{user.Username}#{user.Discriminator}**" + : $"**{user.Id}**"); + + replyBuilder.Append(type == HighscoreTypes.messages + ? $" - {value} {type} - {Math.Round((double) (100 * value) / guildMessages, 2)}%\n" + : $" - {value} {type}\n"); + + highscorePlace++; + } + + await ReplyAsync(replyBuilder.ToString()); + } + catch (Exception e) + { + await ErrorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/User/Stats.cs b/src/Bot/Commands/User/Stats.cs index 61505c0..a2a54a2 100644 --- a/src/Bot/Commands/User/Stats.cs +++ b/src/Bot/Commands/User/Stats.cs @@ -3,14 +3,13 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; using Geekbot.Core.ErrorHandling; using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.Levels; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.User { @@ -55,8 +54,6 @@ namespace Geekbot.Bot.Commands.User ?.FirstOrDefault(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong())) ?.Cookies ?? 0; - var quotes = _database.Quotes.Count(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong())); - var eb = new EmbedBuilder(); eb.WithAuthor(new EmbedAuthorBuilder() .WithIconUrl(userInfo.GetAvatarUrl()) @@ -71,9 +68,9 @@ namespace Geekbot.Bot.Commands.User e.UserId.Equals(userInfo.Id.AsLong())); eb.AddInlineField(Localization.Stats.OnDiscordSince, - $"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} {Localization.Stats.Days})") + $"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} days)") .AddInlineField(Localization.Stats.JoinedServer, - $"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} {Localization.Stats.Days})") + $"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} days)") .AddInlineField(Localization.Stats.Karma, karma?.Karma ?? 0) .AddInlineField(Localization.Stats.Level, level) .AddInlineField(Localization.Stats.MessagesSent, messages) @@ -81,7 +78,6 @@ namespace Geekbot.Bot.Commands.User if (correctRolls != null) eb.AddInlineField(Localization.Stats.GuessedRolls, correctRolls.Rolls); if (cookies > 0) eb.AddInlineField(Localization.Stats.Cookies, cookies); - if (quotes > 0) eb.AddInlineField(Localization.Stats.Quotes, quotes); await ReplyAsync("", false, eb.Build()); } diff --git a/src/Bot/Commands/Utils/AvatarGetter.cs b/src/Bot/Commands/Utils/AvatarGetter.cs index 458eec8..6585a75 100644 --- a/src/Bot/Commands/Utils/AvatarGetter.cs +++ b/src/Bot/Commands/Utils/AvatarGetter.cs @@ -2,12 +2,11 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils { - public class AvatarGetter : TransactionModuleBase + public class AvatarGetter : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -22,8 +21,8 @@ namespace Geekbot.Bot.Commands.Utils { try { - user ??= Context.User; - var url = user.GetAvatarUrl(ImageFormat.Auto, 1024); + if (user == null) user = Context.User; + var url = user.GetAvatarUrl().Replace("128", "1024"); await ReplyAsync(url); } catch (Exception e) diff --git a/src/Bot/Commands/Utils/Changelog/Changelog.cs b/src/Bot/Commands/Utils/Changelog/Changelog.cs index 989ac0d..92d5ddd 100644 --- a/src/Bot/Commands/Utils/Changelog/Changelog.cs +++ b/src/Bot/Commands/Utils/Changelog/Changelog.cs @@ -11,7 +11,7 @@ using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils.Changelog { - public class Changelog : TransactionModuleBase + public class Changelog : ModuleBase { private readonly DiscordSocketClient _client; private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs b/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs index 19d93eb..7cabece 100644 --- a/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs +++ b/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs @@ -1,17 +1,11 @@ using System; -using System.Text.Json.Serialization; namespace Geekbot.Bot.Commands.Utils.Changelog { public class CommitAuthorDto { - [JsonPropertyName("name")] public string Name { get; set; } - - [JsonPropertyName("email")] public string Email { get; set; } - - [JsonPropertyName("date")] public DateTimeOffset Date { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Changelog/CommitDto.cs b/src/Bot/Commands/Utils/Changelog/CommitDto.cs index e67d08c..a534730 100644 --- a/src/Bot/Commands/Utils/Changelog/CommitDto.cs +++ b/src/Bot/Commands/Utils/Changelog/CommitDto.cs @@ -1,10 +1,7 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Utils.Changelog +namespace Geekbot.Bot.Commands.Utils.Changelog { public class CommitDto { - [JsonPropertyName("commit")] public CommitInfoDto Commit { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs b/src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs index 592da9e..d6f806e 100644 --- a/src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs +++ b/src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs @@ -1,13 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Utils.Changelog +namespace Geekbot.Bot.Commands.Utils.Changelog { public class CommitInfoDto { - [JsonPropertyName("author")] public CommitAuthorDto Author { get; set; } - - [JsonPropertyName("message")] public string Message { get; set; } } } \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Choose.cs b/src/Bot/Commands/Utils/Choose.cs index 450433d..731bee6 100644 --- a/src/Bot/Commands/Utils/Choose.cs +++ b/src/Bot/Commands/Utils/Choose.cs @@ -1,8 +1,9 @@ -using Discord.Commands; +using System; +using System.Threading.Tasks; +using Discord.Commands; using Geekbot.Core; using Geekbot.Core.ErrorHandling; using Geekbot.Core.GuildSettingsManager; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Utils { @@ -13,7 +14,7 @@ namespace Geekbot.Bot.Commands.Utils } [Command("choose", RunMode = RunMode.Async)] - [Summary("Let the bot choose for you, separate options with a semicolon.")] + [Summary("Let the bot choose for you, seperate options with a semicolon.")] public async Task Command([Remainder] [Summary("option1;option2")] string choices) { diff --git a/src/Bot/Commands/Utils/Corona/CoronaStats.cs b/src/Bot/Commands/Utils/Corona/CoronaStats.cs new file mode 100644 index 0000000..3f9f3ea --- /dev/null +++ b/src/Bot/Commands/Utils/Corona/CoronaStats.cs @@ -0,0 +1,66 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.Core; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.Extensions; + +namespace Geekbot.Bot.Commands.Utils.Corona +{ + public class CoronaStats : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public CoronaStats(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("corona", RunMode = RunMode.Async)] + [Summary("Get the latest worldwide corona statistics")] + public async Task Summary() + { + try + { + var summary = await HttpAbstractions.Get(new Uri("https://api.covid19api.com/world/total")); + var activeCases = summary.TotalConfirmed - (summary.TotalRecovered + summary.TotalDeaths); + + string CalculatePercentage(decimal i) => (i / summary.TotalConfirmed).ToString("#0.##%"); + var activePercent = CalculatePercentage(activeCases); + var recoveredPercentage = CalculatePercentage(summary.TotalRecovered); + var deathsPercentage = CalculatePercentage(summary.TotalDeaths); + + var numberFormat = "#,#"; + var totalFormatted = summary.TotalConfirmed.ToString(numberFormat); + var activeFormatted = activeCases.ToString(numberFormat); + var recoveredFormatted = summary.TotalRecovered.ToString(numberFormat); + var deathsFormatted = summary.TotalDeaths.ToString(numberFormat); + + var eb = new EmbedBuilder + { + Author = new EmbedAuthorBuilder + { + Name = "Confirmed Corona Cases", + IconUrl = "https://www.redcross.org/content/dam/icons/disasters/virus/Virus-1000x1000-R-Pl.png" + }, + Footer = new EmbedFooterBuilder + { + Text = "Source: covid19api.com", + }, + Color = Color.Red + }; + eb.AddField("Total", totalFormatted); + eb.AddInlineField("Active", $"{activeFormatted} ({activePercent})"); + eb.AddInlineField("Recovered", $"{recoveredFormatted} ({recoveredPercentage})"); + eb.AddInlineField("Deaths", $"{deathsFormatted} ({deathsPercentage})"); + + await Context.Channel.SendMessageAsync(String.Empty, false, eb.Build()); + } + catch (Exception e) + { + await _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Corona/CoronaSummaryDto.cs b/src/Bot/Commands/Utils/Corona/CoronaSummaryDto.cs new file mode 100644 index 0000000..3f6a820 --- /dev/null +++ b/src/Bot/Commands/Utils/Corona/CoronaSummaryDto.cs @@ -0,0 +1,9 @@ +namespace Geekbot.Bot.Commands.Utils.Corona +{ + public class CoronaSummaryDto + { + public decimal TotalConfirmed { get; set; } + public decimal TotalDeaths { get; set; } + public decimal TotalRecovered { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Dice.cs b/src/Bot/Commands/Utils/Dice.cs index c57001f..0668493 100644 --- a/src/Bot/Commands/Utils/Dice.cs +++ b/src/Bot/Commands/Utils/Dice.cs @@ -3,13 +3,12 @@ using System.Collections.Generic; using System.Text; using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.DiceParser; using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils { - public class Dice : TransactionModuleBase + public class Dice : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly IDiceParser _diceParser; diff --git a/src/Bot/Commands/Utils/Emojify.cs b/src/Bot/Commands/Utils/Emojify.cs index a513710..8bb880e 100644 --- a/src/Bot/Commands/Utils/Emojify.cs +++ b/src/Bot/Commands/Utils/Emojify.cs @@ -1,17 +1,20 @@ -using Discord.Commands; -using Geekbot.Core; +using System; +using System.Threading.Tasks; +using Discord.Commands; using Geekbot.Core.Converters; using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils { - public class Emojify : TransactionModuleBase + public class Emojify : ModuleBase { + private readonly IEmojiConverter _emojiConverter; private readonly IErrorHandler _errorHandler; - public Emojify(IErrorHandler errorHandler) + public Emojify(IErrorHandler errorHandler, IEmojiConverter emojiConverter) { _errorHandler = errorHandler; + _emojiConverter = emojiConverter; } [Command("emojify", RunMode = RunMode.Async)] @@ -20,7 +23,7 @@ namespace Geekbot.Bot.Commands.Utils { try { - var emojis = EmojiConverter.TextToEmoji(text); + var emojis = _emojiConverter.TextToEmoji(text); if (emojis.Length > 1999) { await ReplyAsync("I can't take that much at once!"); diff --git a/src/Bot/Commands/Utils/Help.cs b/src/Bot/Commands/Utils/Help.cs index 7aa9aff..58630fe 100644 --- a/src/Bot/Commands/Utils/Help.cs +++ b/src/Bot/Commands/Utils/Help.cs @@ -3,12 +3,11 @@ using System.Text; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils { - public class Help : TransactionModuleBase + public class Help : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -27,7 +26,7 @@ namespace Geekbot.Bot.Commands.Utils sb.AppendLine("For a list of all commands, please visit the following page"); sb.AppendLine("https://geekbot.pizzaandcoffee.rocks/commands"); - var dm = await Context.User.CreateDMChannelAsync(RequestOptions.Default); + var dm = await Context.User.GetOrCreateDMChannelAsync(); await dm.SendMessageAsync(sb.ToString()); await Context.Message.AddReactionAsync(new Emoji("✅")); } diff --git a/src/Bot/Commands/Utils/Info.cs b/src/Bot/Commands/Utils/Info.cs index 912528d..663dd07 100644 --- a/src/Bot/Commands/Utils/Info.cs +++ b/src/Bot/Commands/Utils/Info.cs @@ -11,7 +11,7 @@ using Geekbot.Core.Extensions; namespace Geekbot.Bot.Commands.Utils { - public class Info : TransactionModuleBase + public class Info : ModuleBase { private readonly DiscordSocketClient _client; private readonly CommandService _commands; diff --git a/src/Bot/Commands/Utils/Lmgtfy.cs b/src/Bot/Commands/Utils/Lmgtfy.cs index 76fa6fa..6063cf9 100644 --- a/src/Bot/Commands/Utils/Lmgtfy.cs +++ b/src/Bot/Commands/Utils/Lmgtfy.cs @@ -2,12 +2,11 @@ using System; using System.Threading.Tasks; using System.Web; using Discord.Commands; -using Geekbot.Core; using Geekbot.Core.ErrorHandling; namespace Geekbot.Bot.Commands.Utils { - public class Lmgtfy : TransactionModuleBase + public class Lmgtfy : ModuleBase { private readonly IErrorHandler _errorHandler; diff --git a/src/Bot/Commands/Utils/Ping.cs b/src/Bot/Commands/Utils/Ping.cs index ee751cd..d4faa53 100644 --- a/src/Bot/Commands/Utils/Ping.cs +++ b/src/Bot/Commands/Utils/Ping.cs @@ -1,10 +1,9 @@ using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; namespace Geekbot.Bot.Commands.Utils { - public class Ping : TransactionModuleBase + public class Ping : ModuleBase { [Command("👀", RunMode = RunMode.Async)] [Summary("Look at the bot.")] diff --git a/src/Bot/Commands/Utils/Quote/Quote.cs b/src/Bot/Commands/Utils/Quote/Quote.cs index 243e5dd..0b197cd 100644 --- a/src/Bot/Commands/Utils/Quote/Quote.cs +++ b/src/Bot/Commands/Utils/Quote/Quote.cs @@ -4,8 +4,8 @@ using System.Text; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; using Geekbot.Core; +using Geekbot.Core.CommandPreconditions; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.ErrorHandling; @@ -13,11 +13,6 @@ using Geekbot.Core.Extensions; using Geekbot.Core.GuildSettingsManager; using Geekbot.Core.Polyfills; using Geekbot.Core.RandomNumberGenerator; -using Geekbot.Core.UserRepository; -using Microsoft.EntityFrameworkCore; -using Sentry; -using Constants = Geekbot.Core.Constants; -using Localization = Geekbot.Core.Localization; namespace Geekbot.Bot.Commands.Utils.Quote { @@ -27,15 +22,13 @@ namespace Geekbot.Bot.Commands.Utils.Quote { private readonly DatabaseContext _database; private readonly IRandomNumberGenerator _randomNumberGenerator; - private readonly IUserRepository _userRepository; private readonly bool _isDev; - public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager, IUserRepository userRepository) + public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) { _database = database; _randomNumberGenerator = randomNumberGenerator; - _userRepository = userRepository; // to remove restrictions when developing _isDev = Constants.BotVersion() == "0.0.0-DEV"; } @@ -46,26 +39,23 @@ namespace Geekbot.Bot.Commands.Utils.Quote { try { - var getQuoteFromDbSpan = Transaction.StartChild("GetQuoteFromDB"); - var quote = _database.Quotes.FromSqlInterpolated($"select * from \"Quotes\" where \"GuildId\" = {Context.Guild.Id} order by random() limit 1"); - getQuoteFromDbSpan.Finish(); - - if (!quote.Any()) + var totalQuotes = await _database.Quotes.CountAsync(e => e.GuildId.Equals(Context.Guild.Id.AsLong())); + + if (totalQuotes == 0) { await ReplyAsync(Localization.Quote.NoQuotesFound); - Transaction.Status = SpanStatus.NotFound; return; } - var buildQuoteEmbedSpan = Transaction.StartChild("BuildQuoteEmbed"); + var random = _randomNumberGenerator.Next(0, totalQuotes - 1); + var quote = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).Skip(random).Take(1); + var embed = QuoteBuilder(quote.FirstOrDefault()); - buildQuoteEmbedSpan.Finish(); await ReplyAsync("", false, embed.Build()); } catch (Exception e) { await ErrorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return"); - Transaction.Status = SpanStatus.InternalError; } } @@ -84,6 +74,22 @@ namespace Geekbot.Bot.Commands.Utils.Quote { await QuoteFromMention(user, false); } + + [Command("add")] + [Alias("save")] + [Summary("Add a quote from a message id")] + public async Task AddQuote([Summary("message-ID")] ulong messageId) + { + await QuoteFromMessageId(messageId, true); + } + + [Command("make")] + [Alias("preview")] + [Summary("Preview a quote from a message id")] + public async Task ReturnSpecifiedQuote([Summary("message-ID")] ulong messageId) + { + await QuoteFromMessageId(messageId, false); + } [Command("add")] [Alias("save")] @@ -154,8 +160,8 @@ namespace Geekbot.Bot.Commands.Utils.Quote .Where(row => row.GuildId == Context.Guild.Id.AsLong()) .GroupBy(row => row.UserId) .Select(row => new { userId = row.Key, amount = row.Count()}) - .OrderByDescending(row => row.amount) - .First(); + .OrderBy(row => row.amount) + .Last(); var mostQuotedPersonUser = Context.Client.GetUserAsync(mostQuotedPerson.userId.AsUlong()).Result ?? new UserPolyfillDto {Username = "Unknown User"}; var quotesByYear = _database.Quotes @@ -202,7 +208,21 @@ namespace Geekbot.Bot.Commands.Utils.Quote } - private async Task QuoteFromMessageLink(string messageLink, bool saveToDb) + private async Task QuoteFromMessageId(ulong messageId, bool saveToDb) + { + try + { + var message = await Context.Channel.GetMessageAsync(messageId); + + await ProcessQuote(message, saveToDb, true); + } + catch (Exception e) + { + await ErrorHandler.HandleCommandException(e, Context, "I couldn't find a message with that id :disappointed:"); + } + } + + private async Task QuoteFromMessageLink(string messageLink, bool saveToDb) { try { @@ -233,7 +253,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote } } - private async Task ProcessQuote(IMessage message, bool saveToDb) + private async Task ProcessQuote(IMessage message, bool saveToDb, bool showMessageIdWarning = false) { if (message.Author.Id == Context.Message.Author.Id && saveToDb && !_isDev) { @@ -258,38 +278,27 @@ namespace Geekbot.Bot.Commands.Utils.Quote var sb = new StringBuilder(); if (saveToDb) sb.AppendLine(Localization.Quote.QuoteAdded); + if (showMessageIdWarning) sb.AppendLine(Localization.Quote.MessageIdDeprecation); await ReplyAsync(sb.ToString(), false, embed.Build()); } private EmbedBuilder QuoteBuilder(QuoteModel quote) { - var getEmbedUserSpan = Transaction.StartChild("GetEmbedUser"); - var user = Context.Client.GetUserAsync(quote.UserId.AsUlong()).Result; - if (user == null) - { - var getEmbedUserFromRepoSpan = Transaction.StartChild("GetEmbedUserFromRepo"); - var fallbackUserFromRepo = _userRepository.Get(quote.UserId.AsUlong()); - user = new UserPolyfillDto() - { - Username = fallbackUserFromRepo?.Username ?? "Unknown User", - AvatarUrl = fallbackUserFromRepo?.AvatarUrl - }; - getEmbedUserFromRepoSpan.Finish(); - } - getEmbedUserSpan.Finish(); - - var embedBuilderSpan = Transaction.StartChild("EmbedBuilder"); + var user = Context.Client.GetUserAsync(quote.UserId.AsUlong()).Result ?? new UserPolyfillDto { Username = "Unknown User" }; var eb = new EmbedBuilder(); eb.WithColor(new Color(143, 167, 232)); - eb.Title = quote.InternalId == 0 - ? $"{user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}" - : $"#{quote.InternalId} | {user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}"; + if (quote.InternalId == 0) + { + eb.Title = $"{user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}"; + } + else + { + eb.Title = $"#{quote.InternalId} | {user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}"; + } eb.Description = quote.Quote; eb.ThumbnailUrl = user.GetAvatarUrl(); if (quote.Image != null) eb.ImageUrl = quote.Image; - embedBuilderSpan.Finish(); - return eb; } @@ -313,7 +322,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote InternalId = internalId, GuildId = Context.Guild.Id.AsLong(), UserId = message.Author.Id.AsLong(), - Time = message.Timestamp.DateTime.ToUniversalTime(), + Time = message.Timestamp.DateTime, Quote = message.Content, Image = image }; diff --git a/src/Bot/Handlers/CommandHandler.cs b/src/Bot/Handlers/CommandHandler.cs index 19d4edd..52e9a52 100644 --- a/src/Bot/Handlers/CommandHandler.cs +++ b/src/Bot/Handlers/CommandHandler.cs @@ -21,10 +21,12 @@ namespace Geekbot.Bot.Handlers private readonly RestApplication _applicationInfo; private readonly IGuildSettingsManager _guildSettingsManager; private readonly List _ignoredServers; + private readonly DatabaseContext _database; - public CommandHandler(IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo, + public CommandHandler(DatabaseContext database, IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo, IGuildSettingsManager guildSettingsManager) { + _database = database; _client = client; _logger = logger; _servicesProvider = servicesProvider; @@ -37,7 +39,7 @@ namespace Geekbot.Bot.Handlers _ignoredServers = new List { 228623803201224704, // SwitzerLAN - // 169844523181015040, // EEvent + 169844523181015040, // EEvent 248531441548263425, // MYI 110373943822540800 // Discord Bots }; diff --git a/src/Bot/Handlers/MessageDeletedHandler.cs b/src/Bot/Handlers/MessageDeletedHandler.cs index b8ffe5c..d0377f7 100644 --- a/src/Bot/Handlers/MessageDeletedHandler.cs +++ b/src/Bot/Handlers/MessageDeletedHandler.cs @@ -23,11 +23,11 @@ namespace Geekbot.Bot.Handlers _client = client; } - public async Task HandleMessageDeleted(Cacheable message, Cacheable cacheableMessageChannel) + public async Task HandleMessageDeleted(Cacheable message, ISocketMessageChannel channel) { try { - var guildSocketData = ((IGuildChannel) cacheableMessageChannel.Value).Guild; + var guildSocketData = ((IGuildChannel) channel).Guild; var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildSocketData.Id.AsLong())); if ((guild?.ShowDelete ?? false) && guild?.ModChannel != 0) { @@ -35,7 +35,7 @@ namespace Geekbot.Bot.Handlers var sb = new StringBuilder(); if (message.Value != null) { - sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{cacheableMessageChannel.Id}>"); + sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>"); sb.AppendLine(message.Value.Content); } else diff --git a/src/Bot/Handlers/ReactionHandler.cs b/src/Bot/Handlers/ReactionHandler.cs index 816e125..66af3e8 100644 --- a/src/Bot/Handlers/ReactionHandler.cs +++ b/src/Bot/Handlers/ReactionHandler.cs @@ -14,19 +14,19 @@ namespace Geekbot.Bot.Handlers _reactionListener = reactionListener; } - public Task Added(Cacheable cacheableUserMessage, Cacheable cacheableMessageChannel, SocketReaction reaction) + public Task Added(Cacheable cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction) { if (reaction.User.Value.IsBot) return Task.CompletedTask; if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; - _reactionListener.GiveRole(cacheableMessageChannel.Value, reaction); + _reactionListener.GiveRole(socketMessageChannel, reaction); return Task.CompletedTask; } - public Task Removed(Cacheable cacheableUserMessage, Cacheable cacheableMessageChannel, SocketReaction reaction) + public Task Removed(Cacheable cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction) { if (reaction.User.Value.IsBot) return Task.CompletedTask; if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; - _reactionListener.RemoveRole(cacheableMessageChannel.Value, reaction); + _reactionListener.RemoveRole(socketMessageChannel, reaction); return Task.CompletedTask; } } diff --git a/src/Bot/Handlers/StatsHandler.cs b/src/Bot/Handlers/StatsHandler.cs index b089515..197bbb8 100644 --- a/src/Bot/Handlers/StatsHandler.cs +++ b/src/Bot/Handlers/StatsHandler.cs @@ -4,7 +4,6 @@ using Discord.WebSocket; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.Extensions; -using Geekbot.Core.Highscores; using Geekbot.Core.Logger; using Microsoft.EntityFrameworkCore; @@ -14,26 +13,11 @@ namespace Geekbot.Bot.Handlers { private readonly IGeekbotLogger _logger; private readonly DatabaseContext _database; - private string _season; public StatsHandler(IGeekbotLogger logger, DatabaseContext database) { _logger = logger; _database = database; - _season = SeasonsUtils.GetCurrentSeason(); - - var timer = new System.Timers.Timer() - { - Enabled = true, - AutoReset = true, - Interval = TimeSpan.FromMinutes(5).TotalMilliseconds - }; - timer.Elapsed += (sender, args) => - { - var current = SeasonsUtils.GetCurrentSeason(); - if (current == _season) return; - _season = SeasonsUtils.GetCurrentSeason(); - }; } public async Task UpdateStats(SocketMessage message) @@ -49,16 +33,22 @@ namespace Geekbot.Bot.Handlers var channel = (SocketGuildChannel) message.Channel; - // ignore the discord bots server - // ToDo: create a clean solution for this... - if (channel.Guild.Id == 110373943822540800) + var rowId = await _database.Database.ExecuteSqlRawAsync( + "UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}", + channel.Guild.Id.AsLong(), + message.Author.Id.AsLong() + ); + + if (rowId == 0) { - return; + await _database.Messages.AddAsync(new MessagesModel + { + UserId = message.Author.Id.AsLong(), + GuildId = channel.Guild.Id.AsLong(), + MessageCount = 1 + }); + await _database.SaveChangesAsync(); } - - await UpdateTotalTable(message, channel); - await UpdateSeasonsTable(message, channel); - if (message.Author.IsBot) return; _logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message)); @@ -68,47 +58,5 @@ namespace Geekbot.Bot.Handlers _logger.Error(LogSource.Message, "Could not process message stats", e); } } - - private async Task UpdateTotalTable(SocketMessage message, SocketGuildChannel channel) - { - var rowId = await _database.Database.ExecuteSqlRawAsync( - "UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}", - channel.Guild.Id.AsLong(), - message.Author.Id.AsLong() - ); - - if (rowId == 0) - { - await _database.Messages.AddAsync(new MessagesModel - { - UserId = message.Author.Id.AsLong(), - GuildId = channel.Guild.Id.AsLong(), - MessageCount = 1 - }); - await _database.SaveChangesAsync(); - } - } - - private async Task UpdateSeasonsTable(SocketMessage message, SocketGuildChannel channel) - { - var rowId = await _database.Database.ExecuteSqlRawAsync( - "UPDATE \"MessagesSeasons\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1} AND \"Season\" = {2}", - channel.Guild.Id.AsLong(), - message.Author.Id.AsLong(), - _season - ); - - if (rowId == 0) - { - await _database.MessagesSeasons.AddAsync(new MessageSeasonsModel() - { - UserId = message.Author.Id.AsLong(), - GuildId = channel.Guild.Id.AsLong(), - Season = _season, - MessageCount = 1 - }); - await _database.SaveChangesAsync(); - } - } } } \ No newline at end of file diff --git a/src/Bot/Handlers/UserHandler.cs b/src/Bot/Handlers/UserHandler.cs index 1f58131..a22d0e1 100644 --- a/src/Bot/Handlers/UserHandler.cs +++ b/src/Bot/Handlers/UserHandler.cs @@ -74,15 +74,15 @@ namespace Geekbot.Bot.Handlers await _userRepository.Update(newUser); } - public async Task Left(SocketGuild socketGuild, SocketUser socketUser) + public async Task Left(SocketGuildUser user) { try { - var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(socketGuild.Id.AsLong())); + var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(user.Guild.Id.AsLong())); if (guild?.ShowLeave ?? false) { var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong()); - await modChannelSocket.SendMessageAsync($"{socketUser.Username}#{socketUser.Discriminator} left the server"); + await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server"); } } catch (Exception e) @@ -90,7 +90,7 @@ namespace Geekbot.Bot.Handlers _logger.Error(LogSource.Geekbot, "Failed to send leave message", e); } - _logger.Information(LogSource.Geekbot, $"{socketUser.Username} ({socketUser.Id}) joined {socketGuild.Name} ({socketGuild.Id})"); + _logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})"); } } } \ No newline at end of file diff --git a/src/Core/Localization/Admin.Designer.cs b/src/Bot/Localization/Admin.Designer.cs similarity index 83% rename from src/Core/Localization/Admin.Designer.cs rename to src/Bot/Localization/Admin.Designer.cs index 460d471..c55adf1 100644 --- a/src/Core/Localization/Admin.Designer.cs +++ b/src/Bot/Localization/Admin.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Admin { + internal class Admin { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Admin() { + internal Admin() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Admin", typeof(Admin).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Admin", typeof(Admin).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to I'm talking english. /// - public static string GetLanguage { + internal static string GetLanguage { get { return ResourceManager.GetString("GetLanguage", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to I will reply in english from now on. /// - public static string NewLanguageSet { + internal static string NewLanguageSet { get { return ResourceManager.GetString("NewLanguageSet", resourceCulture); } diff --git a/src/Core/Localization/Admin.de-ch.resx b/src/Bot/Localization/Admin.de-ch.resx similarity index 100% rename from src/Core/Localization/Admin.de-ch.resx rename to src/Bot/Localization/Admin.de-ch.resx diff --git a/src/Core/Localization/Admin.resx b/src/Bot/Localization/Admin.resx similarity index 100% rename from src/Core/Localization/Admin.resx rename to src/Bot/Localization/Admin.resx diff --git a/src/Core/Localization/Choose.Designer.cs b/src/Bot/Localization/Choose.Designer.cs similarity index 84% rename from src/Core/Localization/Choose.Designer.cs rename to src/Bot/Localization/Choose.Designer.cs index 91ef136..1319140 100644 --- a/src/Core/Localization/Choose.Designer.cs +++ b/src/Bot/Localization/Choose.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Choose { + internal class Choose { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Choose() { + internal Choose() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Choose", typeof(Choose).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Choose", typeof(Choose).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to I Choose **{0}**. /// - public static string Choice { + internal static string Choice { get { return ResourceManager.GetString("Choice", resourceCulture); } diff --git a/src/Core/Localization/Choose.de-ch.resx b/src/Bot/Localization/Choose.de-ch.resx similarity index 100% rename from src/Core/Localization/Choose.de-ch.resx rename to src/Bot/Localization/Choose.de-ch.resx diff --git a/src/Core/Localization/Choose.resx b/src/Bot/Localization/Choose.resx similarity index 100% rename from src/Core/Localization/Choose.resx rename to src/Bot/Localization/Choose.resx diff --git a/src/Core/Localization/Corona.Designer.cs b/src/Bot/Localization/Cookies.Designer.cs similarity index 57% rename from src/Core/Localization/Corona.Designer.cs rename to src/Bot/Localization/Cookies.Designer.cs index a19bbcd..5f2528f 100644 --- a/src/Core/Localization/Corona.Designer.cs +++ b/src/Bot/Localization/Cookies.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Corona { + internal class Cookies { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Corona() { + internal Cookies() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Corona", typeof(Corona).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Cookies", typeof(Cookies).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -58,56 +61,65 @@ namespace Geekbot.Core.Localization { } /// - /// Looks up a localized string similar to Active. + /// Looks up a localized string similar to You ate {0} cookies, you've only got {1} cookies left. /// - public static string Active { + internal static string AteCookies { get { - return ResourceManager.GetString("Active", resourceCulture); + return ResourceManager.GetString("AteCookies", resourceCulture); } } /// - /// Looks up a localized string similar to Confirmed Corona Cases. + /// Looks up a localized string similar to You got {0} cookies, there are now {1} cookies in you cookie jar. /// - public static string ConfirmedCases { + internal static string GetCookies { get { - return ResourceManager.GetString("ConfirmedCases", resourceCulture); + return ResourceManager.GetString("GetCookies", resourceCulture); } } /// - /// Looks up a localized string similar to Deaths. + /// Looks up a localized string similar to You gave {0} cookies to {1}. /// - public static string Deaths { + internal static string Given { get { - return ResourceManager.GetString("Deaths", resourceCulture); + return ResourceManager.GetString("Given", resourceCulture); } } /// - /// Looks up a localized string similar to Recovered. + /// Looks up a localized string similar to There are {0} cookies in you cookie jar. /// - public static string Recovered { + internal static string InYourJar { get { - return ResourceManager.GetString("Recovered", resourceCulture); + return ResourceManager.GetString("InYourJar", resourceCulture); } } /// - /// Looks up a localized string similar to Source. + /// Looks up a localized string similar to Your cookie jar looks almost empty, you should probably not eat a cookie. /// - public static string Source { + internal static string NotEnoughCookiesToEat { get { - return ResourceManager.GetString("Source", resourceCulture); + return ResourceManager.GetString("NotEnoughCookiesToEat", resourceCulture); } } /// - /// Looks up a localized string similar to Total. + /// Looks up a localized string similar to You don't have enough cookies. /// - public static string Total { + internal static string NotEnoughToGive { get { - return ResourceManager.GetString("Total", resourceCulture); + return ResourceManager.GetString("NotEnoughToGive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You already got cookies today, you can have more cookies in {0}. + /// + internal static string WaitForMoreCookies { + get { + return ResourceManager.GetString("WaitForMoreCookies", resourceCulture); } } } diff --git a/src/Core/Localization/Cookies.de-ch.resx b/src/Bot/Localization/Cookies.de-ch.resx similarity index 89% rename from src/Core/Localization/Cookies.de-ch.resx rename to src/Bot/Localization/Cookies.de-ch.resx index 3652224..b53b588 100644 --- a/src/Core/Localization/Cookies.de-ch.resx +++ b/src/Bot/Localization/Cookies.de-ch.resx @@ -32,7 +32,4 @@ Du hesch {0} guetzli gesse und hesch jezt no {1} übrig - - :police_officer: Du chasch nid guetzli vo anderne chlaue... - \ No newline at end of file diff --git a/src/Core/Localization/Cookies.resx b/src/Bot/Localization/Cookies.resx similarity index 91% rename from src/Core/Localization/Cookies.resx rename to src/Bot/Localization/Cookies.resx index a359c5c..53207fa 100644 --- a/src/Core/Localization/Cookies.resx +++ b/src/Bot/Localization/Cookies.resx @@ -39,7 +39,4 @@ You ate {0} cookies, you've only got {1} cookies left - - You can't take someone else's cookies - \ No newline at end of file diff --git a/src/Core/Localization/Internal.Designer.cs b/src/Bot/Localization/Internal.Designer.cs similarity index 83% rename from src/Core/Localization/Internal.Designer.cs rename to src/Bot/Localization/Internal.Designer.cs index 967b26e..e7c18af 100644 --- a/src/Core/Localization/Internal.Designer.cs +++ b/src/Bot/Localization/Internal.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Internal { + internal class Internal { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Internal() { + internal Internal() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Internal", typeof(Internal).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Internal", typeof(Internal).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to and. /// - public static string And { + internal static string And { get { return ResourceManager.GetString("And", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to day|days. /// - public static string Days { + internal static string Days { get { return ResourceManager.GetString("Days", resourceCulture); } @@ -78,7 +81,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to hour|hours. /// - public static string Hours { + internal static string Hours { get { return ResourceManager.GetString("Hours", resourceCulture); } @@ -87,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Seems like i don't have enough permission to that :confused:. /// - public static string Http403 { + internal static string Http403 { get { return ResourceManager.GetString("Http403", resourceCulture); } @@ -96,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to minute|minutes. /// - public static string Minutes { + internal static string Minutes { get { return ResourceManager.GetString("Minutes", resourceCulture); } @@ -105,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to second|seconds. /// - public static string Seconds { + internal static string Seconds { get { return ResourceManager.GetString("Seconds", resourceCulture); } @@ -114,7 +117,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Something went wrong :confused:. /// - public static string SomethingWentWrong { + internal static string SomethingWentWrong { get { return ResourceManager.GetString("SomethingWentWrong", resourceCulture); } diff --git a/src/Core/Localization/Internal.de-ch.resx b/src/Bot/Localization/Internal.de-ch.resx similarity index 100% rename from src/Core/Localization/Internal.de-ch.resx rename to src/Bot/Localization/Internal.de-ch.resx diff --git a/src/Core/Localization/Internal.resx b/src/Bot/Localization/Internal.resx similarity index 100% rename from src/Core/Localization/Internal.resx rename to src/Bot/Localization/Internal.resx diff --git a/src/Core/Localization/Karma.Designer.cs b/src/Bot/Localization/Karma.Designer.cs similarity index 75% rename from src/Core/Localization/Karma.Designer.cs rename to src/Bot/Localization/Karma.Designer.cs index b3e8325..4191fa2 100644 --- a/src/Core/Localization/Karma.Designer.cs +++ b/src/Bot/Localization/Karma.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Karma { + internal class Karma { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Karma() { + internal Karma() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Karma", typeof(Karma).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Karma", typeof(Karma).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Amount. /// - public static string Amount { + internal static string Amount { get { return ResourceManager.GetString("Amount", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to By. /// - public static string By { + internal static string By { get { return ResourceManager.GetString("By", resourceCulture); } @@ -78,25 +81,16 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Sorry {0}, but you can't lower your own karma. /// - public static string CannotChangeOwnDown { + internal static string CannotChangeOwnDown { get { return ResourceManager.GetString("CannotChangeOwnDown", resourceCulture); } } - /// - /// Looks up a localized string similar to Sorry {0}, but you can't give yourself neutral karma. - /// - public static string CannotChangeOwnSame { - get { - return ResourceManager.GetString("CannotChangeOwnSame", resourceCulture); - } - } - /// /// Looks up a localized string similar to Sorry {0}, but you can't give yourself karma. /// - public static string CannotChangeOwnUp { + internal static string CannotChangeOwnUp { get { return ResourceManager.GetString("CannotChangeOwnUp", resourceCulture); } @@ -105,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Current. /// - public static string Current { + internal static string Current { get { return ResourceManager.GetString("Current", resourceCulture); } @@ -114,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Karma lowered. /// - public static string Decreased { + internal static string Decreased { get { return ResourceManager.GetString("Decreased", resourceCulture); } @@ -123,25 +117,16 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Gained Karma. /// - public static string Increased { + internal static string Increased { get { return ResourceManager.GetString("Increased", resourceCulture); } } - /// - /// Looks up a localized string similar to Neutral Karma. - /// - public static string Neutral { - get { - return ResourceManager.GetString("Neutral", resourceCulture); - } - } - /// /// Looks up a localized string similar to Sorry {0}, but you have to wait {1} before you can give karma again.... /// - public static string WaitUntill { + internal static string WaitUntill { get { return ResourceManager.GetString("WaitUntill", resourceCulture); } diff --git a/src/Core/Localization/Karma.de-ch.resx b/src/Bot/Localization/Karma.de-ch.resx similarity index 83% rename from src/Core/Localization/Karma.de-ch.resx rename to src/Bot/Localization/Karma.de-ch.resx index 5805a27..5605f8b 100644 --- a/src/Core/Localization/Karma.de-ch.resx +++ b/src/Bot/Localization/Karma.de-ch.resx @@ -35,10 +35,4 @@ Karma gsenkt - - Neutral Karma - - - Sorry {0}, aber du chasch dr selber kei neutrals karma geh - \ No newline at end of file diff --git a/src/Core/Localization/Karma.resx b/src/Bot/Localization/Karma.resx similarity index 85% rename from src/Core/Localization/Karma.resx rename to src/Bot/Localization/Karma.resx index a16e14a..3a8fe5a 100644 --- a/src/Core/Localization/Karma.resx +++ b/src/Bot/Localization/Karma.resx @@ -42,10 +42,4 @@ Karma lowered - - Neutral Karma - - - Sorry {0}, but you can't give yourself neutral karma - \ No newline at end of file diff --git a/src/Core/Localization/Quote.Designer.cs b/src/Bot/Localization/Quote.Designer.cs similarity index 78% rename from src/Core/Localization/Quote.Designer.cs rename to src/Bot/Localization/Quote.Designer.cs index 9146971..d0926ae 100644 --- a/src/Core/Localization/Quote.Designer.cs +++ b/src/Bot/Localization/Quote.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Quote { + internal class Quote { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Quote() { + internal Quote() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Quote", typeof(Quote).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Quote", typeof(Quote).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to You can't save quotes by a bot.... /// - public static string CannotQuoteBots { + internal static string CannotQuoteBots { get { return ResourceManager.GetString("CannotQuoteBots", resourceCulture); } @@ -69,16 +72,25 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to You can't save your own quotes.... /// - public static string CannotSaveOwnQuotes { + internal static string CannotSaveOwnQuotes { get { return ResourceManager.GetString("CannotSaveOwnQuotes", resourceCulture); } } + /// + /// Looks up a localized string similar to :warning: Creating quotes by message ID is deprecated in favour of message links and will be removed on 1 December 2020. + /// + internal static string MessageIdDeprecation { + get { + return ResourceManager.GetString("MessageIdDeprecation", resourceCulture); + } + } + /// /// Looks up a localized string similar to Most quoted person. /// - public static string MostQuotesPerson { + internal static string MostQuotesPerson { get { return ResourceManager.GetString("MostQuotesPerson", resourceCulture); } @@ -87,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to This server doesn't seem to have any quotes yet. You can add a quote with `!quote save @user` or `!quote save <messageId>`. /// - public static string NoQuotesFound { + internal static string NoQuotesFound { get { return ResourceManager.GetString("NoQuotesFound", resourceCulture); } @@ -96,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to That is not a valid message link. /// - public static string NotAValidMessageLink { + internal static string NotAValidMessageLink { get { return ResourceManager.GetString("NotAValidMessageLink", resourceCulture); } @@ -105,7 +117,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to I couldn't find a quote with that ID :disappointed:. /// - public static string NotFoundWithId { + internal static string NotFoundWithId { get { return ResourceManager.GetString("NotFoundWithId", resourceCulture); } @@ -114,7 +126,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to You can only quote messages from the same server. /// - public static string OnlyQuoteFromSameServer { + internal static string OnlyQuoteFromSameServer { get { return ResourceManager.GetString("OnlyQuoteFromSameServer", resourceCulture); } @@ -123,7 +135,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to **Quote Added**. /// - public static string QuoteAdded { + internal static string QuoteAdded { get { return ResourceManager.GetString("QuoteAdded", resourceCulture); } @@ -132,7 +144,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Quote Stats. /// - public static string QuoteStats { + internal static string QuoteStats { get { return ResourceManager.GetString("QuoteStats", resourceCulture); } @@ -141,7 +153,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to **Removed #{0}**. /// - public static string Removed { + internal static string Removed { get { return ResourceManager.GetString("Removed", resourceCulture); } @@ -150,7 +162,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Total. /// - public static string TotalQuotes { + internal static string TotalQuotes { get { return ResourceManager.GetString("TotalQuotes", resourceCulture); } diff --git a/src/Core/Localization/Quote.de-ch.resx b/src/Bot/Localization/Quote.de-ch.resx similarity index 88% rename from src/Core/Localization/Quote.de-ch.resx rename to src/Bot/Localization/Quote.de-ch.resx index 99fd959..c7e3b8b 100644 --- a/src/Core/Localization/Quote.de-ch.resx +++ b/src/Bot/Localization/Quote.de-ch.resx @@ -44,4 +44,7 @@ Du chasch numme nachrichte vom gliche server quote + + :warning: Es mache vo quotes mit message-IDs isch zgunste vo message-links veraltet und wird am 1. dezember 2020 entfernt + \ No newline at end of file diff --git a/src/Core/Localization/Quote.resx b/src/Bot/Localization/Quote.resx similarity index 89% rename from src/Core/Localization/Quote.resx rename to src/Bot/Localization/Quote.resx index b51d79c..215f0ea 100644 --- a/src/Core/Localization/Quote.resx +++ b/src/Bot/Localization/Quote.resx @@ -51,4 +51,7 @@ You can only quote messages from the same server + + :warning: Creating quotes by message ID is deprecated in favour of message links and will be removed on 1 December 2020 + \ No newline at end of file diff --git a/src/Core/Localization/Rank.Designer.cs b/src/Bot/Localization/Rank.Designer.cs similarity index 83% rename from src/Core/Localization/Rank.Designer.cs rename to src/Bot/Localization/Rank.Designer.cs index 1439a8c..23f5e16 100644 --- a/src/Core/Localization/Rank.Designer.cs +++ b/src/Bot/Localization/Rank.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Rank { + internal class Rank { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Rank() { + internal Rank() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Rank", typeof(Rank).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Rank", typeof(Rank).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to :warning: I couldn't find all usernames. Maybe they left the server?. /// - public static string FailedToResolveAllUsernames { + internal static string FailedToResolveAllUsernames { get { return ResourceManager.GetString("FailedToResolveAllUsernames", resourceCulture); } @@ -69,16 +72,16 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to :bar_chart: **{0} Highscore for {1}**. /// - public static string HighscoresFor { + internal static string HighscoresFor { get { return ResourceManager.GetString("HighscoresFor", resourceCulture); } } /// - /// Looks up a localized string similar to Valid types are '`messages`' '`karma`', '`rolls`', '`cookies`', '`seasons`' and '`quotes`'. + /// Looks up a localized string similar to Valid types are '`messages`' '`karma`', '`rolls`' and '`cookies`'. /// - public static string InvalidType { + internal static string InvalidType { get { return ResourceManager.GetString("InvalidType", resourceCulture); } @@ -87,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to :warning: Limiting to 20. /// - public static string LimitingTo20Warning { + internal static string LimitingTo20Warning { get { return ResourceManager.GetString("LimitingTo20Warning", resourceCulture); } @@ -96,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to No {0} found on this server. /// - public static string NoTypeFoundForServer { + internal static string NoTypeFoundForServer { get { return ResourceManager.GetString("NoTypeFoundForServer", resourceCulture); } diff --git a/src/Core/Localization/Rank.de-ch.resx b/src/Bot/Localization/Rank.de-ch.resx similarity index 93% rename from src/Core/Localization/Rank.de-ch.resx rename to src/Bot/Localization/Rank.de-ch.resx index 743b8cd..0b22fe4 100644 --- a/src/Core/Localization/Rank.de-ch.resx +++ b/src/Bot/Localization/Rank.de-ch.resx @@ -24,6 +24,6 @@ :bar_chart: **{0} Highscore für {1}** - Gültigi paramenter sind '`messages`' '`karma`', '`rolls`', '`cookies`', '`seasons`' und '`quotes`' + Gültigi paramenter sind '`messages`' '`karma`', '`rolls`' und '`cookies` \ No newline at end of file diff --git a/src/Core/Localization/Rank.resx b/src/Bot/Localization/Rank.resx similarity index 94% rename from src/Core/Localization/Rank.resx rename to src/Bot/Localization/Rank.resx index 606a34e..9598cf8 100644 --- a/src/Core/Localization/Rank.resx +++ b/src/Bot/Localization/Rank.resx @@ -19,7 +19,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Valid types are '`messages`' '`karma`', '`rolls`', '`cookies`', '`seasons`' and '`quotes`' + Valid types are '`messages`' '`karma`', '`rolls`' and '`cookies`' :warning: Limiting to 20 diff --git a/src/Core/Localization/Role.Designer.cs b/src/Bot/Localization/Role.Designer.cs similarity index 83% rename from src/Core/Localization/Role.Designer.cs rename to src/Bot/Localization/Role.Designer.cs index fc48852..9128e3d 100644 --- a/src/Core/Localization/Role.Designer.cs +++ b/src/Bot/Localization/Role.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Role { + internal class Role { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Role() { + internal Role() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Role", typeof(Role).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Role", typeof(Role).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Added {0} to the whitelist. /// - public static string AddedRoleToWhitelist { + internal static string AddedRoleToWhitelist { get { return ResourceManager.GetString("AddedRoleToWhitelist", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Added you to {0}. /// - public static string AddedUserFromRole { + internal static string AddedUserFromRole { get { return ResourceManager.GetString("AddedUserFromRole", resourceCulture); } @@ -78,7 +81,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to You cannot add that role to self service because it contains one or more dangerous permissions. /// - public static string CannotAddDangerousRole { + internal static string CannotAddDangerousRole { get { return ResourceManager.GetString("CannotAddDangerousRole", resourceCulture); } @@ -87,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to You can't add a role that is managed by discord. /// - public static string CannotAddManagedRole { + internal static string CannotAddManagedRole { get { return ResourceManager.GetString("CannotAddManagedRole", resourceCulture); } @@ -96,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to **Self Service Roles on {0}**. /// - public static string ListHeader { + internal static string ListHeader { get { return ResourceManager.GetString("ListHeader", resourceCulture); } @@ -105,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to To get a role, use `!role [name]`. /// - public static string ListInstruction { + internal static string ListInstruction { get { return ResourceManager.GetString("ListInstruction", resourceCulture); } @@ -114,7 +117,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to There are no roles configured for this server. /// - public static string NoRolesConfigured { + internal static string NoRolesConfigured { get { return ResourceManager.GetString("NoRolesConfigured", resourceCulture); } @@ -123,7 +126,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Removed {0} from the whitelist. /// - public static string RemovedRoleFromWhitelist { + internal static string RemovedRoleFromWhitelist { get { return ResourceManager.GetString("RemovedRoleFromWhitelist", resourceCulture); } @@ -132,7 +135,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Removed you from {0}. /// - public static string RemovedUserFromRole { + internal static string RemovedUserFromRole { get { return ResourceManager.GetString("RemovedUserFromRole", resourceCulture); } @@ -141,7 +144,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to That role doesn't exist or is not on the whitelist. /// - public static string RoleNotFound { + internal static string RoleNotFound { get { return ResourceManager.GetString("RoleNotFound", resourceCulture); } diff --git a/src/Core/Localization/Role.de-ch.resx b/src/Bot/Localization/Role.de-ch.resx similarity index 100% rename from src/Core/Localization/Role.de-ch.resx rename to src/Bot/Localization/Role.de-ch.resx diff --git a/src/Core/Localization/Role.resx b/src/Bot/Localization/Role.resx similarity index 100% rename from src/Core/Localization/Role.resx rename to src/Bot/Localization/Role.resx diff --git a/src/Core/Localization/Roll.Designer.cs b/src/Bot/Localization/Roll.Designer.cs similarity index 84% rename from src/Core/Localization/Roll.Designer.cs rename to src/Bot/Localization/Roll.Designer.cs index bceb55d..fda0536 100644 --- a/src/Core/Localization/Roll.Designer.cs +++ b/src/Bot/Localization/Roll.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Roll { + internal class Roll { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Roll() { + internal Roll() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Roll", typeof(Roll).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Roll", typeof(Roll).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Congratulations {0}, your guess was correct!. /// - public static string Gratz { + internal static string Gratz { get { return ResourceManager.GetString("Gratz", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to :red_circle: {0}, you can't guess the same number again, guess another number or wait {1}. /// - public static string NoPrevGuess { + internal static string NoPrevGuess { get { return ResourceManager.GetString("NoPrevGuess", resourceCulture); } @@ -78,7 +81,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to {0}, you rolled {1}, your guess was {2}. /// - public static string Rolled { + internal static string Rolled { get { return ResourceManager.GetString("Rolled", resourceCulture); } @@ -87,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to {0}, you rolled {1}. /// - public static string RolledNoGuess { + internal static string RolledNoGuess { get { return ResourceManager.GetString("RolledNoGuess", resourceCulture); } diff --git a/src/Core/Localization/Roll.de-ch.resx b/src/Bot/Localization/Roll.de-ch.resx similarity index 100% rename from src/Core/Localization/Roll.de-ch.resx rename to src/Bot/Localization/Roll.de-ch.resx diff --git a/src/Core/Localization/Roll.resx b/src/Bot/Localization/Roll.resx similarity index 100% rename from src/Core/Localization/Roll.resx rename to src/Bot/Localization/Roll.resx diff --git a/src/Core/Localization/Ship.Designer.cs b/src/Bot/Localization/Ship.Designer.cs similarity index 83% rename from src/Core/Localization/Ship.Designer.cs rename to src/Bot/Localization/Ship.Designer.cs index 2d917b6..d959693 100644 --- a/src/Core/Localization/Ship.Designer.cs +++ b/src/Bot/Localization/Ship.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Ship { + internal class Ship { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Ship() { + internal Ship() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Ship", typeof(Ship).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Ship", typeof(Ship).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,7 +63,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Almost a match. /// - public static string CouldWork { + internal static string CouldWork { get { return ResourceManager.GetString("CouldWork", resourceCulture); } @@ -69,7 +72,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to It's a match. /// - public static string ItsAMatch { + internal static string ItsAMatch { get { return ResourceManager.GetString("ItsAMatch", resourceCulture); } @@ -78,7 +81,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Matchmaking. /// - public static string Matchmaking { + internal static string Matchmaking { get { return ResourceManager.GetString("Matchmaking", resourceCulture); } @@ -87,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Not going happen. /// - public static string NotGoingToHappen { + internal static string NotGoingToHappen { get { return ResourceManager.GetString("NotGoingToHappen", resourceCulture); } @@ -96,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Not such a good idea. /// - public static string NotSuchAGoodIdea { + internal static string NotSuchAGoodIdea { get { return ResourceManager.GetString("NotSuchAGoodIdea", resourceCulture); } @@ -105,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to There might be a chance. /// - public static string ThereMightBeAChance { + internal static string ThereMightBeAChance { get { return ResourceManager.GetString("ThereMightBeAChance", resourceCulture); } diff --git a/src/Core/Localization/Ship.de-ch.resx b/src/Bot/Localization/Ship.de-ch.resx similarity index 100% rename from src/Core/Localization/Ship.de-ch.resx rename to src/Bot/Localization/Ship.de-ch.resx diff --git a/src/Core/Localization/Ship.resx b/src/Bot/Localization/Ship.resx similarity index 100% rename from src/Core/Localization/Ship.resx rename to src/Bot/Localization/Ship.resx diff --git a/src/Core/Localization/Stats.Designer.cs b/src/Bot/Localization/Stats.Designer.cs similarity index 75% rename from src/Core/Localization/Stats.Designer.cs rename to src/Bot/Localization/Stats.Designer.cs index 5f9b96c..d05f937 100644 --- a/src/Core/Localization/Stats.Designer.cs +++ b/src/Bot/Localization/Stats.Designer.cs @@ -8,7 +8,10 @@ // //------------------------------------------------------------------------------ -namespace Geekbot.Core.Localization { +namespace Geekbot.Bot.Localization { + using System; + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -19,24 +22,24 @@ namespace Geekbot.Core.Localization { [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Stats { + internal class Stats { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Stats() { + internal Stats() { } /// /// Returns the cached ResourceManager instance used by this class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { + internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Stats", typeof(Stats).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Stats", typeof(Stats).Assembly); resourceMan = temp; } return resourceMan; @@ -48,7 +51,7 @@ namespace Geekbot.Core.Localization { /// resource lookups using this strongly typed resource class. /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { + internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,25 +63,16 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Cookies. /// - public static string Cookies { + internal static string Cookies { get { return ResourceManager.GetString("Cookies", resourceCulture); } } - /// - /// Looks up a localized string similar to Days. - /// - public static string Days { - get { - return ResourceManager.GetString("Days", resourceCulture); - } - } - /// /// Looks up a localized string similar to Guessed Rolls. /// - public static string GuessedRolls { + internal static string GuessedRolls { get { return ResourceManager.GetString("GuessedRolls", resourceCulture); } @@ -87,7 +81,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Joined Server. /// - public static string JoinedServer { + internal static string JoinedServer { get { return ResourceManager.GetString("JoinedServer", resourceCulture); } @@ -96,7 +90,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Karma. /// - public static string Karma { + internal static string Karma { get { return ResourceManager.GetString("Karma", resourceCulture); } @@ -105,7 +99,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Level. /// - public static string Level { + internal static string Level { get { return ResourceManager.GetString("Level", resourceCulture); } @@ -114,7 +108,7 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to Messages Sent. /// - public static string MessagesSent { + internal static string MessagesSent { get { return ResourceManager.GetString("MessagesSent", resourceCulture); } @@ -123,25 +117,16 @@ namespace Geekbot.Core.Localization { /// /// Looks up a localized string similar to On Discord Since. /// - public static string OnDiscordSince { + internal static string OnDiscordSince { get { return ResourceManager.GetString("OnDiscordSince", resourceCulture); } } - /// - /// Looks up a localized string similar to Quotes. - /// - public static string Quotes { - get { - return ResourceManager.GetString("Quotes", resourceCulture); - } - } - /// /// Looks up a localized string similar to Server Total. /// - public static string ServerTotal { + internal static string ServerTotal { get { return ResourceManager.GetString("ServerTotal", resourceCulture); } diff --git a/src/Core/Localization/Stats.de-ch.resx b/src/Bot/Localization/Stats.de-ch.resx similarity index 86% rename from src/Core/Localization/Stats.de-ch.resx rename to src/Bot/Localization/Stats.de-ch.resx index 0af0477..ab44a2e 100644 --- a/src/Core/Localization/Stats.de-ch.resx +++ b/src/Bot/Localization/Stats.de-ch.resx @@ -35,10 +35,4 @@ Guetzli - - Täg - - - Quotes - \ No newline at end of file diff --git a/src/Core/Localization/Stats.resx b/src/Bot/Localization/Stats.resx similarity index 88% rename from src/Core/Localization/Stats.resx rename to src/Bot/Localization/Stats.resx index 6eb3a92..3b8303a 100644 --- a/src/Core/Localization/Stats.resx +++ b/src/Bot/Localization/Stats.resx @@ -42,10 +42,4 @@ Cookies - - Days - - - Quotes - \ No newline at end of file diff --git a/src/Bot/Program.cs b/src/Bot/Program.cs new file mode 100644 index 0000000..dee6ec3 --- /dev/null +++ b/src/Bot/Program.cs @@ -0,0 +1,228 @@ +using System; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using CommandLine; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.Bot.Handlers; +using Geekbot.Core; +using Geekbot.Core.Converters; +using Geekbot.Core.Database; +using Geekbot.Core.DiceParser; +using Geekbot.Core.ErrorHandling; +using Geekbot.Core.GlobalSettings; +using Geekbot.Core.GuildSettingsManager; +using Geekbot.Core.Highscores; +using Geekbot.Core.KvInMemoryStore; +using Geekbot.Core.Levels; +using Geekbot.Core.Logger; +using Geekbot.Core.Media; +using Geekbot.Core.RandomNumberGenerator; +using Geekbot.Core.ReactionListener; +using Geekbot.Core.UserRepository; +using Geekbot.Core.WikipediaClient; +using Geekbot.Web; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; + +namespace Geekbot.Bot +{ + internal class Program + { + private DiscordSocketClient _client; + private CommandService _commands; + private DatabaseInitializer _databaseInitializer; + private IGlobalSettings _globalSettings; + private IServiceProvider _servicesProvider; + private GeekbotLogger _logger; + private IUserRepository _userRepository; + private RunParameters _runParameters; + private IReactionListener _reactionListener; + private IGuildSettingsManager _guildSettingsManager; + + private static async Task Main(string[] args) + { + RunParameters runParameters = null; + Parser.Default.ParseArguments(args) + .WithParsed(e => runParameters = e) + .WithNotParsed(_ => Environment.Exit(GeekbotExitCode.InvalidArguments.GetHashCode())); + + var logo = new StringBuilder(); + logo.AppendLine(@" ____ _____ _____ _ ______ ___ _____"); + logo.AppendLine(@" / ___| ____| ____| |/ / __ ) / _ \\_ _|"); + logo.AppendLine(@"| | _| _| | _| | ' /| _ \| | | || |"); + logo.AppendLine(@"| |_| | |___| |___| . \| |_) | |_| || |"); + logo.AppendLine(@" \____|_____|_____|_|\_\____/ \___/ |_|"); + logo.AppendLine($"Version {Constants.BotVersion()} ".PadRight(41, '=')); + Console.WriteLine(logo.ToString()); + var logger = new GeekbotLogger(runParameters); + logger.Information(LogSource.Geekbot, "Starting..."); + try + { + await new Program().Start(runParameters, logger); + } + catch (Exception e) + { + logger.Error(LogSource.Geekbot, "RIP", e); + } + } + + private async Task Start(RunParameters runParameters, GeekbotLogger logger) + { + _logger = logger; + _runParameters = runParameters; + + logger.Information(LogSource.Geekbot, "Connecting to Database"); + var database = ConnectToDatabase(); + _globalSettings = new GlobalSettings(database); + + logger.Information(LogSource.Geekbot, "Connecting to Discord"); + SetupDiscordClient(); + await Login(); + _logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers"); + await _client.SetGameAsync(_globalSettings.GetKey("Game")); + + _logger.Information(LogSource.Geekbot, "Loading Dependencies and Handlers"); + RegisterDependencies(); + await RegisterHandlers(); + + _logger.Information(LogSource.Api, "Starting Web API"); + StartWebApi(); + + _logger.Information(LogSource.Geekbot, "Done and ready for use"); + + await Task.Delay(-1); + } + + private async Task Login() + { + try + { + var token = await GetToken(); + await _client.LoginAsync(TokenType.Bot, token); + await _client.StartAsync(); + while (!_client.ConnectionState.Equals(ConnectionState.Connected)) await Task.Delay(25); + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Could not connect to Discord", e); + Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode()); + } + } + + private DatabaseContext ConnectToDatabase() + { + _databaseInitializer = new DatabaseInitializer(_runParameters, _logger); + var database = _databaseInitializer.Initialize(); + database.Database.EnsureCreated(); + if(!_runParameters.InMemory) database.Database.Migrate(); + + return database; + } + + private async Task GetToken() + { + var token = _runParameters.Token ?? _globalSettings.GetKey("DiscordToken"); + if (string.IsNullOrEmpty(token)) + { + Console.Write("Your bot Token: "); + var newToken = Console.ReadLine(); + await _globalSettings.SetKey("DiscordToken", newToken); + await _globalSettings.SetKey("Game", "Ping Pong"); + token = newToken; + } + + return token; + } + + private void SetupDiscordClient() + { + _client = new DiscordSocketClient(new DiscordSocketConfig + { + LogLevel = LogSeverity.Verbose, + MessageCacheSize = 1000, + ExclusiveBulkDelete = true + }); + + var discordLogger = new DiscordLogger(_logger); + _client.Log += discordLogger.Log; + } + + private void RegisterDependencies() + { + var services = new ServiceCollection(); + + _userRepository = new UserRepository(_databaseInitializer.Initialize(), _logger); + _reactionListener = new ReactionListener(_databaseInitializer.Initialize()); + _guildSettingsManager = new GuildSettingsManager(_databaseInitializer.Initialize()); + var fortunes = new FortunesProvider(_logger); + var levelCalc = new LevelCalc(); + var emojiConverter = new EmojiConverter(); + var mtgManaConverter = new MtgManaConverter(); + var wikipediaClient = new WikipediaClient(); + var randomNumberGenerator = new RandomNumberGenerator(_globalSettings); + var mediaProvider = new MediaProvider(_logger, randomNumberGenerator); + var kvMemoryStore = new KvInInMemoryStore(); + var errorHandler = new ErrorHandler(_logger, _runParameters, () => Localization.Internal.SomethingWentWrong); + var diceParser = new DiceParser(randomNumberGenerator); + + services.AddSingleton(_userRepository); + services.AddSingleton(_logger); + services.AddSingleton(levelCalc); + services.AddSingleton(emojiConverter); + services.AddSingleton(fortunes); + services.AddSingleton(mediaProvider); + services.AddSingleton(mtgManaConverter); + services.AddSingleton(wikipediaClient); + services.AddSingleton(randomNumberGenerator); + services.AddSingleton(kvMemoryStore); + services.AddSingleton(_globalSettings); + services.AddSingleton(errorHandler); + services.AddSingleton(diceParser); + services.AddSingleton(_reactionListener); + services.AddSingleton(_guildSettingsManager); + services.AddSingleton(_client); + services.AddTransient(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository)); + services.AddTransient(e => _databaseInitializer.Initialize()); + + _servicesProvider = services.BuildServiceProvider(); + } + + private async Task RegisterHandlers() + { + var applicationInfo = await _client.GetApplicationInfoAsync(); + + _commands = new CommandService(); + await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _servicesProvider); + + var commandHandler = new CommandHandler(_databaseInitializer.Initialize(), _client, _logger, _servicesProvider, _commands, applicationInfo, _guildSettingsManager); + var userHandler = new UserHandler(_userRepository, _logger, _databaseInitializer.Initialize(), _client); + var reactionHandler = new ReactionHandler(_reactionListener); + var statsHandler = new StatsHandler(_logger, _databaseInitializer.Initialize()); + var messageDeletedHandler = new MessageDeletedHandler(_databaseInitializer.Initialize(), _logger, _client); + + _client.MessageReceived += commandHandler.RunCommand; + _client.MessageDeleted += messageDeletedHandler.HandleMessageDeleted; + _client.UserJoined += userHandler.Joined; + _client.UserUpdated += userHandler.Updated; + _client.UserLeft += userHandler.Left; + _client.ReactionAdded += reactionHandler.Added; + _client.ReactionRemoved += reactionHandler.Removed; + if (!_runParameters.InMemory) _client.MessageReceived += statsHandler.UpdateStats; + } + + private void StartWebApi() + { + if (_runParameters.DisableApi) + { + _logger.Warning(LogSource.Api, "Web API is disabled"); + return; + } + + var highscoreManager = new HighscoreManager(_databaseInitializer.Initialize(), _userRepository); + WebApiStartup.StartWebApi(_logger, _runParameters, _commands, _databaseInitializer.Initialize(), _client, _globalSettings, highscoreManager); + } + } +} \ No newline at end of file diff --git a/src/Core/DateLocalization.cs b/src/Bot/Utils/DateLocalization.cs similarity index 86% rename from src/Core/DateLocalization.cs rename to src/Bot/Utils/DateLocalization.cs index 39b447f..eea40fb 100644 --- a/src/Core/DateLocalization.cs +++ b/src/Bot/Utils/DateLocalization.cs @@ -1,17 +1,13 @@ using System; using System.Text; -namespace Geekbot.Core +namespace Geekbot.Bot.Utils { public class DateLocalization { public static string FormatDateTimeAsRemaining(DateTimeOffset dateTime) { - return FormatDateTimeAsRemaining(dateTime - DateTimeOffset.Now); - } - - public static string FormatDateTimeAsRemaining(TimeSpan remaining) - { + var remaining = dateTime - DateTimeOffset.Now; const string formattable = "{0} {1}"; var sb = new StringBuilder(); diff --git a/src/Startup/derp.ico b/src/Bot/derp.ico similarity index 100% rename from src/Startup/derp.ico rename to src/Bot/derp.ico diff --git a/src/Commands/Commands.csproj b/src/Commands/Commands.csproj deleted file mode 100644 index 7f0bd8f..0000000 --- a/src/Commands/Commands.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net6.0 - $(VersionSuffix) - $(VersionSuffix) - 0.0.0-DEV - Geekbot.Commands - Geekbot.Commands - NU1701 - CS8618 - enable - enable - True - Library - - - - - - - - diff --git a/src/Commands/Karma/Karma.cs b/src/Commands/Karma/Karma.cs deleted file mode 100644 index 026af2f..0000000 --- a/src/Commands/Karma/Karma.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Drawing; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; -using Geekbot.Interactions.Embed; -using Geekbot.Interactions.Resolved; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Commands.Karma; - -public class Karma -{ - private readonly DatabaseContext _database; - private readonly long _guildId; - - public Karma(DatabaseContext database, long guildId) - { - _database = database; - _guildId = guildId; - } - - public async Task ChangeKarma(User author, User targetUser, KarmaChange change) - { - // Get the user - var authorRecord = await GetUser(long.Parse(author.Id)); - - // Check if the user can change karma - if (targetUser.Id == author.Id) - { - var message = change switch - { - KarmaChange.Up => Localization.Karma.CannotChangeOwnUp, - KarmaChange.Same => Localization.Karma.CannotChangeOwnSame, - KarmaChange.Down => Localization.Karma.CannotChangeOwnDown, - _ => throw new ArgumentOutOfRangeException(nameof(change), change, null) - }; - return Embed.ErrorEmbed(string.Format(message, author.Username)); - } - - var timeoutMinutes = 3; - if (authorRecord.TimeOut.AddMinutes(timeoutMinutes) > DateTimeOffset.Now.ToUniversalTime()) - { - var remaining = authorRecord.TimeOut.AddMinutes(timeoutMinutes) - DateTimeOffset.Now.ToUniversalTime(); - var formatedWaitTime = DateLocalization.FormatDateTimeAsRemaining(remaining); - return Embed.ErrorEmbed(string.Format(Localization.Karma.WaitUntill, author.Username, formatedWaitTime)); - } - - // Get the values for the change direction - var (title, amount) = change switch - { - KarmaChange.Up => (Localization.Karma.Increased, 1), - KarmaChange.Same => (Localization.Karma.Neutral, 0), - KarmaChange.Down => (Localization.Karma.Decreased, -1), - _ => throw new ArgumentOutOfRangeException(nameof(change), change, null) - }; - - // Change it - var targetUserRecord = await GetUser(long.Parse(targetUser.Id)); - targetUserRecord.Karma += amount; - _database.Karma.Update(targetUserRecord); - - authorRecord.TimeOut = DateTimeOffset.Now.ToUniversalTime(); - _database.Karma.Update(authorRecord); - - await _database.SaveChangesAsync(); - - // Respond - var eb = new Embed() - { - Author = new () - { - Name = targetUser.Username, - IconUrl = targetUser.GetAvatarUrl() - }, - Title = title, - }; - eb.SetColor(Color.PaleGreen); - eb.AddInlineField(Localization.Karma.By, author.Username); - eb.AddInlineField(Localization.Karma.Amount, amount.ToString()); - eb.AddInlineField(Localization.Karma.Current, targetUserRecord.Karma.ToString()); - return eb; - } - - private async Task GetUser(long userId) - { - var user = _database.Karma.FirstOrDefault(u => u.GuildId.Equals(_guildId) && u.UserId.Equals(userId)) ?? await CreateNewRow(userId); - return user; - } - - private async Task CreateNewRow(long userId) - { - var user = new KarmaModel() - { - GuildId = _guildId, - UserId = userId, - Karma = 0, - TimeOut = DateTimeOffset.MinValue.ToUniversalTime() - }; - var newUser = _database.Karma.Add(user).Entity; - await _database.SaveChangesAsync(); - return newUser; - } -} \ No newline at end of file diff --git a/src/Commands/Karma/KarmaChange.cs b/src/Commands/Karma/KarmaChange.cs deleted file mode 100644 index 96cbe88..0000000 --- a/src/Commands/Karma/KarmaChange.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Geekbot.Commands.Karma; - -public enum KarmaChange -{ - Up, - Same, - Down -} diff --git a/src/Commands/Rank.cs b/src/Commands/Rank.cs deleted file mode 100644 index 6de2d83..0000000 --- a/src/Commands/Rank.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System.Text; -using Geekbot.Core.Converters; -using Geekbot.Core.Database; -using Geekbot.Core.Extensions; -using Geekbot.Core.Highscores; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Commands -{ - public class Rank - { - private readonly DatabaseContext _database; - private readonly IHighscoreManager _highscoreManager; - - public Rank(DatabaseContext database, IHighscoreManager highscoreManager) - { - _database = database; - _highscoreManager = highscoreManager; - } - - public string Run(string typeUnformated, int amount, string season, ulong guildId, string guildName) - { - HighscoreTypes type; - try - { - type = Enum.Parse(typeUnformated, true); - if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception(); - } - catch - { - return Localization.Rank.InvalidType; - } - - var replyBuilder = new StringBuilder(); - if (amount > 20) - { - replyBuilder.AppendLine(Localization.Rank.LimitingTo20Warning); - amount = 20; - } - - Dictionary highscoreUsers; - try - { - highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount, season); - } - catch (HighscoreListEmptyException) - { - return string.Format(Core.Localization.Rank.NoTypeFoundForServer, type); - } - - var guildMessages = 0; - if (type == HighscoreTypes.messages) - { - guildMessages = _database.Messages - .Where(e => e.GuildId.Equals(guildId.AsLong())) - .Select(e => e.MessageCount) - .Sum(); - } - - var failedToRetrieveUser = highscoreUsers.Any(e => string.IsNullOrEmpty(e.Key.Username)); - - if (failedToRetrieveUser) replyBuilder.AppendLine(Core.Localization.Rank.FailedToResolveAllUsernames).AppendLine(); - - if (type == HighscoreTypes.seasons) - { - if (string.IsNullOrEmpty(season)) - { - season = SeasonsUtils.GetCurrentSeason(); - } - - replyBuilder.AppendLine(string.Format(Core.Localization.Rank.HighscoresFor, $"{type.ToString().CapitalizeFirst()} ({season})", guildName)); - } - else - { - replyBuilder.AppendLine(string.Format(Core.Localization.Rank.HighscoresFor, type.ToString().CapitalizeFirst(), guildName)); - } - - var highscorePlace = 1; - foreach (var (user, value) in highscoreUsers) - { - replyBuilder.Append(highscorePlace < 11 - ? $"{EmojiConverter.NumberToEmoji(highscorePlace)} " - : $"`{highscorePlace}.` "); - - replyBuilder.Append(user.Username != null - ? $"**{user.Username}#{user.Discriminator}**" - : $"**{user.Id}**"); - - replyBuilder.Append(type switch - { - HighscoreTypes.messages => $" - {value} {HighscoreTypes.messages} - {Math.Round((double)(100 * value) / guildMessages, 2)}%\n", - HighscoreTypes.seasons => $" - {value} {HighscoreTypes.messages}\n", - _ => $" - {value} {type}\n" - }); - - highscorePlace++; - } - - return replyBuilder.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Commands/Roll/Roll.cs b/src/Commands/Roll/Roll.cs deleted file mode 100644 index a431bd9..0000000 --- a/src/Commands/Roll/Roll.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; -using Geekbot.Core.Extensions; -using Geekbot.Core.KvInMemoryStore; -using Geekbot.Core.RandomNumberGenerator; - -namespace Geekbot.Commands.Roll -{ - public class Roll - { - private readonly IKvInMemoryStore _kvInMemoryStore; - private readonly DatabaseContext _database; - private readonly IRandomNumberGenerator _randomNumberGenerator; - - public Roll(IKvInMemoryStore kvInMemoryStore, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator) - { - _kvInMemoryStore = kvInMemoryStore; - _database = database; - _randomNumberGenerator = randomNumberGenerator; - } - - public async Task RunFromGateway(ulong guildId, ulong userId, string userName, string unparsedGuess) - { - int.TryParse(unparsedGuess, out var guess); - return await this.Run(guildId.AsLong(), userId.AsLong(), userName, guess); - } - - public async Task RunFromInteraction(string guildId, string userId, string userName, int guess) - { - return await this.Run(long.Parse(guildId), long.Parse(userId), userName, guess); - } - - private async Task Run(long guildId, long userId, string userName, int guess) - { - var number = _randomNumberGenerator.Next(1, 100); - - if (guess <= 100 && guess > 0) - { - var kvKey = $"{guildId}:{userId}:RollsPrevious"; - var prevRoll = _kvInMemoryStore.Get(kvKey); - - if (prevRoll?.LastGuess == guess && prevRoll?.GuessedOn.AddDays(1) > DateTime.Now) - { - return string.Format( - Core.Localization.Roll.NoPrevGuess, - $"<@{userId}>", - DateLocalization.FormatDateTimeAsRemaining(prevRoll.GuessedOn.AddDays(1))); - } - - _kvInMemoryStore.Set(kvKey, new RollTimeout { LastGuess = guess, GuessedOn = DateTime.Now }); - - var answer = string.Format(Core.Localization.Roll.Rolled, $"<@{userId}>", number, guess); - - if (guess == number) - { - var user = await GetUser(guildId, userId); - user.Rolls += 1; - _database.Rolls.Update(user); - await _database.SaveChangesAsync(); - answer += string.Format(($"\n{Core.Localization.Roll.Gratz}"), userName); - } - - return answer; - } - else - { - return string.Format(Core.Localization.Roll.RolledNoGuess, $"<@{userId}>", number); - } - } - - private async Task GetUser(long guildId, long userId) - { - var user = _database.Rolls.FirstOrDefault(u => u.GuildId.Equals(guildId) && u.UserId.Equals(userId)) ?? await CreateNewRow(guildId, userId); - return user; - } - - private async Task CreateNewRow(long guildId, long userId) - { - var user = new RollsModel() - { - GuildId = guildId, - UserId = userId, - Rolls = 0 - }; - var newUser = _database.Rolls.Add(user).Entity; - await _database.SaveChangesAsync(); - return newUser; - } - } -} \ No newline at end of file diff --git a/src/Commands/UrbanDictionary/UrbanDictionary.cs b/src/Commands/UrbanDictionary/UrbanDictionary.cs deleted file mode 100644 index 9862463..0000000 --- a/src/Commands/UrbanDictionary/UrbanDictionary.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Drawing; -using Geekbot.Core; -using Geekbot.Interactions.Embed; - -namespace Geekbot.Commands.UrbanDictionary; - -public class UrbanDictionary -{ - public static async Task Run(string term) - { - var definitions = await HttpAbstractions.Get(new Uri($"https://api.urbandictionary.com/v0/define?term={term}")); - - if (definitions.List.Count == 0) - { - return null; - } - - var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example)); - - static string ShortenIfToLong(string str, int maxLength) => str.Length > maxLength ? $"{str[..(maxLength - 5)]}[...]" : str; - - var eb = new Embed(); - eb.Author = new() - { - Name = definition.Word, - Url = definition.Permalink - }; - eb.SetColor(Color.Gold); - - if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = ShortenIfToLong(definition.Definition, 1800); - if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", ShortenIfToLong(definition.Example, 1024)); - if (definition.ThumbsUp != 0) eb.AddInlineField("Upvotes", definition.ThumbsUp.ToString()); - if (definition.ThumbsDown != 0) eb.AddInlineField("Downvotes", definition.ThumbsDown.ToString()); - - return eb; - } -} \ No newline at end of file diff --git a/src/Commands/UrbanDictionary/UrbanDictionaryListItem.cs b/src/Commands/UrbanDictionary/UrbanDictionaryListItem.cs deleted file mode 100644 index 822ca8a..0000000 --- a/src/Commands/UrbanDictionary/UrbanDictionaryListItem.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Commands.UrbanDictionary; - -public record UrbanDictionaryListItem -{ - [JsonPropertyName("definition")] - public string Definition { get; set; } - - [JsonPropertyName("permalink")] - public string Permalink { get; set; } - - [JsonPropertyName("thumbs_up")] - public int ThumbsUp { get; set; } - - [JsonPropertyName("word")] - public string Word { get; set; } - - [JsonPropertyName("example")] - public string Example { get; set; } - - [JsonPropertyName("thumbs_down")] - public int ThumbsDown { get; set; } -} diff --git a/src/Commands/UrbanDictionary/UrbanDictionaryResponse.cs b/src/Commands/UrbanDictionary/UrbanDictionaryResponse.cs deleted file mode 100644 index 42861c3..0000000 --- a/src/Commands/UrbanDictionary/UrbanDictionaryResponse.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Commands.UrbanDictionary; - -public struct UrbanDictionaryResponse -{ - [JsonPropertyName("tags")] - public string[] Tags { get; set; } - - [JsonPropertyName("list")] - public List List { get; set; } -} \ No newline at end of file diff --git a/src/Core/BotCommandLookup/CommandInfo.cs b/src/Core/BotCommandLookup/CommandInfo.cs deleted file mode 100644 index c5793ac..0000000 --- a/src/Core/BotCommandLookup/CommandInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Geekbot.Core.BotCommandLookup; - -public struct CommandInfo -{ - public string Name { get; set; } - public Dictionary Parameters { get; set; } - public List Aliases { get; set; } - public string Summary { get; set; } -} \ No newline at end of file diff --git a/src/Core/BotCommandLookup/CommandLookup.cs b/src/Core/BotCommandLookup/CommandLookup.cs deleted file mode 100644 index 62369c6..0000000 --- a/src/Core/BotCommandLookup/CommandLookup.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Discord.Commands; - -namespace Geekbot.Core.BotCommandLookup; - -public class CommandLookup -{ - private readonly Assembly _assembly; - - public CommandLookup(Assembly assembly) - { - _assembly = assembly; - } - - public List GetCommands() - { - var commands = SearchCommands(_assembly); - var result = new List(); - commands.ForEach(x => GetCommandDefinition(ref result, x)); - - return result; - } - - private List SearchCommands(Assembly assembly) - { - bool IsLoadableModule(TypeInfo info) => info.DeclaredMethods.Any(x => x.GetCustomAttribute() != null || x.GetCustomAttribute() != null); - return assembly - .DefinedTypes - .Where(typeInfo => typeInfo.IsPublic || typeInfo.IsNestedPublic) - .Where(IsLoadableModule) - .ToList(); - } - - private void GetCommandDefinition(ref List commandInfos, TypeInfo commandType) - { - var methods = commandType - .GetMethods() - .Where(x => x.GetCustomAttribute() != null) - .ToList(); - - var commandGroup = (commandType.GetCustomAttributes().FirstOrDefault(attr => attr is GroupAttribute) as GroupAttribute)?.Prefix; - - foreach (var command in methods) - { - var commandInfo = new CommandInfo() - { - Parameters = new Dictionary(), - }; - - foreach (var attr in command.GetCustomAttributes()) - { - - switch (attr) - { - case SummaryAttribute name: - commandInfo.Summary = name.Text; - break; - case CommandAttribute name: - commandInfo.Name = string.IsNullOrEmpty(commandGroup) ? name.Text : $"{commandGroup} {name.Text}"; - break; - case AliasAttribute name: - commandInfo.Aliases = name.Aliases.ToList() ?? new List(); - break; - } - } - - foreach (var param in command.GetParameters()) - { - var paramName = param.Name ?? string.Empty; - var paramInfo = new ParameterInfo() - { - Summary = param.GetCustomAttribute()?.Text ?? string.Empty, - Type = param.ParameterType.Name, - DefaultValue = param.DefaultValue?.ToString() - }; - commandInfo.Parameters.Add(paramName, paramInfo); - } - - if (!string.IsNullOrEmpty(commandInfo.Name)) - { - commandInfos.Add(commandInfo); - } - } - } -} \ No newline at end of file diff --git a/src/Core/BotCommandLookup/ParameterInfo.cs b/src/Core/BotCommandLookup/ParameterInfo.cs deleted file mode 100644 index afdfd50..0000000 --- a/src/Core/BotCommandLookup/ParameterInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Geekbot.Core.BotCommandLookup; - -public struct ParameterInfo -{ - public string Summary { get; set; } - public string Type { get; set; } - public string DefaultValue { get; set; } -} \ No newline at end of file diff --git a/src/Bot/CommandPreconditions/DisableInDirectMessageAttribute.cs b/src/Core/CommandPreconditions/DisableInDirectMessageAttribute.cs similarity index 93% rename from src/Bot/CommandPreconditions/DisableInDirectMessageAttribute.cs rename to src/Core/CommandPreconditions/DisableInDirectMessageAttribute.cs index b75f4a1..835e0b3 100644 --- a/src/Bot/CommandPreconditions/DisableInDirectMessageAttribute.cs +++ b/src/Core/CommandPreconditions/DisableInDirectMessageAttribute.cs @@ -2,7 +2,7 @@ using System; using System.Threading.Tasks; using Discord.Commands; -namespace Geekbot.Bot.CommandPreconditions +namespace Geekbot.Core.CommandPreconditions { [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] public class DisableInDirectMessageAttribute : PreconditionAttribute diff --git a/src/Core/Converters/EmojiConverter.cs b/src/Core/Converters/EmojiConverter.cs index d25415f..327aab8 100644 --- a/src/Core/Converters/EmojiConverter.cs +++ b/src/Core/Converters/EmojiConverter.cs @@ -3,133 +3,88 @@ using System.Text; namespace Geekbot.Core.Converters { - public static class EmojiConverter + public class EmojiConverter : IEmojiConverter { - private static readonly string[] NumberEmojiMap = - { - ":zero:", - ":one:", - ":two:", - ":three:", - ":four:", - ":five:", - ":six:", - ":seven:", - ":eight:", - ":nine:" - }; - - public static string NumberToEmoji(int number) + public string NumberToEmoji(int number) { if (number == 10) { return "🔟"; } - + var emojiMap = new[] + { + ":zero:", + ":one:", + ":two:", + ":three:", + ":four:", + ":five:", + ":six:", + ":seven:", + ":eight:", + ":nine:" + }; var numbers = number.ToString().ToCharArray(); var returnString = new StringBuilder(); foreach (var n in numbers) { - returnString.Append(NumberEmojiMap[int.Parse(n.ToString())]); + returnString.Append(emojiMap[int.Parse(n.ToString())]); } return returnString.ToString(); } - private static readonly Hashtable TextEmojiMap = new Hashtable - { - ['A'] = ":regional_indicator_a: ", - ['B'] = ":b: ", - ['C'] = ":regional_indicator_c: ", - ['D'] = ":regional_indicator_d: ", - ['E'] = ":regional_indicator_e: ", - ['F'] = ":regional_indicator_f: ", - ['G'] = ":regional_indicator_g: ", - ['H'] = ":regional_indicator_h: ", - ['I'] = ":regional_indicator_i: ", - ['J'] = ":regional_indicator_j: ", - ['K'] = ":regional_indicator_k: ", - ['L'] = ":regional_indicator_l: ", - ['M'] = ":regional_indicator_m: ", - ['N'] = ":regional_indicator_n: ", - ['O'] = ":regional_indicator_o: ", - ['P'] = ":regional_indicator_p: ", - ['Q'] = ":regional_indicator_q: ", - ['R'] = ":regional_indicator_r: ", - ['S'] = ":regional_indicator_s: ", - ['T'] = ":regional_indicator_t: ", - ['U'] = ":regional_indicator_u: ", - ['V'] = ":regional_indicator_v: ", - ['W'] = ":regional_indicator_w: ", - ['X'] = ":regional_indicator_x: ", - ['Y'] = ":regional_indicator_y: ", - ['Z'] = ":regional_indicator_z: ", - ['!'] = ":exclamation: ", - ['?'] = ":question: ", - ['#'] = ":hash: ", - ['*'] = ":star2: ", - ['+'] = ":heavy_plus_sign: ", - ['0'] = ":zero: ", - ['1'] = ":one: ", - ['2'] = ":two: ", - ['3'] = ":three: ", - ['4'] = ":four: ", - ['5'] = ":five: ", - ['6'] = ":six: ", - ['7'] = ":seven: ", - ['8'] = ":eight: ", - ['9'] = ":nine: ", - [' '] = " " - }; - - public static string TextToEmoji(string text) + public string TextToEmoji(string text) { + var emojiMap = new Hashtable + { + ['A'] = ":regional_indicator_a: ", + ['B'] = ":b: ", + ['C'] = ":regional_indicator_c: ", + ['D'] = ":regional_indicator_d: ", + ['E'] = ":regional_indicator_e: ", + ['F'] = ":regional_indicator_f: ", + ['G'] = ":regional_indicator_g: ", + ['H'] = ":regional_indicator_h: ", + ['I'] = ":regional_indicator_i: ", + ['J'] = ":regional_indicator_j: ", + ['K'] = ":regional_indicator_k: ", + ['L'] = ":regional_indicator_l: ", + ['M'] = ":regional_indicator_m: ", + ['N'] = ":regional_indicator_n: ", + ['O'] = ":regional_indicator_o: ", + ['P'] = ":regional_indicator_p: ", + ['Q'] = ":regional_indicator_q: ", + ['R'] = ":regional_indicator_r: ", + ['S'] = ":regional_indicator_s: ", + ['T'] = ":regional_indicator_t: ", + ['U'] = ":regional_indicator_u: ", + ['V'] = ":regional_indicator_v: ", + ['W'] = ":regional_indicator_w: ", + ['X'] = ":regional_indicator_x: ", + ['Y'] = ":regional_indicator_y: ", + ['Z'] = ":regional_indicator_z: ", + ['!'] = ":exclamation: ", + ['?'] = ":question: ", + ['#'] = ":hash: ", + ['*'] = ":star2: ", + ['+'] = ":heavy_plus_sign: ", + ['0'] = ":zero: ", + ['1'] = ":one: ", + ['2'] = ":two: ", + ['3'] = ":three: ", + ['4'] = ":four: ", + ['5'] = ":five: ", + ['6'] = ":six: ", + ['7'] = ":seven: ", + ['8'] = ":eight: ", + ['9'] = ":nine: ", + [' '] = " " + }; var letters = text.ToUpper().ToCharArray(); var returnString = new StringBuilder(); foreach (var n in letters) { - var emoji = TextEmojiMap[n] ?? n; - returnString.Append(emoji); - } - return returnString.ToString(); - } - - private static readonly Hashtable RegionalIndicatorMap = new Hashtable() - { - ['A'] = new Rune(0x1F1E6), - ['B'] = new Rune(0x1F1E7), - ['C'] = new Rune(0x1F1E8), - ['D'] = new Rune(0x1F1E9), - ['E'] = new Rune(0x1F1EA), - ['F'] = new Rune(0x1F1EB), - ['G'] = new Rune(0x1F1EC), - ['H'] = new Rune(0x1F1ED), - ['I'] = new Rune(0x1F1EE), - ['J'] = new Rune(0x1F1EF), - ['K'] = new Rune(0x1F1F0), - ['L'] = new Rune(0x1F1F1), - ['M'] = new Rune(0x1F1F2), - ['N'] = new Rune(0x1F1F3), - ['O'] = new Rune(0x1F1F4), - ['P'] = new Rune(0x1F1F5), - ['Q'] = new Rune(0x1F1F6), - ['R'] = new Rune(0x1F1F7), - ['S'] = new Rune(0x1F1F8), - ['T'] = new Rune(0x1F1F9), - ['U'] = new Rune(0x1F1FA), - ['V'] = new Rune(0x1F1FB), - ['W'] = new Rune(0x1F1FC), - ['X'] = new Rune(0x1F1FD), - ['Y'] = new Rune(0x1F1FE), - ['Z'] = new Rune(0x1F1FF) - }; - - public static string CountryCodeToEmoji(string countryCode) - { - var letters = countryCode.ToUpper().ToCharArray(); - var returnString = new StringBuilder(); - foreach (var n in letters) - { - var emoji = RegionalIndicatorMap[n]; + var emoji = emojiMap[n] ?? n; returnString.Append(emoji); } return returnString.ToString(); diff --git a/src/Core/Converters/IEmojiConverter.cs b/src/Core/Converters/IEmojiConverter.cs new file mode 100644 index 0000000..79ca0a7 --- /dev/null +++ b/src/Core/Converters/IEmojiConverter.cs @@ -0,0 +1,8 @@ +namespace Geekbot.Core.Converters +{ + public interface IEmojiConverter + { + string NumberToEmoji(int number); + string TextToEmoji(string text); + } +} \ No newline at end of file diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 2cd8dbc..c05d75c 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -1,94 +1,33 @@ - net6.0 + net5.0 $(VersionSuffix) $(VersionSuffix) 0.0.0-DEV Geekbot.Core Geekbot.Core NU1701 - True - Library - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - ResXFileCodeGenerator - Admin.Designer.cs - - - ResXFileCodeGenerator - Choose.Designer.cs - - - ResXFileCodeGenerator - Cookies.Designer.cs - - - ResXFileCodeGenerator - Corona.Designer.cs - - - ResXFileCodeGenerator - EightBall.Designer.cs - - - ResXFileCodeGenerator - Internal.Designer.cs - - - ResXFileCodeGenerator - Karma.Designer.cs - - - ResXFileCodeGenerator - Quote.Designer.cs - - - ResXFileCodeGenerator - Rank.Designer.cs - - - ResXFileCodeGenerator - Role.Designer.cs - - - ResXFileCodeGenerator - Roll.Designer.cs - - - ResXFileCodeGenerator - Ship.Designer.cs - - - ResXFileCodeGenerator - Stats.Designer.cs - + + + + + + + + + + + + + + + + + diff --git a/src/Core/Database/DatabaseContext.cs b/src/Core/Database/DatabaseContext.cs index 14a1275..93d46d3 100644 --- a/src/Core/Database/DatabaseContext.cs +++ b/src/Core/Database/DatabaseContext.cs @@ -11,7 +11,6 @@ namespace Geekbot.Core.Database public DbSet Karma { get; set; } public DbSet Ships { get; set; } public DbSet Rolls { get; set; } - public DbSet MessagesSeasons { get; set; } public DbSet Messages { get; set; } public DbSet Slaps { get; set; } public DbSet Globals { get; set; } diff --git a/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs b/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs index 8a46c0d..29acb93 100644 --- a/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs +++ b/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs @@ -1,7 +1,8 @@ using System; using Geekbot.Core.Logger; +using Microsoft.Extensions.Logging; using Npgsql.Logging; -using LogLevel = NLog.LogLevel; +using Serilog.Events; namespace Geekbot.Core.Database.LoggingAdapter { @@ -21,7 +22,7 @@ namespace Geekbot.Core.Database.LoggingAdapter public override bool IsEnabled(NpgsqlLogLevel level) { - return (_runParameters.DbLogging && _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(level))); + return (_runParameters.DbLogging && _geekbotLogger.GetLogger().IsEnabled(ToGeekbotLogLevel(level))); } public override void Log(NpgsqlLogLevel level, int connectorId, string msg, Exception exception = null) @@ -51,16 +52,16 @@ namespace Geekbot.Core.Database.LoggingAdapter } } - private static LogLevel ToGeekbotLogLevel(NpgsqlLogLevel level) + private static LogEventLevel ToGeekbotLogLevel(NpgsqlLogLevel level) { return level switch { - NpgsqlLogLevel.Trace => LogLevel.Trace, - NpgsqlLogLevel.Debug => LogLevel.Debug, - NpgsqlLogLevel.Info => LogLevel.Info, - NpgsqlLogLevel.Warn => LogLevel.Warn, - NpgsqlLogLevel.Error => LogLevel.Error, - NpgsqlLogLevel.Fatal => LogLevel.Fatal, + NpgsqlLogLevel.Trace => LogEventLevel.Verbose, + NpgsqlLogLevel.Debug => LogEventLevel.Debug, + NpgsqlLogLevel.Info => LogEventLevel.Information, + NpgsqlLogLevel.Warn => LogEventLevel.Warning, + NpgsqlLogLevel.Error => LogEventLevel.Error, + NpgsqlLogLevel.Fatal => LogEventLevel.Fatal, _ => throw new ArgumentOutOfRangeException(nameof(level)) }; } diff --git a/src/Core/Database/Models/MessageSeasonsModel.cs b/src/Core/Database/Models/MessageSeasonsModel.cs deleted file mode 100644 index 5a4252c..0000000 --- a/src/Core/Database/Models/MessageSeasonsModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class MessageSeasonsModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - [Required] - public string Season { get; set; } - - public int MessageCount { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/SingleDie.cs b/src/Core/DiceParser/SingleDie.cs index 7c1ae41..4e0f474 100644 --- a/src/Core/DiceParser/SingleDie.cs +++ b/src/Core/DiceParser/SingleDie.cs @@ -63,9 +63,9 @@ namespace Geekbot.Core.DiceParser throw new DiceException("Die must have at least 2 sides") { DiceName = DiceName }; } - if (Sides > 145) + if (Sides > 144) { - throw new DiceException("Die can not have more than 145 sides") { DiceName = DiceName }; + throw new DiceException("Die can not have more than 144 sides") { DiceName = DiceName }; } } } diff --git a/src/Core/ErrorHandling/ErrorHandler.cs b/src/Core/ErrorHandling/ErrorHandler.cs index 0b55bd8..60d97e9 100644 --- a/src/Core/ErrorHandling/ErrorHandler.cs +++ b/src/Core/ErrorHandling/ErrorHandler.cs @@ -2,7 +2,8 @@ using System.Threading.Tasks; using Discord.Commands; using Geekbot.Core.Logger; -using Sentry; +using SharpRaven; +using SharpRaven.Data; using Exception = System.Exception; namespace Geekbot.Core.ErrorHandling @@ -11,6 +12,7 @@ namespace Geekbot.Core.ErrorHandling { private readonly IGeekbotLogger _logger; private readonly Func _getDefaultErrorText; + private readonly IRavenClient _raven; private readonly bool _errorsInChat; public ErrorHandler(IGeekbotLogger logger, RunParameters runParameters, Func getDefaultErrorText) @@ -18,6 +20,17 @@ namespace Geekbot.Core.ErrorHandling _logger = logger; _getDefaultErrorText = getDefaultErrorText; _errorsInChat = runParameters.ExposeErrors; + + var sentryDsn = runParameters.SentryEndpoint; + if (!string.IsNullOrEmpty(sentryDsn)) + { + _raven = new RavenClient(sentryDsn) { Release = Constants.BotVersion(), Environment = "Production" }; + _logger.Information(LogSource.Geekbot, $"Command Errors will be logged to Sentry: {sentryDsn}"); + } + else + { + _raven = null; + } } public async Task HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def") @@ -70,19 +83,18 @@ namespace Geekbot.Core.ErrorHandling private void ReportExternal(Exception e, MessageDto errorObj) { - if (!SentrySdk.IsEnabled) return; - + if (_raven == null) return; var sentryEvent = new SentryEvent(e) { + Tags = + { + ["discord_server"] = errorObj.Guild.Name, + ["discord_user"] = errorObj.User.Name + }, Message = errorObj.Message.Content, + Extra = errorObj }; - sentryEvent.SetTag("discord_server", errorObj.Guild.Name); - sentryEvent.SetExtra("Channel", errorObj.Channel); - sentryEvent.SetExtra("Guild", errorObj.Guild); - sentryEvent.SetExtra("Message", errorObj.Message); - sentryEvent.SetExtra("User", errorObj.User); - - SentrySdk.CaptureEvent(sentryEvent); + _raven.Capture(sentryEvent); } } } \ No newline at end of file diff --git a/src/Core/GeekbotCommandBase.cs b/src/Core/GeekbotCommandBase.cs index 801c53c..43ced95 100644 --- a/src/Core/GeekbotCommandBase.cs +++ b/src/Core/GeekbotCommandBase.cs @@ -7,7 +7,7 @@ using Geekbot.Core.GuildSettingsManager; namespace Geekbot.Core { - public class GeekbotCommandBase : TransactionModuleBase + public class GeekbotCommandBase : ModuleBase { protected readonly IGuildSettingsManager GuildSettingsManager; protected GuildSettingsModel GuildSettings; @@ -22,14 +22,9 @@ namespace Geekbot.Core protected override void BeforeExecute(CommandInfo command) { base.BeforeExecute(command); - - var setupSpan = Transaction.StartChild("Setup"); - GuildSettings = GuildSettingsManager.GetSettings(Context?.Guild?.Id ?? 0); var language = GuildSettings.Language; - Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language); - - setupSpan.Finish(); + Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language == "CHDE" ? "de-ch" : language); } } } \ No newline at end of file diff --git a/src/Core/Highscores/HighscoreManager.cs b/src/Core/Highscores/HighscoreManager.cs index c839b39..ac8580b 100644 --- a/src/Core/Highscores/HighscoreManager.cs +++ b/src/Core/Highscores/HighscoreManager.cs @@ -18,7 +18,7 @@ namespace Geekbot.Core.Highscores } - public Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null) + public Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount) { var list = type switch { @@ -26,8 +26,6 @@ namespace Geekbot.Core.Highscores HighscoreTypes.karma => GetKarmaList(guildId, amount), HighscoreTypes.rolls => GetRollsList(guildId, amount), HighscoreTypes.cookies => GetCookiesList(guildId, amount), - HighscoreTypes.seasons => GetMessageSeasonList(guildId, amount, season), - HighscoreTypes.quotes => GetQuotesList(guildId, amount), _ => new Dictionary() }; @@ -77,19 +75,6 @@ namespace Geekbot.Core.Highscores .ToDictionary(key => key.UserId.AsUlong(), key => key.MessageCount); } - public Dictionary GetMessageSeasonList(ulong guildId, int amount, string season) - { - if (string.IsNullOrEmpty(season)) - { - season = SeasonsUtils.GetCurrentSeason(); - } - return _database.MessagesSeasons - .Where(k => k.GuildId.Equals(guildId.AsLong()) && k.Season.Equals(season)) - .OrderByDescending(o => o.MessageCount) - .Take(amount) - .ToDictionary(key => key.UserId.AsUlong(), key => key.MessageCount); - } - public Dictionary GetKarmaList(ulong guildId, int amount) { return _database.Karma @@ -116,16 +101,5 @@ namespace Geekbot.Core.Highscores .Take(amount) .ToDictionary(key => key.UserId.AsUlong(), key => key.Cookies); } - - private Dictionary GetQuotesList(ulong guildId, int amount) - { - return _database.Quotes - .Where(row => row.GuildId == guildId.AsLong()) - .GroupBy(row => row.UserId) - .Select(row => new { userId = row.Key, amount = row.Count()}) - .OrderByDescending(row => row.amount) - .Take(amount) - .ToDictionary(key => key.userId.AsUlong(), key => key.amount); - } } } \ No newline at end of file diff --git a/src/Core/Highscores/HighscoreTypes.cs b/src/Core/Highscores/HighscoreTypes.cs index 3aa396e..b577642 100644 --- a/src/Core/Highscores/HighscoreTypes.cs +++ b/src/Core/Highscores/HighscoreTypes.cs @@ -5,8 +5,6 @@ messages, karma, rolls, - cookies, - seasons, - quotes + cookies } } \ No newline at end of file diff --git a/src/Core/Highscores/IHighscoreManager.cs b/src/Core/Highscores/IHighscoreManager.cs index 9c2d6f0..83ba2da 100644 --- a/src/Core/Highscores/IHighscoreManager.cs +++ b/src/Core/Highscores/IHighscoreManager.cs @@ -4,9 +4,8 @@ namespace Geekbot.Core.Highscores { public interface IHighscoreManager { - Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null); + Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount); Dictionary GetMessageList(ulong guildId, int amount); - Dictionary GetMessageSeasonList(ulong guildId, int amount, string season); Dictionary GetKarmaList(ulong guildId, int amount); Dictionary GetRollsList(ulong guildId, int amount); } diff --git a/src/Core/Highscores/SeasonsUtils.cs b/src/Core/Highscores/SeasonsUtils.cs deleted file mode 100644 index d2a8e3e..0000000 --- a/src/Core/Highscores/SeasonsUtils.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Globalization; - -namespace Geekbot.Core.Highscores -{ - public class SeasonsUtils - { - public static string GetCurrentSeason() - { - var now = DateTime.Now; - var year = (now.Year - 2000).ToString(CultureInfo.InvariantCulture); - var quarter = Math.Ceiling(now.Month / 3.0).ToString(CultureInfo.InvariantCulture); - return $"{year}Q{quarter}"; - } - } -} \ No newline at end of file diff --git a/src/Core/HttpAbstractions.cs b/src/Core/HttpAbstractions.cs index 629de74..4fa287b 100644 --- a/src/Core/HttpAbstractions.cs +++ b/src/Core/HttpAbstractions.cs @@ -1,12 +1,8 @@ using System; -using System.Linq; -using System.Net; using System.Net.Http; using System.Net.Http.Headers; -using System.Text; -using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading.Tasks; +using Newtonsoft.Json; namespace Geekbot.Core { @@ -26,164 +22,21 @@ namespace Geekbot.Core return client; } - public static async Task Get(Uri location, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) + public static async Task Get(Uri location, HttpClient httpClient = null, bool disposeClient = true) { httpClient ??= CreateDefaultClient(); httpClient.BaseAddress = location; - HttpResponseMessage response; - try - { - response = await Execute(() => httpClient.GetAsync(location.PathAndQuery), maxRetries); - } - finally - { - if (disposeClient) - { - httpClient.Dispose(); - } - } - + var response = await httpClient.GetAsync(location.PathAndQuery); + response.EnsureSuccessStatusCode(); var stringResponse = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(stringResponse); - } - - public static async Task Post(Uri location, object data, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) - { - httpClient ??= CreateDefaultClient(); - httpClient.BaseAddress = location; - var content = new StringContent( - JsonSerializer.Serialize(data, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }), - Encoding.UTF8, - "application/json" - ); - - HttpResponseMessage response; - try + if (disposeClient) { - response = await Execute(() => httpClient.PostAsync(location, content), maxRetries); - } - finally - { - if (disposeClient) - { - httpClient.Dispose(); - } + httpClient.Dispose(); } - var stringResponse = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(stringResponse); - } - - public static async Task Post(Uri location, object data, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) - { - httpClient ??= CreateDefaultClient(); - httpClient.BaseAddress = location; - - var content = new StringContent( - JsonSerializer.Serialize(data, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }), - Encoding.UTF8, - "application/json" - ); - - try - { - await Execute(() => httpClient.PostAsync(location, content), maxRetries); - } - finally - { - if (disposeClient) - { - httpClient.Dispose(); - } - } - } - - public static async Task Patch(Uri location, object data, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) - { - httpClient ??= CreateDefaultClient(); - httpClient.BaseAddress = location; - - var content = new StringContent( - JsonSerializer.Serialize(data, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }), - Encoding.UTF8, - "application/json" - ); - - try - { - await Execute(() => httpClient.PatchAsync(location, content), maxRetries); - } - finally - { - if (disposeClient) - { - httpClient.Dispose(); - } - } - } - - public static async Task Delete(Uri location, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) - { - httpClient ??= CreateDefaultClient(); - httpClient.BaseAddress = location; - - try - { - await Execute(() => httpClient.DeleteAsync(location), maxRetries); - } - finally - { - if (disposeClient) - { - httpClient.Dispose(); - } - } - } - - private static async Task Execute(Func> request, int maxRetries) - { - var attempt = 0; - while (true) - { - var response = await request(); - if (!response.IsSuccessStatusCode) - { - if (attempt >= maxRetries) - { - throw new HttpRequestException($"Request failed after {attempt} attempts"); - } - - if (response.Headers.Contains("Retry-After")) - { - var retryAfter = response.Headers.GetValues("Retry-After").First(); - if (retryAfter.Contains(':')) - { - var duration = DateTimeOffset.Parse(retryAfter).ToUniversalTime() - DateTimeOffset.Now.ToUniversalTime(); - await Task.Delay(duration); - } - else - { - await Task.Delay(int.Parse(retryAfter) * 1000); - } - } - else if (response.StatusCode is HttpStatusCode.BadGateway or HttpStatusCode.ServiceUnavailable or HttpStatusCode.GatewayTimeout) - { - await Task.Delay(TimeSpan.FromSeconds(Math.Ceiling(attempt * 1.5))); - } - else - { - response.EnsureSuccessStatusCode(); - } - - attempt++; - } - else - { - return response; - } - } + return JsonConvert.DeserializeObject(stringResponse); } } } \ No newline at end of file diff --git a/src/Core/Localization/Cookies.Designer.cs b/src/Core/Localization/Cookies.Designer.cs deleted file mode 100644 index 7a3442c..0000000 --- a/src/Core/Localization/Cookies.Designer.cs +++ /dev/null @@ -1,96 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Geekbot.Core.Localization { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Cookies { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public Cookies() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Geekbot.Core.Localization.Cookies", typeof(Cookies).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - public static string GetCookies { - get { - return ResourceManager.GetString("GetCookies", resourceCulture); - } - } - - public static string WaitForMoreCookies { - get { - return ResourceManager.GetString("WaitForMoreCookies", resourceCulture); - } - } - - public static string InYourJar { - get { - return ResourceManager.GetString("InYourJar", resourceCulture); - } - } - - public static string Given { - get { - return ResourceManager.GetString("Given", resourceCulture); - } - } - - public static string NotEnoughToGive { - get { - return ResourceManager.GetString("NotEnoughToGive", resourceCulture); - } - } - - public static string NotEnoughCookiesToEat { - get { - return ResourceManager.GetString("NotEnoughCookiesToEat", resourceCulture); - } - } - - public static string AteCookies { - get { - return ResourceManager.GetString("AteCookies", resourceCulture); - } - } - - public static string CantTakeCookies { - get { - return ResourceManager.GetString("CantTakeCookies", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Corona.de-ch.resx b/src/Core/Localization/Corona.de-ch.resx deleted file mode 100644 index 3c4180c..0000000 --- a/src/Core/Localization/Corona.de-ch.resx +++ /dev/null @@ -1,32 +0,0 @@ - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Bstätigti Corona Fallzahle - - - Total - - - Aktiv - - - Erholt - - - Gstorbe - - - Quelle - - \ No newline at end of file diff --git a/src/Core/Localization/Corona.resx b/src/Core/Localization/Corona.resx deleted file mode 100644 index 44bf85e..0000000 --- a/src/Core/Localization/Corona.resx +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Confirmed Corona Cases - - - Total - - - Active - - - Recovered - - - Deaths - - - Source - - \ No newline at end of file diff --git a/src/Core/Localization/EightBall.Designer.cs b/src/Core/Localization/EightBall.Designer.cs deleted file mode 100644 index eee2bc5..0000000 --- a/src/Core/Localization/EightBall.Designer.cs +++ /dev/null @@ -1,240 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Geekbot.Core.Localization { - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class EightBall { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public EightBall() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.EightBall", typeof(EightBall).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to As I see it, yes. - /// - public static string AsISeeItYes { - get { - return ResourceManager.GetString("AsISeeItYes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Ask again later. - /// - public static string AskAgainLater { - get { - return ResourceManager.GetString("AskAgainLater", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Better not tell you now. - /// - public static string BetterNotTellYouNow { - get { - return ResourceManager.GetString("BetterNotTellYouNow", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot predict now. - /// - public static string CannotPredictNow { - get { - return ResourceManager.GetString("CannotPredictNow", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Concentrate and ask again. - /// - public static string ConcentrateAndAskAgain { - get { - return ResourceManager.GetString("ConcentrateAndAskAgain", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Don't count on it. - /// - public static string DontCountOnIt { - get { - return ResourceManager.GetString("DontCountOnIt", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It is certain. - /// - public static string ItIsCertain { - get { - return ResourceManager.GetString("ItIsCertain", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It is decidedly so. - /// - public static string ItIsDecidedlySo { - get { - return ResourceManager.GetString("ItIsDecidedlySo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Most likely. - /// - public static string MostLikely { - get { - return ResourceManager.GetString("MostLikely", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to My reply is no. - /// - public static string MyReplyIsNo { - get { - return ResourceManager.GetString("MyReplyIsNo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to My sources say no. - /// - public static string MySourcesSayNo { - get { - return ResourceManager.GetString("MySourcesSayNo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Outlook good. - /// - public static string OutlookGood { - get { - return ResourceManager.GetString("OutlookGood", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Outlook not so good. - /// - public static string OutlookNotSoGood { - get { - return ResourceManager.GetString("OutlookNotSoGood", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reply hazy try again. - /// - public static string ReplyHazyTryAgain { - get { - return ResourceManager.GetString("ReplyHazyTryAgain", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Signs point to yes. - /// - public static string SignsPointToYes { - get { - return ResourceManager.GetString("SignsPointToYes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Very doubtful. - /// - public static string VeryDoubtful { - get { - return ResourceManager.GetString("VeryDoubtful", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Without a doubt. - /// - public static string WithoutADoubt { - get { - return ResourceManager.GetString("WithoutADoubt", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Yes. - /// - public static string Yes { - get { - return ResourceManager.GetString("Yes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Yes, definitely. - /// - public static string YesDefinitely { - get { - return ResourceManager.GetString("YesDefinitely", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You may rely on it. - /// - public static string YouMayRelyOnIt { - get { - return ResourceManager.GetString("YouMayRelyOnIt", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/EightBall.de-ch.resx b/src/Core/Localization/EightBall.de-ch.resx deleted file mode 100644 index 89d7a60..0000000 --- a/src/Core/Localization/EightBall.de-ch.resx +++ /dev/null @@ -1,94 +0,0 @@ - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Es isch sicher - - - - So isch es entschiede worde - - - - Ohni zwifel - - - - Ja, absolut - - - - Chasch davo usgoh - - - - Wie ich es gsehn, ja - - - - Sehr waschinli - - - - Ussicht isch guet - - - - Ja - - - - Ahzeiche zeigend uf ja - - - - Antwort isch verschwumme, versuechs nomol - - - - Frög spöter nomol - - - - Segs dir jetzt besser nid - - - - Im mommnet chani das nid vorussege - - - - Konzentrier di und frog nomol - - - - Zähl nid druf - - - - Mini antwort isch nei - - - - Mini quellene seged nei - - - - Ussicht isch ned so guet - - - - Sehr froglich - - - \ No newline at end of file diff --git a/src/Core/Localization/EightBall.resx b/src/Core/Localization/EightBall.resx deleted file mode 100644 index 6eba369..0000000 --- a/src/Core/Localization/EightBall.resx +++ /dev/null @@ -1,200 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - It is certain - - - - It is decidedly so - - - - Without a doubt - - - - Yes, definitely - - - - You may rely on it - - - - As I see it, yes - - - - Most likely - - - - Outlook good - - - - Yes - - - - Signs point to yes - - - - Reply hazy try again - - - - Ask again later - - - - Better not tell you now - - - - Cannot predict now - - - - Concentrate and ask again - - - - Don't count on it - - - - My reply is no - - - - My sources say no - - - - Outlook not so good - - - - Very doubtful - - - \ No newline at end of file diff --git a/src/Core/Logger/Adapters/ILoggerAdapter.cs b/src/Core/Logger/Adapters/ILoggerAdapter.cs deleted file mode 100644 index 90e7bf3..0000000 --- a/src/Core/Logger/Adapters/ILoggerAdapter.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using Microsoft.Extensions.Logging; - -namespace Geekbot.Core.Logger.Adapters; - -public class ILoggerAdapter : ILogger -{ - private readonly string _categoryName; - private readonly LogSource _logSource; - private readonly IGeekbotLogger _geekbotLogger; - public ILoggerAdapter(string categoryName, LogSource logSource, IGeekbotLogger geekbotLogger) - { - _categoryName = categoryName; - _logSource = logSource; - _geekbotLogger = geekbotLogger; - } - - public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) - { - switch (logLevel) - { - case LogLevel.Trace: - _geekbotLogger.Trace(_logSource, $"{eventId.Id} - {_categoryName} - {state}"); - break; - case LogLevel.Debug: - _geekbotLogger.Debug(_logSource, $"{eventId.Id} - {_categoryName} - {state}"); - break; - case LogLevel.Information: - _geekbotLogger.Information(_logSource, $"{eventId.Id} - {_categoryName} - {state}"); - break; - case LogLevel.Warning: - _geekbotLogger.Warning(_logSource, $"{eventId.Id} - {_categoryName} - {state}", exception); - break; - case LogLevel.Error: - case LogLevel.Critical: - _geekbotLogger.Error(_logSource, $"{eventId.Id} - {_categoryName} - {state}", exception); - break; - case LogLevel.None: - break; - default: - throw new ArgumentOutOfRangeException(nameof(logLevel)); - } - } - - public bool IsEnabled(LogLevel logLevel) - { - return _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(logLevel)); - // return !_geekbotLogger.LogAsJson() && _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(logLevel)); - } - - public IDisposable BeginScope(TState state) - { - return null; - } - - private static NLog.LogLevel ToGeekbotLogLevel(LogLevel level) - { - return level switch - { - LogLevel.Trace => NLog.LogLevel.Trace, - LogLevel.Debug => NLog.LogLevel.Debug, - LogLevel.Information => NLog.LogLevel.Info, - LogLevel.Warning => NLog.LogLevel.Warn, - LogLevel.Error => NLog.LogLevel.Error, - LogLevel.Critical => NLog.LogLevel.Fatal, - LogLevel.None => NLog.LogLevel.Off, - _ => throw new ArgumentOutOfRangeException(nameof(level)) - }; - } -} \ No newline at end of file diff --git a/src/Core/Logger/Adapters/ILoggerProviderProvider.cs b/src/Core/Logger/Adapters/ILoggerProviderProvider.cs deleted file mode 100644 index bc31a24..0000000 --- a/src/Core/Logger/Adapters/ILoggerProviderProvider.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Concurrent; -using Microsoft.Extensions.Logging; - -namespace Geekbot.Core.Logger.Adapters; - -public class ILoggerProviderProvider : ILoggerProvider, ILoggerFactory -{ - private readonly IGeekbotLogger _geekbotLogger; - private readonly LogSource _logSource; - - private readonly ConcurrentDictionary _loggers = new(); - - public ILoggerProviderProvider(IGeekbotLogger geekbotLogger, LogSource logSource) - { - _geekbotLogger = geekbotLogger; - _logSource = logSource; - } - - public void Dispose() - { - _loggers.Clear(); - } - - public ILogger CreateLogger(string categoryName) - { - return _loggers.GetOrAdd(categoryName, name => new ILoggerAdapter(categoryName, _logSource, _geekbotLogger)); - } - - public void AddProvider(ILoggerProvider provider) - { - throw new System.NotImplementedException(); - } -} \ No newline at end of file diff --git a/src/Core/Logger/Adapters/DiscordLogger.cs b/src/Core/Logger/DiscordLogger.cs similarity index 94% rename from src/Core/Logger/Adapters/DiscordLogger.cs rename to src/Core/Logger/DiscordLogger.cs index e9bb02e..f6fb95a 100644 --- a/src/Core/Logger/Adapters/DiscordLogger.cs +++ b/src/Core/Logger/DiscordLogger.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Discord; -namespace Geekbot.Core.Logger.Adapters +namespace Geekbot.Core.Logger { public class DiscordLogger : IDiscordLogger { diff --git a/src/Core/Logger/ExceptionDto.cs b/src/Core/Logger/ExceptionDto.cs deleted file mode 100644 index bd67d90..0000000 --- a/src/Core/Logger/ExceptionDto.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Geekbot.Core.Logger; - -public struct ExceptionDto -{ - public string Message { get; init; } - - public string InnerException { get; init; } - - public string Source { get; init; } - - public ExceptionDto(Exception exception) - { - Message = exception.Message; - InnerException = string.IsNullOrEmpty(exception?.InnerException?.ToString()) ? exception?.StackTrace : exception?.InnerException?.ToString(); - Source = exception.Source; - } -}; \ No newline at end of file diff --git a/src/Core/Logger/GeekbotLogger.cs b/src/Core/Logger/GeekbotLogger.cs index 83a6d49..d9b7752 100644 --- a/src/Core/Logger/GeekbotLogger.cs +++ b/src/Core/Logger/GeekbotLogger.cs @@ -1,47 +1,46 @@ using System; -using System.Text.Json; -using System.Text.Json.Serialization; +using Newtonsoft.Json; namespace Geekbot.Core.Logger { public class GeekbotLogger : IGeekbotLogger { private readonly bool _logAsJson; - private readonly NLog.Logger _logger; - private readonly JsonSerializerOptions _serializerSettings; + private readonly Serilog.ILogger _logger; + private readonly JsonSerializerSettings _serializerSettings; public GeekbotLogger(RunParameters runParameters) { - _logAsJson = !string.IsNullOrEmpty(runParameters.SumologicEndpoint) || runParameters.LogJson; - _logger = LoggerFactory.CreateNLog(runParameters); - _serializerSettings = new JsonSerializerOptions + _logAsJson = !string.IsNullOrEmpty(runParameters.DatadogApiKey) || runParameters.LogJson; + _logger = LoggerFactory.CreateLogger(runParameters); + _serializerSettings = new JsonSerializerSettings { - ReferenceHandler = ReferenceHandler.IgnoreCycles, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, + ReferenceLoopHandling = ReferenceLoopHandling.Serialize, + NullValueHandling = NullValueHandling.Include }; Information(LogSource.Geekbot, "Using GeekbotLogger"); } public void Trace(LogSource source, string message, object extra = null) - => _logger.Trace(CreateLogString("Trace", source, message, null, extra)); + => _logger.Verbose(CreateLogString("Trace", source, message, null, extra)); public void Debug(LogSource source, string message, object extra = null) => _logger.Debug(CreateLogString("Debug", source, message, null, extra)); public void Information(LogSource source, string message, object extra = null) - => _logger.Info(CreateLogString("Information", source, message, null, extra)); + => _logger.Information(CreateLogString("Information", source, message, null, extra)); public void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null) - => _logger.Warn(CreateLogString("Warning", source, message, stackTrace, extra)); + => _logger.Warning(CreateLogString("Warning", source, message, stackTrace, extra)); public void Error(LogSource source, string message, Exception stackTrace, object extra = null) => _logger.Error(stackTrace, CreateLogString("Error", source, message, stackTrace, extra)); - public NLog.Logger GetNLogger() => _logger; + public Serilog.ILogger GetLogger() => _logger; public bool LogAsJson() => _logAsJson; - private string CreateLogString(string type, LogSource source, string message, Exception exception = null, object extra = null) + private string CreateLogString(string type, LogSource source, string message, Exception stackTrace = null, object extra = null) { if (_logAsJson) { @@ -51,10 +50,10 @@ namespace Geekbot.Core.Logger Type = type, Source = source, Message = message, - StackTrace = exception != null ? new ExceptionDto(exception) : null, + StackTrace = stackTrace, Extra = extra }; - return JsonSerializer.Serialize(logObject, _serializerSettings); + return JsonConvert.SerializeObject(logObject, Formatting.None, _serializerSettings); } if (source != LogSource.Message) return $"[{source}] - {message}"; diff --git a/src/Core/Logger/IGeekbotLogger.cs b/src/Core/Logger/IGeekbotLogger.cs index 1363629..3359d10 100644 --- a/src/Core/Logger/IGeekbotLogger.cs +++ b/src/Core/Logger/IGeekbotLogger.cs @@ -9,7 +9,7 @@ namespace Geekbot.Core.Logger void Information(LogSource source, string message, object extra = null); void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null); void Error(LogSource source, string message, Exception stackTrace, object extra = null); - NLog.Logger GetNLogger(); + Serilog.ILogger GetLogger(); bool LogAsJson(); } } \ No newline at end of file diff --git a/src/Core/Logger/LogDto.cs b/src/Core/Logger/LogDto.cs index ee6a3e5..9db0c65 100644 --- a/src/Core/Logger/LogDto.cs +++ b/src/Core/Logger/LogDto.cs @@ -1,20 +1,14 @@ using System; -using System.Text.Json.Serialization; -namespace Geekbot.Core.Logger; - -public struct GeekbotLoggerObject +namespace Geekbot.Core.Logger { - public DateTime Timestamp { get; set; } - - public string Type { get; set; } - - public LogSource Source { get; set; } - - public string Message { get; set; } - - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public ExceptionDto? StackTrace { get; set; } - - public object Extra { get; set; } -} + public class GeekbotLoggerObject + { + public DateTime Timestamp { get; set; } + public string Type { get; set; } + public LogSource Source { get; set; } + public string Message { get; set; } + public Exception StackTrace { get; set; } + public object Extra { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/Logger/LogSource.cs b/src/Core/Logger/LogSource.cs index d2baff5..4518327 100644 --- a/src/Core/Logger/LogSource.cs +++ b/src/Core/Logger/LogSource.cs @@ -1,8 +1,9 @@ -using System.Text.Json.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Geekbot.Core.Logger { - [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonConverter(typeof(StringEnumConverter))] public enum LogSource { Geekbot, @@ -16,7 +17,6 @@ namespace Geekbot.Core.Logger Api, Migration, HighscoreManager, - Interaction, Other } } \ No newline at end of file diff --git a/src/Core/Logger/LoggerFactory.cs b/src/Core/Logger/LoggerFactory.cs index bf3d926..d44c331 100644 --- a/src/Core/Logger/LoggerFactory.cs +++ b/src/Core/Logger/LoggerFactory.cs @@ -1,64 +1,104 @@ using System; -using System.Text; -using NLog; -using NLog.Config; -using NLog.Targets; -using SumoLogic.Logging.NLog; +using Serilog; +using Serilog.Events; +using Serilog.Sinks.Datadog.Logs; namespace Geekbot.Core.Logger { public class LoggerFactory { - public static NLog.Logger CreateNLog(RunParameters runParameters) + public static ILogger CreateLogger(RunParameters runParameters) { - var config = new LoggingConfiguration(); - var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; - - if (!string.IsNullOrEmpty(runParameters.SumologicEndpoint)) + var logger = new LoggerConfiguration(); + var minLevel = runParameters.Verbose ? LogEventLevel.Verbose : LogEventLevel.Information; + if (!string.IsNullOrEmpty(runParameters.DatadogApiKey)) { - Console.WriteLine("Logging Geekbot Logs to Sumologic"); - config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, - new SumoLogicTarget() - { - Url = runParameters.SumologicEndpoint, - SourceName = "GeekbotLogger", - Layout = "${message}", - UseConsoleLog = false, - OptimizeBufferReuse = true, - Name = "Geekbot" - }) + // 2nd error logger + var errorLogger = new LoggerConfiguration().WriteTo.Console().CreateLogger(); + errorLogger.Information("Enabling Datadog Logger"); + + logger.WriteTo.DatadogLogs( + apiKey: runParameters.DatadogApiKey, + source: "GeekbotLogger", + service: "Geekbot", + host: Environment.MachineName, + configuration: new DatadogConfiguration() + { + Url = "https://http-intake.logs.datadoghq.eu", + Port = 443, + UseSSL = true, + UseTCP = false + }, + logLevel: minLevel, + exceptionHandler: exception => + { + var cannotSendLogEventException = exception as CannotSendLogEventException; + errorLogger.Error(cannotSendLogEventException, "Datadog Error"); + } ); } else if (runParameters.LogJson) { - config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, - new ConsoleTarget - { - Name = "Console", - Encoding = Encoding.UTF8, - Layout = "${message}" - } - ) - ); + logger.WriteTo.Console(restrictedToMinimumLevel: minLevel, outputTemplate: "{Message:lj}{NewLine}"); } else { - config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, - new ColoredConsoleTarget - { - Name = "Console", - Encoding = Encoding.UTF8, - Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}" - } - ) - ); + logger.WriteTo.Console(restrictedToMinimumLevel: minLevel); } - var loggerConfig = new LogFactory {Configuration = config}; - return loggerConfig.GetCurrentClassLogger(); + return logger.CreateLogger(); } + + // public static NLog.Logger CreateNLog(RunParameters runParameters) + // { + // var config = new LoggingConfiguration(); + // var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; + // + // if (!string.IsNullOrEmpty(runParameters.SumologicEndpoint)) + // { + // Console.WriteLine("Logging Geekbot Logs to Sumologic"); + // config.LoggingRules.Add( + // new LoggingRule("*", minLevel, LogLevel.Fatal, + // new SumoLogicTarget() + // { + // Url = runParameters.SumologicEndpoint, + // SourceName = "GeekbotLogger", + // Layout = "${message}", + // UseConsoleLog = false, + // OptimizeBufferReuse = true, + // Name = "Geekbot" + // }) + // ); + // } + // else if (runParameters.LogJson) + // { + // config.LoggingRules.Add( + // new LoggingRule("*", minLevel, LogLevel.Fatal, + // new ConsoleTarget + // { + // Name = "Console", + // Encoding = Encoding.UTF8, + // Layout = "${message}" + // } + // ) + // ); + // } + // else + // { + // config.LoggingRules.Add( + // new LoggingRule("*", minLevel, LogLevel.Fatal, + // new ColoredConsoleTarget + // { + // Name = "Console", + // Encoding = Encoding.UTF8, + // Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}" + // } + // ) + // ); + // } + // + // var loggerConfig = new LogFactory {Configuration = config}; + // return loggerConfig.GetCurrentClassLogger(); + // } } } \ No newline at end of file diff --git a/src/Core/Polyfills/UserPolyfillDto.cs b/src/Core/Polyfills/UserPolyfillDto.cs index 3907e05..3a8f43f 100644 --- a/src/Core/Polyfills/UserPolyfillDto.cs +++ b/src/Core/Polyfills/UserPolyfillDto.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading.Tasks; using Discord; @@ -13,29 +12,17 @@ namespace Geekbot.Core.Polyfills public string Mention { get; set; } public IActivity Activity { get; } public UserStatus Status { get; set; } - IReadOnlyCollection IPresence.ActiveClients => ActiveClients; - - IReadOnlyCollection IPresence.Activities => Activities; - public IImmutableSet ActiveClients { get; } - public IImmutableList Activities { get; } - public Task CreateDMChannelAsync(RequestOptions options = null) - { - throw new NotImplementedException(); - } - public string AvatarId { get; set; } - public string AvatarUrl { get; set; } public string Discriminator { get; set; } public ushort DiscriminatorValue { get; set; } public bool IsBot { get; set; } public bool IsWebhook { get; set; } public string Username { get; set; } - public UserProperties? PublicFlags { get; } - + public string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) { - return AvatarUrl ?? "https://discordapp.com/assets/6debd47ed13483642cf09e832ed0bc1b.png"; + return "https://discordapp.com/assets/6debd47ed13483642cf09e832ed0bc1b.png"; } public string GetDefaultAvatarUrl() diff --git a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs b/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs index 7460677..db990a7 100644 --- a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs +++ b/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs @@ -1,14 +1,26 @@ using System; +using System.Security.Cryptography; +using Anemonis.RandomOrg; +using Geekbot.Core.GlobalSettings; namespace Geekbot.Core.RandomNumberGenerator { public class RandomNumberGenerator : IRandomNumberGenerator { - private readonly System.Security.Cryptography.RandomNumberGenerator rng; + private readonly RNGCryptoServiceProvider csp; + private readonly bool _canUseRandomOrg; + private readonly RandomOrgClient _randomOrgClient; - public RandomNumberGenerator() + public RandomNumberGenerator(IGlobalSettings globalSettings) { - rng = System.Security.Cryptography.RandomNumberGenerator.Create(); + csp = new RNGCryptoServiceProvider(); + + var randomOrgApiKey = globalSettings.GetKey("RandomOrgApiKey"); + if (!string.IsNullOrEmpty(randomOrgApiKey)) + { + _canUseRandomOrg = true; + _randomOrgClient = new RandomOrgClient(randomOrgApiKey); + } } public int Next(int minValue, int maxInclusiveValue) @@ -20,12 +32,33 @@ namespace Geekbot.Core.RandomNumberGenerator if (minValue >= maxInclusiveValue) { - throw new ArgumentOutOfRangeException("minValue", "must be lower than maxExclusiveValue"); + throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue"); + } + + if (_canUseRandomOrg) + { + try + { + return GetFromRandomOrg(minValue, maxInclusiveValue); + } + catch + { + // ignore + } } return GetFromCrypto(minValue, maxInclusiveValue); } + private int GetFromRandomOrg(int minValue, int maxInclusiveValue) + { + return _randomOrgClient + .GenerateIntegersAsync(1, minValue, maxInclusiveValue, false) + .Result + .Random + .Data[0]; + } + private int GetFromCrypto(int minValue, int maxInclusiveValue) { var maxExclusiveValue = maxInclusiveValue + 1; @@ -51,7 +84,7 @@ namespace Geekbot.Core.RandomNumberGenerator private byte[] GenerateRandomBytes(int bytesNumber) { var buffer = new byte[bytesNumber]; - rng.GetBytes(buffer); + csp.GetBytes(buffer); return buffer; } } diff --git a/src/Core/ReactionListener/IReactionListener.cs b/src/Core/ReactionListener/IReactionListener.cs index c22d792..4909d68 100644 --- a/src/Core/ReactionListener/IReactionListener.cs +++ b/src/Core/ReactionListener/IReactionListener.cs @@ -8,8 +8,8 @@ namespace Geekbot.Core.ReactionListener { bool IsListener(ulong id); Task AddRoleToListener(ulong messageId, ulong guildId, string emoji, IRole role); - void RemoveRole(IMessageChannel channel, SocketReaction reaction); - void GiveRole(IMessageChannel message, SocketReaction reaction); + void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction); + void GiveRole(ISocketMessageChannel message, SocketReaction reaction); IEmote ConvertStringToEmote(string emoji); } } \ No newline at end of file diff --git a/src/Core/ReactionListener/ReactionListener.cs b/src/Core/ReactionListener/ReactionListener.cs index dcb0d5b..84367c9 100644 --- a/src/Core/ReactionListener/ReactionListener.cs +++ b/src/Core/ReactionListener/ReactionListener.cs @@ -1,29 +1,22 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using Discord; using Discord.WebSocket; using Geekbot.Core.Database; using Geekbot.Core.Database.Models; using Geekbot.Core.Extensions; -using Geekbot.Core.Logger; -using Sentry; namespace Geekbot.Core.ReactionListener { public class ReactionListener : IReactionListener { private readonly DatabaseContext _database; - - private readonly IGeekbotLogger _logger; - // private Dictionary> _listener; - public ReactionListener(DatabaseContext database, IGeekbotLogger logger) + public ReactionListener(DatabaseContext database) { _database = database; - _logger = logger; LoadListeners(); } @@ -67,59 +60,20 @@ namespace Geekbot.Core.ReactionListener _listener[messageId].Add(emote, role.Id); } - public async void RemoveRole(IMessageChannel channel, SocketReaction reaction) + public async void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction) { - _listener.TryGetValue(reaction.MessageId, out var registeredReactions); - if (registeredReactions == null) return; - if (!registeredReactions.ContainsKey(reaction.Emote)) return; - var roleId = registeredReactions[reaction.Emote]; + var roleId = _listener[reaction.MessageId][reaction.Emote]; var guild = (SocketGuildChannel) channel; - - try - { - var role = guild.Guild.GetRole(roleId); - await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role); - } - catch (Exception error) - { - HandleDeletedRole(error, guild, reaction, roleId); - } + var role = guild.Guild.GetRole(roleId); + await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role); } - public async void GiveRole(IMessageChannel channel, SocketReaction reaction) + public async void GiveRole(ISocketMessageChannel channel, SocketReaction reaction) { - _listener.TryGetValue(reaction.MessageId, out var registeredReactions); - if (registeredReactions == null) return; - if (!registeredReactions.ContainsKey(reaction.Emote)) return; - var roleId = registeredReactions[reaction.Emote]; + var roleId = _listener[reaction.MessageId][reaction.Emote]; var guild = (SocketGuildChannel) channel; - - try - { - - var role = guild.Guild.GetRole(roleId); - await ((IGuildUser) reaction.User.Value).AddRoleAsync(role); - } - catch (Exception error) - { - HandleDeletedRole(error, guild, reaction, roleId); - } - } - - private void HandleDeletedRole(Exception error, SocketGuildChannel guild, SocketReaction reaction, ulong roleId) - { - _logger.Warning(LogSource.Interaction, "Failed to get or assign role in reaction listener", error); - - if (!SentrySdk.IsEnabled) return; - var sentryEvent = new SentryEvent(error) - { - Message = "Failed to get or assign role in reaction listener" - }; - sentryEvent.SetTag("discord_server", guild.Id.ToString()); - sentryEvent.SetExtra("Message", reaction.MessageId.ToString()); - sentryEvent.SetExtra("User", roleId.ToString()); - - SentrySdk.CaptureEvent(sentryEvent); + var role = guild.Guild.GetRole(roleId); + await ((IGuildUser) reaction.User.Value).AddRoleAsync(role); } public IEmote ConvertStringToEmote(string emoji) diff --git a/src/Core/RunParameters.cs b/src/Core/RunParameters.cs index a886a98..00ff5f2 100644 --- a/src/Core/RunParameters.cs +++ b/src/Core/RunParameters.cs @@ -20,9 +20,6 @@ namespace Geekbot.Core [Option('e', "expose-errors", HelpText = "Shows internal errors in the chat (default: false) (env: EXPOSE_ERRORS)")] public bool ExposeErrors { get; set; } = ParamFallback("EXPOSE_ERRORS", false); - - [Option("disable-gateway", HelpText = "Disables the Discord Gateway (default: false) (env: GATEWAY_DISABLE)")] - public bool DisableGateway { get; set; } = ParamFallback("GATEWAY_DISABLE", false); /************************************ * Database * @@ -77,12 +74,15 @@ namespace Geekbot.Core * Intergrations * ************************************/ - [Option("sumologic", HelpText = "Sumologic endpoint for logging (default: null) (env: SUMOLOGIC)")] - public string SumologicEndpoint { get; set; } = ParamFallback("SUMOLOGIC"); + // [Option("sumologic", HelpText = "Sumologic endpoint for logging (default: null) (env: SUMOLOGIC)")] + // public string SumologicEndpoint { get; set; } = ParamFallback("SUMOLOGIC"); [Option("sentry", HelpText = "Sentry endpoint for error reporting (default: null) (env: SENTRY)")] public string SentryEndpoint { get; set; } = ParamFallback("SENTRY"); + [Option("datadog-api-key", HelpText = "Datadog API Key (default: null) (env: DATADOG_API_KEY)")] + public string DatadogApiKey { get; set; } = ParamFallback("DATADOG_API_KEY"); + /************************************ * Helper Functions * ************************************/ diff --git a/src/Core/TransactionModuleBase.cs b/src/Core/TransactionModuleBase.cs deleted file mode 100644 index cbe5206..0000000 --- a/src/Core/TransactionModuleBase.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Sentry; - -namespace Geekbot.Core -{ - public class TransactionModuleBase : ModuleBase - { - protected ITransaction Transaction; - - protected override void BeforeExecute(CommandInfo command) - { - base.BeforeExecute(command); - - // Transaction Setup - Transaction = SentrySdk.StartTransaction(new Transaction(command.Name, "Exec")); - Transaction.SetTags(new [] - { - new KeyValuePair("Guild", Context.Guild.Name), - }); - Transaction.User = new User() - { - Id = Context.User.Id.ToString(), - Username = Context.User.Username, - }; - Transaction.Status = SpanStatus.Ok; - } - - protected override void AfterExecute(CommandInfo command) - { - base.AfterExecute(command); - Transaction.Finish(); - } - - protected Task ReplyAsync(string message = null, bool isTTS = false, Embed embed = null, RequestOptions options = null, AllowedMentions allowedMentions = null, MessageReference messageReference = null) - { - var replySpan = Transaction.StartChild("Reply"); - var msg = base.ReplyAsync(message, isTTS, embed, options, allowedMentions, messageReference); - replySpan.Finish(); - return msg; - } - } -} \ No newline at end of file diff --git a/src/Core/UserRepository/UserRepository.cs b/src/Core/UserRepository/UserRepository.cs index 6b436b1..31fe2e2 100644 --- a/src/Core/UserRepository/UserRepository.cs +++ b/src/Core/UserRepository/UserRepository.cs @@ -35,7 +35,7 @@ namespace Geekbot.Core.UserRepository savedUser.Discriminator = user.Discriminator; savedUser.AvatarUrl = user.GetAvatarUrl() ?? ""; savedUser.IsBot = user.IsBot; - savedUser.Joined = user.CreatedAt.ToUniversalTime(); + savedUser.Joined = user.CreatedAt; if (isNew) { diff --git a/src/Core/WikipediaClient/Page/PageApiUrls.cs b/src/Core/WikipediaClient/Page/PageApiUrls.cs index 59d3258..6e3a1b6 100644 --- a/src/Core/WikipediaClient/Page/PageApiUrls.cs +++ b/src/Core/WikipediaClient/Page/PageApiUrls.cs @@ -1,26 +1,14 @@ using System; -using System.Text.Json.Serialization; namespace Geekbot.Core.WikipediaClient.Page { public class PageApiUrls { - [JsonPropertyName("summary")] public Uri Summary { get; set; } - - [JsonPropertyName("metadata")] public Uri Metadata { get; set; } - - [JsonPropertyName("references")] public Uri References { get; set; } - - [JsonPropertyName("media")] public Uri Media { get; set; } - - [JsonPropertyName("edit_html")] public Uri EditHtml { get; set; } - - [JsonPropertyName("talk_page_html")] public Uri TalkPageHtml { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageContentUrlCollection.cs b/src/Core/WikipediaClient/Page/PageContentUrlCollection.cs index 39bbc0c..3b567a7 100644 --- a/src/Core/WikipediaClient/Page/PageContentUrlCollection.cs +++ b/src/Core/WikipediaClient/Page/PageContentUrlCollection.cs @@ -1,13 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Core.WikipediaClient.Page +namespace Geekbot.Core.WikipediaClient.Page { public class PageContentUrlCollection { - [JsonPropertyName("desktop")] public PageContentUrls Desktop { get; set; } - - [JsonPropertyName("mobile")] public PageContentUrls Mobile { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageContentUrls.cs b/src/Core/WikipediaClient/Page/PageContentUrls.cs index 8da17c4..ca30b43 100644 --- a/src/Core/WikipediaClient/Page/PageContentUrls.cs +++ b/src/Core/WikipediaClient/Page/PageContentUrls.cs @@ -1,20 +1,12 @@ using System; -using System.Text.Json.Serialization; namespace Geekbot.Core.WikipediaClient.Page { public class PageContentUrls { - [JsonPropertyName("page")] public Uri Page { get; set; } - - [JsonPropertyName("revisions")] public Uri Revisions { get; set; } - - [JsonPropertyName("edit")] public Uri Edit { get; set; } - - [JsonPropertyName("talk")] public Uri Talk { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageCoordinates.cs b/src/Core/WikipediaClient/Page/PageCoordinates.cs index 8537325..52c31a4 100644 --- a/src/Core/WikipediaClient/Page/PageCoordinates.cs +++ b/src/Core/WikipediaClient/Page/PageCoordinates.cs @@ -1,13 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Core.WikipediaClient.Page +namespace Geekbot.Core.WikipediaClient.Page { public class PageCoordinates { - [JsonPropertyName("lat")] public float Lat { get; set; } - - [JsonPropertyName("lon")] public float Lon { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageImage.cs b/src/Core/WikipediaClient/Page/PageImage.cs index 0d0429a..8c4fb82 100644 --- a/src/Core/WikipediaClient/Page/PageImage.cs +++ b/src/Core/WikipediaClient/Page/PageImage.cs @@ -1,17 +1,11 @@ using System; -using System.Text.Json.Serialization; namespace Geekbot.Core.WikipediaClient.Page { public class PageImage { - [JsonPropertyName("source")] public Uri Source { get; set; } - - [JsonPropertyName("width")] public int Width { get; set; } - - [JsonPropertyName("height")] public int Height { get; set; } } diff --git a/src/Core/WikipediaClient/Page/PageNamespace.cs b/src/Core/WikipediaClient/Page/PageNamespace.cs index 29eaba8..0691ac3 100644 --- a/src/Core/WikipediaClient/Page/PageNamespace.cs +++ b/src/Core/WikipediaClient/Page/PageNamespace.cs @@ -1,13 +1,8 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Core.WikipediaClient.Page +namespace Geekbot.Core.WikipediaClient.Page { public class PageNamespace { - [JsonPropertyName("id")] public ulong Id { get; set; } - - [JsonPropertyName("text")] public string Text { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PagePreview.cs b/src/Core/WikipediaClient/Page/PagePreview.cs index b87a05e..1c1749d 100644 --- a/src/Core/WikipediaClient/Page/PagePreview.cs +++ b/src/Core/WikipediaClient/Page/PagePreview.cs @@ -1,65 +1,67 @@ using System; -using System.Text.Json.Serialization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace Geekbot.Core.WikipediaClient.Page { public class PagePreview { - [JsonPropertyName("type")] + [JsonProperty("type")] + [JsonConverter(typeof(StringEnumConverter))] public PageTypes Type { get; set; } - [JsonPropertyName("title")] + [JsonProperty("title")] public string Title { get; set; } - [JsonPropertyName("displaytitle")] + [JsonProperty("displaytitle")] public string Displaytitle { get; set; } - [JsonPropertyName("namespace")] + [JsonProperty("namespace")] public PageNamespace Namespace { get; set; } - [JsonPropertyName("titles")] + [JsonProperty("titles")] public PageTitles Titles { get; set; } - [JsonPropertyName("pageid")] + [JsonProperty("pageid")] public ulong Pageid { get; set; } - [JsonPropertyName("thumbnail")] + [JsonProperty("thumbnail")] public PageImage Thumbnail { get; set; } - [JsonPropertyName("originalimage")] + [JsonProperty("originalimage")] public PageImage Originalimage { get; set; } - [JsonPropertyName("lang")] + [JsonProperty("lang")] public string Lang { get; set; } - [JsonPropertyName("dir")] + [JsonProperty("dir")] public string Dir { get; set; } - [JsonPropertyName("revision")] - public string Revision { get; set; } + [JsonProperty("revision")] + public ulong Revision { get; set; } - [JsonPropertyName("tid")] + [JsonProperty("tid")] public string Tid { get; set; } - [JsonPropertyName("timestamp")] + [JsonProperty("timestamp")] public DateTimeOffset Timestamp { get; set; } - [JsonPropertyName("description")] + [JsonProperty("description")] public string Description { get; set; } - [JsonPropertyName("coordinates")] + [JsonProperty("coordinates")] public PageCoordinates Coordinates { get; set; } - [JsonPropertyName("content_urls")] + [JsonProperty("content_urls")] public PageContentUrlCollection ContentUrls { get; set; } - [JsonPropertyName("api_urls")] + [JsonProperty("api_urls")] public PageApiUrls ApiUrls { get; set; } - [JsonPropertyName("extract")] + [JsonProperty("extract")] public string Extract { get; set; } - [JsonPropertyName("extract_html")] + [JsonProperty("extract_html")] public string ExtractHtml { get; set; } } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageTitles.cs b/src/Core/WikipediaClient/Page/PageTitles.cs index f550c38..ad83b27 100644 --- a/src/Core/WikipediaClient/Page/PageTitles.cs +++ b/src/Core/WikipediaClient/Page/PageTitles.cs @@ -1,16 +1,10 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Core.WikipediaClient.Page +namespace Geekbot.Core.WikipediaClient.Page { public class PageTitles { - [JsonPropertyName("Canonical")] public string Canonical { get; set; } - - [JsonPropertyName("Normalized")] public string Normalized { get; set; } - - [JsonPropertyName("Display")] public string Display { get; set; } + } } \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageTypes.cs b/src/Core/WikipediaClient/Page/PageTypes.cs index 9ad748a..8bc9f64 100644 --- a/src/Core/WikipediaClient/Page/PageTypes.cs +++ b/src/Core/WikipediaClient/Page/PageTypes.cs @@ -1,9 +1,7 @@ using System.Runtime.Serialization; -using System.Text.Json.Serialization; namespace Geekbot.Core.WikipediaClient.Page { - [JsonConverter(typeof(JsonStringEnumConverter))] public enum PageTypes { [EnumMember(Value = "standard")] diff --git a/src/Core/WikipediaClient/WikipediaClient.cs b/src/Core/WikipediaClient/WikipediaClient.cs index cf13277..f577d92 100644 --- a/src/Core/WikipediaClient/WikipediaClient.cs +++ b/src/Core/WikipediaClient/WikipediaClient.cs @@ -1,7 +1,7 @@ using System.Net.Http; -using System.Text.Json; using System.Threading.Tasks; using Geekbot.Core.WikipediaClient.Page; +using Newtonsoft.Json; namespace Geekbot.Core.WikipediaClient { @@ -19,7 +19,7 @@ namespace Geekbot.Core.WikipediaClient response.EnsureSuccessStatusCode(); var stringResponse = await response.Content.ReadAsStringAsync(); - return JsonSerializer.Deserialize(stringResponse); + return JsonConvert.DeserializeObject(stringResponse); } } } \ No newline at end of file diff --git a/src/Interactions/ApplicationCommand/Command.cs b/src/Interactions/ApplicationCommand/Command.cs deleted file mode 100644 index 37a0ffd..0000000 --- a/src/Interactions/ApplicationCommand/Command.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Interactions.ApplicationCommand -{ - /// - public record Command - { - /// - /// unique id of the command - /// - [JsonPropertyName("id")] - public string? Id { get; set; } - - /// - /// the type of command, defaults 1 if not set - /// - [JsonPropertyName("type")] - public CommandType Type { get; set; } - - /// - /// unique id of the parent application - /// - [JsonPropertyName("application_id")] - public string? ApplicationId { get; set; } - - /// - /// guild id of the command, if not global - /// - [JsonPropertyName("guild_id")] - public string? GuildId { get; set; } - - /// - /// 1-32 character name - /// - /// - /// CHAT_INPUT command names and command option names must match the following regex ^[\w-]{1,32}$ with the unicode flag set. If there is a lowercase variant of any letters used, you must use those. - /// Characters with no lowercase variants and/or uncased letters are still allowed. USER and MESSAGE commands may be mixed case and can include spaces. - /// - [JsonPropertyName("name")] - public string Name { get; set; } - - /// - /// 1-100 character description for CHAT_INPUT commands, empty string for USER and MESSAGE commands - /// - /// - /// Exclusive: CHAT_INPUT - /// - [JsonPropertyName("description")] - public string? Description { get; set; } - - /// - /// the parameters for the command, max 25 - /// - /// - /// Exclusive: CHAT_INPUT - /// - [JsonPropertyName("options")] - public List