diff --git a/.deploy.yml b/.deploy.yml deleted file mode 100644 index 5fb394d..0000000 --- a/.deploy.yml +++ /dev/null @@ -1,38 +0,0 @@ ---- -- name: Geekbot Deploy - hosts: all - remote_user: geekbot - vars: - ansible_port: 65432 - ansible_python_interpreter: /usr/bin/python3 - tasks: - - name: Login to Gitlab Docker Registry - 'community.docker.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': - name: GeekbotProd - image: "{{ lookup('env', 'IMAGE_TAG') }}" - recreate: yes - pull: yes - restart_policy: always - keep_volumes: no - ports: - - "12995:12995" - env: - GEEKBOT_DB_HOST: "{{ lookup('env', 'GEEKBOT_DB_HOST') }}" - GEEKBOT_DB_USER: "{{ lookup('env', 'GEEKBOT_DB_USER') }}" - GEEKBOT_DB_PASSWORD: "{{ lookup('env', 'GEEKBOT_DB_PASSWORD') }}" - GEEKBOT_DB_PORT: "{{ lookup('env', 'GEEKBOT_DB_PORT') }}" - GEEKBOT_DB_DATABASE: "{{ lookup('env', 'GEEKBOT_DB_DATABASE') }}" - GEEKBOT_DB_REQUIRE_SSL: "true" - GEEKBOT_DB_TRUST_CERT: "true" - GEEKBOT_SUMOLOGIC: "{{ lookup('env', 'GEEKBOT_SUMOLOCIG') }}" - GEEKBOT_SENTRY: "{{ lookup('env', 'GEEKBOT_SENTRY') }}" - GEEKBOT_DB_REDSHIFT_COMPAT: "true" - - name: Cleanup Old Container - 'community.docker.docker_prune': - images: yes diff --git a/.gitignore b/.gitignore index 066c4b4..fe7e3d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,16 @@ -/*/**/bin -/*/**/obj -src/Bot/tmp/ -src/Bot/Logs/* -!/src/Bot/Logs/.keep +Geekbot.net/bin +Geekbot.net/obj +Geekbot.net/tmp/ +Tests/bin +Tests/obj +Backup/ .vs/ +UpgradeLog.htm .idea .vscode +Geekbot.net/Logs/* +!/Geekbot.net/Logs/.keep Geekbot.net.sln.DotSettings.user -app +Geekbot.net/temp/ +WikipediaApi/bin/ +WikipediaApi/obj/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a774f5e..98eb9ba 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,69 +1,54 @@ -stages: - - build - - docker - - deploy - - ops - -variables: - VERSION: 4.4.0-V$CI_COMMIT_SHORT_SHA - IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG - -Build: - stage: build - image: mcr.microsoft.com/dotnet/sdk:6.0 - artifacts: - expire_in: 1h - paths: - - app - 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/ - -Package: - stage: docker - image: docker - only: - - master - services: - - docker:stable-dind - script: - - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - docker build -t $IMAGE_TAG . - - docker push $IMAGE_TAG - -Deploy: - stage: deploy - image: quay.io/ansible/ansible-runner:stable-2.12-latest - only: - - master - variables: - ANSIBLE_NOCOWS: 1 - before_script: - - mkdir /root/.ssh - - cp $SSH_PRIVATE_KEY /root/.ssh/id_ed25519 - - cp $SSH_PUBLIC_KEY /root/.ssh/id_ed25519.pub - - 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: - stage: ops - image: getsentry/sentry-cli - allow_failure: true - only: - - master - script: - - sentry-cli releases new -p geekbot $VERSION - - sentry-cli releases set-commits --auto $VERSION - - sentry-cli releases deploys $VERSION new -e Production - -Github Mirror: - stage: ops - image: runebaas/rsync-ssh-git - only: - - master - script: - - git push https://runebaas:$TOKEN@github.com/pizzaandcoffee/Geekbot.net.git origin/master:master -f +stages: + - build + - deploy + +before_script: + - set -e + - set -u + - set -o pipefail + +build: + stage: build + image: microsoft/dotnet:2.0.3-sdk-stretch + variables: + NUGET_PACKAGES: "${CI_PROJECT_DIR}/.nugetcache" + cache: + paths: + - .nugetcache + artifacts: + expire_in: 1h + paths: + - Geekbot.net/Binaries/ + script: + - dotnet restore + - dotnet test Tests + - dotnet publish --version-suffix ${CI_COMMIT_SHA:0:8} --configuration Release -o Binaries ./ + +deploy: + stage: deploy + image: instrumentisto/rsync-ssh + only: + - master + dependencies: + - build + environment: + name: Production + url: https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054 + before_script: + - eval $(ssh-agent -s) + - mkdir -p ~/.ssh + - '[[ -f /.dockerenv ]] && echo -e "Host *\n StrictHostKeyChecking no" > ~/.ssh/config' + - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null + - chmod 700 ~/.ssh + script: + - rsync -rav -e "ssh -p 65432" ./Geekbot.net/Binaries/* www-data@31.220.42.224:$DEPPATH + - ssh -p 65432 www-data@31.220.42.224 "sudo systemctl restart geekbot.service" + +mirror: + stage: deploy + image: bravissimolabs/alpine-git:latest + only: + - master + script: + - git push https://runebaas:$TOKEN@github.com/pizzaandcoffee/Geekbot.net.git origin/master:master -f + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 39529ff..0000000 --- a/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM mcr.microsoft.com/dotnet/aspnet:6.0 - -COPY ./app /app/ - -EXPOSE 12995/tcp -WORKDIR /app -ENTRYPOINT ./Geekbot diff --git a/Geekbot.net.sln b/Geekbot.net.sln index f33d887..b542f25 100644 --- a/Geekbot.net.sln +++ b/Geekbot.net.sln @@ -3,19 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.0.0 MinimumVisualStudioVersion = 10.0.0.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geekbot.net", "Geekbot.net/Geekbot.net.csproj", "{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{47671723-52A9-4668-BBC5-2BA76AE3B288}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{0A63D5DC-6325-4F53-8ED2-9843239B76CC}" -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}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WikipediaApi", "WikipediaApi\WikipediaApi.csproj", "{1084D499-EF94-4834-9E6A-B2AD81B60078}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,34 +15,18 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.Build.0 = Release|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.Build.0 = Debug|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.ActiveCfg = Release|Any CPU {4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.Build.0 = Release|Any CPU - {47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.Build.0 = Debug|Any CPU - {47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.ActiveCfg = Release|Any CPU - {47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.Build.0 = Release|Any CPU - {0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.Build.0 = Release|Any CPU - {DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {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 + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Geekbot.net.sln.DotSettings b/Geekbot.net.sln.DotSettings deleted file mode 100644 index 6d439b8..0000000 --- a/Geekbot.net.sln.DotSettings +++ /dev/null @@ -1,12 +0,0 @@ - - NEVER - 200 - True - True - True - True - True - True - True - True - True \ No newline at end of file diff --git a/Geekbot.net/Commands/Admin/Admin.cs b/Geekbot.net/Commands/Admin/Admin.cs new file mode 100644 index 0000000..7d30689 --- /dev/null +++ b/Geekbot.net/Commands/Admin/Admin.cs @@ -0,0 +1,196 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Localization; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Admin +{ + [Group("admin")] + [RequireUserPermission(GuildPermission.Administrator)] + public class Admin : ModuleBase + { + private readonly DiscordSocketClient _client; + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly ITranslationHandler _translation; + + public Admin(IDatabase redis, DiscordSocketClient client, IErrorHandler errorHandler, + ITranslationHandler translationHandler) + { + _redis = redis; + _client = client; + _errorHandler = errorHandler; + _translation = translationHandler; + } + + [Command("welcome", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Set a Welcome Message (use '$user' to mention the new joined user).")] + public async Task SetWelcomeMessage([Remainder] [Summary("message")] string welcomeMessage) + { + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("WelcomeMsg", welcomeMessage)}); + var formatedMessage = welcomeMessage.Replace("$user", Context.User.Mention); + await ReplyAsync($"Welcome message has been changed\r\nHere is an example of how it would look:\r\n{formatedMessage}"); + } + + [Command("modchannel", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Set a channel for moderation purposes")] + public async Task SelectModChannel([Summary("#Channel")] ISocketMessageChannel channel) + { + try + { + var sb = new StringBuilder(); + sb.AppendLine("Successfully saved mod channel, you can now do the following"); + sb.AppendLine("- `!admin showleave true` - send message to mod channel when someone leaves"); + sb.AppendLine("- `!admin showdel true` - send message to mod channel when someone deletes a message"); + await channel.SendMessageAsync(sb.ToString()); + _redis.HashSet($"{Context.Guild.Id}:Settings", + new[] {new HashEntry("ModChannel", channel.Id.ToString())}); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to be valid"); + } + } + + [Command("showleave", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Notify modchannel when someone leaves")] + public async Task ShowLeave([Summary("true/false")] bool enabled) + { + var modChannelId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel")); + try + { + var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId); + if (enabled) + { + await modChannel.SendMessageAsync("Saved - now sending messages here when someone leaves"); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ShowLeave", true)}); + } + else + { + await modChannel.SendMessageAsync("Saved - stopping sending messages here when someone leaves"); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ShowLeave", false)}); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`"); + } + } + + [Command("showdel", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Notify modchannel when someone deletes a message")] + public async Task ShowDelete([Summary("true/false")] bool enabled) + { + var modChannelId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel")); + try + { + var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId); + if (enabled) + { + await modChannel.SendMessageAsync( + "Saved - now sending messages here when someone deletes a message"); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ShowDelete", true)}); + } + else + { + await modChannel.SendMessageAsync( + "Saved - stopping sending messages here when someone deletes a message"); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ShowDelete", false)}); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`"); + } + } + + [Command("setlang", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Change the bots language")] + public async Task SetLanguage([Summary("language")] string languageRaw) + { + try + { + var language = languageRaw.ToUpper(); + var success = _translation.SetLanguage(Context.Guild.Id, language); + if (success) + { + var trans = _translation.GetDict(Context); + await ReplyAsync(trans["NewLanguageSet"]); + return; + } + + await ReplyAsync( + $"That doesn't seem to be a supported language\r\nSupported Languages are {string.Join(", ", _translation.GetSupportedLanguages())}"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("wiki", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Change the wikipedia instance (use lang code in xx.wikipedia.org)")] + public async Task SetWikiLanguage([Summary("language")] string languageRaw) + { + try + { + var language = languageRaw.ToLower(); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("WikiLang", language) }); + + await ReplyAsync($"Now using the {language} wikipedia"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("lang", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Change the bots language")] + public async Task GetLanguage() + { + try + { + var trans = _translation.GetDict(Context); + await ReplyAsync(trans["GetLanguage"]); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("ping", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Enable the ping reply.")] + public async Task TogglePing() + { + try + { + bool.TryParse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ping"), out var current); + _redis.HashSet($"{Context.Guild.Id}:Settings", new[] {new HashEntry("ping", current ? "false" : "true") }); + await ReplyAsync(!current ? "i will reply to ping now" : "No more pongs..."); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Admin/Mod.cs b/Geekbot.net/Commands/Admin/Mod.cs new file mode 100644 index 0000000..7551a47 --- /dev/null +++ b/Geekbot.net/Commands/Admin/Mod.cs @@ -0,0 +1,90 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.UserRepository; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Admin +{ + [Group("mod")] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireUserPermission(GuildPermission.ManageRoles)] + public class Mod : ModuleBase + { + private readonly DiscordSocketClient _client; + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly IUserRepository _userRepository; + + public Mod(IUserRepository userRepositry, IErrorHandler errorHandler, IDatabase redis, + DiscordSocketClient client) + { + _userRepository = userRepositry; + _errorHandler = errorHandler; + _redis = redis; + _client = client; + } + + [Command("namehistory", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("See past usernames of an user")] + public async Task UsernameHistory([Summary("@user")] IUser user) + { + try + { + var userRepo = _userRepository.Get(user.Id); + var sb = new StringBuilder(); + sb.AppendLine($":bust_in_silhouette: {user.Username} has been known as:"); + foreach (var name in userRepo.UsedNames) sb.AppendLine($"- `{name}`"); + await ReplyAsync(sb.ToString()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + $"I don't have enough permissions do that"); + } + } + + [Command("kick", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Ban a user")] + public async Task Kick([Summary("@user")] IUser userNormal, + [Summary("reason")] [Remainder] string reason = "none") + { + try + { + var user = (IGuildUser) userNormal; + if (reason == "none") reason = "No reason provided"; + await user.GetOrCreateDMChannelAsync().Result.SendMessageAsync( + $"You have been kicked from {Context.Guild.Name} for the following reason: \"{reason}\""); + await user.KickAsync(); + try + { + var modChannelId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:Settings", "ModChannel")); + var modChannel = (ISocketMessageChannel) _client.GetChannel(modChannelId); + var eb = new EmbedBuilder(); + eb.Title = ":x: User Kicked"; + eb.AddInlineField("User", user.Username); + eb.AddInlineField("By Mod", Context.User.Username); + eb.AddField("Reason", reason); + await modChannel.SendMessageAsync("", false, eb.Build()); + } + catch + { + await ReplyAsync($"{user.Username} was kicked for the following reason: \"{reason}\""); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, "I don't have enough permissions to kick someone"); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Admin/Owner.cs b/Geekbot.net/Commands/Admin/Owner.cs new file mode 100644 index 0000000..2d097e0 --- /dev/null +++ b/Geekbot.net/Commands/Admin/Owner.cs @@ -0,0 +1,94 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Logger; +using Geekbot.net.Lib.UserRepository; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Admin +{ + [Group("owner")] + [RequireOwner] + public class Owner : ModuleBase + { + private readonly DiscordSocketClient _client; + private readonly IErrorHandler _errorHandler; + private readonly IGeekbotLogger _logger; + private readonly IDatabase _redis; + private readonly IUserRepository _userRepository; + + public Owner(IDatabase redis, DiscordSocketClient client, IGeekbotLogger logger, IUserRepository userRepositry, IErrorHandler errorHandler) + { + _redis = redis; + _client = client; + _logger = logger; + _userRepository = userRepositry; + _errorHandler = errorHandler; + } + + [Command("youtubekey", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Set the youtube api key")] + public async Task SetYoutubeKey([Summary("API Key")] string key) + { + _redis.StringSet("youtubeKey", key); + await ReplyAsync("Apikey has been set"); + } + + [Command("game", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Set the game that the bot is playing")] + public async Task SetGame([Remainder] [Summary("Game")] string key) + { + _redis.StringSet("Game", key); + await _client.SetGameAsync(key); + _logger.Information(LogSource.Geekbot, $"Changed game to {key}"); + await ReplyAsync($"Now Playing {key}"); + } + + [Command("popuserrepo", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Populate user cache")] + public async Task PopUserRepoCommand() + { + var success = 0; + var failed = 0; + try + { + _logger.Warning(LogSource.UserRepository, "Populating User Repositry"); + await ReplyAsync("Starting Population of User Repository"); + foreach (var guild in _client.Guilds) + { + _logger.Information(LogSource.UserRepository, $"Populating users from {guild.Name}"); + foreach (var user in guild.Users) + { + var succeded = await _userRepository.Update(user); + var inc = succeded ? success++ : failed++; + } + } + + _logger.Warning(LogSource.UserRepository, "Finished Updating User Repositry"); + await ReplyAsync( + $"Successfully Populated User Repository with {success} Users in {_client.Guilds.Count} Guilds (Failed: {failed})"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "Couldn't complete User Repository, see console for more info"); + } + } + + [Command("error", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Throw an error un purpose")] + public void PurposefulError() + { + var e = new Exception("Error Generated by !owner error"); + _errorHandler.HandleCommandException(e, Context); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Admin/Role.cs b/Geekbot.net/Commands/Admin/Role.cs new file mode 100644 index 0000000..24d19dd --- /dev/null +++ b/Geekbot.net/Commands/Admin/Role.cs @@ -0,0 +1,193 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.Net; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.ReactionListener; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Admin +{ + [Group("role")] + public class Role : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly IReactionListener _reactionListener; + + public Role(IErrorHandler errorHandler, IDatabase redis, IReactionListener reactionListener) + { + _errorHandler = errorHandler; + _redis = redis; + _reactionListener = reactionListener; + } + + [Command(RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Get a list of all available roles.")] + public async Task GetAllRoles() + { + try + { + var roles = _redis.HashGetAll($"{Context.Guild.Id}:RoleWhitelist"); + if (roles.Length == 0) + { + await ReplyAsync("There are no roles configured for this server"); + return; + } + + var sb = new StringBuilder(); + sb.AppendLine($"**Self Service Roles on {Context.Guild.Name}**"); + sb.AppendLine("To get a role, use `!role name`"); + foreach (var role in roles) sb.AppendLine($"- {role.Name}"); + await ReplyAsync(sb.ToString()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command(RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Get a role by mentioning it.")] + public async Task GiveRole([Summary("roleNickname")] string roleNameRaw) + { + try + { + var roleName = roleNameRaw.ToLower(); + if (_redis.HashExists($"{Context.Guild.Id}:RoleWhitelist", roleName)) + { + var guildUser = (IGuildUser) Context.User; + var roleId = ulong.Parse(_redis.HashGet($"{Context.Guild.Id}:RoleWhitelist", roleName)); + var role = Context.Guild.Roles.First(r => r.Id == roleId); + if (role == null) + { + await ReplyAsync("That role doesn't seem to exist"); + return; + } + + if (guildUser.RoleIds.Contains(roleId)) + { + await guildUser.RemoveRoleAsync(role); + await ReplyAsync($"Removed you from {role.Name}"); + return; + } + + await guildUser.AddRoleAsync(role); + await ReplyAsync($"Added you to {role.Name}"); + return; + } + + await ReplyAsync("That role doesn't seem to exist"); + } + catch (HttpException e) + { + _errorHandler.HandleHttpException(e, Context); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [RequireUserPermission(GuildPermission.ManageRoles)] + [Command("add", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Add a role to the whitelist.")] + public async Task AddRole([Summary("@role")] IRole role, [Summary("alias")] string roleName) + { + try + { + if (role.IsManaged) + { + await ReplyAsync("You can't add a role that is managed by discord"); + return; + } + + if (role.Permissions.ManageRoles + || role.Permissions.Administrator + || role.Permissions.ManageGuild + || role.Permissions.BanMembers + || role.Permissions.KickMembers) + { + await ReplyAsync( + "Woah, i don't think you want to add that role to self service as it contains some dangerous permissions"); + return; + } + + _redis.HashSet($"{Context.Guild.Id}:RoleWhitelist", + new[] {new HashEntry(roleName.ToLower(), role.Id.ToString())}); + await ReplyAsync($"Added {role.Name} to the whitelist"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [RequireUserPermission(GuildPermission.ManageRoles)] + [Command("remove", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Remove a role from the whitelist.")] + public async Task RemoveRole([Summary("roleNickname")] string roleName) + { + try + { + + var success = _redis.HashDelete($"{Context.Guild.Id}:RoleWhitelist", roleName.ToLower()); + if (success) + { + await ReplyAsync($"Removed {roleName} from the whitelist"); + return; + } + + await ReplyAsync("There is not whitelisted role with that name..."); + + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [RequireUserPermission(GuildPermission.ManageRoles)] + [Remarks(CommandCategories.Admin)] + [Summary("Give a role by clicking on an emoji")] + [Command("listen", RunMode = RunMode.Async)] + public async Task AddListener([Summary("messageID")] string messageId, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role) + { + try + { + var message = (IUserMessage) await Context.Channel.GetMessageAsync(ulong.Parse(messageId)); + IEmote emote; + if (!emoji.StartsWith('<')) + { + var emo = new Emoji(emoji); + emote = emo; + } + else + { + emote = Emote.Parse(emoji); + } + await message.AddReactionAsync(emote); + await _reactionListener.AddRoleToListener(messageId, emote, role); + await Context.Message.DeleteAsync(); + } + catch (HttpException e) + { + await Context.Channel.SendMessageAsync("Custom emojis from other servers are not supported"); + Console.WriteLine(e); + } + catch (Exception e) + { + await Context.Channel.SendMessageAsync("Something went wrong... please try again on a new message"); + Console.WriteLine(e); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Admin/Say.cs b/Geekbot.net/Commands/Admin/Say.cs new file mode 100644 index 0000000..97c7a0f --- /dev/null +++ b/Geekbot.net/Commands/Admin/Say.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; + +namespace Geekbot.net.Commands.Admin +{ + public class Say : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Say(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [RequireUserPermission(GuildPermission.Administrator)] + [Command("say", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Admin)] + [Summary("Say Something.")] + public async Task Echo([Remainder] [Summary("What?")] string echo) + { + try + { + await Context.Message.DeleteAsync(); + await ReplyAsync(echo); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Audio/Voice.cs b/Geekbot.net/Commands/Audio/Voice.cs new file mode 100644 index 0000000..410d8e2 --- /dev/null +++ b/Geekbot.net/Commands/Audio/Voice.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib.Audio; +using Geekbot.net.Lib.ErrorHandling; + +namespace Geekbot.net.Commands.Audio +{ + public class Voice : ModuleBase + { + private readonly IAudioUtils _audioUtils; + private readonly IErrorHandler _errorHandler; + + public Voice(IErrorHandler errorHandler, IAudioUtils audioUtils) + { + _errorHandler = errorHandler; + _audioUtils = audioUtils; + } + +// [Command("join")] + public async Task JoinChannel() + { + try + { + // Get the audio channel + var channel = (Context.User as IGuildUser)?.VoiceChannel; + if (channel == null) + { + await Context.Channel.SendMessageAsync("You must be in a voice channel."); + return; + } + + var audioClient = await channel.ConnectAsync(); + _audioUtils.StoreAudioClient(Context.Guild.Id, audioClient); + await ReplyAsync($"Connected to {channel.Name}"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + +// [Command("disconnect")] + public async Task DisconnectChannel() + { + try + { + var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id); + if (audioClient == null) + { + await Context.Channel.SendMessageAsync("I'm not in a voice channel at the moment"); + return; + } + + await audioClient.StopAsync(); + await ReplyAsync("Disconnected from channel!"); + _audioUtils.Cleanup(Context.Guild.Id); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + _audioUtils.Cleanup(Context.Guild.Id); + } + } + +// [Command("ytplay")] + public async Task ytplay(string url) + { + try + { + if (!url.Contains("youtube")) + { + await ReplyAsync("I can only play youtube videos"); + return; + } + var audioClient = _audioUtils.GetAudioClient(Context.Guild.Id); + if (audioClient == null) + { + await ReplyAsync("I'm not in a voice channel at the moment"); + return; + } + + var message = await Context.Channel.SendMessageAsync("Just a second, i'm still a bit slow at this"); + var ffmpeg = _audioUtils.CreateStreamFromYoutube(url, Context.Guild.Id); + var output = ffmpeg.StandardOutput.BaseStream; + await message.ModifyAsync(msg => msg.Content = "**Playing!** Please note that this feature is experimental"); + var discord = audioClient.CreatePCMStream(Discord.Audio.AudioApplication.Mixed); + await output.CopyToAsync(discord); + await discord.FlushAsync(); + _audioUtils.Cleanup(Context.Guild.Id); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + _audioUtils.Cleanup(Context.Guild.Id); + } + } + } + +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Games/BattleTag.cs b/Geekbot.net/Commands/Games/BattleTag.cs new file mode 100644 index 0000000..88cc0d8 --- /dev/null +++ b/Geekbot.net/Commands/Games/BattleTag.cs @@ -0,0 +1,72 @@ +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.UserRepository; + +namespace Geekbot.net.Commands.Games +{ + [Group("battletag")] + public class BattleTag : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IUserRepository _userRepository; + + public BattleTag(IErrorHandler errorHandler, IUserRepository userRepository) + { + _errorHandler = errorHandler; + _userRepository = userRepository; + } + + [Command(RunMode = RunMode.Async)] + [Remarks(CommandCategories.Games)] + [Summary("Get your battletag")] + public async Task BattleTagCmd() + { + try + { + var tag = _userRepository.GetUserSetting(Context.User.Id, "BattleTag"); + if (!string.IsNullOrEmpty(tag)) + await ReplyAsync($"Your BattleTag is {tag}"); + else + await ReplyAsync("You haven't set your BattleTag, set it with `!battletag user#1234`"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command(RunMode = RunMode.Async)] + [Remarks(CommandCategories.Games)] + [Summary("Save your battletag")] + public async Task BattleTagCmd([Summary("Battletag")] string tag) + { + try + { + if (IsValidTag(tag)) + { + _userRepository.SaveUserSetting(Context.User.Id, "BattleTag", tag); + await ReplyAsync("Saved!"); + } + else + { + await ReplyAsync("That doesn't seem to be a valid battletag"); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + public static bool IsValidTag(string tag) + { + var splited = tag.Split("#"); + if (splited.Length != 2) return false; + if (!int.TryParse(splited[1], out var discriminator)) return false; + return splited[1].Length == 4 || splited[1].Length == 5; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Games/Overwatch.cs b/Geekbot.net/Commands/Games/Overwatch.cs new file mode 100644 index 0000000..bda75b3 --- /dev/null +++ b/Geekbot.net/Commands/Games/Overwatch.cs @@ -0,0 +1,132 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.UserRepository; +using OverwatchAPI; +using OverwatchAPI.Config; + +namespace Geekbot.net.Commands.Games +{ + [Group("ow")] + public class Overwatch : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IUserRepository _userRepository; + + public Overwatch(IErrorHandler errorHandler, IUserRepository userRepository) + { + _errorHandler = errorHandler; + _userRepository = userRepository; + } + + [Command("profile", RunMode = RunMode.Async)] + [Summary("Get someones overwatch profile. EU on PC only. Default battletag is your own (if set).")] + [Remarks(CommandCategories.Games)] + public async Task OwProfile() + { + try + { + var tag = _userRepository.GetUserSetting(Context.User.Id, "BattleTag"); + if (string.IsNullOrEmpty(tag)) + { + await ReplyAsync("You have no battle Tag saved, use `!battletag`"); + return; + } + + var profile = await CreateProfile(tag); + if (profile == null) + { + await ReplyAsync("That player doesn't seem to exist"); + return; + } + + await ReplyAsync("", false, profile.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("profile", RunMode = RunMode.Async)] + [Summary("Get someones overwatch profile. EU on PC only. Default battletag is your own (if set).")] + [Remarks(CommandCategories.Games)] + public async Task OwProfile([Summary("BattleTag")] string tag) + { + try + { + if (!BattleTag.IsValidTag(tag)) + { + await ReplyAsync("That doesn't seem to be a valid battletag..."); + return; + } + + var profile = await CreateProfile(tag); + if (profile == null) + { + await ReplyAsync("That player doesn't seem to exist"); + return; + } + + await ReplyAsync("", false, profile.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("profile", RunMode = RunMode.Async)] + [Summary("Get someones overwatch profile. EU on PC only.")] + [Remarks(CommandCategories.Games)] + public async Task OwProfile([Summary("@someone")] IUser user) + { + try + { + var tag = _userRepository.GetUserSetting(user.Id, "BattleTag"); + if (string.IsNullOrEmpty(tag)) + { + await ReplyAsync("This user didn't set a battletag"); + return; + } + + var profile = await CreateProfile(tag); + if (profile == null) + { + await ReplyAsync("That player doesn't seem to exist"); + return; + } + + await ReplyAsync("", false, profile.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private async Task CreateProfile(string battletag) + { + var owConfig = new OverwatchConfig.Builder().WithPlatforms(Platform.Pc); + using (var owClient = new OverwatchClient(owConfig)) + { + var player = await owClient.GetPlayerAsync(battletag); + if (player.Username == null) return null; + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(player.ProfilePortraitUrl) + .WithName(player.Username)); + eb.Url = player.ProfileUrl; + eb.AddInlineField("Level", player.PlayerLevel); + eb.AddInlineField("Current Rank", + player.CompetitiveRank > 0 ? player.CompetitiveRank.ToString() : "Unranked"); + + return eb; + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Games/Pokedex.cs b/Geekbot.net/Commands/Games/Pokedex.cs similarity index 84% rename from src/Bot/Commands/Games/Pokedex.cs rename to Geekbot.net/Commands/Games/Pokedex.cs index 325ee8c..780c564 100644 --- a/src/Bot/Commands/Games/Pokedex.cs +++ b/Geekbot.net/Commands/Games/Pokedex.cs @@ -3,14 +3,14 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; using PokeAPI; -namespace Geekbot.Bot.Commands.Games +namespace Geekbot.net.Commands.Games { - public class Pokedex : TransactionModuleBase + public class Pokedex : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -20,8 +20,9 @@ namespace Geekbot.Bot.Commands.Games } [Command("pokedex", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("A Pokedex Tool")] - public async Task GetPokemon([Summary("pokemon-name")] string pokemonName) + public async Task GetPokemon([Summary("pokemonName")] string pokemonName) { try { @@ -42,7 +43,7 @@ namespace Geekbot.Bot.Commands.Games } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } diff --git a/Geekbot.net/Commands/Games/Roll.cs b/Geekbot.net/Commands/Games/Roll.cs new file mode 100644 index 0000000..e8a89c0 --- /dev/null +++ b/Geekbot.net/Commands/Games/Roll.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Localization; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Games +{ + public class Roll : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly ITranslationHandler _translation; + + public Roll(IDatabase redis, IErrorHandler errorHandler, ITranslationHandler translation) + { + _redis = redis; + _translation = translation; + _errorHandler = errorHandler; + } + + [Command("roll", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Fun)] + [Summary("Guess which number the bot will roll (1-100")] + public async Task RollCommand([Remainder] [Summary("guess")] string stuff = "noGuess") + { + try + { + var number = new Random().Next(1, 100); + var guess = 1000; + int.TryParse(stuff, out guess); + var transDict = _translation.GetDict(Context); + if (guess <= 100 && guess > 0) + { + var prevRoll = _redis.HashGet($"{Context.Guild.Id}:RollsPrevious2", Context.Message.Author.Id).ToString()?.Split('|'); + if (prevRoll?.Length == 2) + { + if (prevRoll[0] == guess.ToString() && DateTime.Parse(prevRoll[1]) > DateTime.Now.AddDays(-1)) + { + await ReplyAsync(string.Format(transDict["NoPrevGuess"], Context.Message.Author.Mention)); + return; + } + } + + _redis.HashSet($"{Context.Guild.Id}:RollsPrevious2", + new[] {new HashEntry(Context.Message.Author.Id, $"{guess}|{DateTime.Now}")}); + await ReplyAsync(string.Format(transDict["Rolled"], Context.Message.Author.Mention, number, guess)); + if (guess == number) + { + await ReplyAsync(string.Format(transDict["Gratz"], Context.Message.Author)); + _redis.HashIncrement($"{Context.Guild.Id}:Rolls", Context.User.Id.ToString()); + } + } + else + { + await ReplyAsync(string.Format(transDict["RolledNoGuess"], Context.Message.Author.Mention, number)); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/Google.cs b/Geekbot.net/Commands/Integrations/Google/Google.cs new file mode 100644 index 0000000..7bd3a56 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/Google.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Integrations.Google +{ + public class Google : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + + public Google(IErrorHandler errorHandler, IDatabase redis) + { + _errorHandler = errorHandler; + _redis = redis; + } + + [Command("google", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Google Something.")] + public async Task AskGoogle([Remainder, Summary("SearchText")] string searchText) + { + try + { + using (var client = new WebClient()) + { + var apiKey = _redis.StringGet("googleGraphKey"); + if (!apiKey.HasValue) + { + await ReplyAsync("No Google API key has been set, please contact my owner"); + return; + } + + var url = new Uri($"https://kgsearch.googleapis.com/v1/entities:search?languages=en&limit=1&query={searchText}&key={apiKey}"); + var responseString = client.DownloadString(url); + var response = JsonConvert.DeserializeObject(responseString); + + if (!response.ItemListElement.Any()) + { + await ReplyAsync("No results were found..."); + return; + } + + var data = response.ItemListElement.First().Result; + var eb = new EmbedBuilder(); + eb.Title = data.Name; + if(!string.IsNullOrEmpty(data.Description)) eb.WithDescription(data.Description); + if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.Url)) eb.WithUrl(data.DetailedDtoDescription.Url); + if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.ArticleBody)) eb.AddField("Details", data.DetailedDtoDescription.ArticleBody); + if(!string.IsNullOrEmpty(data.Image?.ContentUrl)) eb.WithThumbnailUrl(data.Image.ContentUrl); + + await ReplyAsync("", false, eb.Build()); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiDetailedDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiDetailedDto.cs new file mode 100644 index 0000000..031d1e7 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiDetailedDto.cs @@ -0,0 +1,9 @@ +namespace Geekbot.net.Commands.Integrations.Google +{ + public class GoogleKgApiDetailedDto + { + public string ArticleBody { get; set; } + public string Url { get; set; } + public string License { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs new file mode 100644 index 0000000..a48b184 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiElementDto.cs @@ -0,0 +1,8 @@ +namespace Geekbot.net.Commands.Integrations.Google +{ + public class GoogleKgApiElementDto + { + public GoogleKgApiResultDto Result { get; set; } + public double ResultScore { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiImageDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiImageDto.cs new file mode 100644 index 0000000..fe7cdaa --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiImageDto.cs @@ -0,0 +1,8 @@ +namespace Geekbot.net.Commands.Integrations.Google +{ + public class GoogleKgApiImageDto + { + public string ContentUrl { get; set; } + public string Url { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResponseDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResponseDto.cs new file mode 100644 index 0000000..af337db --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResponseDto.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Geekbot.net.Commands.Integrations.Google +{ + public class GoogleKgApiResponseDto + { + public List ItemListElement { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs new file mode 100644 index 0000000..465f1d7 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Google/GoogleKgApiResultDto.cs @@ -0,0 +1,10 @@ +namespace Geekbot.net.Commands.Integrations.Google +{ + public class GoogleKgApiResultDto + { + public string Name { get; set; } + public string Description { get; set; } + public GoogleKgApiImageDto Image { get; set; } + public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/MagicTheGathering.cs b/Geekbot.net/Commands/Integrations/MagicTheGathering.cs new file mode 100644 index 0000000..8ecefd2 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/MagicTheGathering.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Converters; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using MtgApiManager.Lib.Service; + +namespace Geekbot.net.Commands.Integrations +{ + public class Magicthegathering : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IMtgManaConverter _manaConverter; + + public Magicthegathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter) + { + _errorHandler = errorHandler; + _manaConverter = manaConverter; + } + + [Command("mtg", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Games)] + [Summary("Find a Magic The Gathering Card.")] + public async Task GetCard([Remainder] [Summary("name")] string cardName) + { + try + { + var service = new CardService(); + var result = service.Where(x => x.Name, cardName); + + var card = result.All().Value.FirstOrDefault(); + if (card == null) + { + await ReplyAsync("I couldn't find that card..."); + return; + } + + var eb = new EmbedBuilder(); + eb.Title = card.Name; + eb.Description = card.Type; + + if (card.Colors != null) eb.WithColor(GetColor(card.Colors)); + + if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString(); + + if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", _manaConverter.ConvertMana(card.Text)); + + if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor); + if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName); + if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power); + if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty); + if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness); + + if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", _manaConverter.ConvertMana(card.ManaCost)); + if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity); + + if (card.Legalities != null) + eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format))); + + await ReplyAsync("", false, eb.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private Color GetColor(IEnumerable colors) + { + var color = colors.FirstOrDefault(); + switch (color) + { + case "Black": + return new Color(203, 194, 191); + case "White": + return new Color(255, 251, 213); + case "Blue": + return new Color(170, 224, 250); + case "Red": + return new Color(250, 170, 143); + case "Green": + return new Color(155, 211, 174); + default: + return new Color(204, 194, 212); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/Mal.cs b/Geekbot.net/Commands/Integrations/Mal.cs new file mode 100644 index 0000000..eee5782 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Mal.cs @@ -0,0 +1,122 @@ +using System; +using System.Threading.Tasks; +using System.Web; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Clients; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; + +namespace Geekbot.net.Commands.Integrations +{ + public class Mal : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IMalClient _malClient; + + public Mal(IMalClient malClient, IErrorHandler errorHandler) + { + _malClient = malClient; + _errorHandler = errorHandler; + } + + [Command("anime", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Show Info about an Anime.")] + public async Task SearchAnime([Remainder] [Summary("AnimeName")] string animeName) + { + try + { + if (_malClient.IsLoggedIn()) + { + var anime = await _malClient.GetAnime(animeName); + if (anime != null) + { + var eb = new EmbedBuilder(); + + var description = HttpUtility.HtmlDecode(anime.Synopsis) + .Replace("
", "") + .Replace("[i]", "*") + .Replace("[/i]", "*"); + + eb.Title = anime.Title; + eb.Description = description; + eb.ImageUrl = anime.Image; + eb.AddInlineField("Premiered", $"{anime.StartDate}"); + eb.AddInlineField("Ended", anime.EndDate == "0000-00-00" ? "???" : anime.EndDate); + eb.AddInlineField("Status", anime.Status); + eb.AddInlineField("Episodes", anime.Episodes); + eb.AddInlineField("MAL Score", anime.Score); + eb.AddInlineField("Type", anime.Type); + eb.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.Id}"); + + await ReplyAsync("", false, eb.Build()); + } + else + { + await ReplyAsync("No anime found with that name..."); + } + } + else + { + await ReplyAsync( + "Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me"); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("manga", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Show Info about a Manga.")] + public async Task SearchManga([Remainder] [Summary("MangaName")] string mangaName) + { + try + { + if (_malClient.IsLoggedIn()) + { + var manga = await _malClient.GetManga(mangaName); + if (manga != null) + { + var eb = new EmbedBuilder(); + + var description = HttpUtility.HtmlDecode(manga.Synopsis) + .Replace("
", "") + .Replace("[i]", "*") + .Replace("[/i]", "*"); + + eb.Title = manga.Title; + eb.Description = description; + eb.ImageUrl = manga.Image; + eb.AddInlineField("Premiered", $"{manga.StartDate}"); + eb.AddInlineField("Ended", manga.EndDate == "0000-00-00" ? "???" : manga.EndDate); + eb.AddInlineField("Status", manga.Status); + eb.AddInlineField("Volumes", manga.Volumes); + eb.AddInlineField("Chapters", manga.Chapters); + eb.AddInlineField("MAL Score", manga.Score); + eb.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.Id}"); + + await ReplyAsync("", false, eb.Build()); + } + else + { + await ReplyAsync("No manga found with that name..."); + } + } + else + { + await ReplyAsync( + "Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me"); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs new file mode 100644 index 0000000..e98885b --- /dev/null +++ b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictListItemDto.cs @@ -0,0 +1,12 @@ +namespace Geekbot.net.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/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs new file mode 100644 index 0000000..2c3e014 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictResponseDto.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Geekbot.net.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/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictionary.cs b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictionary.cs new file mode 100644 index 0000000..9d99885 --- /dev/null +++ b/Geekbot.net/Commands/Integrations/UbranDictionary/UrbanDictionary.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Integrations.UbranDictionary +{ + public class UrbanDictionary : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public UrbanDictionary(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("urban", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Lookup something on urban dictionary")] + public async Task UrbanDefine([Remainder] [Summary("word")] string word) + { + try + { + using (var client = new HttpClient()) + { + client.BaseAddress = new Uri("https://api.urbandictionary.com"); + var response = await client.GetAsync($"/v0/define?term={word}"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var definitions = JsonConvert.DeserializeObject(stringResponse); + 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)); + if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = definition.Definition; + if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", definition.Example ?? "(no example given...)"); + 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) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/Wikipedia.cs b/Geekbot.net/Commands/Integrations/Wikipedia.cs similarity index 82% rename from src/Bot/Commands/Integrations/Wikipedia.cs rename to Geekbot.net/Commands/Integrations/Wikipedia.cs index 82f42a0..68589f6 100644 --- a/src/Bot/Commands/Integrations/Wikipedia.cs +++ b/Geekbot.net/Commands/Integrations/Wikipedia.cs @@ -5,36 +5,36 @@ 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; -using Geekbot.Core.WikipediaClient; -using Geekbot.Core.WikipediaClient.Page; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; using HtmlAgilityPack; +using StackExchange.Redis; +using WikipediaApi; +using WikipediaApi.Page; -namespace Geekbot.Bot.Commands.Integrations +namespace Geekbot.net.Commands.Integrations { - public class Wikipedia : TransactionModuleBase + public class Wikipedia : ModuleBase { private readonly IErrorHandler _errorHandler; private readonly IWikipediaClient _wikipediaClient; - private readonly DatabaseContext _database; + private readonly IDatabase _redis; - public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, DatabaseContext database) + public Wikipedia(IErrorHandler errorHandler, IWikipediaClient wikipediaClient, IDatabase redis) { _errorHandler = errorHandler; _wikipediaClient = wikipediaClient; - _database = database; + _redis = redis; } [Command("wiki", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("Get an article from wikipedia.")] - public async Task GetPreview([Remainder] [Summary("article")] string articleName) + public async Task GetPreview([Remainder] [Summary("Article")] string articleName) { try { - var wikiLang = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(Context.Guild.Id.AsLong()))?.WikiLang; + var wikiLang = _redis.HashGet($"{Context.Guild.Id}:Settings", "WikiLang").ToString(); if (string.IsNullOrEmpty(wikiLang)) { wikiLang = "en"; @@ -88,7 +88,7 @@ namespace Geekbot.Bot.Commands.Integrations } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } diff --git a/Geekbot.net/Commands/Integrations/Youtube.cs b/Geekbot.net/Commands/Integrations/Youtube.cs new file mode 100644 index 0000000..f534bcd --- /dev/null +++ b/Geekbot.net/Commands/Integrations/Youtube.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Google.Apis.Services; +using Google.Apis.YouTube.v3; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Integrations +{ + public class Youtube : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + + public Youtube(IDatabase redis, IErrorHandler errorHandler) + { + _redis = redis; + _errorHandler = errorHandler; + } + + [Command("yt", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Search for something on youtube.")] + public async Task Yt([Remainder] [Summary("Title")] string searchQuery) + { + var key = _redis.StringGet("youtubeKey"); + if (key.IsNullOrEmpty) + { + await ReplyAsync("No youtube key set, please tell my senpai to set one"); + return; + } + + try + { + var youtubeService = new YouTubeService(new BaseClientService.Initializer + { + ApiKey = key.ToString(), + 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) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Cat/Cat.cs b/Geekbot.net/Commands/Randomness/Cat/Cat.cs new file mode 100644 index 0000000..88a9ce5 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Cat/Cat.cs @@ -0,0 +1,54 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Randomness.Cat +{ + public class Cat : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Cat(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("cat", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("Return a random image of a cat.")] + public async Task Say() + { + try + { + using (var client = new HttpClient()) + { + try + { + client.BaseAddress = new Uri("https://aws.random.cat"); + var response = await client.GetAsync("/meow"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var catFile = JsonConvert.DeserializeObject(stringResponse); + var eb = new EmbedBuilder(); + eb.ImageUrl = catFile.File; + await ReplyAsync("", false, eb.Build()); + } + catch + { + await ReplyAsync("Seems like the dog cought the cat (error occured)"); + } + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Cat/CatResponseDto.cs b/Geekbot.net/Commands/Randomness/Cat/CatResponseDto.cs new file mode 100644 index 0000000..05ebf2b --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Cat/CatResponseDto.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Commands.Randomness.Cat +{ + internal class CatResponseDto + { + public string File { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/CheckEm.cs b/Geekbot.net/Commands/Randomness/CheckEm.cs new file mode 100644 index 0000000..fc962cc --- /dev/null +++ b/Geekbot.net/Commands/Randomness/CheckEm.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Media; + +namespace Geekbot.net.Commands.Randomness +{ + public class CheckEm : ModuleBase + { + private readonly IMediaProvider _checkEmImages; + private readonly IErrorHandler _errorHandler; + + public CheckEm(IMediaProvider mediaProvider, IErrorHandler errorHandler) + { + _checkEmImages = mediaProvider; + _errorHandler = errorHandler; + } + + [Command("checkem", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("Check for dubs")] + public async Task MuhDubs() + { + try + { + var number = new Random().Next(10000000, 99999999); + var dubtriqua = ""; + + var ns = GetIntArray(number); + if (ns[7] == ns[6]) + { + dubtriqua = "DUBS"; + if (ns[6] == ns[5]) + { + dubtriqua = "TRIPS"; + if (ns[5] == ns[4]) + dubtriqua = "QUADS"; + } + } + + var sb = new StringBuilder(); + sb.AppendLine($"Check em {Context.User.Mention}"); + sb.AppendLine($"**{number}**"); + if (!string.IsNullOrEmpty(dubtriqua)) + sb.AppendLine($":tada: {dubtriqua} :tada:"); + sb.AppendLine(_checkEmImages.GetCheckem()); + + await ReplyAsync(sb.ToString()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private int[] GetIntArray(int num) + { + var listOfInts = new List(); + while (num > 0) + { + listOfInts.Add(num % 10); + num = num / 10; + } + + listOfInts.Reverse(); + return listOfInts.ToArray(); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs b/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs new file mode 100644 index 0000000..8d513b8 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Commands.Randomness.Chuck +{ + internal class ChuckNorrisJokeResponseDto + { + public string Value { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokes.cs b/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokes.cs new file mode 100644 index 0000000..6ff2255 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Chuck/ChuckNorrisJokes.cs @@ -0,0 +1,53 @@ +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Randomness.Chuck +{ + public class ChuckNorrisJokes : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public ChuckNorrisJokes(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("chuck", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("A random chuck norris joke")] + public async Task Say() + { + try + { + using (var client = new HttpClient()) + { + try + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); + var response = await client.GetAsync("https://api.chucknorris.io/jokes/random"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var data = JsonConvert.DeserializeObject(stringResponse); + await ReplyAsync(data.Value); + } + catch (HttpRequestException) + { + await ReplyAsync("Api down..."); + } + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Dad/DadJokeResponseDto.cs b/Geekbot.net/Commands/Randomness/Dad/DadJokeResponseDto.cs new file mode 100644 index 0000000..262eee9 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Dad/DadJokeResponseDto.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Commands.Randomness.Dad +{ + internal class DadJokeResponseDto + { + public string Joke { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Dad/DadJokes.cs b/Geekbot.net/Commands/Randomness/Dad/DadJokes.cs new file mode 100644 index 0000000..e35798c --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Dad/DadJokes.cs @@ -0,0 +1,53 @@ +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Randomness.Dad +{ + public class DadJokes : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public DadJokes(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("dad", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("A random dad joke")] + public async Task Say() + { + try + { + using (var client = new HttpClient()) + { + try + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json")); + var response = await client.GetAsync("https://icanhazdadjoke.com/"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var data = JsonConvert.DeserializeObject(stringResponse); + await ReplyAsync(data.Joke); + } + catch (HttpRequestException) + { + await ReplyAsync("Api down..."); + } + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Dog/Dog.cs b/Geekbot.net/Commands/Randomness/Dog/Dog.cs new file mode 100644 index 0000000..08c1a9b --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Dog/Dog.cs @@ -0,0 +1,54 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Randomness.Dog +{ + public class Dog : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Dog(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("dog", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("Return a random image of a dog.")] + public async Task Say() + { + try + { + using (var client = new HttpClient()) + { + try + { + client.BaseAddress = new Uri("http://random.dog"); + var response = await client.GetAsync("/woof.json"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var dogFile = JsonConvert.DeserializeObject(stringResponse); + var eb = new EmbedBuilder(); + eb.ImageUrl = dogFile.Url; + await ReplyAsync("", false, eb.Build()); + } + catch (HttpRequestException e) + { + await ReplyAsync($"Seems like the dog got lost (error occured)\r\n{e.Message}"); + } + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Dog/DogResponseDto.cs b/Geekbot.net/Commands/Randomness/Dog/DogResponseDto.cs new file mode 100644 index 0000000..1fc1a82 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Dog/DogResponseDto.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Commands.Randomness.Dog +{ + internal class DogResponseDto + { + public string Url { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/EightBall.cs b/Geekbot.net/Commands/Randomness/EightBall.cs new file mode 100644 index 0000000..79ba6d1 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/EightBall.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; + +namespace Geekbot.net.Commands.Randomness +{ + public class EightBall : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public EightBall(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("8ball", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("Ask 8Ball a Question.")] + public async Task Ball([Remainder] [Summary("Question")] string echo) + { + try + { + var replies = new List + { + "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) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Fortune.cs b/Geekbot.net/Commands/Randomness/Fortune.cs similarity index 68% rename from src/Bot/Commands/Randomness/Fortune.cs rename to Geekbot.net/Commands/Randomness/Fortune.cs index 1157603..abc9ce5 100644 --- a/src/Bot/Commands/Randomness/Fortune.cs +++ b/Geekbot.net/Commands/Randomness/Fortune.cs @@ -1,11 +1,11 @@ using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.Media; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Media; -namespace Geekbot.Bot.Commands.Randomness +namespace Geekbot.net.Commands.Randomness { - public class Fortune : TransactionModuleBase + public class Fortune : ModuleBase { private readonly IFortunesProvider _fortunes; @@ -15,6 +15,7 @@ namespace Geekbot.Bot.Commands.Randomness } [Command("fortune", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random fortune")] public async Task GetAFortune() { diff --git a/Geekbot.net/Commands/Randomness/Gdq.cs b/Geekbot.net/Commands/Randomness/Gdq.cs new file mode 100644 index 0000000..3e17451 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Gdq.cs @@ -0,0 +1,40 @@ +using System; +using System.Net; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; + +namespace Geekbot.net.Commands.Randomness +{ + public class Gdq : ModuleBase + { + private readonly IErrorHandler _errorHandler; + + public Gdq(IErrorHandler errorHandler) + { + _errorHandler = errorHandler; + } + + [Command("gdq", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Games)] + [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) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/RandomAnimals.cs b/Geekbot.net/Commands/Randomness/RandomAnimals.cs similarity index 52% rename from src/Bot/Commands/Randomness/RandomAnimals.cs rename to Geekbot.net/Commands/Randomness/RandomAnimals.cs index 5493485..0e3b81d 100644 --- a/src/Bot/Commands/Randomness/RandomAnimals.cs +++ b/Geekbot.net/Commands/Randomness/RandomAnimals.cs @@ -1,12 +1,12 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.Media; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Media; -namespace Geekbot.Bot.Commands.Randomness +namespace Geekbot.net.Commands.Randomness { - public class RandomAnimals : TransactionModuleBase + public class RandomAnimals : ModuleBase { private readonly IMediaProvider _mediaProvider; @@ -16,64 +16,64 @@ namespace Geekbot.Bot.Commands.Randomness } [Command("panda", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random panda image")] public async Task Panda() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Panda))); + await ReplyAsync("", false, Eb(_mediaProvider.GetPanda())); } [Command("croissant", RunMode = RunMode.Async)] [Alias("gipfeli")] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random croissant image")] public async Task Croissant() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Croissant))); + await ReplyAsync("", false, Eb(_mediaProvider.GetCrossant())); } [Command("pumpkin", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random pumpkin image")] public async Task Pumpkin() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Pumpkin))); + await ReplyAsync("", false, Eb(_mediaProvider.GetPumpkin())); } [Command("squirrel", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random squirrel image")] public async Task Squirrel() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Squirrel))); + await ReplyAsync("", false, Eb(_mediaProvider.GetSquirrel())); } [Command("turtle", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random turtle image")] public async Task Turtle() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Turtle))); + await ReplyAsync("", false, Eb(_mediaProvider.GetTurtle())); } - [Command("penguin", RunMode = RunMode.Async)] - [Alias("pengu")] - [Summary("Get a random penguin image")] - public async Task Penguin() + [Command("pinguin", RunMode = RunMode.Async)] + [Alias("pingu")] + [Remarks(CommandCategories.Randomness)] + [Summary("Get a random pinguin image")] + public async Task Pinguin() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Penguin))); + await ReplyAsync("", false, Eb(_mediaProvider.GetPinguin())); } [Command("fox", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] [Summary("Get a random fox image")] public async Task Fox() { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Fox))); - } - - [Command("dab", RunMode = RunMode.Async)] - [Summary("Get a random dab image")] - public async Task Dab() - { - await ReplyAsync("", false, Eb(_mediaProvider.GetMedia(MediaType.Dab))); + await ReplyAsync("", false, Eb(_mediaProvider.GetFox())); } - private static Embed Eb(string image) + private Embed Eb(string image) { return new EmbedBuilder {ImageUrl = image}.Build(); } diff --git a/Geekbot.net/Commands/Randomness/Ship.cs b/Geekbot.net/Commands/Randomness/Ship.cs new file mode 100644 index 0000000..ffa18b4 --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Ship.cs @@ -0,0 +1,91 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Randomness +{ + public class Ship : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + + public Ship(IDatabase redis, IErrorHandler errorHandler) + { + _redis = redis; + _errorHandler = errorHandler; + } + + [Command("Ship", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Fun)] + [Summary("Ask the Shipping meter")] + public async Task Command([Summary("@User1")] IUser user1, [Summary("@User2")] IUser user2) + { + try + { + var dbstring = ""; + if (user1.Id > user2.Id) + dbstring = $"{user1.Id}-{user2.Id}"; + else + dbstring = $"{user2.Id}-{user1.Id}"; + + var dbval = _redis.HashGet($"{Context.Guild.Id}:Ships", dbstring); + var shippingRate = 0; + if (dbval.IsNullOrEmpty) + { + shippingRate = new Random().Next(1, 100); + _redis.HashSet($"{Context.Guild.Id}:Ships", dbstring, shippingRate); + } + else + { + shippingRate = int.Parse(dbval.ToString()); + } + + var reply = ":heartpulse: **Matchmaking** :heartpulse:\r\n"; + reply = reply + $":two_hearts: {user1.Mention} :heart: {user2.Mention} :two_hearts:\r\n"; + reply = reply + $"0% [{BlockCounter(shippingRate)}] 100% - {DeterminateSuccess(shippingRate)}"; + await ReplyAsync(reply); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private string DeterminateSuccess(int rate) + { + if (rate < 20) + return "Not gonna happen"; + if (rate >= 20 && rate < 40) + return "Not such a good idea"; + if (rate >= 40 && rate < 60) + return "There might be a chance"; + if (rate >= 60 && rate < 80) + return "Almost a match, but could work"; + return rate >= 80 ? "It's a match" : "a"; + } + + private string BlockCounter(int rate) + { + var amount = Math.Floor(decimal.Floor(rate / 10)); + Console.WriteLine(amount); + var blocks = ""; + for (var i = 1; i <= 10; i++) + if (i <= amount) + { + blocks = blocks + ":white_medium_small_square:"; + if (i == amount) + blocks = blocks + $" {rate}% "; + } + else + { + blocks = blocks + ":black_medium_small_square:"; + } + + return blocks; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Randomness/Slap.cs b/Geekbot.net/Commands/Randomness/Slap.cs new file mode 100644 index 0000000..129e89d --- /dev/null +++ b/Geekbot.net/Commands/Randomness/Slap.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Randomness +{ + public class Slap : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + + public Slap(IErrorHandler errorHandler, IDatabase redis) + { + _errorHandler = errorHandler; + _redis = redis; + } + + [Command("slap", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Fun)] + [Summary("slap someone")] + public async Task Slapper([Summary("@user")] IUser user) + { + try + { + if (user.Id == Context.User.Id) + { + await ReplyAsync("Why would you slap yourself?"); + return; + } + + var things = new List + { + "thing", + "rubber chicken", + "leek stick", + "large trout", + "flat hand", + "strip of bacon", + "feather", + "piece of pizza", + "moldy banana", + "sharp retort", + "printed version of wikipedia", + "panda paw", + "spiked sledgehammer", + "monstertruck", + "dirty toilet brush", + "sleeping seagull", + "sunflower", + "mousepad", + "lolipop", + "bottle of rum", + "cheese slice", + "critical 1", + "natural 20", + "mjölnir (aka mewmew)", + "kamehameha", + "copy of Twilight", + "med pack (get ready for the end boss)", + "derp", + "condom (used)", + "gremlin fed after midnight", + "wet baguette", + "exploding kitten", + "shiny piece of shit", + "mismatched pair of socks", + "horcrux", + "tuna", + "suggestion", + "teapot", + "candle", + "dictionary", + "powerless banhammer" + }; + + _redis.HashIncrement($"{Context.Guild.Id}:SlapsRecieved", user.Id.ToString()); + _redis.HashIncrement($"{Context.Guild.Id}:SlapsGiven", Context.User.Id.ToString()); + + await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[new Random().Next(things.Count - 1)]}"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/User/GuildInfo.cs b/Geekbot.net/Commands/User/GuildInfo.cs similarity index 59% rename from src/Bot/Commands/User/GuildInfo.cs rename to Geekbot.net/Commands/User/GuildInfo.cs index c063d89..18618d7 100644 --- a/src/Bot/Commands/User/GuildInfo.cs +++ b/Geekbot.net/Commands/User/GuildInfo.cs @@ -3,31 +3,30 @@ using System.Linq; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; -using Geekbot.Core.Levels; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.Levels; +using StackExchange.Redis; -namespace Geekbot.Bot.Commands.User +namespace Geekbot.net.Commands.User { - public class GuildInfo : TransactionModuleBase + public class GuildInfo : ModuleBase { private readonly IErrorHandler _errorHandler; - private readonly DatabaseContext _database; private readonly ILevelCalc _levelCalc; + private readonly IDatabase _redis; - public GuildInfo(DatabaseContext database, ILevelCalc levelCalc, IErrorHandler errorHandler) + public GuildInfo(IDatabase redis, ILevelCalc levelCalc, IErrorHandler errorHandler) { - _database = database; + _redis = redis; _levelCalc = levelCalc; _errorHandler = errorHandler; } [Command("serverstats", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Statistics)] [Summary("Show some info about the bot.")] - [DisableInDirectMessage] public async Task GetInfo() { try @@ -41,10 +40,8 @@ namespace Geekbot.Bot.Commands.User var created = Context.Guild.CreatedAt; var age = Math.Floor((DateTime.Now - created).TotalDays); - var messages = _database.Messages - .Where(e => e.GuildId == Context.Guild.Id.AsLong()) - .Sum(e => e.MessageCount); - var level = _levelCalc.GetLevel(messages); + var messages = _redis.HashGet($"{Context.Guild.Id}:Messages", 0.ToString()); + var level = _levelCalc.GetLevel((int) messages); eb.AddField("Server Age", $"{created.Day}/{created.Month}/{created.Year} ({age} days)"); eb.AddInlineField("Level", level) @@ -54,7 +51,7 @@ namespace Geekbot.Bot.Commands.User } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } } diff --git a/Geekbot.net/Commands/User/Karma.cs b/Geekbot.net/Commands/User/Karma.cs new file mode 100644 index 0000000..6290dc4 --- /dev/null +++ b/Geekbot.net/Commands/User/Karma.cs @@ -0,0 +1,130 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.Localization; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.User +{ + public class Karma : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly ITranslationHandler _translation; + + public Karma(IDatabase redis, IErrorHandler errorHandler, ITranslationHandler translation) + { + _redis = redis; + _errorHandler = errorHandler; + _translation = translation; + } + + [Command("good", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Karma)] + [Summary("Increase Someones Karma")] + public async Task Good([Summary("@someone")] IUser user) + { + try + { + var transDict = _translation.GetDict(Context); + var lastKarmaFromRedis = _redis.HashGet($"{Context.Guild.Id}:KarmaTimeout", Context.User.Id.ToString()); + var lastKarma = ConvertToDateTimeOffset(lastKarmaFromRedis.ToString()); + if (user.Id == Context.User.Id) + { + await ReplyAsync(string.Format(transDict["CannotChangeOwn"], Context.User.Username)); + } + else if (TimeoutFinished(lastKarma)) + { + await ReplyAsync(string.Format(transDict["WaitUntill"], Context.User.Username, + GetTimeLeft(lastKarma))); + } + else + { + var newKarma = _redis.HashIncrement($"{Context.Guild.Id}:Karma", user.Id.ToString()); + _redis.HashSet($"{Context.Guild.Id}:KarmaTimeout", + new[] {new HashEntry(Context.User.Id.ToString(), DateTimeOffset.Now.ToString("u"))}); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(user.GetAvatarUrl()) + .WithName(user.Username)); + + eb.WithColor(new Color(138, 219, 146)); + eb.Title = transDict["Increased"]; + eb.AddInlineField(transDict["By"], Context.User.Username); + eb.AddInlineField(transDict["Amount"], "+1"); + eb.AddInlineField(transDict["Current"], newKarma); + await ReplyAsync("", false, eb.Build()); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("bad", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Karma)] + [Summary("Decrease Someones Karma")] + public async Task Bad([Summary("@someone")] IUser user) + { + try + { + var transDict = _translation.GetDict(Context); + var lastKarmaFromRedis = _redis.HashGet($"{Context.Guild.Id}:KarmaTimeout", Context.User.Id.ToString()); + var lastKarma = ConvertToDateTimeOffset(lastKarmaFromRedis.ToString()); + if (user.Id == Context.User.Id) + { + await ReplyAsync(string.Format(transDict["CannotChangeOwn"], Context.User.Username)); + } + else if (TimeoutFinished(lastKarma)) + { + await ReplyAsync(string.Format(transDict["WaitUntill"], Context.User.Username, + GetTimeLeft(lastKarma))); + } + else + { + var newKarma = _redis.HashDecrement($"{Context.Guild.Id}:Karma", user.Id.ToString()); + _redis.HashSet($"{Context.Guild.Id}:KarmaTimeout", + new[] {new HashEntry(Context.User.Id.ToString(), DateTimeOffset.Now.ToString())}); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(user.GetAvatarUrl()) + .WithName(user.Username)); + + eb.WithColor(new Color(138, 219, 146)); + eb.Title = transDict["Decreased"]; + eb.AddInlineField(transDict["By"], Context.User.Username); + eb.AddInlineField(transDict["Amount"], "-1"); + eb.AddInlineField(transDict["Current"], newKarma); + await ReplyAsync("", false, eb.Build()); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private DateTimeOffset ConvertToDateTimeOffset(string dateTimeOffsetString) + { + return string.IsNullOrEmpty(dateTimeOffsetString) ? DateTimeOffset.Now.Subtract(new TimeSpan(7, 18, 0, 0)) : DateTimeOffset.Parse(dateTimeOffsetString); + } + + private bool TimeoutFinished(DateTimeOffset lastKarma) + { + return lastKarma.AddMinutes(3) > DateTimeOffset.Now; + } + + private string GetTimeLeft(DateTimeOffset lastKarma) + { + var dt = lastKarma.AddMinutes(3).Subtract(DateTimeOffset.Now); + return $"{dt.Minutes} Minutes and {dt.Seconds} Seconds"; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/User/Ranking/Rank.cs b/Geekbot.net/Commands/User/Ranking/Rank.cs new file mode 100644 index 0000000..08d4d3b --- /dev/null +++ b/Geekbot.net/Commands/User/Ranking/Rank.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Converters; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Logger; +using Geekbot.net.Lib.UserRepository; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.User.Ranking +{ + public class Rank : ModuleBase + { + private readonly IEmojiConverter _emojiConverter; + private readonly IErrorHandler _errorHandler; + private readonly IGeekbotLogger _logger; + private readonly IDatabase _redis; + private readonly IUserRepository _userRepository; + private readonly DiscordSocketClient _client; + + public Rank(IDatabase redis, IErrorHandler errorHandler, IGeekbotLogger logger, IUserRepository userRepository, + IEmojiConverter emojiConverter, DiscordSocketClient client) + { + _redis = redis; + _errorHandler = errorHandler; + _logger = logger; + _userRepository = userRepository; + _emojiConverter = emojiConverter; + _client = client; + } + + [Command("rank", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Statistics)] + [Summary("get user top 10 in messages or karma")] + public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10) + { + try + { + var type = typeUnformated.ToCharArray().First().ToString().ToUpper() + typeUnformated.Substring(1); + + if (!type.Equals("Messages") && !type.Equals("Karma") && !type.Equals("Rolls")) + { + await ReplyAsync("Valid types are '`messages`' '`karma`', '`rolls`'"); + return; + } + + var replyBuilder = new StringBuilder(); + + if (amount > 20) + { + replyBuilder.AppendLine(":warning: Limiting to 20"); + amount = 20; + } + + var messageList = _redis.HashGetAll($"{Context.Guild.Id}:{type}"); + if (messageList.Length == 0) + { + await ReplyAsync($"No {type.ToLowerInvariant()} found on this server"); + return; + } + var sortedList = messageList.OrderByDescending(e => e.Value).ToList(); + var guildMessages = (int) sortedList.First().Value; + var theBot = sortedList.FirstOrDefault(e => e.Name.ToString().Equals(_client.CurrentUser.Id.ToString())); + if (!string.IsNullOrEmpty(theBot.Name)) + { + sortedList.Remove(theBot); + } + if (type == "Messages") sortedList.RemoveAt(0); + + var highscoreUsers = new Dictionary(); + var listLimiter = 1; + var failedToRetrieveUser = false; + foreach (var user in sortedList) + { + if (listLimiter > amount) break; + try + { + var guildUser = _userRepository.Get((ulong) user.Name); + if (guildUser.Username != null) + { + highscoreUsers.Add(new RankUserPolyfillDto + { + Username = guildUser.Username, + Discriminator = guildUser.Discriminator + }, (int) user.Value); + } + else + { + highscoreUsers.Add(new RankUserPolyfillDto + { + Id = user.Name + }, (int) user.Value); + failedToRetrieveUser = true; + } + + listLimiter++; + } + catch (Exception e) + { + _logger.Warning(LogSource.Geekbot, $"Could not retrieve user {user.Name}", e); + } + } + + if (failedToRetrieveUser) replyBuilder.AppendLine(":warning: Couldn't get all userdata\n"); + replyBuilder.AppendLine($":bar_chart: **{type} Highscore for {Context.Guild.Name}**"); + var highscorePlace = 1; + foreach (var user in highscoreUsers) + { + replyBuilder.Append(highscorePlace < 11 + ? $"{_emojiConverter.NumberToEmoji(highscorePlace)} " + : $"`{highscorePlace}.` "); + + replyBuilder.Append(user.Key.Username != null + ? $"**{user.Key.Username}#{user.Key.Discriminator}**" + : $"**{user.Key.Id}**"); + + switch (type) + { + case "Messages": + var percent = Math.Round((double) (100 * user.Value) / guildMessages, 2); + replyBuilder.Append($" - {percent}% of total - {user.Value} messages"); + break; + case "Karma": + replyBuilder.Append($" - {user.Value} Karma"); + break; + case "Rolls": + replyBuilder.Append($" - {user.Value} Guessed"); + break; + } + + replyBuilder.Append("\n"); + + highscorePlace++; + } + + await ReplyAsync(replyBuilder.ToString()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Core/Highscores/HighscoreUserDto.cs b/Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs similarity index 54% rename from src/Core/Highscores/HighscoreUserDto.cs rename to Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs index 58e1897..625c326 100644 --- a/src/Core/Highscores/HighscoreUserDto.cs +++ b/Geekbot.net/Commands/User/Ranking/RankUserPolyfillDto.cs @@ -1,9 +1,8 @@ -namespace Geekbot.Core.Highscores +namespace Geekbot.net.Commands.User.Ranking { - public class HighscoreUserDto + internal class RankUserPolyfillDto { public string Username { get; set; } - public string Avatar { get; set; } public string Discriminator { get; set; } public string Id { get; set; } } diff --git a/Geekbot.net/Commands/User/Stats.cs b/Geekbot.net/Commands/User/Stats.cs new file mode 100644 index 0000000..476d643 --- /dev/null +++ b/Geekbot.net/Commands/User/Stats.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.Levels; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.User +{ + public class Stats : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly ILevelCalc _levelCalc; + private readonly IDatabase _redis; + + public Stats(IDatabase redis, IErrorHandler errorHandler, ILevelCalc levelCalc) + { + _redis = redis; + _errorHandler = errorHandler; + _levelCalc = levelCalc; + } + + [Command("stats", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Statistics)] + [Summary("Get information about this user")] + public async Task User([Summary("@someone")] IUser user = null) + { + try + { + var userInfo = user ?? Context.Message.Author; + var userGuildInfo = (IGuildUser) userInfo; + var createdAt = userInfo.CreatedAt; + var joinedAt = userGuildInfo.JoinedAt.Value; + var age = Math.Floor((DateTime.Now - createdAt).TotalDays); + var joinedDayAgo = Math.Floor((DateTime.Now - joinedAt).TotalDays); + + var messages = (int) _redis.HashGet($"{Context.Guild.Id}:Messages", userInfo.Id.ToString()); + var guildMessages = (int) _redis.HashGet($"{Context.Guild.Id}:Messages", 0.ToString()); + var level = _levelCalc.GetLevel(messages); + + var percent = Math.Round((double) (100 * messages) / guildMessages, 2); + + var eb = new EmbedBuilder(); + eb.WithAuthor(new EmbedAuthorBuilder() + .WithIconUrl(userInfo.GetAvatarUrl()) + .WithName(userInfo.Username)); + eb.WithColor(new Color(221, 255, 119)); + + var karma = _redis.HashGet($"{Context.Guild.Id}:Karma", userInfo.Id.ToString()); + var correctRolls = _redis.HashGet($"{Context.Guild.Id}:Rolls", userInfo.Id.ToString()); + + eb.AddInlineField("Discordian Since", + $"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} days)") + .AddInlineField("Joined Server", + $"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} days)") + .AddInlineField("Karma", karma.ToString() ?? "0") + .AddInlineField("Level", level) + .AddInlineField("Messages Sent", messages) + .AddInlineField("Server Total", $"{percent}%"); + + if (!correctRolls.IsNullOrEmpty) + eb.AddInlineField("Guessed Rolls", correctRolls); + + await ReplyAsync("", false, eb.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/AvatarGetter.cs b/Geekbot.net/Commands/Utils/AvatarGetter.cs similarity index 51% rename from src/Bot/Commands/Utils/AvatarGetter.cs rename to Geekbot.net/Commands/Utils/AvatarGetter.cs index 458eec8..d42c779 100644 --- a/src/Bot/Commands/Utils/AvatarGetter.cs +++ b/Geekbot.net/Commands/Utils/AvatarGetter.cs @@ -2,12 +2,12 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; -namespace Geekbot.Bot.Commands.Utils +namespace Geekbot.net.Commands.Utils { - public class AvatarGetter : TransactionModuleBase + public class AvatarGetter : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -17,18 +17,19 @@ namespace Geekbot.Bot.Commands.Utils } [Command("avatar", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("Get someones avatar")] - public async Task GetAvatar([Remainder, Summary("@someone")] IUser user = null) + public async Task GetAvatar([Remainder] [Summary("user")] IUser user = null) { 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) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } } diff --git a/Geekbot.net/Commands/Utils/Changelog/Changelog.cs b/Geekbot.net/Commands/Utils/Changelog/Changelog.cs new file mode 100644 index 0000000..f1752f7 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Changelog/Changelog.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Newtonsoft.Json; + +namespace Geekbot.net.Commands.Utils.Changelog +{ + public class Changelog : ModuleBase + { + private readonly DiscordSocketClient _client; + private readonly IErrorHandler _errorHandler; + + public Changelog(IErrorHandler errorHandler, DiscordSocketClient client) + { + _errorHandler = errorHandler; + _client = client; + } + + [Command("changelog", RunMode = RunMode.Async)] + [Alias("updates")] + [Remarks(CommandCategories.Helpers)] + [Summary("Show the latest 5 updates")] + public async Task GetChangelog() + { + try + { + using (var client = new HttpClient()) + { + client.BaseAddress = new Uri("https://api.github.com"); + client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", + "http://developer.github.com/v3/#user-agent-required"); + var response = await client.GetAsync("/repos/pizzaandcoffee/geekbot.net/commits"); + response.EnsureSuccessStatusCode(); + + var stringResponse = await response.Content.ReadAsStringAsync(); + var commits = JsonConvert.DeserializeObject>(stringResponse); + var eb = new EmbedBuilder(); + eb.WithColor(new Color(143, 165, 102)); + eb.WithAuthor(new EmbedAuthorBuilder + { + IconUrl = _client.CurrentUser.GetAvatarUrl(), + Name = "Latest Updates", + Url = "https://geekbot.pizzaandcoffee.rocks/updates" + }); + var sb = new StringBuilder(); + foreach (var commit in commits.Take(10)) + sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.Author.Date:yyyy-MM-dd})"); + eb.Description = sb.ToString(); + eb.WithFooter(new EmbedFooterBuilder + { + Text = $"List generated from github commits on {DateTime.Now:yyyy-MM-dd}" + }); + await ReplyAsync("", false, eb.Build()); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs new file mode 100644 index 0000000..8debd77 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Changelog/CommitAuthorDto.cs @@ -0,0 +1,11 @@ +using System; + +namespace Geekbot.net.Commands.Utils.Changelog +{ + public class CommitAuthorDto + { + public string Name { get; set; } + public string Email { get; set; } + public DateTimeOffset Date { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs new file mode 100644 index 0000000..3379697 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Changelog/CommitDto.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Commands.Utils.Changelog +{ + public class CommitDto + { + public CommitInfoDto Commit { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs b/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs new file mode 100644 index 0000000..9008343 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Changelog/CommitInfoDto.cs @@ -0,0 +1,8 @@ +namespace Geekbot.net.Commands.Utils.Changelog +{ + public class CommitInfoDto + { + public CommitAuthorDto Author { get; set; } + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Choose.cs b/Geekbot.net/Commands/Utils/Choose.cs new file mode 100644 index 0000000..4d54654 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Choose.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Localization; + +namespace Geekbot.net.Commands.Utils +{ + public class Choose : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly ITranslationHandler _translation; + + public Choose(IErrorHandler errorHandler, ITranslationHandler translation) + { + _errorHandler = errorHandler; + _translation = translation; + } + + [Command("choose", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Let the bot choose for you, seperate options with a semicolon.")] + public async Task Command([Remainder] [Summary("option1;option2")] + string choices) + { + try + { + var transDict = _translation.GetDict(Context); + var choicesArray = choices.Split(';'); + var choice = new Random().Next(choicesArray.Length); + await ReplyAsync(string.Format(transDict["Choice"], choicesArray[choice])); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Dice/Dice.cs b/Geekbot.net/Commands/Utils/Dice/Dice.cs new file mode 100644 index 0000000..9c169c7 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Dice/Dice.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; + +namespace Geekbot.net.Commands.Utils.Dice +{ + public class Dice : ModuleBase + { + [Command("dice", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Randomness)] + [Summary("Roll a dice.")] + public async Task RollCommand([Remainder] [Summary("diceType")] string diceType = "1d20") + { + var splitedDices = diceType.Split("+"); + var dices = new List(); + var mod = 0; + foreach (var i in splitedDices) + { + var dice = ToDice(i); + if (dice.Sides != 0 && dice.Times != 0) + { + dices.Add(dice); + } + else if (dice.Mod != 0) + { + if (mod != 0) + { + await ReplyAsync("You can only have one mod"); + return; + } + + mod = dice.Mod; + } + } + + if (!dices.Any()) + { + await ReplyAsync( + "That is not a valid dice, examples are: 1d20, 1d6, 2d6, 1d6+2, 1d6+2d8+1d20+6, etc..."); + return; + } + + + if (dices.Any(d => d.Times > 20)) + { + await ReplyAsync("You can't throw more than 20 dices"); + return; + } + + if (dices.Any(d => d.Sides > 144)) + { + await ReplyAsync("A dice can't have more than 144 sides"); + return; + } + + var rep = new StringBuilder(); + rep.AppendLine($":game_die: {Context.User.Mention}"); + rep.Append("**Result:** "); + var resultStrings = new List(); + var total = 0; + var extraText = ""; + foreach (var dice in dices) + { + var results = new List(); + for (var i = 0; i < dice.Times; i++) + { + var roll = new Random().Next(1, dice.Sides); + total += roll; + results.Add(roll); + if (roll == dice.Sides) extraText = "**Critical Hit!**"; + if (roll == 1) extraText = "**Critical Fail!**"; + } + + resultStrings.Add($"{dice.DiceType} ({string.Join(",", results)})"); + } + + rep.Append(string.Join(" + ", resultStrings)); + if (mod != 0) + { + rep.Append($" + {mod}"); + total += mod; + } + + rep.AppendLine(); + rep.AppendLine($"**Total:** {total}"); + if (extraText != "") rep.AppendLine(extraText); + await ReplyAsync(rep.ToString()); + } + + private DiceTypeDto ToDice(string dice) + { + var diceParts = dice.Split('d'); + if (diceParts.Length == 2 + && int.TryParse(diceParts[0], out var times) + && int.TryParse(diceParts[1], out var max)) + return new DiceTypeDto + { + DiceType = dice, + Times = times, + Sides = max + }; + if (dice.Length == 1 + && int.TryParse(diceParts[0], out var mod)) + return new DiceTypeDto + { + Mod = mod + }; + return new DiceTypeDto(); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Dice/DiceTypeDto.cs b/Geekbot.net/Commands/Utils/Dice/DiceTypeDto.cs new file mode 100644 index 0000000..5c54792 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Dice/DiceTypeDto.cs @@ -0,0 +1,10 @@ +namespace Geekbot.net.Commands.Utils.Dice +{ + internal class DiceTypeDto + { + public string DiceType { get; set; } + public int Times { get; set; } + public int Sides { get; set; } + public int Mod { get; set; } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Emojify.cs b/Geekbot.net/Commands/Utils/Emojify.cs similarity index 51% rename from src/Bot/Commands/Utils/Emojify.cs rename to Geekbot.net/Commands/Utils/Emojify.cs index a513710..57363c2 100644 --- a/src/Bot/Commands/Utils/Emojify.cs +++ b/Geekbot.net/Commands/Utils/Emojify.cs @@ -1,26 +1,31 @@ -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.Converters; -using Geekbot.Core.ErrorHandling; +using System; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Converters; +using Geekbot.net.Lib.ErrorHandling; -namespace Geekbot.Bot.Commands.Utils +namespace Geekbot.net.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)] + [Remarks(CommandCategories.Helpers)] [Summary("Emojify text")] public async Task Dflt([Remainder] [Summary("text")] string text) { 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!"); @@ -29,18 +34,10 @@ namespace Geekbot.Bot.Commands.Utils await ReplyAsync($"{Context.User.Username}#{Context.User.Discriminator} said:"); await ReplyAsync(emojis); - try - { - await Context.Message.DeleteAsync(); - } - catch - { - // bot may not have enough permission, doesn't matter if it fails - } } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } } diff --git a/src/Bot/Commands/Utils/Help.cs b/Geekbot.net/Commands/Utils/Help.cs similarity index 73% rename from src/Bot/Commands/Utils/Help.cs rename to Geekbot.net/Commands/Utils/Help.cs index 7aa9aff..be9a747 100644 --- a/src/Bot/Commands/Utils/Help.cs +++ b/Geekbot.net/Commands/Utils/Help.cs @@ -3,12 +3,12 @@ using System.Text; using System.Threading.Tasks; using Discord; using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; -namespace Geekbot.Bot.Commands.Utils +namespace Geekbot.net.Commands.Utils { - public class Help : TransactionModuleBase + public class Help : ModuleBase { private readonly IErrorHandler _errorHandler; @@ -18,6 +18,7 @@ namespace Geekbot.Bot.Commands.Utils } [Command("help", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("List all Commands")] public async Task GetHelp() { @@ -27,13 +28,13 @@ 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("✅")); } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } } diff --git a/src/Bot/Commands/Utils/Info.cs b/Geekbot.net/Commands/Utils/Info.cs similarity index 65% rename from src/Bot/Commands/Utils/Info.cs rename to Geekbot.net/Commands/Utils/Info.cs index 912528d..467b9d3 100644 --- a/src/Bot/Commands/Utils/Info.cs +++ b/Geekbot.net/Commands/Utils/Info.cs @@ -5,26 +5,30 @@ using System.Threading.Tasks; using Discord; using Discord.Commands; using Discord.WebSocket; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using StackExchange.Redis; -namespace Geekbot.Bot.Commands.Utils +namespace Geekbot.net.Commands.Utils { - public class Info : TransactionModuleBase + public class Info : ModuleBase { private readonly DiscordSocketClient _client; private readonly CommandService _commands; private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; - public Info(IErrorHandler errorHandler, DiscordSocketClient client, CommandService commands) + public Info(IDatabase redis, IErrorHandler errorHandler, DiscordSocketClient client, CommandService commands) { + _redis = redis; _errorHandler = errorHandler; _client = client; _commands = commands; } [Command("info", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("Get Information about the bot")] public async Task BotInfo() { @@ -32,30 +36,31 @@ namespace Geekbot.Bot.Commands.Utils { var eb = new EmbedBuilder(); - var appInfo = await _client.GetApplicationInfoAsync(); - eb.WithAuthor(new EmbedAuthorBuilder() - .WithIconUrl(appInfo.IconUrl) + .WithIconUrl(_client.CurrentUser.GetAvatarUrl()) .WithName($"{Constants.Name} V{Constants.BotVersion()}")); + var botOwner = await Context.Guild.GetUserAsync(ulong.Parse(_redis.StringGet("botOwner"))); var uptime = DateTime.Now.Subtract(Process.GetCurrentProcess().StartTime); eb.AddInlineField("Bot Name", _client.CurrentUser.Username); - eb.AddInlineField("Bot Owner", $"{appInfo.Owner.Username}#{appInfo.Owner.Discriminator}"); - eb.AddInlineField("Library", $"Discord.NET {Constants.LibraryVersion()}"); + eb.AddInlineField("Bot Owner", $"{botOwner.Username}#{botOwner.Discriminator}"); + eb.AddInlineField("Library", "Discord.NET V1.0.2"); eb.AddInlineField("Uptime", $"{uptime.Days}D {uptime.Hours}H {uptime.Minutes}M {uptime.Seconds}S"); eb.AddInlineField("Servers", Context.Client.GetGuildsAsync().Result.Count); eb.AddInlineField("Total Commands", _commands.Commands.Count()); + eb.AddField("Website", "https://geekbot.pizzaandcoffee.rocks/"); await ReplyAsync("", false, eb.Build()); } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } [Command("uptime", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] [Summary("Get the Bot Uptime")] public async Task BotUptime() { @@ -66,7 +71,7 @@ namespace Geekbot.Bot.Commands.Utils } catch (Exception e) { - await _errorHandler.HandleCommandException(e, Context); + _errorHandler.HandleCommandException(e, Context); } } } diff --git a/src/Bot/Commands/Utils/Ping.cs b/Geekbot.net/Commands/Utils/Ping.cs similarity index 67% rename from src/Bot/Commands/Utils/Ping.cs rename to Geekbot.net/Commands/Utils/Ping.cs index ee751cd..226e9a3 100644 --- a/src/Bot/Commands/Utils/Ping.cs +++ b/Geekbot.net/Commands/Utils/Ping.cs @@ -1,13 +1,14 @@ using System.Threading.Tasks; using Discord.Commands; -using Geekbot.Core; +using Geekbot.net.Lib; -namespace Geekbot.Bot.Commands.Utils +namespace Geekbot.net.Commands.Utils { - public class Ping : TransactionModuleBase + public class Ping : ModuleBase { [Command("👀", RunMode = RunMode.Async)] [Summary("Look at the bot.")] + [Remarks(CommandCategories.Fun)] public async Task Eyes() { await ReplyAsync("S... Stop looking at me... baka!"); diff --git a/Geekbot.net/Commands/Utils/Poll/Poll.cs b/Geekbot.net/Commands/Utils/Poll/Poll.cs new file mode 100644 index 0000000..b32a7c9 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Poll/Poll.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Converters; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Extensions; +using Geekbot.net.Lib.UserRepository; +using Newtonsoft.Json; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Utils.Poll +{ + [Group("poll")] + public class Poll : ModuleBase + { + private readonly IEmojiConverter _emojiConverter; + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + private readonly IUserRepository _userRepository; + + public Poll(IErrorHandler errorHandler, IDatabase redis, IEmojiConverter emojiConverter, + IUserRepository userRepository) + { + _errorHandler = errorHandler; + _redis = redis; + _emojiConverter = emojiConverter; + _userRepository = userRepository; + } + + [Command(RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Check status of the current poll")] + public async Task Dflt() + { + try + { + var currentPoll = GetCurrentPoll(); + if (currentPoll.Question == null || currentPoll.IsFinshed) + { + await ReplyAsync( + "There is no poll in this channel ongoing at the moment\r\nYou can create one with `!poll create question;option1;option2;option3`"); + return; + } + + await ReplyAsync("There is a poll running at the moment"); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("create", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("Create a poll")] + public async Task Create([Remainder] [Summary("question;option1;option2")] + string rawPollString) + { + try + { + var currentPoll = GetCurrentPoll(); + if (currentPoll.Question != null && !currentPoll.IsFinshed) + { + await ReplyAsync("You have not finished you last poll yet. To finish it use `!poll end`"); + return; + } + + var pollList = rawPollString.Split(';').ToList(); + if (pollList.Count <= 2) + { + await ReplyAsync( + "You need a question with atleast 2 options, a valid creation would look like this `question;option1;option2`"); + return; + } + + var eb = new EmbedBuilder(); + eb.Title = $"Poll by {Context.User.Username}"; + var question = pollList[0]; + eb.Description = question; + pollList.RemoveAt(0); + var i = 1; + pollList.ForEach(option => + { + eb.AddInlineField($"Option {_emojiConverter.NumberToEmoji(i)}", option); + i++; + }); + var pollMessage = await ReplyAsync("", false, eb.Build()); + i = 1; + pollList.ForEach(option => + { + pollMessage.AddReactionAsync(new Emoji(_emojiConverter.NumberToEmoji(i))); + i++; + }); + var poll = new PollDataDto + { + Creator = Context.User.Id, + MessageId = pollMessage.Id, + IsFinshed = false, + Question = question, + Options = pollList + }; + var pollJson = JsonConvert.SerializeObject(poll); + _redis.HashSet($"{Context.Guild.Id}:Polls", new[] {new HashEntry(Context.Channel.Id, pollJson)}); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + [Command("end", RunMode = RunMode.Async)] + [Remarks(CommandCategories.Helpers)] + [Summary("End the current poll")] + public async Task End() + { + try + { + var currentPoll = GetCurrentPoll(); + if (currentPoll.Question == null || currentPoll.IsFinshed) + { + await ReplyAsync("There is no ongoing poll at the moment"); + return; + } + + var results = await GetPollResults(currentPoll); + var sb = new StringBuilder(); + sb.AppendLine("**Poll Results**"); + sb.AppendLine(currentPoll.Question); + foreach (var result in results) sb.AppendLine($"{result.VoteCount} - {result.Option}"); + await ReplyAsync(sb.ToString()); + currentPoll.IsFinshed = true; + var pollJson = JsonConvert.SerializeObject(currentPoll); + _redis.HashSet($"{Context.Guild.Id}:Polls", new[] {new HashEntry(Context.Channel.Id, pollJson)}); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context); + } + } + + private PollDataDto GetCurrentPoll() + { + try + { + var currentPoll = _redis.HashGet($"{Context.Guild.Id}:Polls", Context.Channel.Id); + return JsonConvert.DeserializeObject(currentPoll.ToString()); + } + catch + { + return new PollDataDto(); + } + } + + private async Task> GetPollResults(PollDataDto poll) + { + var message = (IUserMessage) await Context.Channel.GetMessageAsync(poll.MessageId); + var results = new List(); + foreach (var r in message.Reactions) + try + { + var option = int.Parse(r.Key.Name.ToCharArray()[0].ToString()); + var result = new PollResultDto + { + Option = poll.Options[option - 1], + VoteCount = r.Value.ReactionCount + }; + results.Add(result); + } + catch {} + + results.Sort((x, y) => y.VoteCount.CompareTo(x.VoteCount)); + return results; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Poll/PollDataDto.cs b/Geekbot.net/Commands/Utils/Poll/PollDataDto.cs new file mode 100644 index 0000000..3d21479 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Poll/PollDataDto.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Geekbot.net.Commands.Utils.Poll +{ + internal class PollDataDto + { + public ulong Creator { get; set; } + public ulong MessageId { get; set; } + public bool IsFinshed { get; set; } + public string Question { get; set; } + public List Options { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Poll/PollResultDto.cs b/Geekbot.net/Commands/Utils/Poll/PollResultDto.cs new file mode 100644 index 0000000..b4f14a2 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Poll/PollResultDto.cs @@ -0,0 +1,8 @@ +namespace Geekbot.net.Commands.Utils.Poll +{ + internal class PollResultDto + { + public string Option { get; set; } + public int VoteCount { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Commands/Utils/Quote/Quote.cs b/Geekbot.net/Commands/Utils/Quote/Quote.cs new file mode 100644 index 0000000..84eec26 --- /dev/null +++ b/Geekbot.net/Commands/Utils/Quote/Quote.cs @@ -0,0 +1,239 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Geekbot.net.Lib; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Polyfills; +using Newtonsoft.Json; +using StackExchange.Redis; + +namespace Geekbot.net.Commands.Utils.Quote +{ + [Group("quote")] + public class Quote : ModuleBase + { + private readonly IErrorHandler _errorHandler; + private readonly IDatabase _redis; + + public Quote(IDatabase redis, IErrorHandler errorHandler) + { + _redis = redis; + _errorHandler = errorHandler; + } + + [Command] + [Remarks(CommandCategories.Quotes)] + [Summary("Return a random quoute from the database")] + public async Task GetRandomQuote() + { + try + { + var randomQuotes = _redis.SetMembers($"{Context.Guild.Id}:Quotes"); + if (!randomQuotes.Any()) + { + await ReplyAsync("This server doesn't seem to have any quotes yet. You can add a quote with `!quote save @user` or `!quote save `"); + return; + } + var randomNumber = new Random().Next(randomQuotes.Length - 1); + var randomQuote = randomQuotes[randomNumber]; + var quote = JsonConvert.DeserializeObject(randomQuote); + var embed = QuoteBuilder(quote, randomNumber + 1); + await ReplyAsync("", false, embed.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return"); + } + } + + [Command("save")] + [Remarks(CommandCategories.Quotes)] + [Summary("Save a quote from the last sent message by @user")] + public async Task SaveQuote([Summary("@user")] IUser user) + { + try + { + if (user.Id == Context.Message.Author.Id) + { + await ReplyAsync("You can't save your own quotes..."); + return; + } + + if (user.IsBot) + { + await ReplyAsync("You can't save quotes by a bot..."); + return; + } + + var lastMessage = await GetLastMessageByUser(user); + if (lastMessage == null) return; + var quote = CreateQuoteObject(lastMessage); + var quoteStore = JsonConvert.SerializeObject(quote); + _redis.SetAdd($"{Context.Guild.Id}:Quotes", quoteStore); + var embed = QuoteBuilder(quote); + await ReplyAsync("**Quote Added**", false, embed.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "I counldn't find a quote from that user :disappointed:"); + } + } + + [Command("save")] + [Remarks(CommandCategories.Quotes)] + [Summary("Save a quote from a message id")] + public async Task SaveQuote([Summary("messageId")] ulong messageId) + { + try + { + var message = await Context.Channel.GetMessageAsync(messageId); + if (message.Author.Id == Context.Message.Author.Id) + { + await ReplyAsync("You can't save your own quotes..."); + return; + } + + if (message.Author.IsBot) + { + await ReplyAsync("You can't save quotes by a bot..."); + return; + } + + var quote = CreateQuoteObject(message); + var quoteStore = JsonConvert.SerializeObject(quote); + _redis.SetAdd($"{Context.Guild.Id}:Quotes", quoteStore); + var embed = QuoteBuilder(quote); + await ReplyAsync("**Quote Added**", false, embed.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "I couldn't find a message with that id :disappointed:"); + } + } + + [Command("make")] + [Remarks(CommandCategories.Quotes)] + [Summary("Create a quote from the last sent message by @user")] + public async Task ReturnSpecifiedQuote([Summary("@user")] IUser user) + { + try + { + var lastMessage = await GetLastMessageByUser(user); + if (lastMessage == null) return; + var quote = CreateQuoteObject(lastMessage); + var embed = QuoteBuilder(quote); + await ReplyAsync("", false, embed.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "I counldn't find a quote from that user :disappointed:"); + } + } + + [Command("make")] + [Remarks(CommandCategories.Quotes)] + [Summary("Create a quote from a message id")] + public async Task ReturnSpecifiedQuote([Summary("messageId")] ulong messageId) + { + try + { + var message = await Context.Channel.GetMessageAsync(messageId); + var quote = CreateQuoteObject(message); + var embed = QuoteBuilder(quote); + await ReplyAsync("", false, embed.Build()); + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "I couldn't find a message with that id :disappointed:"); + } + } + + [Command("remove")] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireUserPermission(GuildPermission.ManageRoles)] + [Remarks(CommandCategories.Quotes)] + [Summary("Remove a quote (required mod permissions)")] + public async Task RemoveQuote([Summary("quoteId")] int id) + { + try + { + var quotes = _redis.SetMembers($"{Context.Guild.Id}:Quotes"); + var success = _redis.SetRemove($"{Context.Guild.Id}:Quotes", quotes[id - 1]); + if (success) + { + var quote = JsonConvert.DeserializeObject(quotes[id - 1]); + var embed = QuoteBuilder(quote); + await ReplyAsync($"**Removed #{id}**", false, embed.Build()); + } + else + { + await ReplyAsync("I couldn't find a quote with that id :disappointed:"); + } + } + catch (Exception e) + { + _errorHandler.HandleCommandException(e, Context, + "I couldn't find a quote with that id :disappointed:"); + } + } + + private async Task GetLastMessageByUser(IUser user) + { + try + { + var list = Context.Channel.GetMessagesAsync().Flatten(); + return await list.FirstOrDefault(msg => + msg.Author.Id == user.Id && + msg.Embeds.Count == 0 && + msg.Id != Context.Message.Id && + !msg.Content.ToLower().StartsWith("!")); + } + catch + { + await ReplyAsync($"No quoteable message have been sent by {user.Username} in this channel"); + return null; + } + } + + private EmbedBuilder QuoteBuilder(QuoteObjectDto quote, int id = 0) + { + var user = Context.Client.GetUserAsync(quote.UserId).Result ?? new UserPolyfillDto { Username = "Unknown User" }; + var eb = new EmbedBuilder(); + eb.WithColor(new Color(143, 167, 232)); + eb.Title = id == 0 ? "" : $"#{id} | "; + eb.Title += $"{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; + return eb; + } + + private QuoteObjectDto CreateQuoteObject(IMessage message) + { + string image; + try + { + image = message.Attachments.First().Url; + } + catch (Exception) + { + image = null; + } + + return new QuoteObjectDto + { + UserId = message.Author.Id, + Time = message.Timestamp.DateTime, + Quote = message.Content, + Image = image + }; + } + } +} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Quote/QuoteObjectDto.cs b/Geekbot.net/Commands/Utils/Quote/QuoteObjectDto.cs similarity index 81% rename from src/Bot/Commands/Utils/Quote/QuoteObjectDto.cs rename to Geekbot.net/Commands/Utils/Quote/QuoteObjectDto.cs index 32b65cf..a37ff76 100644 --- a/src/Bot/Commands/Utils/Quote/QuoteObjectDto.cs +++ b/Geekbot.net/Commands/Utils/Quote/QuoteObjectDto.cs @@ -1,6 +1,6 @@ using System; -namespace Geekbot.Bot.Commands.Utils.Quote +namespace Geekbot.net.Commands.Utils.Quote { internal class QuoteObjectDto { diff --git a/Geekbot.net/Geekbot.net.csproj b/Geekbot.net/Geekbot.net.csproj new file mode 100755 index 0000000..81f3a6c --- /dev/null +++ b/Geekbot.net/Geekbot.net.csproj @@ -0,0 +1,87 @@ + + + Exe + netcoreapp2.0 + derp.ico + 3.7.0 + $(VersionSuffix) + $(Version)-$(VersionSuffix) + Pizza and Coffee Studios + Pizza and Coffee Studios + A Discord bot + https://github.com/pizzaandcoffee/Geekbot.net + NU1701 + + + + + 2.0.0-beta + + + + + + + + + + + + + + + + + + 1.2.6 + + + + + + 4.3.0 + + + 4.3.0 + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + Always + + + + + + \ No newline at end of file diff --git a/Geekbot.net/Handlers.cs b/Geekbot.net/Handlers.cs new file mode 100644 index 0000000..f248d5d --- /dev/null +++ b/Geekbot.net/Handlers.cs @@ -0,0 +1,214 @@ +using System; +using System.Text; +using System.Threading.Tasks; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib.Logger; +using Geekbot.net.Lib.ReactionListener; +using Geekbot.net.Lib.UserRepository; +using StackExchange.Redis; + +namespace Geekbot.net +{ + public class Handlers + { + private readonly IDiscordClient _client; + private readonly IGeekbotLogger _logger; + private readonly IDatabase _redis; + private readonly IServiceProvider _servicesProvider; + private readonly CommandService _commands; + private readonly IUserRepository _userRepository; + private readonly IReactionListener _reactionListener; + + public Handlers(IDiscordClient client, IGeekbotLogger logger, IDatabase redis, IServiceProvider servicesProvider, CommandService commands, IUserRepository userRepository, IReactionListener reactionListener) + { + _client = client; + _logger = logger; + _redis = redis; + _servicesProvider = servicesProvider; + _commands = commands; + _userRepository = userRepository; + _reactionListener = reactionListener; + } + + // + // Incoming Messages + // + + public Task RunCommand(SocketMessage messageParam) + { + try + { + if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask; + if (message.Author.IsBot) return Task.CompletedTask; + var argPos = 0; + var lowCaseMsg = message.ToString().ToLower(); + if (lowCaseMsg.StartsWith("hui")) + { + message.Channel.SendMessageAsync("hui!!!"); + return Task.CompletedTask; + } + if (lowCaseMsg.StartsWith("ping ") || lowCaseMsg.Equals("ping")) + { + bool.TryParse(_redis.HashGet($"{((SocketGuildChannel) message.Channel).Guild.Id}:Settings", "ping"), out var allowPings); + if (allowPings) + { + message.Channel.SendMessageAsync("pong"); + return Task.CompletedTask; + } + } + if (!(message.HasCharPrefix('!', ref argPos) || + message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return Task.CompletedTask; + var context = new CommandContext(_client, message); + var commandExec = _commands.ExecuteAsync(context, argPos, _servicesProvider); + _logger.Information(LogSource.Command, + context.Message.Content.Split(" ")[0].Replace("!", ""), + SimpleConextConverter.ConvertContext(context)); + return Task.CompletedTask; + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Failed to Process Message", e); + return Task.CompletedTask; + } + } + + public Task UpdateStats(SocketMessage message) + { + try + { + if (message == null) return Task.CompletedTask; + if (message.Channel.Name.StartsWith('@')) + { + _logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message)); + return Task.CompletedTask; + } + var channel = (SocketGuildChannel) message.Channel; + + _redis.HashIncrementAsync($"{channel.Guild.Id}:Messages", message.Author.Id.ToString()); + _redis.HashIncrementAsync($"{channel.Guild.Id}:Messages", 0.ToString()); + + if (message.Author.IsBot) return Task.CompletedTask; + _logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message)); + } + catch (Exception e) + { + _logger.Error(LogSource.Message, "Could not process message stats", e); + } + return Task.CompletedTask; + } + + // + // User Stuff + // + + public Task UserJoined(SocketGuildUser user) + { + try + { + if (!user.IsBot) + { + var message = _redis.HashGet($"{user.Guild.Id}:Settings", "WelcomeMsg"); + if (!message.IsNullOrEmpty) + { + message = message.ToString().Replace("$user", user.Mention); + user.Guild.DefaultChannel.SendMessageAsync(message); + } + } + _userRepository.Update(user); + _logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})"); + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Failed to send welcome message", e); + } + return Task.CompletedTask; + } + + public Task UserUpdated(SocketUser oldUser, SocketUser newUser) + { + _userRepository.Update(newUser); + return Task.CompletedTask; + } + + public async Task UserLeft(SocketGuildUser user) + { + try + { + var sendLeftEnabled = _redis.HashGet($"{user.Guild.Id}:Settings", "ShowLeave"); + if (sendLeftEnabled.ToString() == "1") + { + var modChannel = ulong.Parse(_redis.HashGet($"{user.Guild.Id}:Settings", "ModChannel")); + if (!string.IsNullOrEmpty(modChannel.ToString())) + { + var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(modChannel); + await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server"); + } + } + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Failed to send leave message", e); + } + _logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})"); + } + + // + // Message Stuff + // + + public async Task MessageDeleted(Cacheable message, ISocketMessageChannel channel) + { + try + { + var guild = ((IGuildChannel) channel).Guild; + var sendLeftEnabled = _redis.HashGet($"{guild.Id}:Settings", "ShowDelete"); + if (sendLeftEnabled.ToString() == "1") + { + var modChannel = ulong.Parse(_redis.HashGet($"{guild.Id}:Settings", "ModChannel")); + if (!string.IsNullOrEmpty(modChannel.ToString()) && modChannel != channel.Id) + { + var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(modChannel); + 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 <#{channel.Id}>"); + sb.AppendLine(message.Value.Content); + } + else + { + sb.AppendLine("Someone deleted a message, the message was not cached..."); + } + await modChannelSocket.SendMessageAsync(sb.ToString()); + } + } + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Failed to send delete message...", e); + } + } + + // + // Reactions + // + + public Task ReactionAdded(Cacheable cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction) + { + if (reaction.User.Value.IsBot) return Task.CompletedTask; + if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; + _reactionListener.GiveRole(socketMessageChannel, reaction); + return Task.CompletedTask; + } + + public Task ReactionRemoved(Cacheable cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction) + { + if (reaction.User.Value.IsBot) return Task.CompletedTask; + if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; + _reactionListener.RemoveRole(socketMessageChannel, reaction); + return Task.CompletedTask; + } + } +} diff --git a/Geekbot.net/Lib/Audio/AudioUtils.cs b/Geekbot.net/Lib/Audio/AudioUtils.cs new file mode 100644 index 0000000..024019d --- /dev/null +++ b/Geekbot.net/Lib/Audio/AudioUtils.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using Discord.Audio; + +namespace Geekbot.net.Lib.Audio +{ + public class AudioUtils : IAudioUtils + { + private string _tempFolderPath; + private Dictionary _audioClients; + + public AudioUtils() + { + _audioClients = new Dictionary(); + _tempFolderPath = Path.GetFullPath("./tmp/"); + if (Directory.Exists(_tempFolderPath)) + { + Directory.Delete(_tempFolderPath, true); + } + Directory.CreateDirectory(_tempFolderPath); + } + + public IAudioClient GetAudioClient(ulong guildId) + { + return _audioClients[guildId]; + } + + public void StoreAudioClient(ulong guildId, IAudioClient client) + { + _audioClients[guildId] = client; + } + + public Process CreateStreamFromFile(string path) + { + var ffmpeg = new ProcessStartInfo + { + FileName = "ffmpeg", + Arguments = $"-i {path} -ac 2 -f s16le -ar 48000 pipe:1", + UseShellExecute = false, + RedirectStandardOutput = true, + }; + return Process.Start(ffmpeg); + } + + public Process CreateStreamFromYoutube(string url, ulong guildId) + { + var ytdlMediaUrl = GetYoutubeMediaUrl(url); + DownloadMediaUrl(ytdlMediaUrl, guildId); + return CreateStreamFromFile($"{_tempFolderPath}{guildId}"); + } + + public void Cleanup(ulong guildId) + { + File.Delete($"{_tempFolderPath}{guildId}"); + } + + private string GetYoutubeMediaUrl(string url) + { + var ytdl = new ProcessStartInfo() + { + FileName = "youtube-dl", + Arguments = $"-f bestaudio -g {url}", + UseShellExecute = false, + RedirectStandardOutput = true + }; + var output = Process.Start(ytdl).StandardOutput.ReadToEnd(); + if (string.IsNullOrWhiteSpace(output)) + { + throw new Exception("Could not get Youtube Media URL"); + } + return output; + } + + private void DownloadMediaUrl(string url, ulong guildId) + { + using (var web = new WebClient()) + { + web.DownloadFile(url, $"{_tempFolderPath}{guildId}"); + } +// var ffmpeg = new ProcessStartInfo +// { +// FileName = "ffmpeg", +// Arguments = $"-i \"{_tempFolderPath}{guildId}\" -c:a mp3 -b:a 256k {_tempFolderPath}{guildId}.mp3", +// UseShellExecute = false, +// RedirectStandardOutput = true, +// }; +// Process.Start(ffmpeg).WaitForExit(); +// File.Delete($"{_tempFolderPath}{guildId}"); + return; + } + + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Audio/IAudioUtils.cs b/Geekbot.net/Lib/Audio/IAudioUtils.cs new file mode 100644 index 0000000..4af1293 --- /dev/null +++ b/Geekbot.net/Lib/Audio/IAudioUtils.cs @@ -0,0 +1,15 @@ +using System.Diagnostics; +using Discord.Audio; + +namespace Geekbot.net.Lib.Audio +{ + public interface IAudioUtils + { + IAudioClient GetAudioClient(ulong guildId); + void StoreAudioClient(ulong guildId, IAudioClient client); + Process CreateStreamFromFile(string path); + Process CreateStreamFromYoutube(string url, ulong guildId); + void Cleanup(ulong guildId); + + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Clients/IMalClient.cs b/Geekbot.net/Lib/Clients/IMalClient.cs new file mode 100644 index 0000000..f59c511 --- /dev/null +++ b/Geekbot.net/Lib/Clients/IMalClient.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using MyAnimeListSharp.Core; + +namespace Geekbot.net.Lib.Clients +{ + public interface IMalClient + { + bool IsLoggedIn(); + Task GetAnime(string query); + Task GetManga(string query); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Clients/MalClient.cs b/Geekbot.net/Lib/Clients/MalClient.cs new file mode 100644 index 0000000..95d7dbd --- /dev/null +++ b/Geekbot.net/Lib/Clients/MalClient.cs @@ -0,0 +1,70 @@ +using System.Threading.Tasks; +using Geekbot.net.Lib.Logger; +using MyAnimeListSharp.Auth; +using MyAnimeListSharp.Core; +using MyAnimeListSharp.Facade.Async; +using StackExchange.Redis; + +namespace Geekbot.net.Lib.Clients +{ + public class MalClient : IMalClient + { + private readonly IDatabase _redis; + private readonly IGeekbotLogger _logger; + private ICredentialContext _credentials; + private AnimeSearchMethodsAsync _animeSearch; + private MangaSearchMethodsAsync _mangaSearch; + + public MalClient(IDatabase redis, IGeekbotLogger logger) + { + _redis = redis; + _logger = logger; + ReloadClient(); + } + + public bool ReloadClient() + { + var malCredentials = _redis.HashGetAll("malCredentials"); + if (malCredentials.Length != 0) + { + _credentials = new CredentialContext(); + foreach (var c in malCredentials) + { + switch (c.Name) + { + case "Username": + _credentials.UserName = c.Value; + break; + case "Password": + _credentials.Password = c.Value; + break; + } + } + _animeSearch = new AnimeSearchMethodsAsync(_credentials); + _mangaSearch = new MangaSearchMethodsAsync(_credentials); + _logger.Debug(LogSource.Geekbot, "Logged in to MAL"); + return true; + } + _logger.Debug(LogSource.Geekbot, "No MAL Credentials Set!"); + return false; + + } + + public bool IsLoggedIn() + { + return _credentials != null; + } + + public async Task GetAnime(string query) + { + var response = await _animeSearch.SearchDeserializedAsync(query); + return response.Entries.Count == 0 ? null : response.Entries[0]; + } + + public async Task GetManga(string query) + { + var response = await _mangaSearch.SearchDeserializedAsync(query); + return response.Entries.Count == 0 ? null : response.Entries[0]; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/CommandCategories.cs b/Geekbot.net/Lib/CommandCategories.cs new file mode 100644 index 0000000..d67123b --- /dev/null +++ b/Geekbot.net/Lib/CommandCategories.cs @@ -0,0 +1,15 @@ +namespace Geekbot.net.Lib +{ + public static class CommandCategories + { + public const string Randomness = "Randomness"; + public const string Karma = "Karma"; + public const string Quotes = "Quotes"; + public const string Fun = "Fun"; + public const string Statistics = "Statistics"; + public const string Helpers = "Helpers"; + public const string Games = "Games"; + public const string Admin = "Admin"; + public const string Uncategorized = "Uncategorized"; + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Constants.cs b/Geekbot.net/Lib/Constants.cs new file mode 100644 index 0000000..f80f182 --- /dev/null +++ b/Geekbot.net/Lib/Constants.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +namespace Geekbot.net.Lib +{ + public static class Constants + { + public const string Name = "Geekbot"; + + public static string BotVersion() + { + return typeof(Program).Assembly.GetCustomAttribute().InformationalVersion; + } + + public const double ApiVersion = 1; + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Converters/EmojiConverter.cs b/Geekbot.net/Lib/Converters/EmojiConverter.cs new file mode 100644 index 0000000..06f1aa8 --- /dev/null +++ b/Geekbot.net/Lib/Converters/EmojiConverter.cs @@ -0,0 +1,93 @@ +using System.Collections; +using System.Text; + +namespace Geekbot.net.Lib.Converters +{ + public class EmojiConverter : IEmojiConverter + { + 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(emojiMap[int.Parse(n.ToString())]); + } + return returnString.ToString(); + } + + 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 = emojiMap[n] ?? n; + returnString.Append(emoji); + } + return returnString.ToString(); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Converters/IEmojiConverter.cs b/Geekbot.net/Lib/Converters/IEmojiConverter.cs new file mode 100644 index 0000000..b0f666f --- /dev/null +++ b/Geekbot.net/Lib/Converters/IEmojiConverter.cs @@ -0,0 +1,8 @@ +namespace Geekbot.net.Lib.Converters +{ + public interface IEmojiConverter + { + string NumberToEmoji(int number); + string TextToEmoji(string text); + } +} \ No newline at end of file diff --git a/src/Core/Converters/IMtgManaConverter.cs b/Geekbot.net/Lib/Converters/IMtgManaConverter.cs similarity index 67% rename from src/Core/Converters/IMtgManaConverter.cs rename to Geekbot.net/Lib/Converters/IMtgManaConverter.cs index 0dd3034..d558f09 100644 --- a/src/Core/Converters/IMtgManaConverter.cs +++ b/Geekbot.net/Lib/Converters/IMtgManaConverter.cs @@ -1,4 +1,4 @@ -namespace Geekbot.Core.Converters +namespace Geekbot.net.Lib.Converters { public interface IMtgManaConverter { diff --git a/Geekbot.net/Lib/Converters/MtgManaConverter.cs b/Geekbot.net/Lib/Converters/MtgManaConverter.cs new file mode 100644 index 0000000..c29e1e0 --- /dev/null +++ b/Geekbot.net/Lib/Converters/MtgManaConverter.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using Utf8Json; + +namespace Geekbot.net.Lib.Converters +{ + public class MtgManaConverter : IMtgManaConverter + { + private Dictionary _manaDict; + + public MtgManaConverter() + { + // these emotes can be found at https://discord.gg/bz8HyA7 + var mtgEmojis = File.ReadAllText(Path.GetFullPath("./Lib/Converters/MtgManaEmojis.json")); + _manaDict = JsonSerializer.Deserialize>(mtgEmojis); + } + + public string ConvertMana(string mana) + { + var rgx = Regex.Matches(mana, @"(\{(.*?)\})"); + foreach (Match manaTypes in rgx) + { + var m = _manaDict.GetValueOrDefault(manaTypes.Value); + if (!string.IsNullOrEmpty(m)) + { + mana = mana.Replace(manaTypes.Value, m); + } + } + return mana; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Converters/MtgManaEmojis.json b/Geekbot.net/Lib/Converters/MtgManaEmojis.json new file mode 100644 index 0000000..8ebe75b --- /dev/null +++ b/Geekbot.net/Lib/Converters/MtgManaEmojis.json @@ -0,0 +1,50 @@ +{ + "{0}": "<:mtg_0:415216130043412482>", + "{1}": "<:mtg_1:415216130253389835>", + "{2}": "<:mtg_2:415216130031091713>", + "{3}": "<:mtg_3:415216130467037194>", + "{4}": "<:mtg_4:415216130026635295>", + "{5}": "<:mtg_5:415216130492203008>", + "{6}": "<:mtg_6:415216130458779658>", + "{7}": "<:mtg_7:415216130190475265>", + "{8}": "<:mtg_8:415216130517630986>", + "{9}": "<:mtg_9:415216130500722689>", + "{10": "<:mtg_10:415216130450391051>", + "{11}": "<:mtg_11:415216130811101185>", + "{12}": "<:mtg_12:415216130525888532>", + "{13}": "<:mtg_13:415216130517631000>", + "{14}": "<:mtg_14:415216130165178370>", + "{15}": "<:mtg_15:415216130576089108>", + "{16}": "<:mtg_16:415216130358247425>", + "{17}": "<:mtg_17:415216130601517056>", + "{18}": "<:mtg_18:415216130462842891>", + "{19}": "<:mtg_19:415216130614099988>", + "{20}": "<:mtg_20:415216130656043038>", + "{W}": "<:mtg_white:415216131515744256>", + "{U}": "<:mtg_blue:415216130521694209>", + "{B}": "<:mtg_black:415216130873884683>", + "{R}": "<:mtg_red:415216131322806272>", + "{G}": "<:mtg_green:415216131180331009>", + "{S}": "<:mtg_s:415216131293446144>", + "{T}": "<:mtg_tap:415258392727257088>", + "{C}": "<:mtg_colorless:415216130706374666>", + "{2/W}": "<:mtg_2w:415216130446065664>", + "{2/U}": "<:mtg_2u:415216130429550592>", + "{2/B}": "<:mtg_2b:415216130160984065>", + "{2/R}": "<:mtg_2r:415216130454716436>", + "{2/G}": "<:mtg_2g:415216130420899840>", + "{W/U}": "<:mtg_wu:415216130970484736>", + "{W/B}": "<:mtg_wb:415216131222011914>", + "{U/R}": "<:mtg_ur:415216130962096128>", + "{U/B}": "<:mtg_ub:415216130865758218>", + "{R/W}": "<:mtg_rw:415216130878210057>", + "{G/W}": "<:mtg_gw:415216130567962646>", + "{G/U}": "<:mtg_gu:415216130739666945>", + "{B/R}": "<:mtg_br:415216130580283394>", + "{B/G}": "<:mtg_bg:415216130781609994>", + "{U/P}": "<:mtg_up:415216130861432842>", + "{R/P}": "<:mtg_rp:415216130597322783>", + "{G/P}": "<:mtg_gp:415216130760769546>", + "{W/P}": "<:mtg_wp:415216131541041172>", + "{B/P}": "<:mtg_bp:415216130664169482>" +} \ No newline at end of file diff --git a/Geekbot.net/Lib/ErrorHandling/ErrorHandler.cs b/Geekbot.net/Lib/ErrorHandling/ErrorHandler.cs new file mode 100644 index 0000000..99d1e8b --- /dev/null +++ b/Geekbot.net/Lib/ErrorHandling/ErrorHandler.cs @@ -0,0 +1,102 @@ +using System; +using System.Net; +using Discord.Commands; +using Discord.Net; +using Geekbot.net.Lib.Localization; +using Geekbot.net.Lib.Logger; +using SharpRaven; +using SharpRaven.Data; + +namespace Geekbot.net.Lib.ErrorHandling +{ + public class ErrorHandler : IErrorHandler + { + private readonly IGeekbotLogger _logger; + private readonly ITranslationHandler _translation; + private readonly IRavenClient _raven; + private readonly bool _errorsInChat; + + public ErrorHandler(IGeekbotLogger logger, ITranslationHandler translation, bool errorsInChat) + { + _logger = logger; + _translation = translation; + _errorsInChat = errorsInChat; + + var sentryDsn = Environment.GetEnvironmentVariable("SENTRY"); + if (!string.IsNullOrEmpty(sentryDsn)) + { + _raven = new RavenClient(sentryDsn) { Release = Constants.BotVersion() }; + _logger.Information(LogSource.Geekbot, $"Command Errors will be logged to Sentry: {sentryDsn}"); + } + else + { + _raven = null; + } + } + + public void HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def") + { + try + { + var errorString = errorMessage == "def" ? _translation.GetString(context.Guild.Id, "errorHandler", "SomethingWentWrong") : errorMessage; + var errorObj = SimpleConextConverter.ConvertContext(context); + if (e.Message.Contains("50007")) return; + if (e.Message.Contains("50013")) return; + _logger.Error(LogSource.Geekbot, "An error ocured", e, errorObj); + if (!string.IsNullOrEmpty(errorMessage)) + { + if (_errorsInChat) + { + var resStackTrace = string.IsNullOrEmpty(e.InnerException?.ToString()) ? e.StackTrace : e.InnerException?.ToString(); + if (!string.IsNullOrEmpty(resStackTrace)) + { + var maxLen = Math.Min(resStackTrace.Length, 1850); + context.Channel.SendMessageAsync($"{e.Message}\r\n```\r\n{resStackTrace.Substring(0, maxLen)}\r\n```"); + } + else + { + context.Channel.SendMessageAsync(e.Message); + } + } + else + { + context.Channel.SendMessageAsync(errorString); + } + + } + + 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 + }; + _raven.Capture(sentryEvent); + } + catch (Exception ex) + { + context.Channel.SendMessageAsync("Something went really really wrong here"); + _logger.Error(LogSource.Geekbot, "Errorception", ex); + } + } + + public async void HandleHttpException(HttpException e, ICommandContext context) + { + var errorStrings = _translation.GetDict(context, "httpErrors"); + switch(e.HttpCode) + { + case HttpStatusCode.Forbidden: + await context.Channel.SendMessageAsync(errorStrings["403"]); + break; + } + } + + + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/ErrorHandling/IErrorHandler.cs b/Geekbot.net/Lib/ErrorHandling/IErrorHandler.cs new file mode 100644 index 0000000..f2d8dac --- /dev/null +++ b/Geekbot.net/Lib/ErrorHandling/IErrorHandler.cs @@ -0,0 +1,12 @@ +using System; +using Discord.Commands; +using Discord.Net; + +namespace Geekbot.net.Lib.ErrorHandling +{ + public interface IErrorHandler + { + void HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def"); + void HandleHttpException(HttpException e, ICommandContext context); + } +} \ No newline at end of file diff --git a/src/Core/Extensions/EmbedBuilderExtensions.cs b/Geekbot.net/Lib/Extensions/EmbedBuilderExtensions.cs similarity index 82% rename from src/Core/Extensions/EmbedBuilderExtensions.cs rename to Geekbot.net/Lib/Extensions/EmbedBuilderExtensions.cs index c546306..2a84622 100644 --- a/src/Core/Extensions/EmbedBuilderExtensions.cs +++ b/Geekbot.net/Lib/Extensions/EmbedBuilderExtensions.cs @@ -1,12 +1,12 @@ -using Discord; - -namespace Geekbot.Core.Extensions -{ - public static class EmbedBuilderExtensions - { - public static EmbedBuilder AddInlineField(this EmbedBuilder builder, string name, object value) - { - return builder.AddField(new EmbedFieldBuilder().WithIsInline(true).WithName(name).WithValue(value)); - } - } -} \ No newline at end of file +using Discord; + +namespace Geekbot.net.Lib.Extensions +{ + public static class EmbedBuilderExtensions + { + public static EmbedBuilder AddInlineField(this EmbedBuilder builder, string name, object value) + { + return builder.AddField(new EmbedFieldBuilder().WithIsInline(true).WithName(name).WithValue(value)); + } + } +} diff --git a/src/Core/GeekbotExitCode.cs b/Geekbot.net/Lib/GeekbotExitCode.cs similarity index 57% rename from src/Core/GeekbotExitCode.cs rename to Geekbot.net/Lib/GeekbotExitCode.cs index 51006e1..e9e1210 100644 --- a/src/Core/GeekbotExitCode.cs +++ b/Geekbot.net/Lib/GeekbotExitCode.cs @@ -1,6 +1,6 @@ -namespace Geekbot.Core +namespace Geekbot.net.Lib { - public enum GeekbotExitCode + public enum GeekbotExitCode : int { // General Clean = 0, @@ -8,11 +8,9 @@ // Geekbot Internals TranslationsFailed = 201, - KilledByApiCall = 210, // Dependent Services - /* 301 not in use anymore (redis) */ - DatabaseConnectionFailed = 302, + RedisConnectionFailed = 301, // Discord Related CouldNotLogin = 401 diff --git a/Geekbot.net/Lib/Levels/ILevelCalc.cs b/Geekbot.net/Lib/Levels/ILevelCalc.cs new file mode 100644 index 0000000..6353132 --- /dev/null +++ b/Geekbot.net/Lib/Levels/ILevelCalc.cs @@ -0,0 +1,7 @@ +namespace Geekbot.net.Lib.Levels +{ + public interface ILevelCalc + { + int GetLevel(int experience); + } +} \ No newline at end of file diff --git a/src/Core/Levels/LevelCalc.cs b/Geekbot.net/Lib/Levels/LevelCalc.cs similarity index 60% rename from src/Core/Levels/LevelCalc.cs rename to Geekbot.net/Lib/Levels/LevelCalc.cs index 8203f97..9ecf803 100644 --- a/src/Core/Levels/LevelCalc.cs +++ b/Geekbot.net/Lib/Levels/LevelCalc.cs @@ -1,12 +1,11 @@ using System; using System.Collections.Generic; -using System.Linq; -namespace Geekbot.Core.Levels +namespace Geekbot.net.Lib.Levels { public class LevelCalc : ILevelCalc { - private readonly int[] _levels; + private int[] _levels; public LevelCalc() { @@ -20,9 +19,15 @@ namespace Geekbot.Core.Levels _levels = levels.ToArray(); } - public int GetLevel(int? messages) + public int GetLevel(int messages) { - return 1 + _levels.TakeWhile(level => !(level > messages)).Count(); + var returnVal = 1; + foreach (var level in _levels) + { + if (level > messages) break; + returnVal++; + } + return returnVal; } } } \ No newline at end of file diff --git a/Geekbot.net/Lib/Localization/ITranslationHandler.cs b/Geekbot.net/Lib/Localization/ITranslationHandler.cs new file mode 100644 index 0000000..3cd9549 --- /dev/null +++ b/Geekbot.net/Lib/Localization/ITranslationHandler.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using Discord.Commands; + +namespace Geekbot.net.Lib.Localization +{ + public interface ITranslationHandler + { + string GetString(ulong guildId, string command, string stringName); + Dictionary GetDict(ICommandContext context); + Dictionary GetDict(ICommandContext context, string command); + bool SetLanguage(ulong guildId, string language); + List GetSupportedLanguages(); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Localization/TranslationHandler.cs b/Geekbot.net/Lib/Localization/TranslationHandler.cs new file mode 100644 index 0000000..550759d --- /dev/null +++ b/Geekbot.net/Lib/Localization/TranslationHandler.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib.Logger; +using StackExchange.Redis; +using Utf8Json; + +namespace Geekbot.net.Lib.Localization +{ + public class TranslationHandler : ITranslationHandler + { + private readonly IGeekbotLogger _logger; + private readonly IDatabase _redis; + private Dictionary>> _translations; + private Dictionary _serverLanguages; + private List _supportedLanguages; + + public TranslationHandler(IReadOnlyCollection clientGuilds, IDatabase redis, IGeekbotLogger logger) + { + _logger = logger; + _redis = redis; + _logger.Information(LogSource.Geekbot, "Loading Translations"); + LoadTranslations(); + LoadServerLanguages(clientGuilds); + } + + private void LoadTranslations() + { + try + { + var translationFile = File.ReadAllText(Path.GetFullPath("./Lib/Localization/Translations.json")); + var rawTranslations = JsonSerializer.Deserialize>>>(translationFile); + var sortedPerLanguage = new Dictionary>>(); + foreach (var command in rawTranslations) + { + foreach (var str in command.Value) + { + foreach (var lang in str.Value) + { + if (!sortedPerLanguage.ContainsKey(lang.Key)) + { + var commandDict = new Dictionary>(); + var strDict = new Dictionary(); + strDict.Add(str.Key, lang.Value); + commandDict.Add(command.Key, strDict); + sortedPerLanguage.Add(lang.Key, commandDict); + } + if (!sortedPerLanguage[lang.Key].ContainsKey(command.Key)) + { + var strDict = new Dictionary(); + strDict.Add(str.Key, lang.Value); + sortedPerLanguage[lang.Key].Add(command.Key, strDict); + } + if (!sortedPerLanguage[lang.Key][command.Key].ContainsKey(str.Key)) + { + sortedPerLanguage[lang.Key][command.Key].Add(str.Key, lang.Value); + } + } + } + } + _translations = sortedPerLanguage; + + _supportedLanguages = new List(); + foreach (var lang in sortedPerLanguage) + { + _supportedLanguages.Add(lang.Key); + } + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Failed to load Translations", e); + Environment.Exit(GeekbotExitCode.TranslationsFailed.GetHashCode()); + } + } + + private void LoadServerLanguages(IReadOnlyCollection clientGuilds) + { + _serverLanguages = new Dictionary(); + foreach (var guild in clientGuilds) + { + var language = _redis.HashGet($"{guild.Id}:Settings", "Language"); + if (string.IsNullOrEmpty(language) || !_supportedLanguages.Contains(language)) + { + _serverLanguages[guild.Id] = "EN"; + } + else + { + _serverLanguages[guild.Id] = language.ToString(); + } + } + } + + public string GetString(ulong guildId, string command, string stringName) + { + var translation = _translations[_serverLanguages[guildId]][command][stringName]; + if (!string.IsNullOrWhiteSpace(translation)) return translation; + translation = _translations[command][stringName]["EN"]; + if (string.IsNullOrWhiteSpace(translation)) + { + _logger.Warning(LogSource.Geekbot, $"No translation found for {command} - {stringName}"); + } + return translation; + } + + public Dictionary GetDict(ICommandContext context) + { + try + { + var command = context.Message.Content.Split(' ').First().TrimStart('!').ToLower(); + return _translations[_serverLanguages[context.Guild.Id]][command]; + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "No translations for command found", e); + return new Dictionary(); + } + } + + public Dictionary GetDict(ICommandContext context, string command) + { + try + { + return _translations[_serverLanguages[context.Guild.Id]][command]; + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "No translations for command found", e); + return new Dictionary(); + } + } + + public bool SetLanguage(ulong guildId, string language) + { + try + { + if (!_supportedLanguages.Contains(language)) return false; + _redis.HashSet($"{guildId}:Settings", new[]{ new HashEntry("Language", language) }); + _serverLanguages[guildId] = language; + return true; + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Error while changing language", e); + return false; + } + } + + public List GetSupportedLanguages() + { + return _supportedLanguages; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Localization/Translations.json b/Geekbot.net/Lib/Localization/Translations.json new file mode 100644 index 0000000..fab8b94 --- /dev/null +++ b/Geekbot.net/Lib/Localization/Translations.json @@ -0,0 +1,100 @@ +{ + "admin": { + "NewLanguageSet": { + "EN": "I will reply in english from now on", + "CHDE": "I werd ab jetzt uf schwiizerdüütsch antworte, äuuä" + }, + "GetLanguage": { + "EN": "I'm talking english", + "CHDE": "I red schwiizerdüütsch" + } + }, + "errorHandler": { + "SomethingWentWrong": { + "EN": "Something went wrong :confused:", + "CHDE": "Öppis isch schief gange :confused:" + } + }, + "httpErrors": { + "403": { + "EN": "Seems like i don't have enough permission to that :confused:", + "CHDE": "Gseht danach us das ich nid gnueg recht han zum das mache :confused:" + } + }, + "choose": { + "Choice": { + "EN": "I Choose **{0}**", + "CHDE": "I nimme **{0}**" + } + }, + "good": { + "CannotChangeOwn": { + "EN": "Sorry {0}, but you can't give yourself karma", + "CHDE": "Sorry {0}, aber du chasch dr selber kei karma geh" + }, + "WaitUntill": { + "EN": "Sorry {0}, but you have to wait {1} before you can give karma again...", + "CHDE": "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch geh..." + }, + "Increased": { + "EN": "Karma gained", + "CHDE": "Karma becho" + }, + "By": { + "EN": "By", + "CHDE": "Vo" + }, + "Amount": { + "EN": "Amount", + "CHDE": "Mengi" + }, + "Current": { + "EN": "Current", + "CHDE": "Jetzt" + } + }, + "bad": { + "CannotChangeOwn": { + "EN": "Sorry {0}, but you can't lower your own karma", + "CHDE": "Sorry {0}, aber du chasch dr din eigete karma nid weg neh" + }, + "WaitUntill": { + "EN": "Sorry {0}, but you have to wait {1} before you can lower karma again...", + "CHDE": "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch senke..." + }, + "Decreased": { + "EN": "Karma lowered", + "CHDE": "Karma gsenkt" + }, + "By": { + "EN": "By", + "CHDE": "Vo" + }, + "Amount": { + "EN": "Amount", + "CHDE": "Mengi" + }, + "Current": { + "EN": "Current", + "CHDE": "Jetzt" + } + }, + "roll": { + "Rolled": { + "EN": "{0}, you rolled {1}, your guess was {2}", + "CHDE": "{0}, du hesch {1} grollt und hesch {2} grate" + }, + "Gratz": { + "EN": "Congratulations {0}, your guess was correct!", + "CHDE": "Gratuliere {0}, du hesch richtig grate!" + }, + "RolledNoGuess": { + "EN": "{0}, you rolled {1}", + "CHDE": "{0}, du hesch {1} grollt" + }, + "NoPrevGuess": { + "EN": ":red_circle: {0}, you can't guess the same number again within 24 hours", + "CHDE": ":red_circle: {0}, du chasch nid nomol es gliche rate innerhalb vo 24 stund" + } + } +} \ No newline at end of file diff --git a/src/Core/Logger/Adapters/DiscordLogger.cs b/Geekbot.net/Lib/Logger/DiscordLogger.cs similarity index 92% rename from src/Core/Logger/Adapters/DiscordLogger.cs rename to Geekbot.net/Lib/Logger/DiscordLogger.cs index e9bb02e..2adcd73 100644 --- a/src/Core/Logger/Adapters/DiscordLogger.cs +++ b/Geekbot.net/Lib/Logger/DiscordLogger.cs @@ -1,8 +1,9 @@ using System; using System.Threading.Tasks; using Discord; +using Geekbot.net.Commands.Randomness.Cat; -namespace Geekbot.Core.Logger.Adapters +namespace Geekbot.net.Lib.Logger { public class DiscordLogger : IDiscordLogger { diff --git a/Geekbot.net/Lib/Logger/GeekbotLogger.cs b/Geekbot.net/Lib/Logger/GeekbotLogger.cs new file mode 100644 index 0000000..b2bb677 --- /dev/null +++ b/Geekbot.net/Lib/Logger/GeekbotLogger.cs @@ -0,0 +1,74 @@ +using System; +using Newtonsoft.Json; + +namespace Geekbot.net.Lib.Logger +{ + public class GeekbotLogger : IGeekbotLogger + { + private readonly bool _logAsJson; + private readonly NLog.Logger _logger; + private readonly JsonSerializerSettings _serializerSettings; + + public GeekbotLogger(RunParameters runParameters, bool sumologicActive) + { + _logAsJson = sumologicActive || runParameters.LogJson; + _logger = LoggerFactory.CreateNLog(runParameters, sumologicActive); + _serializerSettings = new JsonSerializerSettings + { + 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)); + } + + public void Debug(LogSource source, string message, object extra = null) + { + if (_logAsJson) _logger.Info(CreateLogString("Debug", source, message, null, extra)); + else _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)); + } + + public void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null) + { + if (_logAsJson) _logger.Info(CreateLogString("Warning", source, message, stackTrace, extra)); + else _logger.Warn(CreateLogString("Warning", source, message, stackTrace, extra)); + } + + public void Error(LogSource source, string message, Exception stackTrace, object extra = null) + { + if (_logAsJson) _logger.Info(CreateLogString("Error", source, message, stackTrace, extra)); + else _logger.Error(stackTrace, CreateLogString("Error", source, message, stackTrace, extra)); + } + + private string CreateLogString(string type, LogSource source, string message, Exception stackTrace = null, object extra = null) + { + if (_logAsJson) + { + var logObject = new GeekbotLoggerObject + { + Timestamp = DateTime.Now, + Type = type, + Source = source, + Message = message, + StackTrace = stackTrace, + Extra = extra + }; + return JsonConvert.SerializeObject(logObject, Formatting.None, _serializerSettings); + } + + if (source != LogSource.Message) return $"[{source}] - {message}"; + + var m = (MessageDto) extra; + return $"[{source}] - [{m?.Guild.Name} - {m?.Channel.Name}] {m?.User.Name}: {m?.Message.Content}"; + } + } +} \ No newline at end of file diff --git a/src/Core/Logger/IDiscordLogger.cs b/Geekbot.net/Lib/Logger/IDiscordLogger.cs similarity index 76% rename from src/Core/Logger/IDiscordLogger.cs rename to Geekbot.net/Lib/Logger/IDiscordLogger.cs index c127e0c..fdc8c7f 100644 --- a/src/Core/Logger/IDiscordLogger.cs +++ b/Geekbot.net/Lib/Logger/IDiscordLogger.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using Discord; -namespace Geekbot.Core.Logger +namespace Geekbot.net.Lib.Logger { public interface IDiscordLogger { diff --git a/src/Core/Logger/IGeekbotLogger.cs b/Geekbot.net/Lib/Logger/IGeekbotLogger.cs similarity index 82% rename from src/Core/Logger/IGeekbotLogger.cs rename to Geekbot.net/Lib/Logger/IGeekbotLogger.cs index 1363629..1f76cb0 100644 --- a/src/Core/Logger/IGeekbotLogger.cs +++ b/Geekbot.net/Lib/Logger/IGeekbotLogger.cs @@ -1,6 +1,6 @@ using System; -namespace Geekbot.Core.Logger +namespace Geekbot.net.Lib.Logger { public interface IGeekbotLogger { @@ -9,7 +9,5 @@ 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(); - bool LogAsJson(); } } \ No newline at end of file diff --git a/Geekbot.net/Lib/Logger/LogDto.cs b/Geekbot.net/Lib/Logger/LogDto.cs new file mode 100644 index 0000000..8ccfcdf --- /dev/null +++ b/Geekbot.net/Lib/Logger/LogDto.cs @@ -0,0 +1,14 @@ +using System; + +namespace Geekbot.net.Lib.Logger +{ + 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/Geekbot.net/Lib/Logger/LogSource.cs b/Geekbot.net/Lib/Logger/LogSource.cs new file mode 100644 index 0000000..d9a8629 --- /dev/null +++ b/Geekbot.net/Lib/Logger/LogSource.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Geekbot.net.Lib.Logger +{ + [JsonConverter(typeof(StringEnumConverter))] + public enum LogSource + { + Geekbot, + Rest, + Gateway, + Discord, + Redis, + Message, + UserRepository, + Command, + Api, + Other + } +} \ No newline at end of file diff --git a/src/Core/Logger/LoggerFactory.cs b/Geekbot.net/Lib/Logger/LoggerFactory.cs similarity index 51% rename from src/Core/Logger/LoggerFactory.cs rename to Geekbot.net/Lib/Logger/LoggerFactory.cs index bf3d926..4095d00 100644 --- a/src/Core/Logger/LoggerFactory.cs +++ b/Geekbot.net/Lib/Logger/LoggerFactory.cs @@ -5,59 +5,62 @@ using NLog.Config; using NLog.Targets; using SumoLogic.Logging.NLog; -namespace Geekbot.Core.Logger +namespace Geekbot.net.Lib.Logger { public class LoggerFactory { - public static NLog.Logger CreateNLog(RunParameters runParameters) + public static NLog.Logger CreateNLog(RunParameters runParameters, bool sumologicActive) { var config = new LoggingConfiguration(); - var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; - if (!string.IsNullOrEmpty(runParameters.SumologicEndpoint)) + if (sumologicActive) { Console.WriteLine("Logging Geekbot Logs to Sumologic"); config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, + new LoggingRule("*", LogLevel.Debug, LogLevel.Fatal, new SumoLogicTarget() { - Url = runParameters.SumologicEndpoint, + Url = Environment.GetEnvironmentVariable("GEEKBOT_SUMO"), SourceName = "GeekbotLogger", Layout = "${message}", UseConsoleLog = false, OptimizeBufferReuse = true, - Name = "Geekbot" + Name = "Geekbot", + AppendException = false }) - ); - } - else if (runParameters.LogJson) - { - config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, - new ConsoleTarget - { - Name = "Console", - Encoding = Encoding.UTF8, - Layout = "${message}" - } - ) - ); + ); } else { + var minLevel = runParameters.Verbose ? LogLevel.Trace : LogLevel.Info; config.LoggingRules.Add( - new LoggingRule("*", minLevel, LogLevel.Fatal, + new LoggingRule("*", LogLevel.Info, LogLevel.Fatal, new ColoredConsoleTarget { Name = "Console", Encoding = Encoding.UTF8, Layout = "[${longdate} ${level:format=FirstCharacter}] ${message} ${exception:format=toString}" - } - ) - ); + }) + ); + + config.LoggingRules.Add( + new LoggingRule("*", minLevel, LogLevel.Fatal, + new FileTarget + { + Name = "File", + Layout = "[${longdate} ${level}] ${message}", + Encoding = Encoding.UTF8, + LineEnding = LineEndingMode.Default, + MaxArchiveFiles = 30, + ArchiveNumbering = ArchiveNumberingMode.Date, + ArchiveEvery = FileArchivePeriod.Day, + ArchiveFileName = "./Logs/Archive/{#####}.log", + FileName = "./Logs/Geekbot.log" + }) + ); } - - var loggerConfig = new LogFactory {Configuration = config}; + + var loggerConfig = new LogFactory { Configuration = config }; return loggerConfig.GetCurrentClassLogger(); } } diff --git a/src/Core/Logger/MessageDto.cs b/Geekbot.net/Lib/Logger/MessageDto.cs similarity index 92% rename from src/Core/Logger/MessageDto.cs rename to Geekbot.net/Lib/Logger/MessageDto.cs index 039024e..011acf3 100644 --- a/src/Core/Logger/MessageDto.cs +++ b/Geekbot.net/Lib/Logger/MessageDto.cs @@ -1,4 +1,4 @@ -namespace Geekbot.Core.Logger +namespace Geekbot.net.Lib.Logger { public class MessageDto { diff --git a/src/Core/Logger/SimpleConextConverter.cs b/Geekbot.net/Lib/Logger/SimpleConextConverter.cs similarity index 74% rename from src/Core/Logger/SimpleConextConverter.cs rename to Geekbot.net/Lib/Logger/SimpleConextConverter.cs index 23cee40..0845cc1 100644 --- a/src/Core/Logger/SimpleConextConverter.cs +++ b/Geekbot.net/Lib/Logger/SimpleConextConverter.cs @@ -1,7 +1,7 @@ using Discord.Commands; using Discord.WebSocket; -namespace Geekbot.Core.Logger +namespace Geekbot.net.Lib.Logger { public class SimpleConextConverter { @@ -11,7 +11,7 @@ namespace Geekbot.Core.Logger { Message = new MessageDto.MessageContent { - Content = context.Message.Content, // Only when an error occurs, including for diagnostic reason + Content = context.Message.Content, Id = context.Message.Id.ToString(), Attachments = context.Message.Attachments.Count, ChannelMentions = context.Message.MentionedChannelIds.Count, @@ -25,23 +25,24 @@ namespace Geekbot.Core.Logger }, Guild = new MessageDto.IdAndName { - Id = context.Guild?.Id.ToString(), - Name = context.Guild?.Name + Id = context.Guild.Id.ToString(), + Name = context.Guild.Name }, Channel = new MessageDto.IdAndName { - Id = context.Channel?.Id.ToString() ?? context.User.Id.ToString(), - Name = context.Channel?.Name ?? "DM-Channel" + Id = context.Channel.Id.ToString(), + Name = context.Channel.Name } }; } - public static MessageDto ConvertSocketMessage(SocketMessage message, bool isPrivate = false) + public static MessageDto ConvertSocketMessage(SocketMessage message) { - var channel = isPrivate ? null : (SocketGuildChannel) message.Channel; + var channel = (SocketGuildChannel) message.Channel; return new MessageDto { Message = new MessageDto.MessageContent { + Content = message.Content, Id = message.Id.ToString(), Attachments = message.Attachments.Count, ChannelMentions = message.MentionedChannels.Count, @@ -60,8 +61,8 @@ namespace Geekbot.Core.Logger }, Channel = new MessageDto.IdAndName { - Id = channel?.Id.ToString() ?? message.Author.Id.ToString(), - Name = channel?.Name ?? "DM-Channel" + Id = channel?.Id.ToString(), + Name = channel?.Name } }; } diff --git a/src/Core/Media/FortunesProvider.cs b/Geekbot.net/Lib/Media/FortunesProvider.cs similarity index 85% rename from src/Core/Media/FortunesProvider.cs rename to Geekbot.net/Lib/Media/FortunesProvider.cs index 1b0d87a..56b5ed6 100644 --- a/src/Core/Media/FortunesProvider.cs +++ b/Geekbot.net/Lib/Media/FortunesProvider.cs @@ -1,10 +1,10 @@ using System; using System.IO; -using Geekbot.Core.Logger; +using Geekbot.net.Lib.Logger; -namespace Geekbot.Core.Media +namespace Geekbot.net.Lib.Media { - public class FortunesProvider : IFortunesProvider + internal class FortunesProvider : IFortunesProvider { private readonly string[] _fortuneArray; private readonly int _totalFortunes; diff --git a/src/Core/Media/IFortunesProvider.cs b/Geekbot.net/Lib/Media/IFortunesProvider.cs similarity index 68% rename from src/Core/Media/IFortunesProvider.cs rename to Geekbot.net/Lib/Media/IFortunesProvider.cs index a4ef0d9..c82e45c 100644 --- a/src/Core/Media/IFortunesProvider.cs +++ b/Geekbot.net/Lib/Media/IFortunesProvider.cs @@ -1,4 +1,4 @@ -namespace Geekbot.Core.Media +namespace Geekbot.net.Lib.Media { public interface IFortunesProvider { diff --git a/Geekbot.net/Lib/Media/IMediaProvider.cs b/Geekbot.net/Lib/Media/IMediaProvider.cs new file mode 100644 index 0000000..79c6c98 --- /dev/null +++ b/Geekbot.net/Lib/Media/IMediaProvider.cs @@ -0,0 +1,14 @@ +namespace Geekbot.net.Lib.Media +{ + public interface IMediaProvider + { + string GetCheckem(); + string GetPanda(); + string GetCrossant(); + string GetSquirrel(); + string GetPumpkin(); + string GetTurtle(); + string GetPinguin(); + string GetFox(); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Media/MediaProvider.cs b/Geekbot.net/Lib/Media/MediaProvider.cs new file mode 100644 index 0000000..7f883ae --- /dev/null +++ b/Geekbot.net/Lib/Media/MediaProvider.cs @@ -0,0 +1,133 @@ +using System; +using System.IO; +using Geekbot.net.Lib.Logger; + +namespace Geekbot.net.Lib.Media +{ + public class MediaProvider : IMediaProvider + { + private readonly Random _random; + private readonly IGeekbotLogger _logger; + private string[] _checkemImages; + private string[] _pandaImages; + private string[] _croissantImages; + private string[] _squirrelImages; + private string[] _pumpkinImages; + private string[] _turtlesImages; + private string[] _pinguinImages; + private string[] _foxImages; + + public MediaProvider(IGeekbotLogger logger) + { + _random = new Random(); + _logger = logger; + + logger.Information(LogSource.Geekbot, "Loading Media Files"); + + LoadCheckem(); + LoadPandas(); + BakeCroissants(); + LoadSquirrels(); + LoadPumpkins(); + LoadTurtles(); + LoadPinguins(); + LoadFoxes(); + } + + private void LoadCheckem() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/checkEmPics")); + _checkemImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_checkemImages.Length} CheckEm Images"); + } + + private void LoadPandas() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pandas")); + _pandaImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_pandaImages.Length} Panda Images"); + } + + private void BakeCroissants() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/croissant")); + _croissantImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_croissantImages.Length} Croissant Images"); + } + + private void LoadSquirrels() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/squirrel")); + _squirrelImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_squirrelImages.Length} Squirrel Images"); + } + + private void LoadPumpkins() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pumpkin")); + _pumpkinImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_pumpkinImages.Length} Pumpkin Images"); + } + + private void LoadTurtles() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/turtles")); + _turtlesImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_turtlesImages.Length} Turtle Images"); + } + + private void LoadPinguins() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pinguins")); + _pinguinImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_pinguinImages.Length} Pinguin Images"); + } + + private void LoadFoxes() + { + var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/foxes")); + _foxImages = rawLinks.Split("\n"); + _logger.Trace(LogSource.Geekbot, $"Loaded {_foxImages.Length} Foxes Images"); + } + + public string GetCheckem() + { + return _checkemImages[_random.Next(0, _checkemImages.Length)]; + } + + public string GetPanda() + { + return _pandaImages[_random.Next(0, _pandaImages.Length)]; + } + + public string GetCrossant() + { + return _croissantImages[_random.Next(0, _croissantImages.Length)]; + } + + public string GetSquirrel() + { + return _squirrelImages[_random.Next(0, _squirrelImages.Length)]; + } + + public string GetPumpkin() + { + return _pumpkinImages[_random.Next(0, _pumpkinImages.Length)]; + } + + public string GetTurtle() + { + return _turtlesImages[_random.Next(0, _turtlesImages.Length)]; + } + + public string GetPinguin() + { + return _pinguinImages[_random.Next(0, _pinguinImages.Length)]; + } + + public string GetFox() + { + return _foxImages[_random.Next(0, _foxImages.Length)]; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/Polyfills/UserPolyfillDto.cs b/Geekbot.net/Lib/Polyfills/UserPolyfillDto.cs new file mode 100644 index 0000000..568bdd7 --- /dev/null +++ b/Geekbot.net/Lib/Polyfills/UserPolyfillDto.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Discord; + +namespace Geekbot.net.Lib.Polyfills +{ + internal class UserPolyfillDto : IUser + { + public ulong Id { get; set; } + public DateTimeOffset CreatedAt { get; set; } + public string Mention { get; set; } + public IActivity Activity { get; } + public UserStatus Status { get; set; } + public string AvatarId { 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 string GetAvatarUrl(ImageFormat format = ImageFormat.Auto, ushort size = 128) + { + return "https://discordapp.com/assets/6debd47ed13483642cf09e832ed0bc1b.png"; + } + + public Task GetOrCreateDMChannelAsync(RequestOptions options = null) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/ReactionListener/IReactionListener.cs b/Geekbot.net/Lib/ReactionListener/IReactionListener.cs new file mode 100644 index 0000000..792a516 --- /dev/null +++ b/Geekbot.net/Lib/ReactionListener/IReactionListener.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Discord; +using Discord.WebSocket; + +namespace Geekbot.net.Lib.ReactionListener +{ + public interface IReactionListener + { + bool IsListener(ulong id); + Task AddRoleToListener(string messageId, IEmote emoji, IRole role); + void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction); + void GiveRole(ISocketMessageChannel message, SocketReaction reaction); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/ReactionListener/ReactionListener.cs b/Geekbot.net/Lib/ReactionListener/ReactionListener.cs new file mode 100644 index 0000000..950edd1 --- /dev/null +++ b/Geekbot.net/Lib/ReactionListener/ReactionListener.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Discord; +using Discord.WebSocket; +using StackExchange.Redis; + +namespace Geekbot.net.Lib.ReactionListener +{ + public class ReactionListener : IReactionListener + { + private readonly IDatabase _database; + private Dictionary> _listener; + + public ReactionListener(IDatabase database) + { + _database = database; + LoadListeners(); + } + + private Task LoadListeners() + { + var ids = _database.SetMembers("MessageIds"); + _listener = new Dictionary>(); + foreach (var id in ids) + { + var reactions = _database.HashGetAll($"Messages:{id}"); + var messageId = id; + var emojiDict = new Dictionary(); + foreach (var r in reactions) + { + IEmote emote; + if (!r.Name.ToString().StartsWith('<')) + { + var emo = new Emoji(r.Name); + emote = emo; + } + else + { + emote = Emote.Parse(r.Name); + } + emojiDict.Add(emote, ulong.Parse(r.Value)); + } + _listener.Add(messageId, emojiDict); + } + + return Task.CompletedTask; + } + + public bool IsListener(ulong id) + { + return _listener.ContainsKey(id.ToString()); + } + + public Task AddRoleToListener(string messageId, IEmote emoji, IRole role) + { + if (_database.SetMembers("MessageIds").All(e => e.ToString() != messageId)) + { + _database.SetAdd("MessageIds", messageId); + } + _database.HashSet($"Messages:{messageId}", new[] {new HashEntry(emoji.ToString(), role.Id.ToString())}); + _database.SetAdd("MessageIds", messageId); + if (_listener.ContainsKey(messageId)) + { + _listener[messageId].Add(emoji, role.Id); + return Task.CompletedTask; + } + var dict = new Dictionary(); + dict.Add(emoji, role.Id); + _listener.Add(messageId, dict); + return Task.CompletedTask; + } + + public async void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction) + { + var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote]; + var guild = (SocketGuildChannel) channel; + var role = guild.Guild.GetRole(roleId); + await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role); + } + + public async void GiveRole(ISocketMessageChannel channel, SocketReaction reaction) + { + var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote]; + var guild = (SocketGuildChannel) channel; + var role = guild.Guild.GetRole(roleId); + await ((IGuildUser) reaction.User.Value).AddRoleAsync(role); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/RunParameters.cs b/Geekbot.net/Lib/RunParameters.cs new file mode 100644 index 0000000..35c1a2a --- /dev/null +++ b/Geekbot.net/Lib/RunParameters.cs @@ -0,0 +1,26 @@ +using System; +using CommandLine; + +namespace Geekbot.net.Lib +{ + public class RunParameters + { + [Option('V', "verbose", Default = false, HelpText = "Prints all messages to standard output.")] + public bool Verbose { get; set; } + + [Option('r', "reset", Default = false, HelpText = "Resets the bot")] + public bool Reset { get; set; } + + [Option('j', "log-json", Default = false, HelpText = "Logs messages as json")] + public bool LogJson { get; set; } + + [Option("disable-api", Default = false, HelpText = "Disables the web api")] + public bool DisableApi { get; set; } + + [Option('e', "expose-errors", Default = false, HelpText = "Shows internal errors in the chat")] + public bool ExposeErrors { get; set; } + + [Option("token", Default = null, HelpText = "Set a new bot token")] + public string Token { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/UserRepository/IUserRepository.cs b/Geekbot.net/Lib/UserRepository/IUserRepository.cs new file mode 100644 index 0000000..9466621 --- /dev/null +++ b/Geekbot.net/Lib/UserRepository/IUserRepository.cs @@ -0,0 +1,13 @@ +using System.Threading.Tasks; +using Discord.WebSocket; + +namespace Geekbot.net.Lib.UserRepository +{ + public interface IUserRepository + { + Task Update(SocketUser user); + UserRepositoryUser Get(ulong userId); + string GetUserSetting(ulong userId, string setting); + bool SaveUserSetting(ulong userId, string setting, string value); + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/UserRepository/UserRepository.cs b/Geekbot.net/Lib/UserRepository/UserRepository.cs new file mode 100644 index 0000000..3937107 --- /dev/null +++ b/Geekbot.net/Lib/UserRepository/UserRepository.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Discord.WebSocket; +using Geekbot.net.Lib.Logger; +using StackExchange.Redis; +using Utf8Json; + +namespace Geekbot.net.Lib.UserRepository +{ + public class UserRepository : IUserRepository + { + private readonly IDatabase _redis; + private readonly IGeekbotLogger _logger; + public UserRepository(IDatabase redis, IGeekbotLogger logger) + { + _redis = redis; + _logger = logger; + } + + public Task Update(SocketUser user) + { + try + { + var savedUser = Get(user.Id); + savedUser.Id = user.Id; + savedUser.Username = user.Username; + savedUser.Discriminator = user.Discriminator; + savedUser.AvatarUrl = user.GetAvatarUrl() ?? "0"; + savedUser.IsBot = user.IsBot; + savedUser.Joined = user.CreatedAt; + if(savedUser.UsedNames == null) savedUser.UsedNames = new List(); + if (!savedUser.UsedNames.Contains(user.Username)) + { + savedUser.UsedNames.Add(user.Username); + } + Store(savedUser); + + _logger.Information(LogSource.UserRepository, "Updated User", savedUser); + return Task.FromResult(true); + } + catch (Exception e) + { + _logger.Warning(LogSource.UserRepository, $"Failed to update user: {user.Username}#{user.Discriminator} ({user.Id})", e); + return Task.FromResult(false); + } + } + + private void Store(UserRepositoryUser user) + { + _redis.HashSetAsync($"Users:{user.Id.ToString()}", new[] + { + new HashEntry("Id", user.Id.ToString()), + new HashEntry("Username", user.Username), + new HashEntry("Discriminator", user.Discriminator), + new HashEntry("AvatarUrl", user.AvatarUrl), + new HashEntry("IsBot", user.IsBot), + new HashEntry("Joined", user.Joined.ToString()), + new HashEntry("UsedNames", JsonSerializer.Serialize(user.UsedNames)) + }); + } + + public UserRepositoryUser Get(ulong userId) + { + try + { + var user = _redis.HashGetAll($"Users:{userId.ToString()}"); + for (var i = 1; i < 11; i++) + { + if (user.Length != 0) break; + user = _redis.HashGetAll($"Users:{(userId + (ulong) i).ToString()}"); + + } + var dto = new UserRepositoryUser(); + foreach (var a in user.ToDictionary()) + { + switch (a.Key) + { + case "Id": + dto.Id = ulong.Parse(a.Value); + break; + case "Username": + dto.Username = a.Value.ToString(); + break; + case "Discriminator": + dto.Discriminator = a.Value.ToString(); + break; + case "AvatarUrl": + dto.AvatarUrl = a.Value != "0" ? a.Value.ToString() : null; + break; + case "IsBot": + dto.IsBot = a.Value == 1; + break; + case "Joined": + dto.Joined = DateTimeOffset.Parse(a.Value.ToString()); + break; + case "UsedNames": + dto.UsedNames = JsonSerializer.Deserialize>(a.Value.ToString()) ?? new List(); + break; + } + } + return dto; + } + catch (Exception e) + { + _logger.Warning(LogSource.UserRepository, $"Failed to get {userId} from repository", e); + return new UserRepositoryUser(); + } + } + + public string GetUserSetting(ulong userId, string setting) + { + return _redis.HashGet($"Users:{userId}", setting); + } + + public bool SaveUserSetting(ulong userId, string setting, string value) + { + _redis.HashSet($"Users:{userId}", new[] + { + new HashEntry(setting, value) + }); + return true; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Lib/UserRepository/UserRepositoryUserDto.cs b/Geekbot.net/Lib/UserRepository/UserRepositoryUserDto.cs new file mode 100644 index 0000000..4af719b --- /dev/null +++ b/Geekbot.net/Lib/UserRepository/UserRepositoryUserDto.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; + +namespace Geekbot.net.Lib.UserRepository +{ + public class UserRepositoryUser + { + public ulong Id { get; set; } + public string Username { get; set; } + public string Discriminator { get; set; } + public string AvatarUrl { get; set; } + public bool IsBot { get; set; } + public DateTimeOffset Joined { get; set; } + public List UsedNames { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/Logs/.keep b/Geekbot.net/Logs/.keep new file mode 100755 index 0000000..e69de29 diff --git a/Geekbot.net/Program.cs b/Geekbot.net/Program.cs new file mode 100755 index 0000000..3a35d19 --- /dev/null +++ b/Geekbot.net/Program.cs @@ -0,0 +1,224 @@ +using System; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using CommandLine; +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Audio; +using Geekbot.net.Lib.Clients; +using Geekbot.net.Lib.Converters; +using Geekbot.net.Lib.ErrorHandling; +using Geekbot.net.Lib.Levels; +using Geekbot.net.Lib.Localization; +using Geekbot.net.Lib.Logger; +using Geekbot.net.Lib.Media; +using Geekbot.net.Lib.ReactionListener; +using Geekbot.net.Lib.UserRepository; +using Microsoft.Extensions.DependencyInjection; +using Nancy.Hosting.Self; +using StackExchange.Redis; +using WikipediaApi; + +namespace Geekbot.net +{ + internal class Program + { + private DiscordSocketClient _client; + private CommandService _commands; + private IDatabase _redis; + private IServiceCollection _services; + private IServiceProvider _servicesProvider; + private RedisValue _token; + private GeekbotLogger _logger; + private IUserRepository _userRepository; + private bool _firstStart; + private RunParameters _runParameters; + + private static void 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("========================================="); + Console.WriteLine(logo.ToString()); + var sumologicActive = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GEEKBOT_SUMO")); + var logger = new GeekbotLogger(runParameters, sumologicActive); + logger.Information(LogSource.Geekbot, "Starting..."); + try + { + new Program().MainAsync(runParameters, logger).GetAwaiter().GetResult(); + } + catch (Exception e) + { + logger.Error(LogSource.Geekbot, "RIP", e); + } + } + + private async Task MainAsync(RunParameters runParameters, GeekbotLogger logger) + { + _logger = logger; + _runParameters = runParameters; + logger.Information(LogSource.Geekbot, "Initing Stuff"); + var discordLogger = new DiscordLogger(logger); + + _client = new DiscordSocketClient(new DiscordSocketConfig + { + LogLevel = LogSeverity.Verbose, + MessageCacheSize = 1000 + }); + _client.Log += discordLogger.Log; + _commands = new CommandService(); + + try + { + var redisMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1:6379"); + _redis = redisMultiplexer.GetDatabase(6); + logger.Information(LogSource.Redis, $"Connected to db {_redis.Database}"); + } + catch (Exception e) + { + logger.Error(LogSource.Redis, "Redis Connection Failed", e); + Environment.Exit(GeekbotExitCode.RedisConnectionFailed.GetHashCode()); + } + + _token = runParameters.Token ?? _redis.StringGet("discordToken"); + if (_token.IsNullOrEmpty) + { + Console.Write("Your bot Token: "); + var newToken = Console.ReadLine(); + _redis.StringSet("discordToken", newToken); + _redis.StringSet("Game", "Ping Pong"); + _token = newToken; + _firstStart = true; + } + + _services = new ServiceCollection(); + + _userRepository = new UserRepository(_redis, logger); + var fortunes = new FortunesProvider(logger); + var mediaProvider = new MediaProvider(logger); + var malClient = new MalClient(_redis, logger); + var levelCalc = new LevelCalc(); + var emojiConverter = new EmojiConverter(); + var mtgManaConverter = new MtgManaConverter(); + var wikipediaClient = new WikipediaClient(); + var audioUtils = new AudioUtils(); + + _services.AddSingleton(_redis); + _services.AddSingleton(_userRepository); + _services.AddSingleton(logger); + _services.AddSingleton(levelCalc); + _services.AddSingleton(emojiConverter); + _services.AddSingleton(fortunes); + _services.AddSingleton(mediaProvider); + _services.AddSingleton(malClient); + _services.AddSingleton(mtgManaConverter); + _services.AddSingleton(wikipediaClient); + _services.AddSingleton(audioUtils); + + logger.Information(LogSource.Geekbot, "Connecting to Discord"); + + await Login(); + + await Task.Delay(-1); + } + + private async Task Login() + { + try + { + await _client.LoginAsync(TokenType.Bot, _token); + await _client.StartAsync(); + var isConneted = await IsConnected(); + if (isConneted) + { + await _client.SetGameAsync(_redis.StringGet("Game")); + _logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers"); + + _logger.Information(LogSource.Geekbot, "Registering Stuff"); + var translationHandler = new TranslationHandler(_client.Guilds, _redis, _logger); + var errorHandler = new ErrorHandler(_logger, translationHandler, _runParameters.ExposeErrors); + var reactionListener = new ReactionListener(_redis); + await _commands.AddModulesAsync(Assembly.GetEntryAssembly()); + _services.AddSingleton(_commands); + _services.AddSingleton(errorHandler); + _services.AddSingleton(translationHandler); + _services.AddSingleton(_client); + _services.AddSingleton(reactionListener); + _servicesProvider = _services.BuildServiceProvider(); + + var handlers = new Handlers(_client, _logger, _redis, _servicesProvider, _commands, _userRepository, reactionListener); + + _client.MessageReceived += handlers.RunCommand; + _client.MessageReceived += handlers.UpdateStats; + _client.MessageDeleted += handlers.MessageDeleted; + _client.UserJoined += handlers.UserJoined; + _client.UserUpdated += handlers.UserUpdated; + _client.UserLeft += handlers.UserLeft; + _client.ReactionAdded += handlers.ReactionAdded; + _client.ReactionRemoved += handlers.ReactionRemoved; + + if (_firstStart || _runParameters.Reset) + { + _logger.Information(LogSource.Geekbot, "Finishing setup"); + await FinishSetup(); + _logger.Information(LogSource.Geekbot, "Setup finished"); + } + if (!_runParameters.DisableApi) + { + StartWebApi(); + } + + _logger.Information(LogSource.Geekbot, "Done and ready for use"); + } + } + catch (Exception e) + { + _logger.Error(LogSource.Geekbot, "Could not connect...", e); + Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode()); + } + } + + private async Task IsConnected() + { + while (!_client.ConnectionState.Equals(ConnectionState.Connected)) + await Task.Delay(25); + return true; + } + + private void StartWebApi() + { + _logger.Information(LogSource.Api, "Starting Webserver"); + var webApiUrl = new Uri("http://localhost:12995"); + new NancyHost(webApiUrl).Start(); + _logger.Information(LogSource.Api, $"Webserver now running on {webApiUrl}"); + } + + private async Task FinishSetup() + { + try + { + // ToDo: Set bot avatar + var appInfo = await _client.GetApplicationInfoAsync(); + _redis.StringSet("botOwner", appInfo.Owner.Id); + } + catch (Exception e) + { + _logger.Warning(LogSource.Geekbot, "Setup Failed, couldn't retrieve discord application data", e); + } + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/Storage/checkEmPics b/Geekbot.net/Storage/checkEmPics new file mode 100644 index 0000000..03be23e --- /dev/null +++ b/Geekbot.net/Storage/checkEmPics @@ -0,0 +1,122 @@ +http://s19.postimg.org/pcq2kwzoj/4cb.png +http://s19.postimg.org/cvetk0f4z/5_Dim_Dy6p.jpg +http://s19.postimg.org/5hzfl1v37/1310151998600.jpg +http://s19.postimg.org/53y3lgazn/1324181141954.jpg +http://s19.postimg.org/724rjg3hf/1392512742365.png +http://s19.postimg.org/3rgejkdk3/1393501296733.png +http://s19.postimg.org/a6ffg8k9v/1401667341503.jpg +http://s19.postimg.org/qiph5yylf/1419231572452.jpg +http://s19.postimg.org/fqwi4m8ir/1427600681401.png +http://s19.postimg.org/4c00zzw6b/1447813628974.png +http://s19.postimg.org/uuio8puw3/b5_3q_ycaaavxtf.jpg +http://s19.postimg.org/bghu913fn/check_em_by_boyboy99100_d57xp3y.png +http://s19.postimg.org/s1pgooujn/l_Hkppjs.jpg +http://s19.postimg.org/m08itft0j/checkem.jpg +https://old.postimg.org/image/6vx33rb1b/ +https://old.postimg.org/image/wxiaz1mov/ +https://old.postimg.org/image/azqfizx27/ +https://old.postimg.org/image/6iy2kbiu7/ +https://old.postimg.org/image/k8slt45y7/ +https://old.postimg.org/image/t7ruxmplr/ +https://old.postimg.org/image/ssbzqvean/ +https://old.postimg.org/image/kbchfy9lr/ +https://old.postimg.org/image/dl0lk9btr/ +https://old.postimg.org/image/e5k80oufz/ +https://old.postimg.org/image/er005baqn/ +https://old.postimg.org/image/bfk2uzcin/ +https://old.postimg.org/image/556fp0jkv/ +https://old.postimg.org/image/i0efbryu7/ +https://old.postimg.org/image/943n7u87z/ +https://old.postimg.org/image/xn5op5cm7/ +https://old.postimg.org/image/3l5p4d0kf/ +https://old.postimg.org/image/5boq5ui3j/ +https://old.postimg.org/image/ru082bqcf/ +https://old.postimg.org/image/ytea1oqan/ +https://old.postimg.org/image/vu7dekgtb/ +https://old.postimg.org/image/hl7qwi2an/ +https://old.postimg.org/image/5aescfg9r/ +https://old.postimg.org/image/9gzmrrfvj/ +https://old.postimg.org/image/50bv6tr1b/ +https://old.postimg.org/image/afkl7silb/ +https://old.postimg.org/image/nrdsgzllr/ +https://old.postimg.org/image/s32e5zsin/ +https://old.postimg.org/image/5sej60v8f/ +https://old.postimg.org/image/lgfqctau7/ +https://old.postimg.org/image/tn7q4e0wv/ +https://old.postimg.org/image/8612arz1b/ +https://old.postimg.org/image/w5tf52mn3/ +https://old.postimg.org/image/zdxwi48wv/ +https://old.postimg.org/image/lphwghd0f/ +https://old.postimg.org/image/uzu0k0nq7/ +https://old.postimg.org/image/3vqzsxjbz/ +https://old.postimg.org/image/5d7uqqyov/ +https://old.postimg.org/image/dntnyku8v/ +https://old.postimg.org/image/dsxf891jz/ +https://old.postimg.org/image/3nyrioizj/ +https://old.postimg.org/image/6zx2bzaqn/ +https://old.postimg.org/image/wu6v1raqn/ +https://old.postimg.org/image/hb9f4n2fz/ +https://old.postimg.org/image/p7yhqm3a7/ +https://old.postimg.org/image/oelvxzx9b/ +https://old.postimg.org/image/vcq03xvdr/ +https://old.postimg.org/image/b08t1yqlb/ +https://old.postimg.org/image/6yrpwayan/ +https://old.postimg.org/image/btleukwm7/ +https://old.postimg.org/image/62ztuldzz/ +https://old.postimg.org/image/w3iq9pxr3/ +https://old.postimg.org/image/byp6493xb/ +https://old.postimg.org/image/xp2lf9xcv/ +https://old.postimg.org/image/j9p9u49pb/ +https://old.postimg.org/image/hvxmytafz/ +https://old.postimg.org/image/5eqzbnfa7/ +https://old.postimg.org/image/do2uq290f/ +https://old.postimg.org/image/54o261q1r/ +https://old.postimg.org/image/94qm4jr4v/ +https://old.postimg.org/image/lee88y0pr/ +https://old.postimg.org/image/bncb58cv3/ +https://old.postimg.org/image/5246j7me7/ +https://old.postimg.org/image/4uby8ym1r/ +https://old.postimg.org/image/qn996tj4v/ +https://old.postimg.org/image/c1dn4twyn/ +https://old.postimg.org/image/6rd9ra23j/ +https://lehcark14.files.wordpress.com/2008/08/botan16.jpg +http://i.imgur.com/p9vALew.jpg +http://i.imgur.com/4a9l2Rm.png +http://i.imgur.com/RNtixMQ.jpg +https://pbs.twimg.com/media/Cro9aIGUEAAkXCP.jpg +http://s16.postimg.org/empvloimd/Check_em_Guts.png +https://s18.postimg.io/qgbhe7u09/1424491645996.gif +http://s19.postimg.org/hhemlt7xf/3eb.jpg +http://s19.postimg.org/cwsg6vo83/8aa.png +http://s19.postimg.org/rh9j1pj6r/28mohl4.png +http://s19.postimg.org/zba4n3qzn/86d.jpg +http://s19.postimg.org/cb3hart5v/2016_09_16_08_58_45.png +http://s19.postimg.org/m9ofx92lf/bb1.jpg +http://s19.postimg.org/maydqo4f7/e8b.jpg +http://s19.postimg.org/yqzoy5n4z/fbe.png +http://s19.postimg.org/xd822unvn/giphy.gif +http://s19.postimg.org/c4udlf9er/l_TU3eup.jpg +https://66.media.tumblr.com/cc893a0ee40d73d083da3df4bdaf45cc/tumblr_mx8psiFduG1t1g1k8o1_500.gif +http://i.imgur.com/swbXHSy.gif +http://img1.reactor.cc/pics/post/full/Anime-Touhou-Project-Yakumo-Yukari-%D0%A0%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F-1303807.jpeg +http://i.imgur.com/ftGLHE0.png +http://i.imgur.com/JELDhKQ.png +http://imgur.com/yBJound +http://i.imgur.com/f7gAVPJ.png +http://i.imgur.com/HxWyo2Z.jpg +http://i.imgur.com/8Eb9CxQ.png +http://i.imgur.com/kOECcjz.png +http://i.imgur.com/MJLu7oJ.jpg +http://i.imgur.com/itG3rPM.jpg +http://i.imgur.com/G83Go9t.jpg +http://i.imgur.com/jI2dBnU.jpg +http://i.imgur.com/FtALzg0.jpg +http://i.imgur.com/GwZpJEv.gif +http://i.imgur.com/TYGRD3B.gif +http://i.imgur.com/P6TxLS3.png +http://i.imgur.com/phTVTdn.jpg +http://i.imgur.com/thhR6UE.jpg +http://i.imgur.com/KbROufx.jpg +http://i.imgur.com/sQqWbcm.jpg +http://i.imgur.com/YYpis53.png +http://i.imgur.com/kwaRd54.gif \ No newline at end of file diff --git a/Geekbot.net/Storage/croissant b/Geekbot.net/Storage/croissant new file mode 100644 index 0000000..281b790 --- /dev/null +++ b/Geekbot.net/Storage/croissant @@ -0,0 +1,17 @@ +https://i2.wp.com/epicureandculture.com/wp-content/uploads/2014/12/shutterstock_172040546.jpg +http://www.bakespace.com/images/large/5d79070cf21b2f33c3a1dd4336cb27d2.jpeg +http://food.fnr.sndimg.com/content/dam/images/food/fullset/2015/5/7/1/SD1B43_croissants-recipe_s4x3.jpg.rend.hgtvcom.616.462.suffix/1431052139248.jpeg +http://img.taste.com.au/u-Bwjfm_/taste/2016/11/mini-croissants-with-3-fillings-14692-1.jpeg +https://media.newyorker.com/photos/590974702179605b11ad8096/16:9/w_1200,h_630,c_limit/Gopnik-TheMurkyMeaningsofStraightenedOutCroissants.jpg +http://bt.static-redmouse.ch/sites/bielertagblatt.ch/files/styles/bt_article_showroom_landscape/hash/84/c9/84c9aed08415265911ec05c46d25d3ef.jpg?itok=hP5PnHaT +https://www.dermann.at/wp-content/uploads/Schokocroissant_HPBild_1400x900px.jpeg +https://www.bettybossi.ch/static/rezepte/x/bb_bkxx060101_0360a_x.jpg +http://www.engel-beck.ch/uploads/pics/tete-de-moine-gipfel-.jpg +https://storage.cpstatic.ch/storage/og_image/laugengipfel--425319.jpg +https://www.backhaus-kutzer.de/fileadmin/templates/Resources/Public/img/produkte/suesses-gebaeck/Milchhoernchen.png +https://www.kuechengoetter.de/uploads/media/1000x524/00/36390-vanillekipferl-0.jpg?v=1-0 +https://c1.staticflickr.com/3/2835/10874180753_2b2916e3ce_b.jpg +http://www.mistercool.ch/wp-content/uploads/2017/02/Gipfel-mit-Cerealien-7168.png +https://scontent-sea1-1.cdninstagram.com/t51.2885-15/s480x480/e35/c40.0.999.999/15099604_105396696611384_2866237281000226816_n.jpg?ig_cache_key=MTM4MzQxOTU1MDc5NjUxNzcwMA%3D%3D.2.c +http://www.lecrobag.de/wp-content/uploads/2014/03/Wurst_2014_l.jpg +https://www.thecookierookie.com/wp-content/uploads/2017/02/sheet-pan-chocolate-croissants-collage1.jpeg \ No newline at end of file diff --git a/src/Bot/Storage/fortunes b/Geekbot.net/Storage/fortunes similarity index 100% rename from src/Bot/Storage/fortunes rename to Geekbot.net/Storage/fortunes diff --git a/Geekbot.net/Storage/foxes b/Geekbot.net/Storage/foxes new file mode 100644 index 0000000..020c1cf --- /dev/null +++ b/Geekbot.net/Storage/foxes @@ -0,0 +1,29 @@ +https://i.ytimg.com/vi/qF6OOGuT_hI/maxresdefault.jpg +https://www.hd-wallpapersdownload.com/script/bulk-upload/desktop-funny-fox-wallpaper.jpg +http://moziru.com/images/drawn-fox-funny-18.jpg +https://static.tumblr.com/bb34d8f163098ad1daafcffbdbb03975/rk23uap/Nwwp0rmi2/tumblr_static_tumblr_static__640.jpg +https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoHUFOnZ3wJ2kT1skNdztFXXSvpU8bEoGS1alNZiuyLXvGJhcY +http://childrenstorytales.com/wp-content/uploads/2011/03/how-to-draw-a-red-fox-in-the-snow.jpg +https://www.popsci.com/sites/popsci.com/files/styles/1000_1x_/public/import/2013/images/2013/09/redfoxyawn.jpg?itok=yRkSVe8T +https://hdqwalls.com/wallpapers/wild-fox-art.jpg +https://ae01.alicdn.com/kf/HTB1Q9dpLpXXXXbhXpXXq6xXFXXXl/new-cute-fox-toy-lifelike-soft-long-yellow-fox-doll-gift-about-73cm.jpg_640x640.jpg +https://i.imgur.com/ktK9yXX.jpg +https://res.cloudinary.com/teepublic/image/private/s--yTx2ncFA--/t_Preview/b_rgb:c8e0ec,c_limit,f_auto,h_313,q_90,w_313/v1506478249/production/designs/1932607_0 +http://4.bp.blogspot.com/-Hz-o_KYj3Xk/Vlm2mwbztjI/AAAAAAAA8Ss/jbH5ovjmC9A/s1600/ScreenShot5502.jpg +https://i.pinimg.com/originals/1e/d5/2f/1ed52f70873a95ac02fa074e48edfb71.jpg +https://i.imgur.com/2vCrtap.jpg +https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSfukWGu_IBaDeJOMBqOhVAwsDfqEPw0BFpCn5_-Iyr_xjd7zi9 +https://cdn.pixabay.com/photo/2017/01/31/18/36/animal-2026297_960_720.png +https://i.pinimg.com/originals/e2/63/67/e26367a0844633b2a697b0a9d69e8cc9.jpg +https://i.ebayimg.com/images/g/BvkAAOSwqxdTqrip/s-l300.jpg +https://res.cloudinary.com/teepublic/image/private/s--1R53bger--/t_Preview/b_rgb:eae0c7,c_limit,f_jpg,h_630,q_90,w_630/v1481013120/production/designs/914528_1.jpg +https://i.pinimg.com/originals/97/fe/69/97fe698462afde7b4209ccefeecbce71.jpg +https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT6G0ch6g-wG1TuDJ6BbkOFelMNnkgFXC6CxOw7qSNjoFkx-BCe +https://wallpaperscraft.com/image/fox_forest_grass_117190_540x960.jpg +https://image.freepik.com/free-vector/cartoon-flat-illustration-funny-cute-fox_6317-1174.jpg +https://orig00.deviantart.net/2feb/f/2013/137/a/f/fox_and_curious_squirrel_by_tamarar-d65ju8d.jpg +https://res.cloudinary.com/teepublic/image/private/s--dICeNmBx--/t_Preview/b_rgb:6e2229,c_limit,f_jpg,h_630,q_90,w_630/v1505243196/production/designs/1890493_1.jpg +https://vignette.wikia.nocookie.net/puppyinmypocketfanon/images/4/49/L-Baby-Fox.jpg/revision/latest?cb=20130421001806 +http://7-themes.com/data_images/out/69/7009194-fox-puppy.jpg +http://www.tehcute.com/pics/201401/little-fox-big.jpg +https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR6QXB1APLdUsyzO39kPvhnC9cOvcwzEtsxown9QjWilWppia2mwg \ No newline at end of file diff --git a/src/Bot/Storage/pandas b/Geekbot.net/Storage/pandas similarity index 78% rename from src/Bot/Storage/pandas rename to Geekbot.net/Storage/pandas index 6c6d725..9d5046c 100644 --- a/src/Bot/Storage/pandas +++ b/Geekbot.net/Storage/pandas @@ -4,9 +4,8 @@ https://nationalzoo.si.edu/sites/default/files/styles/slide_1400x700/public/supp https://media4.s-nbcnews.com/j/newscms/2016_36/1685951/ss-160826-twip-05_8cf6d4cb83758449fd400c7c3d71aa1f.nbcnews-ux-2880-1000.jpg https://ichef-1.bbci.co.uk/news/660/cpsprodpb/169F6/production/_91026629_gettyimages-519508400.jpg https://cdn.history.com/sites/2/2017/03/GettyImages-157278376.jpg +https://www.pandasinternational.org/wptemp/wp-content/uploads/2012/10/slider1.jpg https://tctechcrunch2011.files.wordpress.com/2015/11/panda.jpg http://www.nationalgeographic.com/content/dam/magazine/rights-exempt/2016/08/departments/panda-mania-12.jpg http://animals.sandiegozoo.org/sites/default/files/2016-09/panda1_10.jpg -http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Mammals/A-G/giant-panda-eating.adapt.945.1.jpg -https://static.independent.co.uk/s3fs-public/thumbnails/image/2015/10/08/15/Hong-Kong-pandas.jpg -https://3sn4dm1qd6i72l8a4r2ig7fl-wpengine.netdna-ssl.com/wp-content/uploads/2016/11/panda_lunlun_ZA_2083-b.jpg \ No newline at end of file +http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Mammals/A-G/giant-panda-eating.adapt.945.1.jpg \ No newline at end of file diff --git a/Geekbot.net/Storage/pinguins b/Geekbot.net/Storage/pinguins new file mode 100644 index 0000000..631f9d0 --- /dev/null +++ b/Geekbot.net/Storage/pinguins @@ -0,0 +1,13 @@ +https://i.ytimg.com/vi/Qr6sULJnu2o/maxresdefault.jpg +https://www.apex-expeditions.com/wp-content/uploads/2015/08/newzealandSlider_Macquarie_ElephantSealKingPenguins_GRiehle_1366x601.jpg +https://www.birdlife.org/sites/default/files/styles/1600/public/slide.jpg?itok=HRhQfA1S +http://experimentexchange.com/wp-content/uploads/2016/07/penguins-fact.jpg +http://images.mentalfloss.com/sites/default/files/styles/mf_image_16x9/public/istock-511366776.jpg?itok=cWhdWNZ8&resize=1100x619 +https://www.thevaporplace.ch/media/catalog/product/cache/1/thumbnail/800x800/9df78eab33525d08d6e5fb8d27136e95/a/t/atopack_penguin-15.jpg +https://www.superfastbusiness.com/wp-content/uploads/2015/10/real-time-penguin-algorithm-featured.jpg +http://www.antarctica.gov.au/__data/assets/image/0011/147737/varieties/antarctic.jpg +https://vignette.wikia.nocookie.net/robloxcreepypasta/images/1/11/AAEAAQAAAAAAAAdkAAAAJDc3YzkyYjJhLTYyZjctNDY2Mi04M2VjLTg4NjY4ZjgwYzRmNg.png/revision/latest?cb=20180207200526 +https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR3xV0lhpZuhT8Nmm6LaITsppZ7VfWcWXuyu2cPHrlv_dt_M92K5g +http://goboiano.com/wp-content/uploads/2017/04/Penguin-Kemeno-Friends-Waifu.jpg +https://cdn.yoast.com/app/uploads/2015/10/Penguins_1200x628.png +https://images.justwatch.com/backdrop/8611153/s1440/pingu \ No newline at end of file diff --git a/Geekbot.net/Storage/pumpkin b/Geekbot.net/Storage/pumpkin new file mode 100644 index 0000000..4b8e6f2 --- /dev/null +++ b/Geekbot.net/Storage/pumpkin @@ -0,0 +1,23 @@ +https://i.pinimg.com/736x/0a/a7/8a/0aa78af25e114836e1a42585fb7b09ed--funny-pumpkins-pumkin-carving.jpg +http://wdy.h-cdn.co/assets/16/31/980x1470/gallery-1470321728-shot-two-021.jpg +https://i.pinimg.com/736x/6c/62/bf/6c62bfa73a19ffd9fc6f2d720d5e9764--cool-pumpkin-carving-carving-pumpkins.jpg +http://images6.fanpop.com/image/photos/38900000/Jack-o-Lantern-halloween-38991566-500-415.jpg +http://ghk.h-cdn.co/assets/15/37/1441834730-pumpkin-carve-2.jpg +http://diy.sndimg.com/content/dam/images/diy/fullset/2011/7/26/1/iStock-10761186_halloween-pumpkin-in-garden_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420851319631.jpeg +http://ghk.h-cdn.co/assets/cm/15/11/54ffe537af882-snail-pumpkin-de.jpg +https://www.digsdigs.com/photos/2009/10/100-halloween-pumpkin-carving-ideas-12.jpg +http://diy.sndimg.com/content/dam/images/diy/fullset/2010/6/4/0/CI-Kyle-Nishioka_big-teeth-Jack-O-Lantern_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420699522718.jpeg +https://twistedsifter.files.wordpress.com/2011/10/most-amazing-pumpkin-carving-ray-villafane-10.jpg?w=521&h=739 +https://i.pinimg.com/736x/09/c4/b1/09c4b187b266c1f65332294f66009944--funny-pumpkins-halloween-pumpkins.jpg +http://www.evilmilk.com/pictures/The_Pumpkin_Man.jpg +http://cache.lovethispic.com/uploaded_images/blogs/13-Funny-Pumpkin-Carvings-5773-9.JPG +http://ihappyhalloweenpictures.com/wp-content/uploads/2016/10/funny-halloween-pumpkin.jpg +http://www.smallhomelove.com/wp-content/uploads/2012/08/leg-eating-pumpkin.jpg +https://cdn.shopify.com/s/files/1/0773/6789/articles/Halloween_Feature_8ff7a7c4-2cb3-4584-a85f-5d4d1e6ca26e.jpg?v=1476211360 +http://4vector.com/i/free-vector-pumpkin-boy-color-version-clip-art_107714_Pumpkin_Boy_Color_Version_clip_art_hight.png +https://i.pinimg.com/736x/59/8a/0f/598a0fbf789631b76c1ffd4443194d8e--halloween-pumpkins-fall-halloween.jpg +https://i.pinimg.com/originals/8f/86/f9/8f86f95457467872b371ba697d341961.jpg +http://nerdist.com/wp-content/uploads/2015/08/taleshalloween1.jpg +http://www.designbolts.com/wp-content/uploads/2014/09/Scary-Pumpkin_Grin_stencil-Ideas.jpg +http://vignette2.wikia.nocookie.net/scoobydoo/images/7/75/Pumpkin_monsters_%28Witch%27s_Ghost%29.png/revision/latest?cb=20140520070213 +https://taholtorf.files.wordpress.com/2013/10/36307-1920x1280.jpg diff --git a/Geekbot.net/Storage/squirrel b/Geekbot.net/Storage/squirrel new file mode 100644 index 0000000..2216465 --- /dev/null +++ b/Geekbot.net/Storage/squirrel @@ -0,0 +1,45 @@ +http://orig14.deviantart.net/6016/f/2010/035/c/b/first_squirrel_assassin_by_shotokanteddy.jpg +https://thumbs-prod.si-cdn.com/eoEYA_2Hau4795uKoecUZZgz-3w=/800x600/filters:no_upscale()/https://public-media.smithsonianmag.com/filer/52/f9/52f93262-c29b-4a4f-b031-0c7ad145ed5f/42-33051942.jpg +http://images5.fanpop.com/image/photos/30700000/Squirrel-squirrels-30710732-400-300.jpg +https://www.lovethegarden.com/sites/default/files/files/Red%20%26%20Grey%20Squirrel%20picture%20side%20by%20side-LR.jpg +http://i.dailymail.co.uk/i/pix/2016/02/24/16/158F7E7C000005DC-3462228-image-a-65_1456331226865.jpg +http://2.bp.blogspot.com/-egfnMhUb8tg/T_dAIu1m6cI/AAAAAAAAPPU/v4x9q4WqWl8/s640/cute-squirrel-hey-watcha-thinkin-about.jpg +https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Squirrel_posing.jpg/287px-Squirrel_posing.jpg +https://i.pinimg.com/736x/51/db/9b/51db9bad4a87d445d321923c7d56b501--red-squirrel-animal-kingdom.jpg +https://metrouk2.files.wordpress.com/2016/10/ad_223291521.jpg?w=620&h=949&crop=1 +http://www.redsquirrelsunited.org.uk/wp-content/uploads/2016/07/layer-slider.jpg +http://images.mentalfloss.com/sites/default/files/squirrel-hero.jpg?resize=1100x740 +https://i.pinimg.com/736x/ce/9c/59/ce9c5990b193046400d98724595cdaf3--red-squirrel-chipmunks.jpg +https://www.brooklynpaper.com/assets/photos/40/30/dtg-squirrel-attacks-prospect-park-patrons-2017-07-28-bk01_z.jpg +http://www.freakingnews.com/pictures/16000/Squirrel-Shark-16467.jpg +http://img09.deviantart.net/5c1c/i/2013/138/0/6/barbarian_squirel_by_coucoucmoa-d64r9m4.jpg +https://i.pinimg.com/736x/b4/5c/0d/b45c0d00b1a57e9f84f27f13cb019001--baby-squirrel-red-squirrel.jpg +https://i.pinimg.com/736x/0f/75/87/0f7587bb613ab524763afe8c9a532e5c--cute-squirrel-squirrels.jpg +http://cdn.images.express.co.uk/img/dynamic/128/590x/Grey-squirrel-828838.jpg +http://www.lovethispic.com/uploaded_images/79964-Squirrel-Smelling-A-Flower.jpg +https://i.pinimg.com/736x/23/d5/f9/23d5f9868f7d76c79c49bef53ae08f7f--squirrel-funny-red-squirrel.jpg +http://stories.barkpost.com/wp-content/uploads/2016/01/squirrel-3-copy.jpg +https://i.ytimg.com/vi/pzUs0DdzK3Y/hqdefault.jpg +https://www.askideas.com/media/41/I-Swear-It-Wasnt-Me-Funny-Squirrel-Meme-Picture-For-Facebook.jpg +https://i.pinimg.com/736x/2d/54/d8/2d54d8d2a9b3ab9d3e78544b75afd88e--funny-animal-pictures-humorous-pictures.jpg +http://www.funny-animalpictures.com/media/content/items/images/funnysquirrels0012_O.jpg +http://funny-pics.co/wp-content/uploads/funny-squirrel-and-coffee-picture.jpg +https://pbs.twimg.com/media/Bi4Ij6CIgAAgEdZ.jpg +http://www.funnyjunksite.com/pictures/wp-content/uploads/2015/06/Funny-Superman-Squirrels.jpg +https://i.pinimg.com/736x/bf/35/00/bf3500104f8394909d116259d1f0575e--funny-squirrel-squirrel-girl.jpg +http://quotespill.com/wp-content/uploads/2017/07/Squirrel-Meme-Draw-me-like-one-of-your-french-squirrrels-min.jpg +https://i.pinimg.com/736x/e2/16/bb/e216bba53f80fc8e0111d371e9850159--funny-squirrels-cute-squirrel.jpg +https://i.pinimg.com/736x/52/43/c9/5243c93377245be1f686218c266d775c--funny-squirrel-baby-squirrel.jpg +https://i.pinimg.com/736x/0c/be/1d/0cbe1da8ad2c0cf3882a806b6fd88965--cute-pictures-funny-animal-pictures.jpg +https://i.pinimg.com/736x/e5/08/67/e508670aa00ca3c896eccb81c4f6e2a8--funny-squirrel-baby-squirrel.jpg +https://i.pinimg.com/736x/1c/7d/4f/1c7d4f067a10066aad802ce5ac468d71--group-boards-a-squirrel.jpg +http://funny-pics.co/wp-content/uploads/funny-squirrel-on-a-branch.jpg +http://loldamn.com/wp-content/uploads/2016/06/funny-squirrel-playing-water-bending.jpg +https://cdn.trendhunterstatic.com/thumbs/squirrel-photography.jpeg +https://i.pinimg.com/736x/d6/42/12/d64212cc6221916db4173962bf6c131a--cute-squirrel-baby-squirrel.jpg +https://i.pinimg.com/236x/10/13/58/101358f2afc2c7d6b6a668046e7b8382--funny-animal-pictures-funny-animals.jpg +https://i.pinimg.com/736x/da/0d/fe/da0dfe93bb26887795f906e8fa97d68e--secret-squirrel-cute-squirrel.jpg +http://2.bp.blogspot.com/-HLieBqEuQoM/UDkRmeyzB5I/AAAAAAAABHs/RtsEynn5t6Y/s1600/hd-squirrel-wallpaper-with-a-brown-squirrel-eating-watermelon-wallpapers-backgrounds-pictures-photos.jpg +http://www.city-data.com/forum/members/brenda-starz-328928-albums-brenda-s-funny-squirrel-comment-pic-s-pic5075-punk-squirrels.jpg +http://img15.deviantart.net/9c50/i/2011/213/c/9/just_taking_it_easy_by_lou_in_canada-d42do3d.jpg +http://3.bp.blogspot.com/-AwsSk76R2Is/USQa3-dszKI/AAAAAAAABUQ/KF_F8HbtP1U/w1200-h630-p-k-no-nu/crazySquirrel.jpg diff --git a/src/Bot/Storage/turtles b/Geekbot.net/Storage/turtles similarity index 69% rename from src/Bot/Storage/turtles rename to Geekbot.net/Storage/turtles index aa0fbcf..9dbbf72 100644 --- a/src/Bot/Storage/turtles +++ b/Geekbot.net/Storage/turtles @@ -1,20 +1,21 @@ https://i.guim.co.uk/img/media/6b9be13031738e642f93f9271f3592044726a9b1/0_0_2863_1610/2863.jpg?w=640&h=360&q=55&auto=format&usm=12&fit=max&s=85f3b33cc158b5aa120c143dae1916ed http://cf.ltkcdn.net/small-pets/images/std/212089-676x450-Turtle-feeding-on-leaf.jpg +https://static1.squarespace.com/static/5369465be4b0507a1fd05af0/53767a6be4b0ad0822345e52/57e40ba4893fc031e05a018f/1498243318058/solvin.jpg?format=1500w https://c402277.ssl.cf1.rackcdn.com/photos/419/images/story_full_width/HI_287338Hero.jpg?1433950119 https://www.cdc.gov/salmonella/agbeni-08-17/images/turtle.jpg https://cdn.arstechnica.net/wp-content/uploads/2017/08/GettyImages-524757168.jpg http://pmdvod.nationalgeographic.com/NG_Video/595/319/4504517_098_05_TOS_thumbnail_640x360_636296259676.jpg +http://cdn1.arkive.org/media/7D/7D46329A-6ED2-4F08-909E-7B596417994A/Presentation.Large/Big-headed-turtle-close-up.jpg http://s7d2.scene7.com/is/image/PetSmart/ARTHMB-CleaningYourTortoiseOrTurtlesHabitat-20160818?$AR1104$ https://fthmb.tqn.com/9VGWzK_GWlvrjxtdFPX6EJxOq24=/960x0/filters:no_upscale()/133605352-56a2bce53df78cf7727960db.jpg +https://i.imgur.com/46QmzgF.jpg https://www.wildgratitude.com/wp-content/uploads/2015/07/turtle-spirit-animal1.jpg http://www.backwaterreptiles.com/images/turtles/red-eared-slider-turtle-for-sale.jpg +https://i.pinimg.com/736x/f1/f4/13/f1f413d6d07912be6080c08b186630ac--happy-turtle-funny-stuff.jpg +http://www.dupageforest.org/uploadedImages/Content/District_News/Nature_Stories/2016/Snapping%20Turtle%20Scott%20Plantier%20STP4793.jpg http://turtlebackzoo.com/wp-content/uploads/2016/07/exhibit-headers_0008_SOUTH-AMERICA-600x400.jpg +https://i.ytimg.com/vi/_YfYHFM3Das/maxresdefault.jpg https://i.pinimg.com/736x/dd/4e/7f/dd4e7f2f921ac28b1d5a59174d477131--cute-baby-sea-turtles-adorable-turtles.jpg http://kids.nationalgeographic.com/content/dam/kids/photos/animals/Reptiles/A-G/green-sea-turtle-closeup-underwater.adapt.945.1.jpg +https://i.ytimg.com/vi/p4Jj9QZFJvw/hqdefault.jpg https://fthmb.tqn.com/nirxHkH3jBAe74ife6fJJu6k6q8=/2121x1414/filters:fill(auto,1)/Red-eared-sliders-GettyImages-617946009-58fae8835f9b581d59a5bab6.jpg -http://assets.worldwildlife.org/photos/167/images/original/MID_225023-circle-hawksbill-turtle.jpg?1345565600 -https://seaturtles.org/wp-content/uploads/2013/11/GRN-honuAnitaWintner2.jpg -https://images2.minutemediacdn.com/image/upload/c_crop,h_2549,w_4536,x_0,y_237/v1560186367/shape/mentalfloss/istock-687398754.jpg?itok=QsiF5yHP -https://c402277.ssl.cf1.rackcdn.com/photos/13028/images/story_full_width/seaturtle_spring2017.jpg?1485359391 -https://i2.wp.com/rangerrick.org/wp-content/uploads/2018/03/Turtle-Tale-RR-Jr-June-July-2017.jpg?fit=1156%2C650&ssl=1 -https://boyslifeorg.files.wordpress.com/2019/07/greenseaturtle.jpg \ No newline at end of file diff --git a/Geekbot.net/WebApi/Help/CommandDto.cs b/Geekbot.net/WebApi/Help/CommandDto.cs new file mode 100644 index 0000000..5921fa6 --- /dev/null +++ b/Geekbot.net/WebApi/Help/CommandDto.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace Geekbot.net.WebApi.Help +{ + public class CommandDto + { + public string Name { get; set; } + public string Category { get; set; } + public string Summary { get; set; } + public bool IsAdminCommand { get; set; } + public Array Aliases { get; set; } + public List Params { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/WebApi/Help/CommandParamDto.cs b/Geekbot.net/WebApi/Help/CommandParamDto.cs new file mode 100644 index 0000000..f7ce0ea --- /dev/null +++ b/Geekbot.net/WebApi/Help/CommandParamDto.cs @@ -0,0 +1,9 @@ +namespace Geekbot.net.WebApi.Help +{ + public class CommandParamDto + { + public string Summary { get; set; } + public string Default { get; set; } + public string Type { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/WebApi/Help/HelpController.cs b/Geekbot.net/WebApi/Help/HelpController.cs new file mode 100644 index 0000000..d71d26f --- /dev/null +++ b/Geekbot.net/WebApi/Help/HelpController.cs @@ -0,0 +1,48 @@ +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Discord.Commands; +using Geekbot.net.Lib; +using Nancy; + +namespace Geekbot.net.WebApi.Help +{ + public class HelpController : NancyModule + { + public HelpController() + { + Get("/v1/commands", args => + { + var commands = GetCommands().Result; + + var commandList = (from cmd in commands.Commands + let cmdParamsObj = cmd.Parameters.Select(cmdParam => new CommandParamDto + { + Summary = cmdParam.Summary, + Default = cmdParam.DefaultValue?.ToString() ?? null, + Type = cmdParam.Type?.ToString() + }) + .ToList() + let param = string.Join(", !", cmd.Aliases) + select new CommandDto + { + Name = cmd.Name, + Summary = cmd.Summary, + Category = cmd.Remarks ?? CommandCategories.Uncategorized, + IsAdminCommand = (param.Contains("admin")), + Aliases = cmd.Aliases.ToArray(), + Params = cmdParamsObj + }).ToList(); + return Response.AsJson(commandList); + + }); + } + + private async Task GetCommands() + { + var commands = new CommandService(); + await commands.AddModulesAsync(Assembly.GetEntryAssembly()); + return commands; + } + } +} \ No newline at end of file diff --git a/Geekbot.net/WebApi/Status/ApiStatusDto.cs b/Geekbot.net/WebApi/Status/ApiStatusDto.cs new file mode 100644 index 0000000..242bf58 --- /dev/null +++ b/Geekbot.net/WebApi/Status/ApiStatusDto.cs @@ -0,0 +1,9 @@ +namespace Geekbot.net.WebApi.Status +{ + public class ApiStatusDto + { + public string GeekbotVersion { get; set; } + public string ApiVersion { get; set; } + public string Status { get; set; } + } +} \ No newline at end of file diff --git a/Geekbot.net/WebApi/Status/StatusController.cs b/Geekbot.net/WebApi/Status/StatusController.cs new file mode 100644 index 0000000..05196a2 --- /dev/null +++ b/Geekbot.net/WebApi/Status/StatusController.cs @@ -0,0 +1,22 @@ +using Geekbot.net.Lib; +using Nancy; + +namespace Geekbot.net.WebApi.Status +{ + public class StatusController : NancyModule + { + public StatusController() + { + Get("/", args => + { + var responseBody = new ApiStatusDto + { + GeekbotVersion = Constants.BotVersion(), + ApiVersion = Constants.ApiVersion.ToString(), + Status = "Online" + }; + return Response.AsJson(responseBody); + }); + } + } +} \ No newline at end of file diff --git a/Geekbot.net/WebApi/WebConfig.cs b/Geekbot.net/WebApi/WebConfig.cs new file mode 100644 index 0000000..f0b9ca3 --- /dev/null +++ b/Geekbot.net/WebApi/WebConfig.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; +using Nancy; +using Nancy.Bootstrapper; +using Nancy.TinyIoc; + +namespace Geekbot.net.WebApi +{ + public class WebConfig : DefaultNancyBootstrapper + { + protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context) + { + + //CORS Enable + pipelines.AfterRequest.AddItemToEndOfPipeline(ctx => + { + ctx.Response.WithHeader("Access-Control-Allow-Origin", "*") + .WithHeader("Access-Control-Allow-Methods", "GET") + .WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-type") + .WithHeader("Last-Modified", Process.GetCurrentProcess().StartTime.ToString()); + }); + } + } +} \ No newline at end of file diff --git a/src/Startup/derp.ico b/Geekbot.net/derp.ico similarity index 100% rename from src/Startup/derp.ico rename to Geekbot.net/derp.ico diff --git a/Tests/Lib/EmojiConverter.test.cs b/Tests/Lib/EmojiConverter.test.cs new file mode 100644 index 0000000..aaaaa8f --- /dev/null +++ b/Tests/Lib/EmojiConverter.test.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Converters; +using Xunit; + +namespace Tests.Lib +{ + public class EmojiConverterTest + { + public static IEnumerable NumberToEmojiTestData + { + get + { + yield return new object[] + { + 2, + ":two:" + }; + + yield return new object[] + { + 10, + "🔟" + }; + + yield return new object[] + { + 15, + ":one::five:" + }; + + yield return new object[] + { + null, + ":zero:" + }; + } + } + + + [Theory, MemberData(nameof(NumberToEmojiTestData))] + public void NumberToEmoji(int number, string expectedResult) + { + var emojiConverter = new EmojiConverter(); + var result = emojiConverter.NumberToEmoji(number); + Assert.Equal(result, expectedResult); + } + + public static IEnumerable TextToEmojiTestData + { + get + { + yield return new object[] + { + "test", + ":regional_indicator_t: :regional_indicator_e: :regional_indicator_s: :regional_indicator_t: " + }; + yield return new object[] + { + "Best3+?", + ":b: :regional_indicator_e: :regional_indicator_s: :regional_indicator_t: :three: :heavy_plus_sign: :question: " + }; + } + } + + + [Theory, MemberData(nameof(TextToEmojiTestData))] + public void TextToEmoji(string text, string expectedResult) + { + var emojiConverter = new EmojiConverter(); + var result = emojiConverter.TextToEmoji(text); + Assert.Equal(result, expectedResult); + } + } +} \ No newline at end of file diff --git a/Tests/Lib/LevelCalc.test.cs b/Tests/Lib/LevelCalc.test.cs new file mode 100644 index 0000000..4b6b095 --- /dev/null +++ b/Tests/Lib/LevelCalc.test.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using Geekbot.net.Lib; +using Geekbot.net.Lib.Levels; +using Xunit; + +namespace Tests.Lib +{ + public class LevelCalcTest + { + public static IEnumerable LevelCalcTestData + { + get + { + yield return new object[] + { + 500, + 13 + }; + + yield return new object[] + { + 41659, + 55 + }; + + yield return new object[] + { + 0, + 1 + }; + + yield return new object[] + { + 4000000, + 101 + }; + } + } + + + [Theory, MemberData(nameof(LevelCalcTestData))] + public void GetLevel(int messages, int expectedResult) + { + var levelCalc = new LevelCalc(); + var result = levelCalc.GetLevel(messages); + Assert.Equal(result, expectedResult); + } + } +} \ No newline at end of file diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj new file mode 100644 index 0000000..c838db0 --- /dev/null +++ b/Tests/Tests.csproj @@ -0,0 +1,16 @@ + + + netcoreapp2.0 + false + NU1701 + + + + + + + + + + + \ No newline at end of file diff --git a/src/Core/WikipediaClient/IWikipediaClient.cs b/WikipediaApi/IWikipediaClient.cs similarity index 65% rename from src/Core/WikipediaClient/IWikipediaClient.cs rename to WikipediaApi/IWikipediaClient.cs index fdb1ae1..4d1dae9 100644 --- a/src/Core/WikipediaClient/IWikipediaClient.cs +++ b/WikipediaApi/IWikipediaClient.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; -using Geekbot.Core.WikipediaClient.Page; +using WikipediaApi.Page; -namespace Geekbot.Core.WikipediaClient +namespace WikipediaApi { public interface IWikipediaClient { diff --git a/WikipediaApi/Page/PageApiUrls.cs b/WikipediaApi/Page/PageApiUrls.cs new file mode 100644 index 0000000..8a121be --- /dev/null +++ b/WikipediaApi/Page/PageApiUrls.cs @@ -0,0 +1,14 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageApiUrls + { + public Uri Summary { get; set; } + public Uri Metadata { get; set; } + public Uri References { get; set; } + public Uri Media { get; set; } + public Uri EditHtml { get; set; } + public Uri TalkPageHtml { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageContentUrlCollection.cs b/WikipediaApi/Page/PageContentUrlCollection.cs new file mode 100644 index 0000000..f6c680b --- /dev/null +++ b/WikipediaApi/Page/PageContentUrlCollection.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageContentUrlCollection + { + public PageContentUrls Desktop { get; set; } + public PageContentUrls Mobile { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageContentUrls.cs b/WikipediaApi/Page/PageContentUrls.cs new file mode 100644 index 0000000..64a80dc --- /dev/null +++ b/WikipediaApi/Page/PageContentUrls.cs @@ -0,0 +1,12 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageContentUrls + { + public Uri Page { get; set; } + public Uri Revisions { get; set; } + public Uri Edit { get; set; } + public Uri Talk { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageCoordinates.cs b/WikipediaApi/Page/PageCoordinates.cs new file mode 100644 index 0000000..7fa42ba --- /dev/null +++ b/WikipediaApi/Page/PageCoordinates.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageCoordinates + { + public float Lat { get; set; } + public float Lon { get; set; } + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageImage.cs b/WikipediaApi/Page/PageImage.cs new file mode 100644 index 0000000..4a8b28d --- /dev/null +++ b/WikipediaApi/Page/PageImage.cs @@ -0,0 +1,12 @@ +using System; + +namespace WikipediaApi.Page +{ + public class PageImage + { + public Uri Source { get; set; } + public int Width { get; set; } + public int Height { get; set; } + + } +} \ No newline at end of file diff --git a/WikipediaApi/Page/PageNamespace.cs b/WikipediaApi/Page/PageNamespace.cs new file mode 100644 index 0000000..66600b6 --- /dev/null +++ b/WikipediaApi/Page/PageNamespace.cs @@ -0,0 +1,8 @@ +namespace WikipediaApi.Page +{ + public class PageNamespace + { + public ulong Id { get; set; } + public string Text { get; set; } + } +} \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PagePreview.cs b/WikipediaApi/Page/PagePreview.cs similarity index 53% rename from src/Core/WikipediaClient/Page/PagePreview.cs rename to WikipediaApi/Page/PagePreview.cs index b87a05e..8db9dad 100644 --- a/src/Core/WikipediaClient/Page/PagePreview.cs +++ b/WikipediaApi/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 +namespace WikipediaApi.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/WikipediaApi/Page/PageTitles.cs b/WikipediaApi/Page/PageTitles.cs new file mode 100644 index 0000000..31a55b9 --- /dev/null +++ b/WikipediaApi/Page/PageTitles.cs @@ -0,0 +1,10 @@ +namespace WikipediaApi.Page +{ + public class PageTitles + { + public string Canonical { get; set; } + public string Normalized { get; set; } + public string Display { get; set; } + + } +} \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageTypes.cs b/WikipediaApi/Page/PageTypes.cs similarity index 70% rename from src/Core/WikipediaClient/Page/PageTypes.cs rename to WikipediaApi/Page/PageTypes.cs index 9ad748a..a415d75 100644 --- a/src/Core/WikipediaClient/Page/PageTypes.cs +++ b/WikipediaApi/Page/PageTypes.cs @@ -1,9 +1,7 @@ using System.Runtime.Serialization; -using System.Text.Json.Serialization; -namespace Geekbot.Core.WikipediaClient.Page +namespace WikipediaApi.Page { - [JsonConverter(typeof(JsonStringEnumConverter))] public enum PageTypes { [EnumMember(Value = "standard")] diff --git a/WikipediaApi/WikipediaApi.csproj b/WikipediaApi/WikipediaApi.csproj new file mode 100644 index 0000000..f182d90 --- /dev/null +++ b/WikipediaApi/WikipediaApi.csproj @@ -0,0 +1,8 @@ + + + netcoreapp2.0 + + + + + \ No newline at end of file diff --git a/src/Core/WikipediaClient/WikipediaClient.cs b/WikipediaApi/WikipediaClient.cs similarity index 75% rename from src/Core/WikipediaClient/WikipediaClient.cs rename to WikipediaApi/WikipediaClient.cs index cf13277..6576f3d 100644 --- a/src/Core/WikipediaClient/WikipediaClient.cs +++ b/WikipediaApi/WikipediaClient.cs @@ -1,9 +1,9 @@ using System.Net.Http; -using System.Text.Json; using System.Threading.Tasks; -using Geekbot.Core.WikipediaClient.Page; +using Newtonsoft.Json; +using WikipediaApi.Page; -namespace Geekbot.Core.WikipediaClient +namespace WikipediaApi { public class WikipediaClient : IWikipediaClient { @@ -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/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/readme.md b/readme.md index 883e553..7d8544f 100644 --- a/readme.md +++ b/readme.md @@ -1,28 +1,29 @@ -[![pipeline status](https://gitlab.com/dbgit/open/geekbot/badges/master/pipeline.svg)](https://gitlab.com/dbgit/open/geekbot/commits/master) +[![pipeline status](https://git.boerlage.me/open/Geekbot.net/badges/master/pipeline.svg)](https://git.boerlage.me/open/Geekbot.net/commits/master) # [Geekbot.net](https://geekbot.pizzaandcoffee.rocks/) -A General Purpose Discord Bot written in C# +A General Purpose Discord Bot written in DotNet Core. You can invite Geekbot to your server with [this link](https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054) ## Technologies -* .NET 5 -* PostgreSQL +* DotNet Core 2 +* Redis * Discord.net ## Running -You can start geekbot with: `dotnet run` +Make sure redis is running -On your first run geekbot will ask for your bot token. +Run these commands -You might need to pass some additional configuration (e.g. database credentials), these can be passed as commandline arguments or environment variables. +* `dotnet restore` +* `dotnet run` -For a list of commandline arguments and environment variables use `dotnet run -- -h` +On your first run geekbot will ask for your bot token, everything else is taken care of. -All Environment Variables must be prefixed with `GEEKBOT_` +For a list of launch options use `dotnet run -h` ## Contributing diff --git a/src/Bot/Bot.csproj b/src/Bot/Bot.csproj deleted file mode 100644 index 2219b32..0000000 --- a/src/Bot/Bot.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - net6.0 - $(VersionSuffix) - Geekbot.Bot - Geekbot.Bot - $(VersionSuffix) - 0.0.0-DEV - NU1701 - enable - True - Library - - - - - - - - - - - - - - PreserveNewest - - - - - - - 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/CommandPreconditions/DisableInDirectMessageAttribute.cs b/src/Bot/CommandPreconditions/DisableInDirectMessageAttribute.cs deleted file mode 100644 index b75f4a1..0000000 --- a/src/Bot/CommandPreconditions/DisableInDirectMessageAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; - -namespace Geekbot.Bot.CommandPreconditions -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] - public class DisableInDirectMessageAttribute : PreconditionAttribute - { - public override Task CheckPermissionsAsync(ICommandContext context, CommandInfo command, IServiceProvider services) - { - var result = context.Guild.Id != 0 ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Command unavailable in Direct Messaging"); - return Task.FromResult(result); - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Admin/Admin.cs b/src/Bot/Commands/Admin/Admin.cs deleted file mode 100644 index 43fb3c4..0000000 --- a/src/Bot/Commands/Admin/Admin.cs +++ /dev/null @@ -1,253 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Resources; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Discord.WebSocket; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; -using Geekbot.Core.GuildSettingsManager; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Bot.Commands.Admin -{ - [Group("admin")] - [RequireUserPermission(GuildPermission.Administrator)] - [DisableInDirectMessage] - public class Admin : GeekbotCommandBase - { - private readonly DiscordSocketClient _client; - - public Admin(DiscordSocketClient client, IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _client = client; - } - - [Command("welcome", RunMode = RunMode.Async)] - [Summary("Set a Welcome Message (use '$user' to mention the new joined user).")] - public async Task SetWelcomeMessage([Remainder, Summary("message")] string welcomeMessage) - { - GuildSettings.WelcomeMessage = welcomeMessage; - await GuildSettingsManager.UpdateSettings(GuildSettings); - - var formatedMessage = welcomeMessage.Replace("$user", Context.User.Mention); - await ReplyAsync($"Welcome message has been changed\r\nHere is an example of how it would look:\r\n{formatedMessage}"); - } - - [Command("welcomechannel", RunMode = RunMode.Async)] - [Summary("Set a channel for the welcome messages (by default it uses the top most channel)")] - public async Task SelectWelcomeChannel([Summary("#Channel")] ISocketMessageChannel channel) - { - try - { - var m = await channel.SendMessageAsync("..."); - - GuildSettings.WelcomeChannel = channel.Id.AsLong(); - await GuildSettingsManager.UpdateSettings(GuildSettings); - - await m.DeleteAsync(); - - await ReplyAsync("Successfully saved the welcome channel"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions"); - } - } - - [Command("modchannel", RunMode = RunMode.Async)] - [Summary("Set a channel for moderation purposes")] - public async Task SelectModChannel([Summary("#Channel")] ISocketMessageChannel channel) - { - try - { - var m = await channel.SendMessageAsync("verifying..."); - - GuildSettings.ModChannel = channel.Id.AsLong(); - await GuildSettingsManager.UpdateSettings(GuildSettings); - - var sb = new StringBuilder(); - sb.AppendLine("Successfully saved mod channel, you can now do the following"); - sb.AppendLine("- `!admin showleave` - send message to mod channel when someone leaves"); - sb.AppendLine("- `!admin showdel` - send message to mod channel when someone deletes a message"); - await m.ModifyAsync(e => e.Content = sb.ToString()); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions"); - } - } - - [Command("showleave", RunMode = RunMode.Async)] - [Summary("Toggle - notify modchannel when someone leaves")] - public async Task ShowLeave() - { - try - { - var modChannel = await GetModChannel(GuildSettings.ModChannel.AsUlong()); - if (modChannel == null) return; - - GuildSettings.ShowLeave = !GuildSettings.ShowLeave; - await GuildSettingsManager.UpdateSettings(GuildSettings); - await modChannel.SendMessageAsync(GuildSettings.ShowLeave - ? "Saved - now sending messages here when someone leaves" - : "Saved - stopping sending messages here when someone leaves" - ); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("showdel", RunMode = RunMode.Async)] - [Summary("Toggle - notify modchannel when someone deletes a message")] - public async Task ShowDelete() - { - try - { - var modChannel = await GetModChannel(GuildSettings.ModChannel.AsUlong()); - if (modChannel == null) return; - - GuildSettings.ShowDelete = !GuildSettings.ShowDelete; - await GuildSettingsManager.UpdateSettings(GuildSettings); - await modChannel.SendMessageAsync(GuildSettings.ShowDelete - ? "Saved - now sending messages here when someone deletes a message" - : "Saved - stopping sending messages here when someone deletes a message" - ); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("setlang", RunMode = RunMode.Async)] - [Summary("Change the bots language")] - public async Task SetLanguage([Summary("language")] string language) - { - try - { - var availableLanguages = new List(); - availableLanguages.Add("en-GB"); // default - availableLanguages.AddRange(GetAvailableCultures().Select(culture => culture.Name)); - if (availableLanguages.Contains(language)) - { - GuildSettings.Language = language; - await GuildSettingsManager.UpdateSettings(GuildSettings); - - Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language.ToLower() == "chde" ? "de-CH" : language); - - await ReplyAsync(Localization.Admin.NewLanguageSet); - return; - } - - await ReplyAsync($"That doesn't seem to be a supported language\nSupported Languages are {string.Join(", ", availableLanguages)}"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("wiki", RunMode = RunMode.Async)] - [Summary("Change the wikipedia instance (use lang code in xx.wikipedia.org)")] - public async Task SetWikiLanguage([Summary("language")] string languageRaw) - { - try - { - var language = languageRaw.ToLower(); - GuildSettings.WikiLang = language; - await GuildSettingsManager.UpdateSettings(GuildSettings); - - await ReplyAsync($"Now using the {language} wikipedia"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("ping", RunMode = RunMode.Async)] - [Summary("Enable the ping reply.")] - public async Task TogglePing() - { - try - { - // var guild = _guildSettingsManager.GetSettings(Context.Guild.Id); - GuildSettings.Ping = !GuildSettings.Ping; - await GuildSettingsManager.UpdateSettings(GuildSettings); - await ReplyAsync(GuildSettings.Ping ? "i will reply to ping now" : "No more pongs..."); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("hui", RunMode = RunMode.Async)] - [Summary("Enable the ping reply.")] - public async Task ToggleHui() - { - try - { - // var guild = _guildSettingsManager.GetSettings(Context.Guild.Id); - GuildSettings.Hui = !GuildSettings.Hui; - await GuildSettingsManager.UpdateSettings(GuildSettings); - await ReplyAsync(GuildSettings.Hui ? "i will reply to hui now" : "No more hui's..."); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - private async Task GetModChannel(ulong channelId) - { - try - { - if (channelId == ulong.MinValue) throw new Exception(); - var modChannel = (ISocketMessageChannel) _client.GetChannel(channelId); - if (modChannel == null) throw new Exception(); - return modChannel; - } - catch - { - await ReplyAsync("Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`"); - return null; - } - } - - private IEnumerable GetAvailableCultures() - { - var result = new List(); - var rm = new ResourceManager(typeof(Localization.Admin)); - var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); - foreach (var culture in cultures) - { - try - { - if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work - - var rs = rm.GetResourceSet(culture, true, false); - if (rs != null) - { - result.Add(culture); - } - } - catch (CultureNotFoundException) - { - //NOP - } - } - return result; - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Admin/Owner/Owner.cs b/src/Bot/Commands/Admin/Owner/Owner.cs deleted file mode 100644 index 64292e9..0000000 --- a/src/Bot/Commands/Admin/Owner/Owner.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Discord.WebSocket; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GlobalSettings; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.Logger; -using Geekbot.Core.UserRepository; - -namespace Geekbot.Bot.Commands.Admin.Owner -{ - [Group("owner")] - [RequireOwner] - public class Owner : GeekbotCommandBase - { - private readonly DiscordSocketClient _client; - private readonly IGlobalSettings _globalSettings; - private readonly IGeekbotLogger _logger; - private readonly IUserRepository _userRepository; - - public Owner(DiscordSocketClient client, IGeekbotLogger logger, IUserRepository userRepositry, IErrorHandler errorHandler, IGlobalSettings globalSettings, - IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _client = client; - _logger = logger; - _userRepository = userRepositry; - _globalSettings = globalSettings; - } - - [Command("youtubekey", RunMode = RunMode.Async)] - [Summary("Set the youtube api key")] - public async Task SetYoutubeKey([Summary("API-Key")] string key) - { - await _globalSettings.SetKey("YoutubeKey", key); - await ReplyAsync("Apikey has been set"); - } - - [Command("game", RunMode = RunMode.Async)] - [Summary("Set the game that the bot is playing")] - public async Task SetGame([Remainder] [Summary("Game")] string key) - { - await _globalSettings.SetKey("Game", key); - await _client.SetGameAsync(key); - _logger.Information(LogSource.Geekbot, $"Changed game to {key}"); - await ReplyAsync($"Now Playing {key}"); - } - - [Command("popuserrepo", RunMode = RunMode.Async)] - [Summary("Populate user cache")] - public async Task PopUserRepoCommand() - { - var success = 0; - var failed = 0; - try - { - _logger.Warning(LogSource.UserRepository, "Populating User Repositry"); - await ReplyAsync("Starting Population of User Repository"); - foreach (var guild in _client.Guilds) - { - _logger.Information(LogSource.UserRepository, $"Populating users from {guild.Name}"); - foreach (var user in guild.Users) - { - var succeded = await _userRepository.Update(user); - var inc = succeded ? success++ : failed++; - } - } - - _logger.Warning(LogSource.UserRepository, "Finished Updating User Repositry"); - await ReplyAsync( - $"Successfully Populated User Repository with {success} Users in {_client.Guilds.Count} Guilds (Failed: {failed})"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, - "Couldn't complete User Repository, see console for more info"); - } - } - - [Command("refreshuser", RunMode = RunMode.Async)] - [Summary("Refresh a user in the user cache")] - public async Task PopUserRepoCommand([Summary("@someone")] IUser user) - { - try - { - await _userRepository.Update(user as SocketUser); - await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("refreshuser", RunMode = RunMode.Async)] - [Summary("Refresh a user in the user cache")] - public async Task PopUserRepoCommand([Summary("user-id")] ulong userId) - { - try - { - var user = _client.GetUser(userId); - await _userRepository.Update(user); - await ReplyAsync($"Refreshed: {user.Username}#{user.Discriminator}"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("error", RunMode = RunMode.Async)] - [Summary("Throw an error un purpose")] - public async Task PurposefulError() - { - try - { - throw new Exception("Error Generated by !owner error"); - } - 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 deleted file mode 100644 index fb8ef68..0000000 --- a/src/Bot/Commands/Admin/Role.cs +++ /dev/null @@ -1,197 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Discord.Net; -using Geekbot.Bot.CommandPreconditions; -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.ReactionListener; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Bot.Commands.Admin -{ - [Group("role")] - [DisableInDirectMessage] - public class Role : GeekbotCommandBase - { - private readonly DatabaseContext _database; - private readonly IReactionListener _reactionListener; - - public Role(DatabaseContext database, IErrorHandler errorHandler, IReactionListener reactionListener, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _database = database; - _reactionListener = reactionListener; - } - - [Command(RunMode = RunMode.Async)] - [Summary("Get a list of all available roles.")] - public async Task GetAllRoles() - { - try - { - var roles = _database.RoleSelfService.Where(g => g.GuildId.Equals(Context.Guild.Id.AsLong())).ToList(); - if (roles.Count == 0) - { - await ReplyAsync(Localization.Role.NoRolesConfigured); - return; - } - - var sb = new StringBuilder(); - sb.AppendLine(string.Format(Localization.Role.ListHeader, Context.Guild.Name)); - sb.AppendLine(Localization.Role.ListInstruction); - foreach (var role in roles) sb.AppendLine($"- {role.WhiteListName}"); - await ReplyAsync(sb.ToString()); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command(RunMode = RunMode.Async)] - [Summary("Get a role by mentioning it.")] - public async Task GiveRole([Summary("role-nickname")] string roleNameRaw) - { - try - { - var roleName = roleNameRaw.ToLower(); - var roleFromDb = _database.RoleSelfService.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName)); - if (roleFromDb != null) - { - var guildUser = (IGuildUser) Context.User; - var role = Context.Guild.Roles.First(r => r.Id == roleFromDb.RoleId.AsUlong()); - if (role == null) - { - await ReplyAsync(Localization.Role.RoleNotFound); - return; - } - - if (guildUser.RoleIds.Contains(role.Id)) - { - await guildUser.RemoveRoleAsync(role); - await ReplyAsync(string.Format(Localization.Role.RemovedUserFromRole, role.Name)); - return; - } - - await guildUser.AddRoleAsync(role); - await ReplyAsync(string.Format(Localization.Role.AddedUserFromRole, role.Name)); - return; - } - - await ReplyAsync(Localization.Role.RoleNotFound); - } - catch (HttpException e) - { - if (e.HttpCode == HttpStatusCode.Forbidden) - { - await ReplyAsync(Localization.Internal.Http403); - } - else - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [RequireUserPermission(GuildPermission.ManageRoles)] - [Command("add", RunMode = RunMode.Async)] - [Summary("Add a role to the whitelist.")] - public async Task AddRole([Summary("@role")] IRole role, [Summary("alias")] string roleName) - { - try - { - if (role.IsManaged) - { - await ReplyAsync(Localization.Role.CannotAddManagedRole); - return; - } - - if (role.Permissions.ManageRoles - || role.Permissions.Administrator - || role.Permissions.ManageGuild - || role.Permissions.BanMembers - || role.Permissions.KickMembers) - { - await ReplyAsync(Localization.Role.CannotAddDangerousRole); - return; - } - - _database.RoleSelfService.Add(new RoleSelfServiceModel - { - GuildId = Context.Guild.Id.AsLong(), - RoleId = role.Id.AsLong(), - WhiteListName = roleName - }); - await _database.SaveChangesAsync(); - await ReplyAsync(string.Format(Localization.Role.AddedRoleToWhitelist, role.Name)); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [RequireUserPermission(GuildPermission.ManageRoles)] - [Command("remove", RunMode = RunMode.Async)] - [Summary("Remove a role from the whitelist.")] - public async Task RemoveRole([Summary("role-nickname")] string roleName) - { - try - { - var roleFromDb = _database.RoleSelfService.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.WhiteListName.Equals(roleName)); - if (roleFromDb != null) - { - _database.RoleSelfService.Remove(roleFromDb); - await _database.SaveChangesAsync(); - await ReplyAsync(string.Format(Localization.Role.RemovedRoleFromWhitelist, roleName)); - return; - } - - await ReplyAsync(Localization.Role.RoleNotFound); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [RequireUserPermission(GuildPermission.ManageRoles)] - [Summary("Give a role by clicking on an emoji")] - [Command("listen", RunMode = RunMode.Async)] - public async Task AddListener([Summary("message-ID")] string messageIdStr, [Summary("Emoji")] string emoji, [Summary("@role")] IRole role) - { - try - { - var messageId = ulong.Parse(messageIdStr); - var message = (IUserMessage) await Context.Channel.GetMessageAsync(messageId); - var emote = _reactionListener.ConvertStringToEmote(emoji); - - await message.AddReactionAsync(emote); - await _reactionListener.AddRoleToListener(messageId, Context.Guild.Id, emoji, role); - await Context.Message.DeleteAsync(); - } - catch (HttpException) - { - await Context.Channel.SendMessageAsync("Custom emojis from other servers are not supported"); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Games/Roll/Roll.cs b/src/Bot/Commands/Games/Roll/Roll.cs deleted file mode 100644 index e9ed9e9..0000000 --- a/src/Bot/Commands/Games/Roll/Roll.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.KvInMemoryStore; -using Geekbot.Core.RandomNumberGenerator; -using Sentry; - -namespace Geekbot.Bot.Commands.Games.Roll -{ - public class Roll : GeekbotCommandBase - { - private readonly IKvInMemoryStore _kvInMemoryStore; - private readonly DatabaseContext _database; - private readonly IRandomNumberGenerator _randomNumberGenerator; - - public Roll(IKvInMemoryStore kvInMemoryStore, IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager) - : base(errorHandler, guildSettingsManager) - { - _kvInMemoryStore = kvInMemoryStore; - _database = database; - _randomNumberGenerator = randomNumberGenerator; - } - - [Command("roll", RunMode = RunMode.Async)] - [Summary("Guess which number the bot will roll (1-100")] - public async Task RollCommand([Remainder] [Summary("guess")] string stuff = null) - { - 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); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - Transaction.Status = SpanStatus.InternalError; - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs b/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs deleted file mode 100644 index 511d7b8..0000000 --- a/src/Bot/Commands/Integrations/LolMmr/LolMmr.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using System.Web; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Integrations.LolMmr -{ - public class LolMmr : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public LolMmr(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("mmr", RunMode = RunMode.Async)] - [Summary("Get the League of Legends MMR for a specified summoner")] - public async Task GetMmr([Remainder] [Summary("summoner")] string summonerName) - { - try - { - LolMmrDto data; - try - { - var name = HttpUtility.UrlEncode(summonerName.ToLower()); - var httpClient = HttpAbstractions.CreateDefaultClient(); - // setting the user agent in accordance with the whatismymmr.com api rules - httpClient.DefaultRequestHeaders.Remove("User-Agent"); - httpClient.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Linux:rocks.pizzaandcoffee.geekbot:v0.0.0"); - data = await HttpAbstractions.Get(new Uri($"https://euw.whatismymmr.com/api/v1/summoner?name={name}"), httpClient); - } - catch (HttpRequestException e) - { - if (e.StatusCode != HttpStatusCode.NotFound) throw e; - - await Context.Channel.SendMessageAsync("Player not found"); - return; - - } - - 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}"); - - await Context.Channel.SendMessageAsync(sb.ToString()); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs b/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs deleted file mode 100644 index 233bcfc..0000000 --- a/src/Bot/Commands/Integrations/LolMmr/LolMmrDto.cs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index fbcc49a..0000000 --- a/src/Bot/Commands/Integrations/LolMmr/LolMrrInfoDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Integrations.LolMmr -{ - public class LolMrrInfoDto - { - [JsonPropertyName("avg")] - public decimal? Avg { get; set; } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/MagicTheGathering.cs b/src/Bot/Commands/Integrations/MagicTheGathering.cs deleted file mode 100644 index 359b41e..0000000 --- a/src/Bot/Commands/Integrations/MagicTheGathering.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -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; -using MtgApiManager.Lib.Service; - -namespace Geekbot.Bot.Commands.Integrations -{ - public class MagicTheGathering : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - private readonly IMtgManaConverter _manaConverter; - - public MagicTheGathering(IErrorHandler errorHandler, IMtgManaConverter manaConverter) - { - _errorHandler = errorHandler; - _manaConverter = manaConverter; - } - - [Command("mtg", RunMode = RunMode.Async)] - [Summary("Find a Magic The Gathering Card.")] - public async Task GetCard([Remainder] [Summary("card-name")] string cardName) - { - try - { - var message = await Context.Channel.SendMessageAsync($":mag: Looking up \"{cardName}\", please wait..."); - - var service = new CardService(); - var result = service - .Where(x => x.Name, cardName) - // fewer cards less risk of deserialization problems, don't need more than one anyways... - .Where(x => x.PageSize, 1); - - var cards = await result.AllAsync(); - if (!cards.IsSuccess) - { - await message.ModifyAsync(properties => properties.Content = $":warning: The Gatherer reacted in an unexpected way: {cards.Exception.Message}"); - return; - } - - var card = cards.Value.FirstOrDefault(); - - if (card == null) - { - await message.ModifyAsync(properties => properties.Content = ":red_circle: I couldn't find a card with that name..."); - return; - } - - var eb = new EmbedBuilder - { - Title = card.Name, - Description = card.Type - }; - - if (card.Colors != null) eb.WithColor(GetColor(card.Colors)); - - if (card.ImageUrl != null) eb.ImageUrl = card.ImageUrl.ToString(); - - if (!string.IsNullOrEmpty(card.Text)) eb.AddField("Text", _manaConverter.ConvertMana(card.Text)); - - if (!string.IsNullOrEmpty(card.Flavor)) eb.AddField("Flavor", card.Flavor); - if (!string.IsNullOrEmpty(card.SetName)) eb.AddInlineField("Set", card.SetName); - if (!string.IsNullOrEmpty(card.Power)) eb.AddInlineField("Power", card.Power); - if (!string.IsNullOrEmpty(card.Loyalty)) eb.AddInlineField("Loyality", card.Loyalty); - if (!string.IsNullOrEmpty(card.Toughness)) eb.AddInlineField("Thoughness", card.Toughness); - - if (!string.IsNullOrEmpty(card.ManaCost)) eb.AddInlineField("Cost", _manaConverter.ConvertMana(card.ManaCost)); - if (!string.IsNullOrEmpty(card.Rarity)) eb.AddInlineField("Rarity", card.Rarity); - - if (card.Legalities != null && card.Legalities.Count > 0) - eb.AddField("Legality", string.Join(", ", card.Legalities.Select(e => e.Format))); - - await message.ModifyAsync(properties => - { - properties.Content = string.Empty; - properties.Embed = eb.Build(); - }); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - - private Color GetColor(IEnumerable colors) - { - var color = colors.FirstOrDefault(); - return color switch - { - "Black" => new Color(203, 194, 191), - "White" => new Color(255, 251, 213), - "Blue" => new Color(170, 224, 250), - "Red" => new Color(250, 170, 143), - "Green" => new Color(155, 211, 174), - _ => new Color(204, 194, 212) - }; - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Integrations/Mal.cs b/src/Bot/Commands/Integrations/Mal.cs deleted file mode 100644 index ffc8dd7..0000000 --- a/src/Bot/Commands/Integrations/Mal.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; -using Geekbot.Core.GuildSettingsManager; -using JikanDotNet; - -namespace Geekbot.Bot.Commands.Integrations -{ - public class Mal : GeekbotCommandBase - { - private readonly IJikan _client; - - public Mal(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _client = new Jikan(); - } - - [Command("anime", RunMode = RunMode.Async)] - [Summary("Show Info about an Anime.")] - public async Task SearchAnime([Remainder] [Summary("anime-name")] string animeName) - { - try - { - var results = await _client.SearchAnime(animeName); - var anime = results.Results.FirstOrDefault(); - if (anime != null) - { - var eb = new EmbedBuilder - { - Title = anime.Title, - Description = anime.Description, - ImageUrl = anime.ImageURL - }; - - eb.AddInlineField("Premiere", FormatDate(anime.StartDate)) - .AddInlineField("Ended", anime.Airing ? "-" : FormatDate(anime.EndDate)) - .AddInlineField("Episodes", anime.Episodes) - .AddInlineField("MAL Score", anime.Score) - .AddInlineField("Type", anime.Type) - .AddField("MAL Link", $"https://myanimelist.net/anime/{anime.MalId}"); - - await ReplyAsync("", false, eb.Build()); - } - else - { - await ReplyAsync("No anime found with that name..."); - } - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("manga", RunMode = RunMode.Async)] - [Summary("Show Info about a Manga.")] - public async Task SearchManga([Remainder] [Summary("manga-name")] string mangaName) - { - try - { - var results = await _client.SearchManga(mangaName); - var manga = results.Results.FirstOrDefault(); - if (manga != null) - { - var eb = new EmbedBuilder - { - Title = manga.Title, - Description = manga.Description, - ImageUrl = manga.ImageURL - }; - - eb.AddInlineField("Premiere", FormatDate(manga.StartDate)) - .AddInlineField("Ended", manga.Publishing ? "-" : FormatDate(manga.EndDate)) - .AddInlineField("Volumes", manga.Volumes) - .AddInlineField("Chapters", manga.Chapters) - .AddInlineField("MAL Score", manga.Score) - .AddField("MAL Link", $"https://myanimelist.net/manga/{manga.MalId}"); - - await ReplyAsync("", false, eb.Build()); - } - else - { - await ReplyAsync("No manga found with that name..."); - } - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - private string FormatDate(DateTime? dateTime) - { - if (!dateTime.HasValue) - { - return DateTime.MinValue.ToString("d", Thread.CurrentThread.CurrentUICulture); - } - - return dateTime.Value.ToString("d", Thread.CurrentThread.CurrentUICulture); - } - } -} \ 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/Youtube.cs b/src/Bot/Commands/Integrations/Youtube.cs deleted file mode 100644 index 50e9519..0000000 --- a/src/Bot/Commands/Integrations/Youtube.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Discord.Commands; -using Geekbot.Core; -// 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 - { - // private readonly IGlobalSettings _globalSettings; - // private readonly IErrorHandler _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); - // } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs b/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs deleted file mode 100644 index 23187bd..0000000 --- a/src/Bot/Commands/Randomness/BenedictCumberbatchNameGenerator.cs +++ /dev/null @@ -1,63 +0,0 @@ -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 - { - private readonly IErrorHandler _errorHandler; - private readonly IRandomNumberGenerator _randomNumberGenerator; - - public BenedictCumberbatchNameGenerator(IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator) - { - _errorHandler = errorHandler; - _randomNumberGenerator = randomNumberGenerator; - } - - [Command("bdcb", RunMode = RunMode.Async)] - [Summary("Benedict Cumberbatch Name Generator")] - public async Task GetQuote() - { - try - { - var firstnameList = new List - { - "Bumblebee", "Bandersnatch", "Broccoli", "Rinkydink", "Bombadil", "Boilerdang", "Bandicoot", "Fragglerock", "Muffintop", "Congleton", "Blubberdick", "Buffalo", "Benadryl", - "Butterfree", "Burberry", "Whippersnatch", "Buttermilk", "Beezlebub", "Budapest", "Boilerdang", "Blubberwhale", "Bumberstump", "Bulbasaur", "Cogglesnatch", "Liverswort", - "Bodybuild", "Johnnycash", "Bendydick", "Burgerking", "Bonaparte", "Bunsenburner", "Billiardball", "Bukkake", "Baseballmitt", "Blubberbutt", "Baseballbat", "Rumblesack", - "Barister", "Danglerack", "Rinkydink", "Bombadil", "Honkytonk", "Billyray", "Bumbleshack", "Snorkeldink", "Beetlejuice", "Bedlington", "Bandicoot", "Boobytrap", "Blenderdick", - "Bentobox", "Pallettown", "Wimbledon", "Buttercup", "Blasphemy", "Syphilis", "Snorkeldink", "Brandenburg", "Barbituate", "Snozzlebert", "Tiddleywomp", "Bouillabaisse", - "Wellington", "Benetton", "Bendandsnap", "Timothy", "Brewery", "Bentobox", "Brandybuck", "Benjamin", "Buckminster", "Bourgeoisie", "Bakery", "Oscarbait", "Buckyball", - "Bourgeoisie", "Burlington", "Buckingham", "Barnoldswick", "Bumblesniff", "Butercup", "Bubblebath", "Fiddlestick", "Bulbasaur", "Bumblebee", "Bettyboop", "Botany", "Cadbury", - "Brendadirk", "Buckingham", "Barnabus", "Barnacle", "Billybong", "Botany", "Benddadick", "Benderchick" - }; - - var lastnameList = new List - { - "Coddleswort", "Crumplesack", "Curdlesnoot", "Calldispatch", "Humperdinck", "Rivendell", "Cuttlefish", "Lingerie", "Vegemite", "Ampersand", "Cumberbund", "Candycrush", - "Clombyclomp", "Cragglethatch", "Nottinghill", "Cabbagepatch", "Camouflage", "Creamsicle", "Curdlemilk", "Upperclass", "Frumblesnatch", "Crumplehorn", "Talisman", "Candlestick", - "Chesterfield", "Bumbersplat", "Scratchnsniff", "Snugglesnatch", "Charizard", "Carrotstick", "Cumbercooch", "Crackerjack", "Crucifix", "Cuckatoo", "Cockletit", "Collywog", - "Capncrunch", "Covergirl", "Cumbersnatch", "Countryside", "Coggleswort", "Splishnsplash", "Copperwire", "Animorph", "Curdledmilk", "Cheddarcheese", "Cottagecheese", "Crumplehorn", - "Snickersbar", "Banglesnatch", "Stinkyrash", "Cameltoe", "Chickenbroth", "Concubine", "Candygram", "Moldyspore", "Chuckecheese", "Cankersore", "Crimpysnitch", "Wafflesmack", - "Chowderpants", "Toodlesnoot", "Clavichord", "Cuckooclock", "Oxfordshire", "Cumbersome", "Chickenstrips", "Battleship", "Commonwealth", "Cunningsnatch", "Custardbath", - "Kryptonite", "Curdlesnoot", "Cummerbund", "Coochyrash", "Crackerdong", "Crackerdong", "Curdledong", "Crackersprout", "Crumplebutt", "Colonist", "Coochierash", "Anglerfish", - "Cumbersniff", "Charmander", "Scratch-n-sniff", "Cumberbitch", "Pumpkinpatch", "Cramplesnutch", "Lumberjack", "Bonaparte", "Cul-de-sac", "Cankersore", "Cucumbercatch", "Contradict" - }; - - var lastname = lastnameList[_randomNumberGenerator.Next(0, lastnameList.Count - 1)]; - var firstname = firstnameList[_randomNumberGenerator.Next(0, firstnameList.Count - 1)]; - - await ReplyAsync($"{firstname} {lastname}"); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} diff --git a/src/Bot/Commands/Randomness/Cat/Cat.cs b/src/Bot/Commands/Randomness/Cat/Cat.cs deleted file mode 100644 index 1198113..0000000 --- a/src/Bot/Commands/Randomness/Cat/Cat.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Randomness.Cat -{ - public class Cat : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public Cat(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("cat", RunMode = RunMode.Async)] - [Summary("Return a random image of a cat.")] - public async Task Say() - { - try - { - var response = await HttpAbstractions.Get(new Uri("https://aws.random.cat/meow")); - var eb = new EmbedBuilder - { - ImageUrl = response.File - }; - 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/Randomness/Cat/CatResponseDto.cs b/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs deleted file mode 100644 index 523613b..0000000 --- a/src/Bot/Commands/Randomness/Cat/CatResponseDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 7c0aefa..0000000 --- a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokeResponseDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index e2b1f16..0000000 --- a/src/Bot/Commands/Randomness/Chuck/ChuckNorrisJokes.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Randomness.Chuck -{ - public class ChuckNorrisJokes : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public ChuckNorrisJokes(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("chuck", RunMode = RunMode.Async)] - [Summary("A random chuck norris joke")] - public async Task Say() - { - try - { - try - { - var response = await HttpAbstractions.Get(new Uri("https://api.chucknorris.io/jokes/random")); - await ReplyAsync(response.Value); - } - catch (HttpRequestException) - { - await ReplyAsync("Api down..."); - } - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs b/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs deleted file mode 100644 index 012f9e9..0000000 --- a/src/Bot/Commands/Randomness/Dad/DadJokeResponseDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 67f9679..0000000 --- a/src/Bot/Commands/Randomness/Dad/DadJokes.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Randomness.Dad -{ - public class DadJokes : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public DadJokes(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("dad", RunMode = RunMode.Async)] - [Summary("A random dad joke")] - public async Task Say() - { - try - { - var response = await HttpAbstractions.Get(new Uri("https://icanhazdadjoke.com/")); - await ReplyAsync(response.Joke); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Dog/Dog.cs b/src/Bot/Commands/Randomness/Dog/Dog.cs deleted file mode 100644 index 39e57c7..0000000 --- a/src/Bot/Commands/Randomness/Dog/Dog.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Randomness.Dog -{ - public class Dog : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public Dog(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("dog", RunMode = RunMode.Async)] - [Summary("Return a random image of a dog.")] - public async Task Say() - { - try - { - var response = await HttpAbstractions.Get(new Uri("http://random.dog/woof.json")); - await ReplyAsync(response.Url); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs b/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs deleted file mode 100644 index 9f0dfce..0000000 --- a/src/Bot/Commands/Randomness/Dog/DogResponseDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index b5f0c3a..0000000 --- a/src/Bot/Commands/Randomness/EightBall.cs +++ /dev/null @@ -1,41 +0,0 @@ -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 EightBall(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - } - - [Command("8ball", RunMode = RunMode.Async)] - [Summary("Ask 8Ball a Question.")] - public async Task Ball([Remainder] [Summary("question")] string echo) - { - try - { - var enumerator = Localization.EightBall.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true).GetEnumerator(); - var replies = new List(); - while (enumerator.MoveNext()) - { - replies.Add(enumerator.Value?.ToString()); - } - - var answer = new Random().Next(replies.Count); - await ReplyAsync(replies[answer]); - } - 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 deleted file mode 100644 index e5d2e95..0000000 --- a/src/Bot/Commands/Randomness/Kanye/Kanye.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Randomness.Kanye -{ - public class Kanye : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - - public Kanye(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("kanye", RunMode = RunMode.Async)] - [Summary("A random kayne west quote")] - public async Task Say() - { - try - { - var response = await HttpAbstractions.Get(new Uri("https://api.kanye.rest/")); - await ReplyAsync(response.Quote); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs b/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs deleted file mode 100644 index ab8c06f..0000000 --- a/src/Bot/Commands/Randomness/Kanye/KanyeResponseDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Bot.Commands.Randomness.Kanye -{ - public class KanyeResponseDto - { - [JsonPropertyName("quote")] - public string Quote { get; set; } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Ship.cs b/src/Bot/Commands/Randomness/Ship.cs deleted file mode 100644 index 55e55c5..0000000 --- a/src/Bot/Commands/Randomness/Ship.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -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; -using Geekbot.Core.Extensions; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.RandomNumberGenerator; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Bot.Commands.Randomness -{ - public class Ship : GeekbotCommandBase - { - private readonly IRandomNumberGenerator _randomNumberGenerator; - private readonly DatabaseContext _database; - - public Ship(DatabaseContext database, IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _database = database; - _randomNumberGenerator = randomNumberGenerator; - } - - [Command("Ship", RunMode = RunMode.Async)] - [Summary("Ask the Shipping meter")] - public async Task Command([Summary("@user1")] IUser user1, [Summary("@user2")] IUser user2) - { - try - { - var userKeys = user1.Id < user2.Id - ? new Tuple(user1.Id.AsLong(), user2.Id.AsLong()) - : new Tuple(user2.Id.AsLong(), user1.Id.AsLong()); - - var dbval = _database.Ships.FirstOrDefault(s => - s.FirstUserId.Equals(userKeys.Item1) && - s.SecondUserId.Equals(userKeys.Item2)); - - var shippingRate = 0; - if (dbval == null) - { - shippingRate = _randomNumberGenerator.Next(1, 100); - _database.Ships.Add(new ShipsModel() - { - FirstUserId = userKeys.Item1, - SecondUserId = userKeys.Item2, - Strength = shippingRate - }); - await _database.SaveChangesAsync(); - } - else - { - shippingRate = dbval.Strength; - } - - var reply = $":heartpulse: **{Localization.Ship.Matchmaking}** :heartpulse:\r\n"; - reply += $":two_hearts: {user1.Mention} :heart: {user2.Mention} :two_hearts:\r\n"; - reply += $"0% [{BlockCounter(shippingRate)}] 100% - {DeterminateSuccess(shippingRate)}"; - await ReplyAsync(reply); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - private string DeterminateSuccess(int rate) - { - return (rate / 20) switch - { - 0 => Localization.Ship.NotGoingToHappen, - 1 => Localization.Ship.NotSuchAGoodIdea, - 2 => Localization.Ship.ThereMightBeAChance, - 3 => Localization.Ship.CouldWork, - 4 => Localization.Ship.ItsAMatch, - _ => "nope" - }; - } - - private string BlockCounter(int rate) - { - var amount = rate / 10; - Console.WriteLine(amount); - var blocks = ""; - for (var i = 1; i <= 10; i++) - if (i <= amount) - { - blocks += ":white_medium_small_square:"; - if (i == amount) - blocks += $" {rate}% "; - } - else - { - blocks += ":black_medium_small_square:"; - } - - return blocks; - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Randomness/Slap.cs b/src/Bot/Commands/Randomness/Slap.cs deleted file mode 100644 index c99c325..0000000 --- a/src/Bot/Commands/Randomness/Slap.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Generic; -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; -using Geekbot.Core.Extensions; - -namespace Geekbot.Bot.Commands.Randomness -{ - public class Slap : TransactionModuleBase - { - private readonly IErrorHandler _errorHandler; - private readonly DatabaseContext _database; - - public Slap(IErrorHandler errorHandler, DatabaseContext database) - { - _errorHandler = errorHandler; - _database = database; - } - - [Command("slap", RunMode = RunMode.Async)] - [Summary("slap someone")] - public async Task Slapper([Summary("@someone")] IUser user) - { - try - { - if (user.Id == Context.User.Id) - { - await ReplyAsync("Why would you slap yourself?"); - return; - } - - var things = new List - { - "thing", - "rubber chicken", - "leek stick", - "large trout", - "flat hand", - "strip of bacon", - "feather", - "piece of pizza", - "moldy banana", - "sharp retort", - "printed version of wikipedia", - "panda paw", - "spiked sledgehammer", - "monstertruck", - "dirty toilet brush", - "sleeping seagull", - "sunflower", - "mousepad", - "lolipop", - "bottle of rum", - "cheese slice", - "critical 1", - "natural 20", - "mjölnir (aka mewmew)", - "kamehameha", - "copy of Twilight", - "med pack (get ready for the end boss)", - "derp", - "condom (used)", - "gremlin fed after midnight", - "wet baguette", - "exploding kitten", - "shiny piece of shit", - "mismatched pair of socks", - "horcrux", - "tuna", - "suggestion", - "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" - }; - - await ReplyAsync($"{Context.User.Username} slapped {user.Username} with a {things[new Random().Next(0, things.Count - 1)]}"); - - await UpdateRecieved(user.Id); - await UpdateGiven(Context.User.Id); - await _database.SaveChangesAsync(); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - - private async Task UpdateGiven(ulong userId) - { - var user = await GetUser(userId); - user.Given++; - _database.Slaps.Update(user); - } - - private async Task UpdateRecieved(ulong userId) - { - var user = await GetUser(userId); - user.Recieved++; - _database.Slaps.Update(user); - } - - private async Task GetUser(ulong userId) - { - var user = _database.Slaps.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && - e.UserId.Equals(userId.AsLong()) - ); - - if (user != null) return user; - - _database.Slaps.Add(new SlapsModel - { - GuildId = Context.Guild.Id.AsLong(), - UserId = userId.AsLong(), - Recieved = 0, - Given = 0 - }); - await _database.SaveChangesAsync(); - return _database.Slaps.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && - e.UserId.Equals(userId.AsLong())); - } - } -} diff --git a/src/Bot/Commands/Rpg/Cookies.cs b/src/Bot/Commands/Rpg/Cookies.cs deleted file mode 100644 index 66d845f..0000000 --- a/src/Bot/Commands/Rpg/Cookies.cs +++ /dev/null @@ -1,164 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -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.RandomNumberGenerator; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Bot.Commands.Rpg -{ - [DisableInDirectMessage] - [Group("cookies")] - [Alias("cookie")] - public class Cookies : GeekbotCommandBase - { - private readonly DatabaseContext _database; - private readonly IRandomNumberGenerator _randomNumberGenerator; - - public Cookies(DatabaseContext database, IErrorHandler errorHandler, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager) - : base(errorHandler, guildSettingsManager) - { - _database = database; - _randomNumberGenerator = randomNumberGenerator; - } - - [Command("get", RunMode = RunMode.Async)] - [Summary("Get a cookie every 24 hours")] - public async Task GetCookies() - { - try - { - var actor = await GetUser(Context.User.Id); - var timeoutDays = 1; - if (actor.LastPayout?.AddDays(timeoutDays) > DateTime.Now.ToUniversalTime()) - { - var remaining = actor.LastPayout.Value.AddDays(timeoutDays) - DateTimeOffset.Now.ToUniversalTime(); - var formattedWaitTime = DateLocalization.FormatDateTimeAsRemaining(remaining); - await ReplyAsync(string.Format(Localization.Cookies.WaitForMoreCookies, formattedWaitTime)); - return; - } - actor.Cookies += 10; - actor.LastPayout = DateTimeOffset.Now.ToUniversalTime(); - await SetUser(actor); - await ReplyAsync(string.Format(Localization.Cookies.GetCookies, 10, actor.Cookies)); - - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("jar", RunMode = RunMode.Async)] - [Summary("Look at your cookie jar")] - public async Task PeekIntoCookieJar() - { - try - { - var actor = await GetUser(Context.User.Id); - await ReplyAsync(string.Format(Localization.Cookies.InYourJar, actor.Cookies)); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("give", RunMode = RunMode.Async)] - [Summary("Give cookies to someone")] - public async Task GiveACookie([Summary("@someone")] IUser user, [Summary("amount")] int amount = 1) - { - try - { - 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); - return; - } - - var taker = await GetUser(user.Id); - - giver.Cookies -= amount; - taker.Cookies += amount; - - await SetUser(giver); - await SetUser(taker); - - await ReplyAsync(string.Format(Localization.Cookies.Given, amount, user.Username)); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - [Command("eat", RunMode = RunMode.Async)] - [Summary("Eat a cookie")] - public async Task EatACookie() - { - try - { - var actor = await GetUser(Context.User.Id); - - if (actor.Cookies < 5) - { - await ReplyAsync(Localization.Cookies.NotEnoughCookiesToEat); - return; - } - - var amount = _randomNumberGenerator.Next(1, 5); - actor.Cookies -= amount; - - await SetUser(actor); - - await ReplyAsync(string.Format(Localization.Cookies.AteCookies, amount, actor.Cookies)); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - private async Task GetUser(ulong userId) - { - var user = _database.Cookies.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId); - return user; - } - - private async Task SetUser(CookiesModel user) - { - _database.Cookies.Update(user); - await _database.SaveChangesAsync(); - } - - private async Task CreateNewRow(ulong userId) - { - var user = new CookiesModel() - { - GuildId = Context.Guild.Id.AsLong(), - UserId = userId.AsLong(), - Cookies = 0, - LastPayout = DateTimeOffset.MinValue.ToUniversalTime() - }; - var newUser = _database.Cookies.Add(user).Entity; - await _database.SaveChangesAsync(); - return newUser; - } - } -} diff --git a/src/Bot/Commands/User/Karma.cs b/src/Bot/Commands/User/Karma.cs deleted file mode 100644 index 469c371..0000000 --- a/src/Bot/Commands/User/Karma.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Commands.Karma; -using Geekbot.Core; -using Geekbot.Core.Database; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.Extensions; -using Geekbot.Core.GuildSettingsManager; - -namespace Geekbot.Bot.Commands.User -{ - [DisableInDirectMessage] - public class Karma : GeekbotCommandBase - { - private readonly DatabaseContext _database; - - public Karma(DatabaseContext database, IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _database = database; - } - - [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() - { - Id = Context.User.Id.ToString(), - Username = Context.User.Username, - Discriminator = Context.User.Discriminator, - Avatar = Context.User.AvatarId, - }; - var targetUser = new Interactions.Resolved.User() - { - 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); - - await ReplyAsync(string.Empty, false, res.ToDiscordNetEmbed().Build()); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - } -} \ 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/Stats.cs b/src/Bot/Commands/User/Stats.cs deleted file mode 100644 index 61505c0..0000000 --- a/src/Bot/Commands/User/Stats.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -using Geekbot.Core; -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 -{ - public class Stats : GeekbotCommandBase - { - private readonly ILevelCalc _levelCalc; - private readonly DatabaseContext _database; - - public Stats(DatabaseContext database, IErrorHandler errorHandler, ILevelCalc levelCalc, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - _database = database; - _levelCalc = levelCalc; - } - - [Command("stats", RunMode = RunMode.Async)] - [Summary("Get information about this user")] - [DisableInDirectMessage] - public async Task User([Summary("@someone")] IUser user = null) - { - try - { - var userInfo = user ?? Context.Message.Author; - var userGuildInfo = (IGuildUser) userInfo; - var createdAt = userInfo.CreatedAt; - var joinedAt = userGuildInfo.JoinedAt.Value; - var age = Math.Floor((DateTime.Now - createdAt).TotalDays); - var joinedDayAgo = Math.Floor((DateTime.Now - joinedAt).TotalDays); - - var messages = _database.Messages - ?.FirstOrDefault(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong())) - ?.MessageCount ?? 0; - var guildMessages = _database.Messages - ?.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())) - .Select(e => e.MessageCount) - .Sum() ?? 0; - - var level = _levelCalc.GetLevel(messages); - - var percent = Math.Round((double) (100 * messages) / guildMessages, 2); - - var cookies = _database.Cookies - ?.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()) - .WithName(userInfo.Username)); - eb.WithColor(new Color(221, 255, 119)); - - var karma = _database.Karma.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && - e.UserId.Equals(userInfo.Id.AsLong())); - var correctRolls = _database.Rolls.FirstOrDefault(e => - e.GuildId.Equals(Context.Guild.Id.AsLong()) && - e.UserId.Equals(userInfo.Id.AsLong())); - - eb.AddInlineField(Localization.Stats.OnDiscordSince, - $"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} {Localization.Stats.Days})") - .AddInlineField(Localization.Stats.JoinedServer, - $"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} {Localization.Stats.Days})") - .AddInlineField(Localization.Stats.Karma, karma?.Karma ?? 0) - .AddInlineField(Localization.Stats.Level, level) - .AddInlineField(Localization.Stats.MessagesSent, messages) - .AddInlineField(Localization.Stats.ServerTotal, $"{percent}%"); - - 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()); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Changelog/Changelog.cs b/src/Bot/Commands/Utils/Changelog/Changelog.cs deleted file mode 100644 index 989ac0d..0000000 --- a/src/Bot/Commands/Utils/Changelog/Changelog.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Discord.WebSocket; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; - -namespace Geekbot.Bot.Commands.Utils.Changelog -{ - public class Changelog : TransactionModuleBase - { - private readonly DiscordSocketClient _client; - private readonly IErrorHandler _errorHandler; - - public Changelog(IErrorHandler errorHandler, DiscordSocketClient client) - { - _errorHandler = errorHandler; - _client = client; - } - - [Command("changelog", RunMode = RunMode.Async)] - [Summary("Show the latest 10 updates")] - public async Task GetChangelog() - { - try - { - var commits = await HttpAbstractions.Get>(new Uri("https://api.github.com/repos/pizzaandcoffee/geekbot.net/commits")); - - var eb = new EmbedBuilder(); - eb.WithColor(new Color(143, 165, 102)); - eb.WithAuthor(new EmbedAuthorBuilder - { - IconUrl = _client.CurrentUser.GetAvatarUrl(), - Name = "Latest Updates", - Url = "https://geekbot.pizzaandcoffee.rocks/updates" - }); - var sb = new StringBuilder(); - foreach (var commit in commits.Take(10)) - sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.Author.Date:yyyy-MM-dd})"); - eb.Description = sb.ToString(); - eb.WithFooter(new EmbedFooterBuilder - { - Text = $"List generated from github commits on {DateTime.Now:yyyy-MM-dd}" - }); - 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/Utils/Changelog/CommitAuthorDto.cs b/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs deleted file mode 100644 index 19d93eb..0000000 --- a/src/Bot/Commands/Utils/Changelog/CommitAuthorDto.cs +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index e67d08c..0000000 --- a/src/Bot/Commands/Utils/Changelog/CommitDto.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 592da9e..0000000 --- a/src/Bot/Commands/Utils/Changelog/CommitInfoDto.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 450433d..0000000 --- a/src/Bot/Commands/Utils/Choose.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Discord.Commands; -using Geekbot.Core; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GuildSettingsManager; -using Localization = Geekbot.Core.Localization; - -namespace Geekbot.Bot.Commands.Utils -{ - public class Choose : GeekbotCommandBase - { - public Choose(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager) - { - } - - [Command("choose", RunMode = RunMode.Async)] - [Summary("Let the bot choose for you, separate options with a semicolon.")] - public async Task Command([Remainder] [Summary("option1;option2")] - string choices) - { - try - { - var choicesArray = choices.Split(';'); - var choice = new Random().Next(choicesArray.Length); - await ReplyAsync(string.Format(Localization.Choose.Choice, choicesArray[choice].Trim())); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Dice.cs b/src/Bot/Commands/Utils/Dice.cs deleted file mode 100644 index c57001f..0000000 --- a/src/Bot/Commands/Utils/Dice.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -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 - { - private readonly IErrorHandler _errorHandler; - private readonly IDiceParser _diceParser; - - public Dice(IErrorHandler errorHandler, IDiceParser diceParser) - { - _errorHandler = errorHandler; - _diceParser = diceParser; - } - - // ToDo: Separate representation and logic - // ToDo: Translate - [Command("dice", RunMode = RunMode.Async)] - [Summary("Roll a dice. (use '!dice help' for a manual)")] - public async Task RollCommand([Remainder] [Summary("input")] string diceInput = "1d20") - { - try - { - if (diceInput == "help") - { - await ShowDiceHelp(); - return; - } - - var parsed = _diceParser.Parse(diceInput); - - var sb = new StringBuilder(); - sb.AppendLine($"{Context.User.Mention} :game_die:"); - foreach (var die in parsed.Dice) - { - sb.AppendLine($"**{die.DiceName}**"); - var diceResultList = new List(); - var total = 0; - - foreach (var roll in die.Roll()) - { - diceResultList.Add(roll.ToString()); - total += roll.Result; - } - - sb.AppendLine(string.Join(" | ", diceResultList)); - - if (parsed.SkillModifier != 0) - { - sb.AppendLine($"Skill: {parsed.SkillModifier}"); - } - - if (parsed.Options.ShowTotal) - { - var totalLine = $"Total: {total}"; - if (parsed.SkillModifier > 0) - { - totalLine += ($" (+{parsed.SkillModifier} = {total + parsed.SkillModifier})"); - } - - if (parsed.SkillModifier < 0) - { - totalLine += ($" ({parsed.SkillModifier} = {total - parsed.SkillModifier})"); - } - - sb.AppendLine(totalLine); - } - } - - await Context.Channel.SendMessageAsync(sb.ToString()); - } - catch (DiceException e) - { - await Context.Channel.SendMessageAsync($"**:warning: {e.DiceName} is invalid:** {e.Message}"); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - - private async Task ShowDiceHelp() - { - var sb = new StringBuilder(); - sb.AppendLine("**__Examples__**"); - sb.AppendLine("```"); - sb.AppendLine("!dice - throw a 1d20"); - sb.AppendLine("!dice 1d12 - throw a 1d12"); - sb.AppendLine("!dice +1d20 - throw with advantage"); - sb.AppendLine("!dice -1d20 - throw with disadvantage"); - sb.AppendLine("!dice 1d20 +2 - throw with a +2 skill bonus"); - sb.AppendLine("!dice 1d20 -2 - throw with a -2 skill bonus"); - sb.AppendLine("!dice 8d6 - throw a fireball 🔥"); - sb.AppendLine("!dice 8d6 total - calculate the total"); - sb.AppendLine("!dice 2d20 6d6 2d12 - drop your dice pouch"); - sb.AppendLine("```"); - - await Context.Channel.SendMessageAsync(sb.ToString()); - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Lmgtfy.cs b/src/Bot/Commands/Utils/Lmgtfy.cs deleted file mode 100644 index 76fa6fa..0000000 --- a/src/Bot/Commands/Utils/Lmgtfy.cs +++ /dev/null @@ -1,34 +0,0 @@ -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 - { - private readonly IErrorHandler _errorHandler; - - public Lmgtfy(IErrorHandler errorHandler) - { - _errorHandler = errorHandler; - } - - [Command("lmgtfy", RunMode = RunMode.Async)] - [Summary("Get a 'Let me google that for you' link")] - public async Task GetUrl([Remainder] [Summary("question")] string question) - { - try - { - var encoded = HttpUtility.UrlEncode(question).Replace("%20", "+"); - await Context.Channel.SendMessageAsync($""); - } - catch (Exception e) - { - await _errorHandler.HandleCommandException(e, Context); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Quote/MessageLink.cs b/src/Bot/Commands/Utils/Quote/MessageLink.cs deleted file mode 100644 index dff1273..0000000 --- a/src/Bot/Commands/Utils/Quote/MessageLink.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Data; -using System.Text.RegularExpressions; - -namespace Geekbot.Bot.Commands.Utils.Quote -{ - public class MessageLink - { - public readonly static Regex re = new Regex( - @"https:\/\/((canary|ptb)\.)?discord(app)?.com\/channels\/(?\d{16,20})\/(?\d{16,20})\/(?\d{16,20})", - RegexOptions.Compiled | RegexOptions.IgnoreCase, - new TimeSpan(0, 0, 2)); - - public ulong GuildId { get; set; } - public ulong ChannelId { get; set; } - public ulong MessageId { get; set; } - - public MessageLink(string url) - { - var matches = re.Matches(url); - - foreach (Match match in matches) - { - foreach (Group matchGroup in match.Groups) - { - switch (matchGroup.Name) - { - case "GuildId": - GuildId = ulong.Parse(matchGroup.Value); - break; - case "ChannelId": - ChannelId = ulong.Parse(matchGroup.Value); - break; - case "MessageId": - MessageId = ulong.Parse(matchGroup.Value); - break; - } - } - } - } - - public static bool IsValid(string link) - { - return re.IsMatch(link); - } - } -} \ No newline at end of file diff --git a/src/Bot/Commands/Utils/Quote/Quote.cs b/src/Bot/Commands/Utils/Quote/Quote.cs deleted file mode 100644 index 243e5dd..0000000 --- a/src/Bot/Commands/Utils/Quote/Quote.cs +++ /dev/null @@ -1,322 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Geekbot.Bot.CommandPreconditions; -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.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 -{ - [Group("quote")] - [DisableInDirectMessage] - public class Quote : GeekbotCommandBase - { - 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) - : base(errorHandler, guildSettingsManager) - { - _database = database; - _randomNumberGenerator = randomNumberGenerator; - _userRepository = userRepository; - // to remove restrictions when developing - _isDev = Constants.BotVersion() == "0.0.0-DEV"; - } - - [Command] - [Summary("Return a random quote from the database")] - public async Task GetRandomQuote() - { - 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()) - { - await ReplyAsync(Localization.Quote.NoQuotesFound); - Transaction.Status = SpanStatus.NotFound; - return; - } - - var buildQuoteEmbedSpan = Transaction.StartChild("BuildQuoteEmbed"); - 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; - } - } - - [Command("add")] - [Alias("save")] - [Summary("Add a quote from the last sent message by @user")] - public async Task AddQuote([Summary("@someone")] IUser user) - { - await QuoteFromMention(user, true); - } - - [Command("make")] - [Alias("preview")] - [Summary("Preview a quote from the last sent message by @user")] - public async Task ReturnSpecifiedQuote([Summary("@someone")] IUser user) - { - await QuoteFromMention(user, false); - } - - [Command("add")] - [Alias("save")] - [Summary("Add a quote from a message link")] - public async Task AddQuote([Summary("message-link")] string messageLink) - { - await QuoteFromMessageLink(messageLink, true); - } - - [Command("make")] - [Alias("preview")] - [Summary("Preview a quote from a message link")] - public async Task ReturnSpecifiedQuote([Summary("message-link")] string messageLink) - { - await QuoteFromMessageLink(messageLink, false); - } - - [Command("remove")] - [RequireUserPermission(GuildPermission.ManageMessages)] - [Summary("Remove a quote (user needs the 'ManageMessages' permission)")] - public async Task RemoveQuote([Summary("quote-ID")] int id) - { - try - { - var quote = _database.Quotes.Where(e => e.GuildId == Context.Guild.Id.AsLong() && e.InternalId == id)?.FirstOrDefault(); - if (quote != null) - { - _database.Quotes.Remove(quote); - await _database.SaveChangesAsync(); - var embed = QuoteBuilder(quote); - await ReplyAsync(string.Format(Localization.Quote.Removed, id), false, embed.Build()); - } - else - { - await ReplyAsync(Localization.Quote.NotFoundWithId); - } - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, "I couldn't find a quote with that id :disappointed:"); - } - } - - [Command("stats")] - [Summary("Show quote stats for this server")] - public async Task GetQuoteStatsForServer() - { - try - { - // setup - var eb = new EmbedBuilder(); - eb.Author = new EmbedAuthorBuilder() - { - IconUrl = Context.Guild.IconUrl, - Name = $"{Context.Guild.Name} - {Localization.Quote.QuoteStats}" - }; - - // gather data - var totalQuotes = _database.Quotes.Count(row => row.GuildId == Context.Guild.Id.AsLong()); - if (totalQuotes == 0) - { - // no quotes, no stats, end of the road - await ReplyAsync(Localization.Quote.NoQuotesFound); - return; - } - - var mostQuotedPerson = _database.Quotes - .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(); - var mostQuotedPersonUser = Context.Client.GetUserAsync(mostQuotedPerson.userId.AsUlong()).Result ?? new UserPolyfillDto {Username = "Unknown User"}; - - var quotesByYear = _database.Quotes - .Where(row => row.GuildId == Context.Guild.Id.AsLong()) - .GroupBy(row => row.Time.Year) - .Select(row => new { year = row.Key, amount = row.Count()}) - .OrderBy(row => row.year); - - // add data to the embed - eb.AddField(Localization.Quote.MostQuotesPerson, $"{mostQuotedPersonUser.Username} ({mostQuotedPerson.amount})"); - eb.AddInlineField(Localization.Quote.TotalQuotes, totalQuotes); - - foreach (var year in quotesByYear) - { - eb.AddInlineField(year.year.ToString(), year.amount); - } - - await ReplyAsync("", false, eb.Build()); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context); - } - } - - private async Task QuoteFromMention(IUser user, bool saveToDb) - { - try - { - var list = Context.Channel.GetMessagesAsync().Flatten(); - var message = await list.FirstOrDefaultAsync(msg => - msg.Author.Id == user.Id && - msg.Embeds.Count == 0 && - msg.Id != Context.Message.Id && - !msg.Content.ToLower().StartsWith("!")); - if (message == null) return; - - await ProcessQuote(message, saveToDb); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, $"No quoteable messages have been sent by {user.Username} in this channel"); - } - - } - - private async Task QuoteFromMessageLink(string messageLink, bool saveToDb) - { - try - { - if (!MessageLink.IsValid(messageLink)) - { - await ReplyAsync(Localization.Quote.NotAValidMessageLink); - return; - } - - var link = new MessageLink(messageLink); - if (link.GuildId != Context.Guild.Id) - { - await ReplyAsync(Localization.Quote.OnlyQuoteFromSameServer); - return; - } - - var channel = link.ChannelId == Context.Channel.Id - ? Context.Channel - : await Context.Guild.GetTextChannelAsync(link.ChannelId); - - var message = await channel.GetMessageAsync(link.MessageId); - - await ProcessQuote(message, saveToDb); - } - catch (Exception e) - { - await ErrorHandler.HandleCommandException(e, Context, "I couldn't find that message :disappointed:"); - } - } - - private async Task ProcessQuote(IMessage message, bool saveToDb) - { - if (message.Author.Id == Context.Message.Author.Id && saveToDb && !_isDev) - { - await ReplyAsync(Localization.Quote.CannotSaveOwnQuotes); - return; - } - - if (message.Author.IsBot && saveToDb && !_isDev) - { - await ReplyAsync(Localization.Quote.CannotQuoteBots); - return; - } - - var quote = CreateQuoteObject(message); - if (saveToDb) - { - await _database.Quotes.AddAsync(quote); - await _database.SaveChangesAsync(); - } - - var embed = QuoteBuilder(quote); - - var sb = new StringBuilder(); - if (saveToDb) sb.AppendLine(Localization.Quote.QuoteAdded); - - 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 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}"; - eb.Description = quote.Quote; - eb.ThumbnailUrl = user.GetAvatarUrl(); - if (quote.Image != null) eb.ImageUrl = quote.Image; - embedBuilderSpan.Finish(); - - return eb; - } - - private QuoteModel CreateQuoteObject(IMessage message) - { - string image; - try - { - image = message.Attachments.First().Url; - } - catch (Exception) - { - image = null; - } - - var last = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).OrderByDescending(e => e.InternalId).FirstOrDefault(); - var internalId = 0; - if (last != null) internalId = last.InternalId + 1; - return new QuoteModel() - { - InternalId = internalId, - GuildId = Context.Guild.Id.AsLong(), - UserId = message.Author.Id.AsLong(), - Time = message.Timestamp.DateTime.ToUniversalTime(), - Quote = message.Content, - Image = image - }; - } - } -} \ No newline at end of file diff --git a/src/Bot/Handlers/CommandHandler.cs b/src/Bot/Handlers/CommandHandler.cs deleted file mode 100644 index 19d4edd..0000000 --- a/src/Bot/Handlers/CommandHandler.cs +++ /dev/null @@ -1,124 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Discord; -using Discord.Commands; -using Discord.Rest; -using Discord.WebSocket; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; -using Geekbot.Core.GuildSettingsManager; -using Geekbot.Core.Logger; - -namespace Geekbot.Bot.Handlers -{ - public class CommandHandler - { - private readonly IDiscordClient _client; - private readonly IGeekbotLogger _logger; - private readonly IServiceProvider _servicesProvider; - private readonly CommandService _commands; - private readonly RestApplication _applicationInfo; - private readonly IGuildSettingsManager _guildSettingsManager; - private readonly List _ignoredServers; - - public CommandHandler(IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo, - IGuildSettingsManager guildSettingsManager) - { - _client = client; - _logger = logger; - _servicesProvider = servicesProvider; - _commands = commands; - _applicationInfo = applicationInfo; - _guildSettingsManager = guildSettingsManager; - - // Some guilds only want very specific functionally without any of the commands, a quick hack that solves that "short term" - // ToDo: create a clean solution for this... - _ignoredServers = new List - { - 228623803201224704, // SwitzerLAN - // 169844523181015040, // EEvent - 248531441548263425, // MYI - 110373943822540800 // Discord Bots - }; - } - - public Task RunCommand(SocketMessage messageParam) - { - try - { - if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask; - if (message.Author.IsBot) return Task.CompletedTask; - - ulong guildId = message.Author switch - { - SocketGuildUser user => user.Guild.Id, - _ => 0 // DM Channel - }; - - if (IsIgnoredGuild(guildId, message.Author.Id)) return Task.CompletedTask; - - var lowCaseMsg = message.ToString().ToLower(); - if (ShouldHui(lowCaseMsg, guildId)) - { - message.Channel.SendMessageAsync("hui!!!"); - return Task.CompletedTask; - } - - if (ShouldPong(lowCaseMsg, guildId)) - { - message.Channel.SendMessageAsync("pong"); - return Task.CompletedTask; - } - - var argPos = 0; - if (!IsCommand(message, ref argPos)) return Task.CompletedTask; - - ExecuteCommand(message, argPos); - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Failed to Process Message", e); - } - - return Task.CompletedTask; - } - - private void ExecuteCommand(IUserMessage message, int argPos) - { - var context = new CommandContext(_client, message); - _commands.ExecuteAsync(context, argPos, _servicesProvider); - _logger.Information(LogSource.Command, context.Message.Content.Split(" ")[0].Replace("!", ""), SimpleConextConverter.ConvertContext(context)); - } - - private bool IsIgnoredGuild(ulong guildId, ulong authorId) - { - if (!_ignoredServers.Contains(guildId)) return false; - return authorId == _applicationInfo.Owner.Id; - } - - private bool IsCommand(IUserMessage message, ref int argPos) - { - return message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos); - } - - private bool ShouldPong(string lowerCaseMessage, ulong guildId) - { - if (!lowerCaseMessage.StartsWith("ping ") && !lowerCaseMessage.Equals("ping")) return false; - if (guildId == 0) return true; - return GetGuildSettings(guildId)?.Ping ?? false; - } - - private bool ShouldHui(string lowerCaseMessage, ulong guildId) - { - if (!lowerCaseMessage.StartsWith("hui")) return false; - if (guildId == 0) return true; - return GetGuildSettings(guildId)?.Hui ?? false; - } - - private GuildSettingsModel GetGuildSettings(ulong guildId) - { - return _guildSettingsManager.GetSettings(guildId, false); - } - } -} \ No newline at end of file diff --git a/src/Bot/Handlers/MessageDeletedHandler.cs b/src/Bot/Handlers/MessageDeletedHandler.cs deleted file mode 100644 index b8ffe5c..0000000 --- a/src/Bot/Handlers/MessageDeletedHandler.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Discord; -using Discord.WebSocket; -using Geekbot.Core.Database; -using Geekbot.Core.Extensions; -using Geekbot.Core.Logger; - -namespace Geekbot.Bot.Handlers -{ - public class MessageDeletedHandler - { - private readonly DatabaseContext _database; - private readonly IGeekbotLogger _logger; - private readonly IDiscordClient _client; - - public MessageDeletedHandler(DatabaseContext database, IGeekbotLogger logger, IDiscordClient client) - { - _database = database; - _logger = logger; - _client = client; - } - - public async Task HandleMessageDeleted(Cacheable message, Cacheable cacheableMessageChannel) - { - try - { - var guildSocketData = ((IGuildChannel) cacheableMessageChannel.Value).Guild; - var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildSocketData.Id.AsLong())); - if ((guild?.ShowDelete ?? false) && guild?.ModChannel != 0) - { - var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong()); - 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(message.Value.Content); - } - else - { - sb.AppendLine("Someone deleted a message, the message was not cached..."); - } - - await modChannelSocket.SendMessageAsync(sb.ToString()); - } - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Failed to send delete message...", e); - } - } - } -} \ No newline at end of file diff --git a/src/Bot/Handlers/ReactionHandler.cs b/src/Bot/Handlers/ReactionHandler.cs deleted file mode 100644 index 816e125..0000000 --- a/src/Bot/Handlers/ReactionHandler.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Threading.Tasks; -using Discord; -using Discord.WebSocket; -using Geekbot.Core.ReactionListener; - -namespace Geekbot.Bot.Handlers -{ - public class ReactionHandler - { - private readonly IReactionListener _reactionListener; - - public ReactionHandler(IReactionListener reactionListener) - { - _reactionListener = reactionListener; - } - - public Task Added(Cacheable cacheableUserMessage, Cacheable cacheableMessageChannel, SocketReaction reaction) - { - if (reaction.User.Value.IsBot) return Task.CompletedTask; - if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; - _reactionListener.GiveRole(cacheableMessageChannel.Value, reaction); - return Task.CompletedTask; - } - - public Task Removed(Cacheable cacheableUserMessage, Cacheable cacheableMessageChannel, SocketReaction reaction) - { - if (reaction.User.Value.IsBot) return Task.CompletedTask; - if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask; - _reactionListener.RemoveRole(cacheableMessageChannel.Value, reaction); - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/src/Bot/Handlers/StatsHandler.cs b/src/Bot/Handlers/StatsHandler.cs deleted file mode 100644 index b089515..0000000 --- a/src/Bot/Handlers/StatsHandler.cs +++ /dev/null @@ -1,114 +0,0 @@ -using System; -using System.Threading.Tasks; -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; - -namespace Geekbot.Bot.Handlers -{ - public class StatsHandler - { - 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) - { - try - { - if (message == null) return; - if (message.Channel.Name.StartsWith('@')) - { - _logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message, true)); - return; - } - - var channel = (SocketGuildChannel) message.Channel; - - // ignore the discord bots server - // ToDo: create a clean solution for this... - if (channel.Guild.Id == 110373943822540800) - { - return; - } - - await UpdateTotalTable(message, channel); - await UpdateSeasonsTable(message, channel); - - - if (message.Author.IsBot) return; - _logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message)); - } - catch (Exception e) - { - _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 deleted file mode 100644 index 1f58131..0000000 --- a/src/Bot/Handlers/UserHandler.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Discord; -using Discord.Rest; -using Discord.WebSocket; -using Geekbot.Core.Database; -using Geekbot.Core.Extensions; -using Geekbot.Core.Logger; -using Geekbot.Core.UserRepository; - -namespace Geekbot.Bot.Handlers -{ - public class UserHandler - { - private readonly IUserRepository _userRepository; - private readonly IGeekbotLogger _logger; - private readonly DatabaseContext _database; - private readonly IDiscordClient _client; - - public UserHandler(IUserRepository userRepository, IGeekbotLogger logger, DatabaseContext database, IDiscordClient client) - { - _userRepository = userRepository; - _logger = logger; - _database = database; - _client = client; - } - - public async Task Joined(SocketGuildUser user) - { - try - { - var userRepoUpdate = _userRepository.Update(user); - _logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})"); - - if (!user.IsBot) - { - var guildSettings = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId == user.Guild.Id.AsLong()); - var message = guildSettings?.WelcomeMessage; - if (string.IsNullOrEmpty(message)) return; - message = message.Replace("$user", user.Mention); - - var fallbackSender = new Func>(() => user.Guild.DefaultChannel.SendMessageAsync(message)); - if (guildSettings.WelcomeChannel != 0) - { - try - { - var target = await _client.GetChannelAsync(guildSettings.WelcomeChannel.AsUlong()); - var channel = target as ISocketMessageChannel; - await channel.SendMessageAsync(message); - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Failed to send welcome message to user defined welcome channel", e); - await fallbackSender(); - } - } - else - { - await fallbackSender(); - } - } - - await userRepoUpdate; - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Failed to send welcome message", e); - } - } - - public async Task Updated(SocketUser oldUser, SocketUser newUser) - { - await _userRepository.Update(newUser); - } - - public async Task Left(SocketGuild socketGuild, SocketUser socketUser) - { - try - { - var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(socketGuild.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"); - } - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Failed to send leave message", e); - } - - _logger.Information(LogSource.Geekbot, $"{socketUser.Username} ({socketUser.Id}) joined {socketGuild.Name} ({socketGuild.Id})"); - } - } -} \ No newline at end of file diff --git a/src/Bot/Storage/croissant b/src/Bot/Storage/croissant deleted file mode 100644 index 6b4897f..0000000 --- a/src/Bot/Storage/croissant +++ /dev/null @@ -1,10 +0,0 @@ -https://i2.wp.com/epicureandculture.com/wp-content/uploads/2014/12/shutterstock_172040546.jpg -http://www.bakespace.com/images/large/5d79070cf21b2f33c3a1dd4336cb27d2.jpeg -http://food.fnr.sndimg.com/content/dam/images/food/fullset/2015/5/7/1/SD1B43_croissants-recipe_s4x3.jpg.rend.hgtvcom.616.462.suffix/1431052139248.jpeg -http://img.taste.com.au/u-Bwjfm_/taste/2016/11/mini-croissants-with-3-fillings-14692-1.jpeg -https://media.newyorker.com/photos/590974702179605b11ad8096/16:9/w_1200,h_630,c_limit/Gopnik-TheMurkyMeaningsofStraightenedOutCroissants.jpg -https://storage.cpstatic.ch/storage/og_image/laugengipfel--425319.jpg -https://c1.staticflickr.com/3/2835/10874180753_2b2916e3ce_b.jpg -https://www.spatz-dessert.ch/image_upload/Laugengipfel.jpg -http://www.baeckerei-meier.ch/images/p005_1_03.png -http://i.huffpost.com/gen/1278175/thumbs/o-CROISSANT-facebook.jpg \ No newline at end of file diff --git a/src/Bot/Storage/dab b/src/Bot/Storage/dab deleted file mode 100644 index cba5a5c..0000000 --- a/src/Bot/Storage/dab +++ /dev/null @@ -1,8 +0,0 @@ -https://pre00.deviantart.net/dcde/th/pre/i/2018/247/8/1/dabbing_pug_cute_dab_dance_by_manekibb-dcm2lvd.png -https://banner2.kisspng.com/20180625/xfv/kisspng-squidward-tentacles-dab-desktop-wallpaper-dab-emoji-5b31a97a839bf2.6353972915299813065391.jpg -https://djbooth.net/.image/t_share/MTUzNDg2MDIzOTU4NzM0NzA1/life-death-of-dab-dancejpg.jpg -https://res.cloudinary.com/teepublic/image/private/s--gfsWHvaH--/t_Preview/b_rgb:262c3a,c_limit,f_jpg,h_630,q_90,w_630/v1493209189/production/designs/1524888_1.jpg -https://i1.wp.com/fortniteskins.net/wp-content/uploads/2018/04/dab-skin-1.png?quality=90&strip=all&ssl=1 -https://i.pinimg.com/originals/12/d4/0a/12d40a8fc66b7a7ea8b9044ee0303974.png -https://images.bewakoof.com/t540/dab-penguin-boyfriend-t-shirt-women-s-printed-boyfriend-t-shirts-196918-1538034349.jpg -https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSKH1FLh5L3pOR2tamx-5OBqm_W2FFl8F7gteTAs2vMowwJ1Y32 \ No newline at end of file diff --git a/src/Bot/Storage/foxes b/src/Bot/Storage/foxes deleted file mode 100644 index 52fd9d2..0000000 --- a/src/Bot/Storage/foxes +++ /dev/null @@ -1,20 +0,0 @@ -https://i.ytimg.com/vi/qF6OOGuT_hI/maxresdefault.jpg -https://static.tumblr.com/bb34d8f163098ad1daafcffbdbb03975/rk23uap/Nwwp0rmi2/tumblr_static_tumblr_static__640.jpg -https://www.popsci.com/sites/popsci.com/files/styles/1000_1x_/public/import/2013/images/2013/09/redfoxyawn.jpg?itok=yRkSVe8T -https://hdqwalls.com/wallpapers/wild-fox-art.jpg -https://i.imgur.com/ktK9yXX.jpg -http://4.bp.blogspot.com/-Hz-o_KYj3Xk/Vlm2mwbztjI/AAAAAAAA8Ss/jbH5ovjmC9A/s1600/ScreenShot5502.jpg -https://wallpaperscraft.com/image/fox_forest_grass_117190_540x960.jpg -https://orig00.deviantart.net/2feb/f/2013/137/a/f/fox_and_curious_squirrel_by_tamarar-d65ju8d.jpg -http://www.tehcute.com/pics/201401/little-fox-big.jpg -https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR6QXB1APLdUsyzO39kPvhnC9cOvcwzEtsxown9QjWilWppia2mwg -https://www.wildlifeaid.org.uk/wp-content/uploads/2016/03/FP9_July09.jpg -https://upload.wikimedia.org/wikipedia/commons/thumb/b/bb/Vulpes_vulpes_ssp_fulvus_6568085.jpg/1200px-Vulpes_vulpes_ssp_fulvus_6568085.jpg -http://images.hellogiggles.com/uploads/2017/06/10023347/fox1.jpg -https://i.ytimg.com/vi/mtroFou8Xb4/maxresdefault.jpg -http://wallpapers-best.com/uploads/posts/2015-09/20_fox.jpg -https://www.whats-your-sign.com/wp-content/uploads/2018/02/RedFoxSymbolism4.jpg -https://cdn.zmescience.com/wp-content/uploads/2016/09/8505162700_11394c3f6a_b.jpg -http://wallpapers-best.com/uploads/posts/2015-09/18_fox.jpg -https://s.abcnews.com/images/General/red-fox-new-jersey-gty-jt-191119_hpMain_16x9_992.jpg -https://i.ytimg.com/vi/ClNRWL_9L8s/maxresdefault.jpg \ No newline at end of file diff --git a/src/Bot/Storage/penguins b/src/Bot/Storage/penguins deleted file mode 100644 index 95aa70d..0000000 --- a/src/Bot/Storage/penguins +++ /dev/null @@ -1,15 +0,0 @@ -https://www.birdlife.org/sites/default/files/styles/1600/public/slide.jpg?itok=HRhQfA1S -http://experimentexchange.com/wp-content/uploads/2016/07/penguins-fact.jpg -http://www.antarctica.gov.au/__data/assets/image/0011/147737/varieties/antarctic.jpg -https://images.justwatch.com/backdrop/8611153/s1440/pingu -http://4.bp.blogspot.com/-VhmPPCcZnwA/TWR303DSAuI/AAAAAAAAABU/eSSokmd376s/s1600/2-Penguins-penguins-4234010-1280-1024.jpg -https://media.glamour.com/photos/56959e35d9dab9ff41b308a0/master/pass/inspired-2015-02-gentoo-penguin-main.jpg -https://indiansciencejournal.files.wordpress.com/2012/04/emperor-penguin-credit-british-antarctic-survey.jpg -https://fthmb.tqn.com/7cd9Q3LSapEShHq2mKvQgSPr_tc=/2250x1500/filters:fill(auto,1)/149267744-56a008755f9b58eba4ae8f46.jpg -https://blogs.voanews.com/science-world/files/2014/07/11240219084_941dfbf66e_b.jpg -https://blogs.biomedcentral.com/bmcseriesblog/wp-content/uploads/sites/9/2015/11/IMG_5391-2.jpg -https://i2-prod.mirror.co.uk/incoming/article11682518.ece/ALTERNATES/s615/Emperor-penguins-on-ice.jpg -https://www.gannett-cdn.com/presto/2019/04/15/PPHX/8dfe0433-c22c-4458-9ba8-3aab866774f8-Penguins5cad7bfd107a4.jpg?crop=5759,3224,x0,y0&width=3200&height=1680&fit=bounds -http://4.bp.blogspot.com/_FNQgkfCwYxs/S82jBAxMVEI/AAAAAAAAAns/_3lAuJhUfcs/s1600/311785583_af8f2d1ea7_o.jpg -http://wallsdesk.com/wp-content/uploads/2017/01/Pictures-of-Penguin-.jpg -http://2.bp.blogspot.com/_W90V87w3sr8/TP3RPYwrrjI/AAAAAAAAAXk/riN0GwRwhFM/s1600/leap-of-faith-adelie-penguin-pictures.jpg \ No newline at end of file diff --git a/src/Bot/Storage/pumpkin b/src/Bot/Storage/pumpkin deleted file mode 100644 index 3652397..0000000 --- a/src/Bot/Storage/pumpkin +++ /dev/null @@ -1,14 +0,0 @@ -https://i.pinimg.com/736x/0a/a7/8a/0aa78af25e114836e1a42585fb7b09ed--funny-pumpkins-pumkin-carving.jpg -http://wdy.h-cdn.co/assets/16/31/980x1470/gallery-1470321728-shot-two-021.jpg -http://images6.fanpop.com/image/photos/38900000/Jack-o-Lantern-halloween-38991566-500-415.jpg -http://ghk.h-cdn.co/assets/15/37/1441834730-pumpkin-carve-2.jpg -http://diy.sndimg.com/content/dam/images/diy/fullset/2011/7/26/1/iStock-10761186_halloween-pumpkin-in-garden_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420851319631.jpeg -https://www.digsdigs.com/photos/2009/10/100-halloween-pumpkin-carving-ideas-12.jpg -https://i.pinimg.com/736x/59/8a/0f/598a0fbf789631b76c1ffd4443194d8e--halloween-pumpkins-fall-halloween.jpg -http://i.huffpost.com/gen/1405530/images/o-PUMPKINS-facebook.jpg -https://www.reviewjournal.com/wp-content/uploads/2016/10/web1_thinkstockphotos-491684958_7239666.jpg -https://img.sunset02.com/sites/default/files/1494265591/pumpkins-growing-on-farm-getty-sun-0517.jpg -https://toronto.citynews.ca/wp-content/blogs.dir/sites/10/2015/10/06/pumpkin-patch.jpg -http://i.huffpost.com/gen/3494726/images/o-PUMPKIN-facebook.jpg -https://servingjoy.com/wp-content/uploads/2014/12/Beautiful-autumn-halloween-pumpkins.jpg -https://www.history.com/.image/t_share/MTU3ODc5MDg2NDI4OTg4NzQ1/still-life-of-a-jack-o-lantern.jpg \ No newline at end of file diff --git a/src/Bot/Storage/squirrel b/src/Bot/Storage/squirrel deleted file mode 100644 index 91fd240..0000000 --- a/src/Bot/Storage/squirrel +++ /dev/null @@ -1,25 +0,0 @@ -https://public-media.smithsonianmag.com/filer/52/f9/52f93262-c29b-4a4f-b031-0c7ad145ed5f/42-33051942.jpg -http://images5.fanpop.com/image/photos/30700000/Squirrel-squirrels-30710732-400-300.jpg -http://i.dailymail.co.uk/i/pix/2016/02/24/16/158F7E7C000005DC-3462228-image-a-65_1456331226865.jpg -http://2.bp.blogspot.com/-egfnMhUb8tg/T_dAIu1m6cI/AAAAAAAAPPU/v4x9q4WqWl8/s640/cute-squirrel-hey-watcha-thinkin-about.jpg -https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Squirrel_posing.jpg/287px-Squirrel_posing.jpg -https://i.pinimg.com/736x/51/db/9b/51db9bad4a87d445d321923c7d56b501--red-squirrel-animal-kingdom.jpg -https://i.pinimg.com/736x/ce/9c/59/ce9c5990b193046400d98724595cdaf3--red-squirrel-chipmunks.jpg -https://www.brooklynpaper.com/assets/photos/40/30/dtg-squirrel-attacks-prospect-park-patrons-2017-07-28-bk01_z.jpg -https://i.pinimg.com/736x/b4/5c/0d/b45c0d00b1a57e9f84f27f13cb019001--baby-squirrel-red-squirrel.jpg -https://i.pinimg.com/736x/0f/75/87/0f7587bb613ab524763afe8c9a532e5c--cute-squirrel-squirrels.jpg -http://cdn.images.express.co.uk/img/dynamic/128/590x/Grey-squirrel-828838.jpg -http://www.lovethispic.com/uploaded_images/79964-Squirrel-Smelling-A-Flower.jpg -https://i.pinimg.com/736x/23/d5/f9/23d5f9868f7d76c79c49bef53ae08f7f--squirrel-funny-red-squirrel.jpg -https://i.ytimg.com/vi/pzUs0DdzK3Y/hqdefault.jpg -https://i.pinimg.com/736x/e2/16/bb/e216bba53f80fc8e0111d371e9850159--funny-squirrels-cute-squirrel.jpg -https://i.pinimg.com/736x/52/43/c9/5243c93377245be1f686218c266d775c--funny-squirrel-baby-squirrel.jpg -https://i.pinimg.com/736x/0c/be/1d/0cbe1da8ad2c0cf3882a806b6fd88965--cute-pictures-funny-animal-pictures.jpg -https://i.pinimg.com/736x/1c/7d/4f/1c7d4f067a10066aad802ce5ac468d71--group-boards-a-squirrel.jpg -https://i.pinimg.com/736x/d6/42/12/d64212cc6221916db4173962bf6c131a--cute-squirrel-baby-squirrel.jpg -https://i.pinimg.com/736x/da/0d/fe/da0dfe93bb26887795f906e8fa97d68e--secret-squirrel-cute-squirrel.jpg -http://2.bp.blogspot.com/-HLieBqEuQoM/UDkRmeyzB5I/AAAAAAAABHs/RtsEynn5t6Y/s1600/hd-squirrel-wallpaper-with-a-brown-squirrel-eating-watermelon-wallpapers-backgrounds-pictures-photos.jpg -http://img15.deviantart.net/9c50/i/2011/213/c/9/just_taking_it_easy_by_lou_in_canada-d42do3d.jpg -https://insider.si.edu/wp-content/uploads/2018/01/Chipmunk-Photo-Mark-Rounds.jpg -https://media.mnn.com/assets/images/2014/12/gray-squirrel-uc-berkeley.jpg.1080x0_q100_crop-scale.jpg -https://citywildlife.org/wp-content/uploads/Juvenile-squirrel.jpg \ No newline at end of file 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/Roll/RollTimeout.cs b/src/Commands/Roll/RollTimeout.cs deleted file mode 100644 index d296c45..0000000 --- a/src/Commands/Roll/RollTimeout.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Geekbot.Commands.Roll -{ - public record RollTimeout - { - public int LastGuess { get; set; } - public DateTime GuessedOn { get; set; } - } -} \ 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/Core/Constants.cs b/src/Core/Constants.cs deleted file mode 100644 index 4dd08b9..0000000 --- a/src/Core/Constants.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection; - -namespace Geekbot.Core -{ - public static class Constants - { - public const string Name = "Geekbot"; - - public static string BotVersion() - { - return typeof(Constants).Assembly.GetCustomAttribute().InformationalVersion; - } - - public static string LibraryVersion() - { - return typeof(Discord.WebSocket.DiscordSocketClient).Assembly.GetCustomAttribute().InformationalVersion; - } - - public const double ApiVersion = 1; - } -} \ No newline at end of file diff --git a/src/Core/Converters/EmojiConverter.cs b/src/Core/Converters/EmojiConverter.cs deleted file mode 100644 index d25415f..0000000 --- a/src/Core/Converters/EmojiConverter.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Collections; -using System.Text; - -namespace Geekbot.Core.Converters -{ - public static class EmojiConverter - { - private static readonly string[] NumberEmojiMap = - { - ":zero:", - ":one:", - ":two:", - ":three:", - ":four:", - ":five:", - ":six:", - ":seven:", - ":eight:", - ":nine:" - }; - - public static string NumberToEmoji(int number) - { - if (number == 10) - { - return "🔟"; - } - - var numbers = number.ToString().ToCharArray(); - var returnString = new StringBuilder(); - foreach (var n in numbers) - { - returnString.Append(NumberEmojiMap[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) - { - 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]; - returnString.Append(emoji); - } - return returnString.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Core/Converters/MtgManaConverter.cs b/src/Core/Converters/MtgManaConverter.cs deleted file mode 100644 index aa6b74c..0000000 --- a/src/Core/Converters/MtgManaConverter.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System.Collections.Generic; -using System.Text.RegularExpressions; - -namespace Geekbot.Core.Converters -{ - public class MtgManaConverter : IMtgManaConverter - { - private readonly Dictionary _manaDict; - - public MtgManaConverter() - { - // these emotes can be found at https://discord.gg/bz8HyA7 - _manaDict = new Dictionary - { - {"{0}", "<:mtg_0:415216130043412482>"}, - {"{1}", "<:mtg_1:415216130253389835>"}, - {"{2}", "<:mtg_2:415216130031091713>"}, - {"{3}", "<:mtg_3:415216130467037194>"}, - {"{4}", "<:mtg_4:415216130026635295>"}, - {"{5}", "<:mtg_5:415216130492203008>"}, - {"{6}", "<:mtg_6:415216130458779658>"}, - {"{7}", "<:mtg_7:415216130190475265>"}, - {"{8}", "<:mtg_8:415216130517630986>"}, - {"{9}", "<:mtg_9:415216130500722689>"}, - {"{10", "<:mtg_10:415216130450391051>"}, - {"{11}", "<:mtg_11:415216130811101185>"}, - {"{12}", "<:mtg_12:415216130525888532>"}, - {"{13}", "<:mtg_13:415216130517631000>"}, - {"{14}", "<:mtg_14:415216130165178370>"}, - {"{15}", "<:mtg_15:415216130576089108>"}, - {"{16}", "<:mtg_16:415216130358247425>"}, - {"{17}", "<:mtg_17:415216130601517056>"}, - {"{18}", "<:mtg_18:415216130462842891>"}, - {"{19}", "<:mtg_19:415216130614099988>"}, - {"{20}", "<:mtg_20:415216130656043038>"}, - {"{W}", "<:mtg_white:415216131515744256>"}, - {"{U}", "<:mtg_blue:415216130521694209>"}, - {"{B}", "<:mtg_black:415216130873884683>"}, - {"{R}", "<:mtg_red:415216131322806272>"}, - {"{G}", "<:mtg_green:415216131180331009>"}, - {"{S}", "<:mtg_s:415216131293446144>"}, - {"{T}", "<:mtg_tap:415258392727257088>"}, - {"{C}", "<:mtg_colorless:415216130706374666>"}, - {"{2/W}", "<:mtg_2w:415216130446065664>"}, - {"{2/U}", "<:mtg_2u:415216130429550592>"}, - {"{2/B}", "<:mtg_2b:415216130160984065>"}, - {"{2/R}", "<:mtg_2r:415216130454716436>"}, - {"{2/G}", "<:mtg_2g:415216130420899840>"}, - {"{W/U}", "<:mtg_wu:415216130970484736>"}, - {"{W/B}", "<:mtg_wb:415216131222011914>"}, - {"{U/R}", "<:mtg_ur:415216130962096128>"}, - {"{U/B}", "<:mtg_ub:415216130865758218>"}, - {"{R/W}", "<:mtg_rw:415216130878210057>"}, - {"{G/W}", "<:mtg_gw:415216130567962646>"}, - {"{G/U}", "<:mtg_gu:415216130739666945>"}, - {"{B/R}", "<:mtg_br:415216130580283394>"}, - {"{B/G}", "<:mtg_bg:415216130781609994>"}, - {"{U/P}", "<:mtg_up:415216130861432842>"}, - {"{R/P}", "<:mtg_rp:415216130597322783>"}, - {"{G/P}", "<:mtg_gp:415216130760769546>"}, - {"{W/P}", "<:mtg_wp:415216131541041172>"}, - {"{B/P}", "<:mtg_bp:415216130664169482>"} - }; - } - - public string ConvertMana(string mana) - { - var rgx = Regex.Matches(mana, @"(\{(.*?)\})"); - foreach (Match manaTypes in rgx) - { - var m = _manaDict.GetValueOrDefault(manaTypes.Value); - if (!string.IsNullOrEmpty(m)) - { - mana = mana.Replace(manaTypes.Value, m); - } - } - - return mana; - } - } -} \ No newline at end of file diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj deleted file mode 100644 index 2cd8dbc..0000000 --- a/src/Core/Core.csproj +++ /dev/null @@ -1,94 +0,0 @@ - - - - net6.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 deleted file mode 100644 index 14a1275..0000000 --- a/src/Core/Database/DatabaseContext.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Geekbot.Core.Database.Models; -using Microsoft.EntityFrameworkCore; - -namespace Geekbot.Core.Database -{ - public class DatabaseContext : DbContext - { - public DbSet Quotes { get; set; } - public DbSet Users { get; set; } - public DbSet GuildSettings { get; set; } - 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; } - public DbSet RoleSelfService { get; set; } - public DbSet Cookies { get; set; } - public DbSet ReactionListeners { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/DatabaseInitializer.cs b/src/Core/Database/DatabaseInitializer.cs deleted file mode 100644 index 37f07bc..0000000 --- a/src/Core/Database/DatabaseInitializer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using Geekbot.Core.Database.LoggingAdapter; -using Geekbot.Core.Logger; -using Npgsql.Logging; - -namespace Geekbot.Core.Database -{ - public class DatabaseInitializer - { - private readonly RunParameters _runParameters; - private readonly GeekbotLogger _logger; - - public DatabaseInitializer(RunParameters runParameters, GeekbotLogger logger) - { - _runParameters = runParameters; - _logger = logger; - NpgsqlLogManager.Provider = new NpgsqlLoggingProviderAdapter(logger, runParameters); - } - - public DatabaseContext Initialize() - { - DatabaseContext database = null; - try - { - if (_runParameters.InMemory) - { - database = new InMemoryDatabase("geekbot"); - } - else - { - database = new SqlDatabase(new SqlConnectionString - { - Host = _runParameters.DbHost, - Port = _runParameters.DbPort, - Database = _runParameters.DbDatabase, - Username = _runParameters.DbUser, - Password = _runParameters.DbPassword, - RequireSsl = _runParameters.DbSsl, - TrustServerCertificate = _runParameters.DbTrustCert, - RedshiftCompatibility = _runParameters.DbRedshiftCompatibility - }); - } - } - catch (Exception e) - { - _logger.Error(LogSource.Geekbot, "Could not Connect to datbase", e); - Environment.Exit(GeekbotExitCode.DatabaseConnectionFailed.GetHashCode()); - } - - if (_runParameters.DbLogging) - { - _logger.Information(LogSource.Database, $"Connected with {database.Database.ProviderName}"); - } - - return database; - } - } -} \ No newline at end of file diff --git a/src/Core/Database/InMemoryDatabase.cs b/src/Core/Database/InMemoryDatabase.cs deleted file mode 100644 index 1077aea..0000000 --- a/src/Core/Database/InMemoryDatabase.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace Geekbot.Core.Database -{ - public class InMemoryDatabase : DatabaseContext - { - private readonly string _name; - - public InMemoryDatabase(string name) - { - _name = name; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseInMemoryDatabase(_name); - } -} \ No newline at end of file diff --git a/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs b/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs deleted file mode 100644 index 8a46c0d..0000000 --- a/src/Core/Database/LoggingAdapter/NpgsqlLoggingAdapter.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using Geekbot.Core.Logger; -using Npgsql.Logging; -using LogLevel = NLog.LogLevel; - -namespace Geekbot.Core.Database.LoggingAdapter -{ - public class NpgsqlLoggingAdapter : NpgsqlLogger - { - private readonly string _name; - private readonly IGeekbotLogger _geekbotLogger; - private readonly RunParameters _runParameters; - - public NpgsqlLoggingAdapter(string name, IGeekbotLogger geekbotLogger, RunParameters runParameters) - { - _name = name.Substring(7); - _geekbotLogger = geekbotLogger; - _runParameters = runParameters; - geekbotLogger.Trace(LogSource.Database, $"Loaded Npgsql logging adapter: {name}"); - } - - public override bool IsEnabled(NpgsqlLogLevel level) - { - return (_runParameters.DbLogging && _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(level))); - } - - public override void Log(NpgsqlLogLevel level, int connectorId, string msg, Exception exception = null) - { - var nameAndMessage = $"{_name}: {msg}"; - switch (level) - { - case NpgsqlLogLevel.Trace: - _geekbotLogger.Trace(LogSource.Database, nameAndMessage); - break; - case NpgsqlLogLevel.Debug: - _geekbotLogger.Debug(LogSource.Database, nameAndMessage); - break; - case NpgsqlLogLevel.Info: - _geekbotLogger.Information(LogSource.Database, nameAndMessage); - break; - case NpgsqlLogLevel.Warn: - _geekbotLogger.Warning(LogSource.Database, nameAndMessage, exception); - break; - case NpgsqlLogLevel.Error: - case NpgsqlLogLevel.Fatal: - _geekbotLogger.Error(LogSource.Database, nameAndMessage, exception); - break; - default: - _geekbotLogger.Information(LogSource.Database, nameAndMessage); - break; - } - } - - private static LogLevel 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, - _ => throw new ArgumentOutOfRangeException(nameof(level)) - }; - } - } -} \ No newline at end of file diff --git a/src/Core/Database/LoggingAdapter/NpgsqlLoggingProviderAdapter.cs b/src/Core/Database/LoggingAdapter/NpgsqlLoggingProviderAdapter.cs deleted file mode 100644 index c4f76d7..0000000 --- a/src/Core/Database/LoggingAdapter/NpgsqlLoggingProviderAdapter.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Geekbot.Core.Logger; -using Npgsql.Logging; - -namespace Geekbot.Core.Database.LoggingAdapter -{ - public class NpgsqlLoggingProviderAdapter : INpgsqlLoggingProvider - { - private readonly GeekbotLogger _geekbotLogger; - private readonly RunParameters _runParameters; - - public NpgsqlLoggingProviderAdapter(GeekbotLogger geekbotLogger, RunParameters runParameters) - { - _geekbotLogger = geekbotLogger; - _runParameters = runParameters; - } - - public NpgsqlLogger CreateLogger(string name) - { - return new NpgsqlLoggingAdapter(name, _geekbotLogger, _runParameters); - } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/CookiesModel.cs b/src/Core/Database/Models/CookiesModel.cs deleted file mode 100644 index 6ec71f9..0000000 --- a/src/Core/Database/Models/CookiesModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class CookiesModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - public int Cookies { get; set; } = 0; - - public DateTimeOffset? LastPayout { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/GlobalsModel.cs b/src/Core/Database/Models/GlobalsModel.cs deleted file mode 100644 index af084f9..0000000 --- a/src/Core/Database/Models/GlobalsModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class GlobalsModel - { - [Key] - public int Id { get; set; } - - [Required] - public string Name { get; set; } - - [Required] - public string Value { get; set; } - - public string Meta { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/GuildSettingsModel.cs b/src/Core/Database/Models/GuildSettingsModel.cs deleted file mode 100644 index 80655f7..0000000 --- a/src/Core/Database/Models/GuildSettingsModel.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class GuildSettingsModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - public bool Ping { get; set; } = false; - - public bool Hui { get; set; } = false; - - public long ModChannel { get; set; } = 0; - - public string WelcomeMessage { get; set; } - - public long WelcomeChannel { get; set; } - - public bool ShowDelete { get; set; } = false; - - public bool ShowLeave { get; set; } = false; - - public string WikiLang { get; set; } = "en"; - - public string Language { get; set; } = "EN"; - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/KarmaModel.cs b/src/Core/Database/Models/KarmaModel.cs deleted file mode 100644 index 2ec64f0..0000000 --- a/src/Core/Database/Models/KarmaModel.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class KarmaModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - public int Karma { get; set; } - - public DateTimeOffset TimeOut { get; set; } - } -} \ No newline at end of file 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/Database/Models/MessagesModel.cs b/src/Core/Database/Models/MessagesModel.cs deleted file mode 100644 index 87731d8..0000000 --- a/src/Core/Database/Models/MessagesModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class MessagesModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - public int MessageCount { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/QuoteModel.cs b/src/Core/Database/Models/QuoteModel.cs deleted file mode 100644 index 3d356d2..0000000 --- a/src/Core/Database/Models/QuoteModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class QuoteModel - { - [Key] - public int Id { get; set; } - - [Required] - public int InternalId { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - [Required] - [DataType(DataType.DateTime)] - public DateTime Time { get; set; } - - public string Quote { get; set; } - - public string Image { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/ReactionListenerModel.cs b/src/Core/Database/Models/ReactionListenerModel.cs deleted file mode 100644 index 5ec28be..0000000 --- a/src/Core/Database/Models/ReactionListenerModel.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class ReactionListenerModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long MessageId { get; set; } - - [Required] - public long RoleId { get; set; } - - [Required] - public string Reaction { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/RoleSelfServiceModel.cs b/src/Core/Database/Models/RoleSelfServiceModel.cs deleted file mode 100644 index 4aa92c4..0000000 --- a/src/Core/Database/Models/RoleSelfServiceModel.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class RoleSelfServiceModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - public long RoleId { get; set; } - - public string WhiteListName { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/RollsModel.cs b/src/Core/Database/Models/RollsModel.cs deleted file mode 100644 index aa6613d..0000000 --- a/src/Core/Database/Models/RollsModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class RollsModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - public int Rolls { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/ShipsModel.cs b/src/Core/Database/Models/ShipsModel.cs deleted file mode 100644 index 23cf367..0000000 --- a/src/Core/Database/Models/ShipsModel.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class ShipsModel - { - [Key] - public int Id { get; set; } - - public long FirstUserId { get; set; } - - public long SecondUserId { get; set; } - - public int Strength { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/SlapsModel.cs b/src/Core/Database/Models/SlapsModel.cs deleted file mode 100644 index 09026c8..0000000 --- a/src/Core/Database/Models/SlapsModel.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class SlapsModel - { - [Key] - public int Id { get; set; } - - [Required] - public long GuildId { get; set; } - - [Required] - public long UserId { get; set; } - - public int Given { get; set; } - - public int Recieved { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/Models/UserModel.cs b/src/Core/Database/Models/UserModel.cs deleted file mode 100644 index aa6281d..0000000 --- a/src/Core/Database/Models/UserModel.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.ComponentModel.DataAnnotations; - -namespace Geekbot.Core.Database.Models -{ - public class UserModel - { - [Key] - public int Id { get; set; } - - [Required] - public long UserId { get; set; } - - [Required] - public string Username { get; set; } - - [Required] - public string Discriminator { get; set; } - - public string AvatarUrl { get; set; } - - [Required] - public bool IsBot { get; set; } - - public DateTimeOffset Joined { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/Database/SqlConnectionString.cs b/src/Core/Database/SqlConnectionString.cs deleted file mode 100644 index ca2858d..0000000 --- a/src/Core/Database/SqlConnectionString.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Text; - -namespace Geekbot.Core.Database -{ - public class SqlConnectionString - { - public string Host { get; set; } - public string Port { get; set; } - public string Database { get; set; } - public string Username { get; set; } - public string Password { get; set; } - public bool RequireSsl { get; set; } - public bool TrustServerCertificate { get; set; } - public bool RedshiftCompatibility { get; set; } - - public override string ToString() - { - var sb = new StringBuilder(); - sb.Append("Application Name=Geekbot;"); - - sb.Append($"Host={Host};"); - sb.Append($"Port={Port};"); - sb.Append($"Database={Database};"); - sb.Append($"Username={Username};"); - sb.Append($"Password={Password};"); - - var sslMode = RequireSsl ? "Require" : "Prefer"; - sb.Append($"SSL Mode={sslMode};"); - sb.Append($"Trust Server Certificate={TrustServerCertificate.ToString()};"); - - if (RedshiftCompatibility) - { - sb.Append("Server Compatibility Mode=Redshift"); - } - - return sb.ToString(); - } - } -} \ No newline at end of file diff --git a/src/Core/Database/SqlDatabase.cs b/src/Core/Database/SqlDatabase.cs deleted file mode 100644 index 8a4d195..0000000 --- a/src/Core/Database/SqlDatabase.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.EntityFrameworkCore; - -namespace Geekbot.Core.Database -{ - public class SqlDatabase : DatabaseContext - { - private readonly SqlConnectionString _connectionString; - - public SqlDatabase(SqlConnectionString connectionString) - { - _connectionString = connectionString; - } - - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - => optionsBuilder.UseNpgsql(_connectionString.ToString()); - } -} \ No newline at end of file diff --git a/src/Core/DateLocalization.cs b/src/Core/DateLocalization.cs deleted file mode 100644 index 39b447f..0000000 --- a/src/Core/DateLocalization.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Text; - -namespace Geekbot.Core -{ - public class DateLocalization - { - public static string FormatDateTimeAsRemaining(DateTimeOffset dateTime) - { - return FormatDateTimeAsRemaining(dateTime - DateTimeOffset.Now); - } - - public static string FormatDateTimeAsRemaining(TimeSpan remaining) - { - const string formattable = "{0} {1}"; - var sb = new StringBuilder(); - - if (remaining.Days > 0) - { - sb.AppendFormat(formattable, remaining.Days, GetSingularOrPlural(remaining.Days, Localization.Internal.Days)); - } - - if (remaining.Hours > 0) - { - if (sb.Length > 0) sb.Append(", "); - sb.AppendFormat(formattable, remaining.Hours, GetSingularOrPlural(remaining.Hours, Localization.Internal.Hours)); - } - - if (remaining.Minutes > 0) - { - if (sb.Length > 0) sb.Append(", "); - sb.AppendFormat(formattable, remaining.Minutes, GetSingularOrPlural(remaining.Minutes, Localization.Internal.Minutes)); - } - - if (remaining.Seconds > 0) - { - if (sb.Length > 0) - { - sb.AppendFormat(" {0} ", Localization.Internal.And); - } - sb.AppendFormat(formattable, remaining.Seconds, GetSingularOrPlural(remaining.Seconds, Localization.Internal.Seconds)); - } - - return sb.ToString().Trim(); - } - - private static string GetSingularOrPlural(int number, string rawString) - { - var versions = rawString.Split('|'); - return number == 1 ? versions[0] : versions[1]; - } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DiceException.cs b/src/Core/DiceParser/DiceException.cs deleted file mode 100644 index 6c6c29c..0000000 --- a/src/Core/DiceParser/DiceException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Geekbot.Core.DiceParser -{ - public class DiceException : Exception - { - public DiceException(string message) : base(message) - { - } - - public string DiceName { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DiceInput.cs b/src/Core/DiceParser/DiceInput.cs deleted file mode 100644 index 60f0bd2..0000000 --- a/src/Core/DiceParser/DiceInput.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections.Generic; - -namespace Geekbot.Core.DiceParser -{ - public class DiceInput - { - public List Dice { get; set; } = new List(); - public DiceInputOptions Options { get; set; } = new DiceInputOptions(); - public int SkillModifier { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DiceInputOptions.cs b/src/Core/DiceParser/DiceInputOptions.cs deleted file mode 100644 index 5606a5e..0000000 --- a/src/Core/DiceParser/DiceInputOptions.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Geekbot.Core.DiceParser -{ - public struct DiceInputOptions - { - public bool ShowTotal { get; set; } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DiceParser.cs b/src/Core/DiceParser/DiceParser.cs deleted file mode 100644 index b0f6a88..0000000 --- a/src/Core/DiceParser/DiceParser.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Linq; -using System.Text.RegularExpressions; -using Geekbot.Core.RandomNumberGenerator; - -namespace Geekbot.Core.DiceParser -{ - public class DiceParser : IDiceParser - { - private readonly IRandomNumberGenerator _randomNumberGenerator; - private readonly Regex _inputRegex; - private readonly Regex _singleDieRegex; - - public DiceParser(IRandomNumberGenerator randomNumberGenerator) - { - _randomNumberGenerator = randomNumberGenerator; - _inputRegex = new Regex( - @"((?\+\d+d\d+)|(?\-\d+d\d+)|(?\d+d\d+)|(?(total))|(?(\+|\-)\d+))\s", - RegexOptions.Compiled | RegexOptions.IgnoreCase, - new TimeSpan(0, 0, 2)); - _singleDieRegex = new Regex( - @"\d+d\d+", - RegexOptions.Compiled | RegexOptions.IgnoreCase, - new TimeSpan(0, 0, 0, 0, 500)); - } - - public DiceInput Parse(string input) - { - // adding a whitespace at the end, otherwise the parser might pickup on false items - var inputWithExtraWhitespace = $"{input} "; - - var matches = _inputRegex.Matches(inputWithExtraWhitespace); - var result = new DiceInput(); - var resultOptions = new DiceInputOptions(); - - foreach (Match match in matches) - { - foreach (Group matchGroup in match.Groups) - { - if (matchGroup.Success) - { - switch (matchGroup.Name) - { - case "DieNormal": - result.Dice.Add(Die(matchGroup.Value, DieAdvantageType.None)); - break; - case "DieAdvantage": - result.Dice.Add(Die(matchGroup.Value, DieAdvantageType.Advantage)); - break; - case "DieDisadvantage": - result.Dice.Add(Die(matchGroup.Value, DieAdvantageType.Disadvantage)); - break; - case "Keywords": - Keywords(matchGroup.Value, ref resultOptions); - break; - case "SkillModifer": - result.SkillModifier = SkillModifer(matchGroup.Value); - break; - } - } - } - } - - if (!result.Dice.Any()) - { - result.Dice.Add(new SingleDie(_randomNumberGenerator)); - } - - result.Options = resultOptions; - - return result; - } - - private SingleDie Die(string match, DieAdvantageType advantageType) - { - var x = _singleDieRegex.Match(match).Value.Split('d'); - var die = new SingleDie(_randomNumberGenerator) - { - Amount = int.Parse(x[0]), - Sides = int.Parse(x[1]), - AdvantageType = advantageType - }; - die.ValidateDie(); - return die; - } - - private int SkillModifer(string match) - { - return int.Parse(match); - } - - private void Keywords(string match, ref DiceInputOptions options) - { - switch (match) - { - case "total": - options.ShowTotal = true; - break; - } - } - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DieAdvantageType.cs b/src/Core/DiceParser/DieAdvantageType.cs deleted file mode 100644 index 9bd7486..0000000 --- a/src/Core/DiceParser/DieAdvantageType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Geekbot.Core.DiceParser -{ - public enum DieAdvantageType - { - Advantage, - Disadvantage, - None - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/DieResult.cs b/src/Core/DiceParser/DieResult.cs deleted file mode 100644 index aa309c0..0000000 --- a/src/Core/DiceParser/DieResult.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Geekbot.Core.DiceParser -{ - public class DieResult - { - // public int Result { get; set; } - public int Roll1 { get; set; } - public int Roll2 { get; set; } - public DieAdvantageType AdvantageType { get; set; } - - public override string ToString() - { - return AdvantageType switch - { - DieAdvantageType.Advantage => Roll1 > Roll2 ? $"(**{Roll1}**, {Roll2})" : $"({Roll1}, **{Roll2}**)", - DieAdvantageType.Disadvantage => Roll1 < Roll2 ? $"(**{Roll1}**, {Roll2})" : $"({Roll1}, **{Roll2}**)", - _ => Result.ToString() - }; - } - - public int Result => AdvantageType switch - { - DieAdvantageType.None => Roll1, - DieAdvantageType.Advantage => Math.Max(Roll1, Roll2), - DieAdvantageType.Disadvantage => Math.Min(Roll1, Roll2), - _ => 0 - }; - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/IDiceParser.cs b/src/Core/DiceParser/IDiceParser.cs deleted file mode 100644 index ab1ebd3..0000000 --- a/src/Core/DiceParser/IDiceParser.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Geekbot.Core.DiceParser -{ - public interface IDiceParser - { - DiceInput Parse(string input); - } -} \ No newline at end of file diff --git a/src/Core/DiceParser/SingleDie.cs b/src/Core/DiceParser/SingleDie.cs deleted file mode 100644 index 7c1ae41..0000000 --- a/src/Core/DiceParser/SingleDie.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Generic; -using Geekbot.Core.Extensions; -using Geekbot.Core.RandomNumberGenerator; - -namespace Geekbot.Core.DiceParser -{ - public class SingleDie - { - private readonly IRandomNumberGenerator _random; - - public SingleDie(IRandomNumberGenerator random) - { - _random = random; - } - - public int Sides { get; set; } = 20; - public int Amount { get; set; } = 1; - public DieAdvantageType AdvantageType { get; set; } = DieAdvantageType.None; - - public string DiceName => AdvantageType switch - { - DieAdvantageType.Advantage => $"{Amount}d{Sides} (with advantage)", - DieAdvantageType.Disadvantage => $"{Amount}d{Sides} (with disadvantage)", - _ => $"{Amount}d{Sides}" - }; - - public List Roll() - { - var results = new List(); - - Amount.Times(() => - { - var result = new DieResult - { - Roll1 = _random.Next(1, Sides), - AdvantageType = AdvantageType - }; - - if (AdvantageType == DieAdvantageType.Advantage || AdvantageType == DieAdvantageType.Disadvantage) - { - result.Roll2 = _random.Next(1, Sides); - } - - results.Add(result); - }); - - return results; - } - - public void ValidateDie() - { - if (Amount < 1) - { - throw new DiceException("To few dice, must be a minimum of 1"); - } - if (Amount > 24) - { - throw new DiceException("To many dice, maximum allowed is 24") { DiceName = DiceName }; - } - - if (Sides < 2) - { - throw new DiceException("Die must have at least 2 sides") { DiceName = DiceName }; - } - - if (Sides > 145) - { - throw new DiceException("Die can not have more than 145 sides") { DiceName = DiceName }; - } - } - } -} \ No newline at end of file diff --git a/src/Core/ErrorHandling/ErrorHandler.cs b/src/Core/ErrorHandling/ErrorHandler.cs deleted file mode 100644 index 0b55bd8..0000000 --- a/src/Core/ErrorHandling/ErrorHandler.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; -using Geekbot.Core.Logger; -using Sentry; -using Exception = System.Exception; - -namespace Geekbot.Core.ErrorHandling -{ - public class ErrorHandler : IErrorHandler - { - private readonly IGeekbotLogger _logger; - private readonly Func _getDefaultErrorText; - private readonly bool _errorsInChat; - - public ErrorHandler(IGeekbotLogger logger, RunParameters runParameters, Func getDefaultErrorText) - { - _logger = logger; - _getDefaultErrorText = getDefaultErrorText; - _errorsInChat = runParameters.ExposeErrors; - } - - public async Task HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def") - { - try - { - var errorString = errorMessage == "def" - ? _getDefaultErrorText() - : errorMessage; - var errorObj = SimpleConextConverter.ConvertContext(context); - if (e.Message.Contains("50007")) return; - if (e.Message.Contains("50013")) return; - _logger.Error(LogSource.Geekbot, "An error ocured", e, errorObj); - if (!string.IsNullOrEmpty(errorMessage)) - { - if (_errorsInChat) - { - var resStackTrace = string.IsNullOrEmpty(e.InnerException?.ToString()) ? e.StackTrace : e.InnerException?.ToString(); - if (!string.IsNullOrEmpty(resStackTrace)) - { - var maxLen = Math.Min(resStackTrace.Length, 1850); - await context.Channel.SendMessageAsync($"{e.Message}\r\n```\r\n{resStackTrace.Substring(0, maxLen)}\r\n```"); - } - else - { - await context.Channel.SendMessageAsync(e.Message); - } - } - else - { - await context.Channel.SendMessageAsync(errorString); - } - - } - - ReportExternal(e, errorObj); - } - catch (Exception ex) - { - try - { - await context.Channel.SendMessageAsync("Something went really really wrong here"); - } - finally - { - _logger.Error(LogSource.Geekbot, "Errorception", ex); - } - } - } - - private void ReportExternal(Exception e, MessageDto errorObj) - { - if (!SentrySdk.IsEnabled) return; - - var sentryEvent = new SentryEvent(e) - { - Message = errorObj.Message.Content, - }; - 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); - } - } -} \ No newline at end of file diff --git a/src/Core/ErrorHandling/IErrorHandler.cs b/src/Core/ErrorHandling/IErrorHandler.cs deleted file mode 100644 index d0e1d20..0000000 --- a/src/Core/ErrorHandling/IErrorHandler.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Threading.Tasks; -using Discord.Commands; - -namespace Geekbot.Core.ErrorHandling -{ - public interface IErrorHandler - { - Task HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def"); - } -} \ No newline at end of file diff --git a/src/Core/Extensions/DbSetExtensions.cs b/src/Core/Extensions/DbSetExtensions.cs deleted file mode 100644 index 3ccffe9..0000000 --- a/src/Core/Extensions/DbSetExtensions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.ChangeTracking; - -namespace Geekbot.Core.Extensions -{ - public static class DbSetExtensions - { - public static EntityEntry AddIfNotExists(this DbSet dbSet, T entity, Expression> predicate = null) where T : class, new() - { - var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any(); - return !exists ? dbSet.Add(entity) : null; - } - - // https://github.com/dotnet/efcore/issues/18124 - public static IAsyncEnumerable AsAsyncEnumerable(this Microsoft.EntityFrameworkCore.DbSet obj) where TEntity : class - { - return Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.AsAsyncEnumerable(obj); - } - public static IQueryable Where(this Microsoft.EntityFrameworkCore.DbSet obj, System.Linq.Expressions.Expression> predicate) where TEntity : class - { - return System.Linq.Queryable.Where(obj, predicate); - } - } -} \ No newline at end of file diff --git a/src/Core/Extensions/IntExtensions.cs b/src/Core/Extensions/IntExtensions.cs deleted file mode 100644 index dac03e7..0000000 --- a/src/Core/Extensions/IntExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace Geekbot.Core.Extensions -{ - public static class IntExtensions - { - public static void Times(this int count, Action action) - { - for (var i = 0; i < count; i++) - { - action(); - } - } - } -} \ No newline at end of file diff --git a/src/Core/Extensions/LongExtensions.cs b/src/Core/Extensions/LongExtensions.cs deleted file mode 100644 index 087910e..0000000 --- a/src/Core/Extensions/LongExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Geekbot.Core.Extensions -{ - public static class LongExtensions - { - public static ulong AsUlong(this long thing) - { - return Convert.ToUInt64(thing); - } - } -} \ No newline at end of file diff --git a/src/Core/Extensions/StringExtensions.cs b/src/Core/Extensions/StringExtensions.cs deleted file mode 100644 index 9affad1..0000000 --- a/src/Core/Extensions/StringExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Linq; - -namespace Geekbot.Core.Extensions -{ - public static class StringExtensions - { - public static string CapitalizeFirst(this string source) - { - return source.First().ToString().ToUpper() + source.Substring(1); - } - } -} \ No newline at end of file diff --git a/src/Core/Extensions/UlongExtensions.cs b/src/Core/Extensions/UlongExtensions.cs deleted file mode 100644 index 295f317..0000000 --- a/src/Core/Extensions/UlongExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Geekbot.Core.Extensions -{ - public static class UlongExtensions - { - public static long AsLong(this ulong thing) - { - return Convert.ToInt64(thing); - } - } -} \ No newline at end of file diff --git a/src/Core/GeekbotCommandBase.cs b/src/Core/GeekbotCommandBase.cs deleted file mode 100644 index 801c53c..0000000 --- a/src/Core/GeekbotCommandBase.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Globalization; -using System.Threading; -using Discord.Commands; -using Geekbot.Core.Database.Models; -using Geekbot.Core.ErrorHandling; -using Geekbot.Core.GuildSettingsManager; - -namespace Geekbot.Core -{ - public class GeekbotCommandBase : TransactionModuleBase - { - protected readonly IGuildSettingsManager GuildSettingsManager; - protected GuildSettingsModel GuildSettings; - protected readonly IErrorHandler ErrorHandler; - - protected GeekbotCommandBase(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) - { - GuildSettingsManager = guildSettingsManager; - ErrorHandler = errorHandler; - } - - 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(); - } - } -} \ No newline at end of file diff --git a/src/Core/GlobalSettings/GlobalSettings.cs b/src/Core/GlobalSettings/GlobalSettings.cs deleted file mode 100644 index a000f8b..0000000 --- a/src/Core/GlobalSettings/GlobalSettings.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; - -namespace Geekbot.Core.GlobalSettings -{ - public class GlobalSettings : IGlobalSettings - { - private readonly DatabaseContext _database; - private readonly Dictionary _cache; - - public GlobalSettings(DatabaseContext database) - { - _database = database; - _cache = new Dictionary(); - } - - public async Task SetKey(string keyName, string value) - { - try - { - var key = GetKeyFull(keyName); - if (key == null) - { - _database.Globals.Add(new GlobalsModel() - { - Name = keyName, - Value = value - }); - await _database.SaveChangesAsync(); - return true; - } - key.Value = value; - _database.Globals.Update(key); - _cache[keyName] = value; - await _database.SaveChangesAsync(); - return true; - } - catch - { - return false; - } - } - - public string GetKey(string keyName) - { - var keyValue = ""; - if (string.IsNullOrEmpty(_cache.GetValueOrDefault(keyName))) - { - keyValue = _database.Globals.FirstOrDefault(k => k.Name.Equals(keyName))?.Value ?? string.Empty; - _cache[keyName] = keyValue; - } - else - { - keyValue = _cache[keyName]; - } - return keyValue ; - } - - public GlobalsModel GetKeyFull(string keyName) - { - var key = _database.Globals.FirstOrDefault(k => k.Name.Equals(keyName)); - return key; - } - } -} \ No newline at end of file diff --git a/src/Core/GlobalSettings/IGlobalSettings.cs b/src/Core/GlobalSettings/IGlobalSettings.cs deleted file mode 100644 index 082b3dc..0000000 --- a/src/Core/GlobalSettings/IGlobalSettings.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; -using Geekbot.Core.Database.Models; - -namespace Geekbot.Core.GlobalSettings -{ - public interface IGlobalSettings - { - Task SetKey(string keyName, string value); - string GetKey(string keyName); - GlobalsModel GetKeyFull(string keyName); - } -} \ No newline at end of file diff --git a/src/Core/GuildSettingsManager/GuildSettingsManager.cs b/src/Core/GuildSettingsManager/GuildSettingsManager.cs deleted file mode 100644 index 565563f..0000000 --- a/src/Core/GuildSettingsManager/GuildSettingsManager.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; -using Geekbot.Core.Extensions; - -namespace Geekbot.Core.GuildSettingsManager -{ - public class GuildSettingsManager : IGuildSettingsManager - { - private readonly DatabaseContext _database; - private readonly Dictionary _settings; - - public GuildSettingsManager(DatabaseContext database) - { - _database = database; - _settings = new Dictionary(); - } - - public GuildSettingsModel GetSettings(ulong guildId, bool createIfNonExist = true) - { - return _settings.ContainsKey(guildId) ? _settings[guildId] : GetFromDatabase(guildId, createIfNonExist); - } - - public async Task UpdateSettings(GuildSettingsModel settings) - { - _database.GuildSettings.Update(settings); - if (_settings.ContainsKey(settings.GuildId.AsUlong())) - { - _settings[settings.GuildId.AsUlong()] = settings; - } - else - { - _settings.Add(settings.GuildId.AsUlong(), settings); - } - await _database.SaveChangesAsync(); - } - - private GuildSettingsModel GetFromDatabase(ulong guildId, bool createIfNonExist) - { - var settings = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(guildId.AsLong())); - if (createIfNonExist && settings == null) - { - settings = CreateSettings(guildId); - } - - _settings.Add(guildId, settings); - return settings; - } - - private GuildSettingsModel CreateSettings(ulong guildId) - { - _database.GuildSettings.Add(new GuildSettingsModel - { - GuildId = guildId.AsLong(), - Hui = false, - Ping = false, - Language = "EN", - ShowDelete = false, - ShowLeave = false, - WikiLang = "en" - }); - _database.SaveChanges(); - return _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildId.AsLong())); - } - } -} \ No newline at end of file diff --git a/src/Core/GuildSettingsManager/IGuildSettingsManager.cs b/src/Core/GuildSettingsManager/IGuildSettingsManager.cs deleted file mode 100644 index d34eb73..0000000 --- a/src/Core/GuildSettingsManager/IGuildSettingsManager.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Threading.Tasks; -using Geekbot.Core.Database.Models; - -namespace Geekbot.Core.GuildSettingsManager -{ - public interface IGuildSettingsManager - { - GuildSettingsModel GetSettings(ulong guildId, bool createIfNonExist = true); - Task UpdateSettings(GuildSettingsModel settings); - } -} \ No newline at end of file diff --git a/src/Core/Highscores/HighscoreListEmptyException.cs b/src/Core/Highscores/HighscoreListEmptyException.cs deleted file mode 100644 index 5fc08ee..0000000 --- a/src/Core/Highscores/HighscoreListEmptyException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Geekbot.Core.Highscores -{ - public class HighscoreListEmptyException : Exception - { - public HighscoreListEmptyException() {} - - public HighscoreListEmptyException(string message) : base(message) {} - - public HighscoreListEmptyException(string message, Exception inner) : base(message, inner) {} - } -} \ No newline at end of file diff --git a/src/Core/Highscores/HighscoreManager.cs b/src/Core/Highscores/HighscoreManager.cs deleted file mode 100644 index c839b39..0000000 --- a/src/Core/Highscores/HighscoreManager.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Geekbot.Core.Database; -using Geekbot.Core.Extensions; -using Geekbot.Core.UserRepository; - -namespace Geekbot.Core.Highscores -{ - public class HighscoreManager : IHighscoreManager - { - private readonly DatabaseContext _database; - private readonly IUserRepository _userRepository; - - public HighscoreManager(DatabaseContext databaseContext, IUserRepository userRepository) - { - _database = databaseContext; - _userRepository = userRepository; - - } - - public Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null) - { - var list = type switch - { - HighscoreTypes.messages => GetMessageList(guildId, amount), - 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() - }; - - if (!list.Any()) - { - throw new HighscoreListEmptyException($"No {type} found for guild {guildId}"); - } - - var highscoreUsers = new Dictionary(); - foreach (var user in list) - { - try - { - var guildUser = _userRepository.Get(user.Key); - if (guildUser?.Username != null) - { - highscoreUsers.Add(new HighscoreUserDto - { - Username = guildUser.Username, - Discriminator = guildUser.Discriminator, - Avatar = guildUser.AvatarUrl - }, user.Value); - } - else - { - highscoreUsers.Add(new HighscoreUserDto - { - Id = user.Key.ToString() - }, user.Value); - } - } - catch - { - // ignore - } - } - - return highscoreUsers; - } - - public Dictionary GetMessageList(ulong guildId, int amount) - { - return _database.Messages - .Where(k => k.GuildId.Equals(guildId.AsLong())) - .OrderByDescending(o => o.MessageCount) - .Take(amount) - .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 - .Where(k => k.GuildId.Equals(guildId.AsLong())) - .OrderByDescending(o => o.Karma) - .Take(amount) - .ToDictionary(key => key.UserId.AsUlong(), key => key.Karma); - } - - public Dictionary GetRollsList(ulong guildId, int amount) - { - return _database.Rolls - .Where(k => k.GuildId.Equals(guildId.AsLong())) - .OrderByDescending(o => o.Rolls) - .Take(amount) - .ToDictionary(key => key.UserId.AsUlong(), key => key.Rolls); - } - - private Dictionary GetCookiesList(ulong guildId, int amount) - { - return _database.Cookies - .Where(k => k.GuildId.Equals(guildId.AsLong())) - .OrderByDescending(o => o.Cookies) - .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 deleted file mode 100644 index 3aa396e..0000000 --- a/src/Core/Highscores/HighscoreTypes.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Geekbot.Core.Highscores -{ - public enum HighscoreTypes - { - messages, - karma, - rolls, - cookies, - seasons, - quotes - } -} \ No newline at end of file diff --git a/src/Core/Highscores/IHighscoreManager.cs b/src/Core/Highscores/IHighscoreManager.cs deleted file mode 100644 index 9c2d6f0..0000000 --- a/src/Core/Highscores/IHighscoreManager.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Geekbot.Core.Highscores -{ - public interface IHighscoreManager - { - Dictionary GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null); - 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); - } -} \ No newline at end of file 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 deleted file mode 100644 index 629de74..0000000 --- a/src/Core/HttpAbstractions.cs +++ /dev/null @@ -1,189 +0,0 @@ -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; - -namespace Geekbot.Core -{ - public static class HttpAbstractions - { - public static HttpClient CreateDefaultClient() - { - var client = new HttpClient - { - DefaultRequestHeaders = - { - Accept = {MediaTypeWithQualityHeaderValue.Parse("application/json")}, - } - }; - client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Geekbot/v0.0.0 (+https://geekbot.pizzaandcoffee.rocks/)"); - - return client; - } - - public static async Task Get(Uri location, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3) - { - httpClient ??= CreateDefaultClient(); - httpClient.BaseAddress = location; - - HttpResponseMessage response; - try - { - response = await Execute(() => httpClient.GetAsync(location.PathAndQuery), maxRetries); - } - finally - { - if (disposeClient) - { - 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" - ); - - HttpResponseMessage response; - try - { - response = await Execute(() => httpClient.PostAsync(location, content), maxRetries); - } - finally - { - if (disposeClient) - { - 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; - } - } - } - } -} \ No newline at end of file diff --git a/src/Core/KvInMemoryStore/IKvInMemoryStore.cs b/src/Core/KvInMemoryStore/IKvInMemoryStore.cs deleted file mode 100644 index 6281f4b..0000000 --- a/src/Core/KvInMemoryStore/IKvInMemoryStore.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Geekbot.Core.KvInMemoryStore -{ - public interface IKvInMemoryStore - { - public T Get(string key); - public void Set(string key, T value); - public void Remove(string key); - } -} \ No newline at end of file diff --git a/src/Core/KvInMemoryStore/KvInMemoryStore.cs b/src/Core/KvInMemoryStore/KvInMemoryStore.cs deleted file mode 100644 index 4a50546..0000000 --- a/src/Core/KvInMemoryStore/KvInMemoryStore.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; - -namespace Geekbot.Core.KvInMemoryStore -{ - public class KvInInMemoryStore : IKvInMemoryStore - { - private readonly Dictionary _storage = new Dictionary(); - - public T Get(string key) - { - try - { - return (T) _storage[key]; - } - catch - { - return default; - } - } - - public void Set(string key, T value) - { - _storage.Remove(key); - _storage.Add(key, value); - } - - public void Remove(string key) - { - _storage.Remove(key); - } - } -} \ No newline at end of file diff --git a/src/Core/Levels/ILevelCalc.cs b/src/Core/Levels/ILevelCalc.cs deleted file mode 100644 index 17413e6..0000000 --- a/src/Core/Levels/ILevelCalc.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Geekbot.Core.Levels -{ - public interface ILevelCalc - { - int GetLevel(int? experience); - } -} \ No newline at end of file diff --git a/src/Core/Localization/Admin.Designer.cs b/src/Core/Localization/Admin.Designer.cs deleted file mode 100644 index 460d471..0000000 --- a/src/Core/Localization/Admin.Designer.cs +++ /dev/null @@ -1,78 +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 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() { - } - - /// - /// 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.Admin", typeof(Admin).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 I'm talking english. - /// - public static string GetLanguage { - get { - return ResourceManager.GetString("GetLanguage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to I will reply in english from now on. - /// - public static string NewLanguageSet { - get { - return ResourceManager.GetString("NewLanguageSet", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Admin.de-ch.resx b/src/Core/Localization/Admin.de-ch.resx deleted file mode 100644 index b89939b..0000000 --- a/src/Core/Localization/Admin.de-ch.resx +++ /dev/null @@ -1,20 +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 - - - I werd ab jetzt uf schwiizerdüütsch antworte, äuuä - - - I red schwiizerdüütsch - - \ No newline at end of file diff --git a/src/Core/Localization/Admin.resx b/src/Core/Localization/Admin.resx deleted file mode 100644 index 6fd2c62..0000000 --- a/src/Core/Localization/Admin.resx +++ /dev/null @@ -1,27 +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 - - - I will reply in english from now on - - - I'm talking english - - \ No newline at end of file diff --git a/src/Core/Localization/Choose.Designer.cs b/src/Core/Localization/Choose.Designer.cs deleted file mode 100644 index 91ef136..0000000 --- a/src/Core/Localization/Choose.Designer.cs +++ /dev/null @@ -1,69 +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 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() { - } - - /// - /// 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.Choose", typeof(Choose).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 I Choose **{0}**. - /// - public static string Choice { - get { - return ResourceManager.GetString("Choice", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Choose.de-ch.resx b/src/Core/Localization/Choose.de-ch.resx deleted file mode 100644 index eedc39b..0000000 --- a/src/Core/Localization/Choose.de-ch.resx +++ /dev/null @@ -1,17 +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 - - - I nimme **{0}** - - \ No newline at end of file diff --git a/src/Core/Localization/Choose.resx b/src/Core/Localization/Choose.resx deleted file mode 100644 index 052177b..0000000 --- a/src/Core/Localization/Choose.resx +++ /dev/null @@ -1,24 +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 - - - I Choose **{0}** - - \ 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/Cookies.de-ch.resx b/src/Core/Localization/Cookies.de-ch.resx deleted file mode 100644 index 3652224..0000000 --- a/src/Core/Localization/Cookies.de-ch.resx +++ /dev/null @@ -1,38 +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 - - - Du häsch {0} guetzli becho, du häsch jetzt {1} guetzli ih dr büchse - - - Du hesch scho guetzli becho hüt, du chasch meh ha in {0} - - - Es hät {0} guetzli ih dineri büchs - - - Du hesch {1} {0} guetzli geh - - - Du hesch nid gnueg guetzli - - - Du hesch chuum no guetzli ih dineri büchs, du sötsch warschinli keini esse - - - 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/Core/Localization/Cookies.resx deleted file mode 100644 index a359c5c..0000000 --- a/src/Core/Localization/Cookies.resx +++ /dev/null @@ -1,45 +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 - - - You got {0} cookies, there are now {1} cookies in you cookie jar - - - You already got cookies today, you can have more cookies in {0} - - - There are {0} cookies in you cookie jar - - - You gave {0} cookies to {1} - - - You don't have enough cookies - - - Your cookie jar looks almost empty, you should probably not eat a cookie - - - 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/Corona.Designer.cs b/src/Core/Localization/Corona.Designer.cs deleted file mode 100644 index a19bbcd..0000000 --- a/src/Core/Localization/Corona.Designer.cs +++ /dev/null @@ -1,114 +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 Corona { - - 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() { - } - - /// - /// 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.Corona", typeof(Corona).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 Active. - /// - public static string Active { - get { - return ResourceManager.GetString("Active", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Confirmed Corona Cases. - /// - public static string ConfirmedCases { - get { - return ResourceManager.GetString("ConfirmedCases", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Deaths. - /// - public static string Deaths { - get { - return ResourceManager.GetString("Deaths", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Recovered. - /// - public static string Recovered { - get { - return ResourceManager.GetString("Recovered", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Source. - /// - public static string Source { - get { - return ResourceManager.GetString("Source", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Total. - /// - public static string Total { - get { - return ResourceManager.GetString("Total", 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/Localization/Internal.Designer.cs b/src/Core/Localization/Internal.Designer.cs deleted file mode 100644 index 967b26e..0000000 --- a/src/Core/Localization/Internal.Designer.cs +++ /dev/null @@ -1,123 +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 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() { - } - - /// - /// 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.Internal", typeof(Internal).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 and. - /// - public static string And { - get { - return ResourceManager.GetString("And", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to day|days. - /// - public static string Days { - get { - return ResourceManager.GetString("Days", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to hour|hours. - /// - public static string Hours { - get { - return ResourceManager.GetString("Hours", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Seems like i don't have enough permission to that :confused:. - /// - public static string Http403 { - get { - return ResourceManager.GetString("Http403", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to minute|minutes. - /// - public static string Minutes { - get { - return ResourceManager.GetString("Minutes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to second|seconds. - /// - public static string Seconds { - get { - return ResourceManager.GetString("Seconds", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Something went wrong :confused:. - /// - public static string SomethingWentWrong { - get { - return ResourceManager.GetString("SomethingWentWrong", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Internal.de-ch.resx b/src/Core/Localization/Internal.de-ch.resx deleted file mode 100644 index 568bb1f..0000000 --- a/src/Core/Localization/Internal.de-ch.resx +++ /dev/null @@ -1,35 +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 - - - Öppis isch schief gange :confused: - - - Gseht danach us das ich nid gnueg recht han zum das mache :confused: - - - tag|täg - - - stund|stunde - - - minute|minute - - - sekunde|sekunde - - - und - - \ No newline at end of file diff --git a/src/Core/Localization/Internal.resx b/src/Core/Localization/Internal.resx deleted file mode 100644 index a771d6b..0000000 --- a/src/Core/Localization/Internal.resx +++ /dev/null @@ -1,42 +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 - - - Something went wrong :confused: - - - Seems like i don't have enough permission to that :confused: - - - day|days - - - hour|hours - - - minute|minutes - - - second|seconds - - - and - - \ No newline at end of file diff --git a/src/Core/Localization/Karma.Designer.cs b/src/Core/Localization/Karma.Designer.cs deleted file mode 100644 index b3e8325..0000000 --- a/src/Core/Localization/Karma.Designer.cs +++ /dev/null @@ -1,150 +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 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() { - } - - /// - /// 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.Karma", typeof(Karma).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 Amount. - /// - public static string Amount { - get { - return ResourceManager.GetString("Amount", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to By. - /// - public static string By { - get { - return ResourceManager.GetString("By", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sorry {0}, but you can't lower your own karma. - /// - public 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 { - get { - return ResourceManager.GetString("CannotChangeOwnUp", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Current. - /// - public static string Current { - get { - return ResourceManager.GetString("Current", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Karma lowered. - /// - public static string Decreased { - get { - return ResourceManager.GetString("Decreased", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Gained Karma. - /// - public 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 { - get { - return ResourceManager.GetString("WaitUntill", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Karma.de-ch.resx b/src/Core/Localization/Karma.de-ch.resx deleted file mode 100644 index 5805a27..0000000 --- a/src/Core/Localization/Karma.de-ch.resx +++ /dev/null @@ -1,44 +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 - - - Sorry {0}, aber du chasch dr selber kei karma geh - - - Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch geh... - - - Karma becho - - - Vo - - - Mengi - - - Jetzt - - - Sorry {0}, aber du chasch dis eigete karma nid senke - - - 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/Core/Localization/Karma.resx deleted file mode 100644 index a16e14a..0000000 --- a/src/Core/Localization/Karma.resx +++ /dev/null @@ -1,51 +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 - - - Sorry {0}, but you can't give yourself karma - - - Sorry {0}, but you have to wait {1} before you can give karma again... - - - Gained Karma - - - By - - - Amount - - - Current - - - Sorry {0}, but you can't lower your own karma - - - 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/Core/Localization/Quote.Designer.cs deleted file mode 100644 index 9146971..0000000 --- a/src/Core/Localization/Quote.Designer.cs +++ /dev/null @@ -1,159 +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 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() { - } - - /// - /// 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.Quote", typeof(Quote).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 You can't save quotes by a bot.... - /// - public static string CannotQuoteBots { - get { - return ResourceManager.GetString("CannotQuoteBots", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't save your own quotes.... - /// - public static string CannotSaveOwnQuotes { - get { - return ResourceManager.GetString("CannotSaveOwnQuotes", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Most quoted person. - /// - public static string MostQuotesPerson { - get { - return ResourceManager.GetString("MostQuotesPerson", resourceCulture); - } - } - - /// - /// 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 { - get { - return ResourceManager.GetString("NoQuotesFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to That is not a valid message link. - /// - public static string NotAValidMessageLink { - get { - return ResourceManager.GetString("NotAValidMessageLink", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to I couldn't find a quote with that ID :disappointed:. - /// - public static string NotFoundWithId { - get { - return ResourceManager.GetString("NotFoundWithId", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can only quote messages from the same server. - /// - public static string OnlyQuoteFromSameServer { - get { - return ResourceManager.GetString("OnlyQuoteFromSameServer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to **Quote Added**. - /// - public static string QuoteAdded { - get { - return ResourceManager.GetString("QuoteAdded", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Quote Stats. - /// - public static string QuoteStats { - get { - return ResourceManager.GetString("QuoteStats", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to **Removed #{0}**. - /// - public static string Removed { - get { - return ResourceManager.GetString("Removed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Total. - /// - public static string TotalQuotes { - get { - return ResourceManager.GetString("TotalQuotes", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Quote.de-ch.resx b/src/Core/Localization/Quote.de-ch.resx deleted file mode 100644 index 99fd959..0000000 --- a/src/Core/Localization/Quote.de-ch.resx +++ /dev/null @@ -1,47 +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 - - - Dä server het no kei quotes. Du chasch quotes hinzuefüege mit `!quote save @user` oder `!quote save <messageId>` - - - Du chasch kei quotes vo dir selber speichere... - - - Du chasch kei quotes vomne bot speichere... - - - **Quote hinzugfüegt** - - - **#{0} glöscht** - - - Ich chan kei quote finde mit därri ID :disappointed: - - - Quote statistike - - - Total - - - Meist quoteti person - - - Das isch kei korrete nachrichtelink - - - Du chasch numme nachrichte vom gliche server quote - - \ No newline at end of file diff --git a/src/Core/Localization/Quote.resx b/src/Core/Localization/Quote.resx deleted file mode 100644 index b51d79c..0000000 --- a/src/Core/Localization/Quote.resx +++ /dev/null @@ -1,54 +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 - - - This server doesn't seem to have any quotes yet. You can add a quote with `!quote save @user` or `!quote save <messageId>` - - - You can't save your own quotes... - - - You can't save quotes by a bot... - - - **Quote Added** - - - **Removed #{0}** - - - I couldn't find a quote with that ID :disappointed: - - - Quote Stats - - - Total - - - Most quoted person - - - That is not a valid message link - - - You can only quote messages from the same server - - \ No newline at end of file diff --git a/src/Core/Localization/Rank.Designer.cs b/src/Core/Localization/Rank.Designer.cs deleted file mode 100644 index 1439a8c..0000000 --- a/src/Core/Localization/Rank.Designer.cs +++ /dev/null @@ -1,105 +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 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() { - } - - /// - /// 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.Rank", typeof(Rank).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 :warning: I couldn't find all usernames. Maybe they left the server?. - /// - public static string FailedToResolveAllUsernames { - get { - return ResourceManager.GetString("FailedToResolveAllUsernames", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to :bar_chart: **{0} Highscore for {1}**. - /// - public 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`'. - /// - public static string InvalidType { - get { - return ResourceManager.GetString("InvalidType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to :warning: Limiting to 20. - /// - public static string LimitingTo20Warning { - get { - return ResourceManager.GetString("LimitingTo20Warning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No {0} found on this server. - /// - public static string NoTypeFoundForServer { - get { - return ResourceManager.GetString("NoTypeFoundForServer", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Rank.de-ch.resx b/src/Core/Localization/Rank.de-ch.resx deleted file mode 100644 index 743b8cd..0000000 --- a/src/Core/Localization/Rank.de-ch.resx +++ /dev/null @@ -1,29 +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 - - - :warning: Limitiert uf 20 - - - Kei {0} gfunde für dä server - - - :warning: Ich han nid alli benutzername gfunde. villiicht hend sie de server verlah? - - - :bar_chart: **{0} Highscore für {1}** - - - Gültigi paramenter sind '`messages`' '`karma`', '`rolls`', '`cookies`', '`seasons`' und '`quotes`' - - \ No newline at end of file diff --git a/src/Core/Localization/Rank.resx b/src/Core/Localization/Rank.resx deleted file mode 100644 index 606a34e..0000000 --- a/src/Core/Localization/Rank.resx +++ /dev/null @@ -1,36 +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 - - - Valid types are '`messages`' '`karma`', '`rolls`', '`cookies`', '`seasons`' and '`quotes`' - - - :warning: Limiting to 20 - - - No {0} found on this server - - - :warning: I couldn't find all usernames. Maybe they left the server? - - - :bar_chart: **{0} Highscore for {1}** - - \ No newline at end of file diff --git a/src/Core/Localization/Role.Designer.cs b/src/Core/Localization/Role.Designer.cs deleted file mode 100644 index fc48852..0000000 --- a/src/Core/Localization/Role.Designer.cs +++ /dev/null @@ -1,150 +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 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() { - } - - /// - /// 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.Role", typeof(Role).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 Added {0} to the whitelist. - /// - public static string AddedRoleToWhitelist { - get { - return ResourceManager.GetString("AddedRoleToWhitelist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Added you to {0}. - /// - public static string AddedUserFromRole { - get { - return ResourceManager.GetString("AddedUserFromRole", resourceCulture); - } - } - - /// - /// 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 { - get { - return ResourceManager.GetString("CannotAddDangerousRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't add a role that is managed by discord. - /// - public static string CannotAddManagedRole { - get { - return ResourceManager.GetString("CannotAddManagedRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to **Self Service Roles on {0}**. - /// - public static string ListHeader { - get { - return ResourceManager.GetString("ListHeader", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to To get a role, use `!role [name]`. - /// - public static string ListInstruction { - get { - return ResourceManager.GetString("ListInstruction", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There are no roles configured for this server. - /// - public static string NoRolesConfigured { - get { - return ResourceManager.GetString("NoRolesConfigured", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Removed {0} from the whitelist. - /// - public static string RemovedRoleFromWhitelist { - get { - return ResourceManager.GetString("RemovedRoleFromWhitelist", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Removed you from {0}. - /// - public static string RemovedUserFromRole { - get { - return ResourceManager.GetString("RemovedUserFromRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to That role doesn't exist or is not on the whitelist. - /// - public static string RoleNotFound { - get { - return ResourceManager.GetString("RoleNotFound", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Role.de-ch.resx b/src/Core/Localization/Role.de-ch.resx deleted file mode 100644 index b0b3259..0000000 --- a/src/Core/Localization/Role.de-ch.resx +++ /dev/null @@ -1,44 +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 sind kei rolle für dä server konfiguriert - - - **Self Service Rollene uf {0}** - - - Zum ä rolle becho, schriib `!role [name]` - - - Die rolle gids nid or isch nid uf dr whitelist - - - Han di entfernt vo {0} - - - Han di hinzue gfüegt zu {0} - - - Du chasch kei rolle hinzuefüge wo verwalted wird vo discord - - - Du chasch die rolle nid hinzuefüge will er ein oder mehreri gföhrlichi berechtigunge het - - - {0} isch zur whitelist hinzuegfüegt - - - {0} isch vo dr whitelist glöscht - - \ No newline at end of file diff --git a/src/Core/Localization/Role.resx b/src/Core/Localization/Role.resx deleted file mode 100644 index 63b70d0..0000000 --- a/src/Core/Localization/Role.resx +++ /dev/null @@ -1,51 +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 - - - There are no roles configured for this server - - - **Self Service Roles on {0}** - - - To get a role, use `!role [name]` - - - That role doesn't exist or is not on the whitelist - - - Removed you from {0} - - - Added you to {0} - - - You can't add a role that is managed by discord - - - You cannot add that role to self service because it contains one or more dangerous permissions - - - Added {0} to the whitelist - - - Removed {0} from the whitelist - - \ No newline at end of file diff --git a/src/Core/Localization/Roll.Designer.cs b/src/Core/Localization/Roll.Designer.cs deleted file mode 100644 index bceb55d..0000000 --- a/src/Core/Localization/Roll.Designer.cs +++ /dev/null @@ -1,96 +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 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() { - } - - /// - /// 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.Roll", typeof(Roll).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 Congratulations {0}, your guess was correct!. - /// - public static string Gratz { - get { - return ResourceManager.GetString("Gratz", resourceCulture); - } - } - - /// - /// 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 { - get { - return ResourceManager.GetString("NoPrevGuess", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0}, you rolled {1}, your guess was {2}. - /// - public static string Rolled { - get { - return ResourceManager.GetString("Rolled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0}, you rolled {1}. - /// - public static string RolledNoGuess { - get { - return ResourceManager.GetString("RolledNoGuess", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Roll.de-ch.resx b/src/Core/Localization/Roll.de-ch.resx deleted file mode 100644 index ba73316..0000000 --- a/src/Core/Localization/Roll.de-ch.resx +++ /dev/null @@ -1,26 +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 - - - {0}, du hesch {1} grollt und hesch {2} grate - - - Gratuliere {0}, du hesch richtig grate! - - - {0}, du hesch {1} grollt - - - :red_circle: {0}, du chasch nid nomol es gliche rate, rate öppis anders oder warte {1} - - \ No newline at end of file diff --git a/src/Core/Localization/Roll.resx b/src/Core/Localization/Roll.resx deleted file mode 100644 index 822abb6..0000000 --- a/src/Core/Localization/Roll.resx +++ /dev/null @@ -1,33 +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 - - - {0}, you rolled {1}, your guess was {2} - - - Congratulations {0}, your guess was correct! - - - {0}, you rolled {1} - - - :red_circle: {0}, you can't guess the same number again, guess another number or wait {1} - - \ No newline at end of file diff --git a/src/Core/Localization/Ship.Designer.cs b/src/Core/Localization/Ship.Designer.cs deleted file mode 100644 index 2d917b6..0000000 --- a/src/Core/Localization/Ship.Designer.cs +++ /dev/null @@ -1,114 +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 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() { - } - - /// - /// 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.Ship", typeof(Ship).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 Almost a match. - /// - public static string CouldWork { - get { - return ResourceManager.GetString("CouldWork", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's a match. - /// - public static string ItsAMatch { - get { - return ResourceManager.GetString("ItsAMatch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Matchmaking. - /// - public static string Matchmaking { - get { - return ResourceManager.GetString("Matchmaking", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Not going happen. - /// - public static string NotGoingToHappen { - get { - return ResourceManager.GetString("NotGoingToHappen", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Not such a good idea. - /// - public static string NotSuchAGoodIdea { - get { - return ResourceManager.GetString("NotSuchAGoodIdea", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to There might be a chance. - /// - public static string ThereMightBeAChance { - get { - return ResourceManager.GetString("ThereMightBeAChance", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Ship.de-ch.resx b/src/Core/Localization/Ship.de-ch.resx deleted file mode 100644 index ec2880b..0000000 --- a/src/Core/Localization/Ship.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 - - - Verkupple - - - Wird nöd klappe - - - Nöd so ä gueti idee - - - Es gid eventuel ä chance - - - Fasch en match - - - Es isch es traumpaar - - \ No newline at end of file diff --git a/src/Core/Localization/Ship.resx b/src/Core/Localization/Ship.resx deleted file mode 100644 index 611040f..0000000 --- a/src/Core/Localization/Ship.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 - - - Matchmaking - - - Not going happen - - - Not such a good idea - - - There might be a chance - - - Almost a match - - - It's a match - - \ No newline at end of file diff --git a/src/Core/Localization/Stats.Designer.cs b/src/Core/Localization/Stats.Designer.cs deleted file mode 100644 index 5f9b96c..0000000 --- a/src/Core/Localization/Stats.Designer.cs +++ /dev/null @@ -1,150 +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 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() { - } - - /// - /// 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.Stats", typeof(Stats).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 Cookies. - /// - public 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 { - get { - return ResourceManager.GetString("GuessedRolls", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Joined Server. - /// - public static string JoinedServer { - get { - return ResourceManager.GetString("JoinedServer", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Karma. - /// - public static string Karma { - get { - return ResourceManager.GetString("Karma", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Level. - /// - public static string Level { - get { - return ResourceManager.GetString("Level", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Messages Sent. - /// - public static string MessagesSent { - get { - return ResourceManager.GetString("MessagesSent", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to On Discord Since. - /// - public 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 { - get { - return ResourceManager.GetString("ServerTotal", resourceCulture); - } - } - } -} diff --git a/src/Core/Localization/Stats.de-ch.resx b/src/Core/Localization/Stats.de-ch.resx deleted file mode 100644 index 0af0477..0000000 --- a/src/Core/Localization/Stats.de-ch.resx +++ /dev/null @@ -1,44 +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 - - - Server Total - - - Uf Discord siit - - - Nachrichte versendet - - - Level - - - Karma - - - Server Bitrette - - - Grateni Rolls - - - Guetzli - - - Täg - - - Quotes - - \ No newline at end of file diff --git a/src/Core/Localization/Stats.resx b/src/Core/Localization/Stats.resx deleted file mode 100644 index 6eb3a92..0000000 --- a/src/Core/Localization/Stats.resx +++ /dev/null @@ -1,51 +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 - - - On Discord Since - - - Joined Server - - - Karma - - - Level - - - Messages Sent - - - Server Total - - - Guessed Rolls - - - Cookies - - - Days - - - Quotes - - \ 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/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 deleted file mode 100644 index 83a6d49..0000000 --- a/src/Core/Logger/GeekbotLogger.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace Geekbot.Core.Logger -{ - public class GeekbotLogger : IGeekbotLogger - { - private readonly bool _logAsJson; - private readonly NLog.Logger _logger; - private readonly JsonSerializerOptions _serializerSettings; - - public GeekbotLogger(RunParameters runParameters) - { - _logAsJson = !string.IsNullOrEmpty(runParameters.SumologicEndpoint) || runParameters.LogJson; - _logger = LoggerFactory.CreateNLog(runParameters); - _serializerSettings = new JsonSerializerOptions - { - ReferenceHandler = ReferenceHandler.IgnoreCycles, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - }; - Information(LogSource.Geekbot, "Using GeekbotLogger"); - } - - public void Trace(LogSource source, string message, object extra = null) - => _logger.Trace(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)); - - public void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null) - => _logger.Warn(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 bool LogAsJson() => _logAsJson; - - private string CreateLogString(string type, LogSource source, string message, Exception exception = null, object extra = null) - { - if (_logAsJson) - { - var logObject = new GeekbotLoggerObject - { - Timestamp = DateTime.Now, - Type = type, - Source = source, - Message = message, - StackTrace = exception != null ? new ExceptionDto(exception) : null, - Extra = extra - }; - return JsonSerializer.Serialize(logObject, _serializerSettings); - } - - if (source != LogSource.Message) return $"[{source}] - {message}"; - - var m = (MessageDto) extra; - return $"[{source}] - [{m?.Guild.Name} - {m?.Channel.Name}] {m?.User.Name}: {m?.Message.Content}"; - } - } -} \ No newline at end of file diff --git a/src/Core/Logger/LogDto.cs b/src/Core/Logger/LogDto.cs deleted file mode 100644 index ee6a3e5..0000000 --- a/src/Core/Logger/LogDto.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace Geekbot.Core.Logger; - -public struct GeekbotLoggerObject -{ - 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; } -} diff --git a/src/Core/Logger/LogSource.cs b/src/Core/Logger/LogSource.cs deleted file mode 100644 index d2baff5..0000000 --- a/src/Core/Logger/LogSource.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Geekbot.Core.Logger -{ - [JsonConverter(typeof(JsonStringEnumConverter))] - public enum LogSource - { - Geekbot, - Rest, - Gateway, - Discord, - Database, - Message, - UserRepository, - Command, - Api, - Migration, - HighscoreManager, - Interaction, - Other - } -} \ No newline at end of file diff --git a/src/Core/Media/IMediaProvider.cs b/src/Core/Media/IMediaProvider.cs deleted file mode 100644 index 03e32cf..0000000 --- a/src/Core/Media/IMediaProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Geekbot.Core.Media -{ - public interface IMediaProvider - { - string GetMedia(MediaType type); - } -} \ No newline at end of file diff --git a/src/Core/Media/MediaProvider.cs b/src/Core/Media/MediaProvider.cs deleted file mode 100644 index 4c72ee0..0000000 --- a/src/Core/Media/MediaProvider.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.IO; -using Geekbot.Core.Logger; -using Geekbot.Core.RandomNumberGenerator; - -namespace Geekbot.Core.Media -{ - public class MediaProvider : IMediaProvider - { - private readonly IRandomNumberGenerator _random; - private readonly IGeekbotLogger _logger; - private readonly string[] _pandaImages; - private readonly string[] _croissantImages; - private readonly string[] _squirrelImages; - private readonly string[] _pumpkinImages; - private readonly string[] _turtlesImages; - private readonly string[] _penguinImages; - private readonly string[] _foxImages; - private readonly string[] _dabImages; - - public MediaProvider(IGeekbotLogger logger, IRandomNumberGenerator random) - { - _random = random; - _logger = logger; - - logger.Information(LogSource.Geekbot, "Loading Media Files"); - LoadMedia("./Storage/pandas", ref _pandaImages); - LoadMedia("./Storage/croissant", ref _croissantImages); - LoadMedia("./Storage/squirrel", ref _squirrelImages); - LoadMedia("./Storage/pumpkin", ref _pumpkinImages); - LoadMedia("./Storage/turtles", ref _turtlesImages); - LoadMedia("./Storage/penguins", ref _penguinImages); - LoadMedia("./Storage/foxes", ref _foxImages); - LoadMedia("./Storage/dab", ref _dabImages); - } - - private void LoadMedia(string path, ref string[] storage) - { - var rawLinks = File.ReadAllText(Path.GetFullPath(path)); - storage = rawLinks.Split("\n"); - _logger.Trace(LogSource.Geekbot, $"Loaded {storage.Length} Images from ${path}"); - } - - public string GetMedia(MediaType type) - { - var collection = type switch - { - MediaType.Panda => _pandaImages, - MediaType.Croissant => _croissantImages, - MediaType.Squirrel => _squirrelImages, - MediaType.Pumpkin => _pumpkinImages, - MediaType.Turtle => _turtlesImages, - MediaType.Penguin => _penguinImages, - MediaType.Fox => _foxImages, - MediaType.Dab => _dabImages, - _ => new string[0] - }; - - return collection[_random.Next(0, collection.Length)]; - } - } -} \ No newline at end of file diff --git a/src/Core/Media/MediaType.cs b/src/Core/Media/MediaType.cs deleted file mode 100644 index fa30164..0000000 --- a/src/Core/Media/MediaType.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Geekbot.Core.Media -{ - public enum MediaType - { - Panda, - Croissant, - Squirrel, - Pumpkin, - Turtle, - Penguin, - Fox, - Dab - } -} \ No newline at end of file diff --git a/src/Core/Polyfills/UserPolyfillDto.cs b/src/Core/Polyfills/UserPolyfillDto.cs deleted file mode 100644 index 3907e05..0000000 --- a/src/Core/Polyfills/UserPolyfillDto.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Threading.Tasks; -using Discord; - -namespace Geekbot.Core.Polyfills -{ - public class UserPolyfillDto : IUser - { - public ulong Id { get; set; } - public DateTimeOffset CreatedAt { get; set; } - 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"; - } - - public string GetDefaultAvatarUrl() - { - throw new NotImplementedException(); - } - - public Task GetOrCreateDMChannelAsync(RequestOptions options = null) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/src/Core/RandomNumberGenerator/IRandomNumberGenerator.cs b/src/Core/RandomNumberGenerator/IRandomNumberGenerator.cs deleted file mode 100644 index f817248..0000000 --- a/src/Core/RandomNumberGenerator/IRandomNumberGenerator.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Geekbot.Core.RandomNumberGenerator -{ - public interface IRandomNumberGenerator - { - int Next(int minValue, int maxExclusiveValue); - } -} \ No newline at end of file diff --git a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs b/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs deleted file mode 100644 index 7460677..0000000 --- a/src/Core/RandomNumberGenerator/RandomNumberGenerator.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -namespace Geekbot.Core.RandomNumberGenerator -{ - public class RandomNumberGenerator : IRandomNumberGenerator - { - private readonly System.Security.Cryptography.RandomNumberGenerator rng; - - public RandomNumberGenerator() - { - rng = System.Security.Cryptography.RandomNumberGenerator.Create(); - } - - public int Next(int minValue, int maxInclusiveValue) - { - if (minValue == maxInclusiveValue) - { - return maxInclusiveValue; - } - - if (minValue >= maxInclusiveValue) - { - throw new ArgumentOutOfRangeException("minValue", "must be lower than maxExclusiveValue"); - } - - return GetFromCrypto(minValue, maxInclusiveValue); - } - - private int GetFromCrypto(int minValue, int maxInclusiveValue) - { - var maxExclusiveValue = maxInclusiveValue + 1; - - var diff = (long) maxExclusiveValue - minValue; - var upperBound = uint.MaxValue / diff * diff; - - uint ui; - do - { - ui = GetRandomUInt(); - } while (ui >= upperBound); - - return (int) (minValue + (ui % diff)); - } - - private uint GetRandomUInt() - { - var randomBytes = GenerateRandomBytes(sizeof(uint)); - return BitConverter.ToUInt32(randomBytes, 0); - } - - private byte[] GenerateRandomBytes(int bytesNumber) - { - var buffer = new byte[bytesNumber]; - rng.GetBytes(buffer); - return buffer; - } - } -} \ No newline at end of file diff --git a/src/Core/ReactionListener/IReactionListener.cs b/src/Core/ReactionListener/IReactionListener.cs deleted file mode 100644 index c22d792..0000000 --- a/src/Core/ReactionListener/IReactionListener.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Threading.Tasks; -using Discord; -using Discord.WebSocket; - -namespace Geekbot.Core.ReactionListener -{ - public interface IReactionListener - { - 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); - IEmote ConvertStringToEmote(string emoji); - } -} \ No newline at end of file diff --git a/src/Core/ReactionListener/ReactionListener.cs b/src/Core/ReactionListener/ReactionListener.cs deleted file mode 100644 index dcb0d5b..0000000 --- a/src/Core/ReactionListener/ReactionListener.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -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) - { - _database = database; - _logger = logger; - LoadListeners(); - } - - private void LoadListeners() - { - _listener = new Dictionary>(); - foreach (var row in _database.ReactionListeners) - { - var messageId = row.MessageId.AsUlong(); - if (!_listener.ContainsKey(messageId)) - { - _listener.Add(messageId, new Dictionary()); - } - - _listener[messageId].Add(ConvertStringToEmote(row.Reaction), row.RoleId.AsUlong()); - } - } - - public bool IsListener(ulong id) - { - return _listener.ContainsKey(id); - } - - public async Task AddRoleToListener(ulong messageId, ulong guildId, string emoji, IRole role) - { - var emote = ConvertStringToEmote(emoji); - - await _database.ReactionListeners.AddAsync(new ReactionListenerModel() - { - GuildId = guildId.AsLong(), - MessageId = messageId.AsLong(), - RoleId = role.Id.AsLong(), - Reaction = emoji - }); - await _database.SaveChangesAsync(); - - if (!_listener.ContainsKey(messageId)) - { - _listener.Add(messageId, new Dictionary()); - } - _listener[messageId].Add(emote, role.Id); - } - - public async void RemoveRole(IMessageChannel 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 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); - } - } - - public async void GiveRole(IMessageChannel 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 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); - } - - public IEmote ConvertStringToEmote(string emoji) - { - if (!emoji.StartsWith('<')) - { - return new Emoji(emoji); - } - return Emote.Parse(emoji); - } - } -} \ No newline at end of file diff --git a/src/Core/RunParameters.cs b/src/Core/RunParameters.cs deleted file mode 100644 index a886a98..0000000 --- a/src/Core/RunParameters.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using CommandLine; - -namespace Geekbot.Core -{ - public class RunParameters - { - /************************************ - * General * - ************************************/ - - [Option("token", HelpText = "Set a new bot token. By default it will use your previous bot token which was stored in the database (default: null) (env: TOKEN)")] - public string Token { get; set; } = ParamFallback("TOKEN"); - - [Option('V', "verbose", HelpText = "Logs everything. (default: false) (env: LOG_VERBOSE)")] - public bool Verbose { get; set; } = ParamFallback("LOG_VERBOSE", false); - - [Option('j', "log-json", HelpText = "Logger outputs json (default: false ) (env: LOG_JSON)")] - public bool LogJson { get; set; } = ParamFallback("LOG_JSON", false); - - [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 * - ************************************/ - - [Option("in-memory", HelpText = "Uses the in-memory database instead of postgresql (default: false) (env: DB_INMEMORY)")] - public bool InMemory { get; set; } = ParamFallback("DB_INMEMORY", false); - - // Postresql connection - [Option("database", HelpText = "Select a postgresql database (default: geekbot) (env: DB_DATABASE)")] - public string DbDatabase { get; set; } = ParamFallback("DB_DATABASE", "geekbot"); - - [Option("db-host", HelpText = "Set a postgresql host (default: localhost) (env: DB_HOST)")] - public string DbHost { get; set; } = ParamFallback("DB_HOST", "localhost"); - - [Option("db-port", HelpText = "Set a postgresql host (default: 5432) (env: DB_PORT)")] - public string DbPort { get; set; } = ParamFallback("DB_PORT", "5432"); - - [Option("db-user", HelpText = "Set a postgresql user (default: geekbot) (env: DB_USER)")] - public string DbUser { get; set; } = ParamFallback("DB_USER", "geekbot"); - - [Option("db-password", HelpText = "Set a posgresql password (default: empty) (env: DB_PASSWORD)")] - public string DbPassword { get; set; } = ParamFallback("DB_PASSWORD", ""); - - [Option("db-require-ssl", HelpText = "Require SSL to connect to the database (default: false) (env: DB_REQUIRE_SSL)")] - public bool DbSsl { get; set; } = ParamFallback("DB_REQUIRE_SSL", false); - - [Option("db-trust-cert", HelpText = "Trust the database certificate, regardless if it is valid (default: false) (env: DB_TRUST_CERT)")] - public bool DbTrustCert { get; set; } = ParamFallback("DB_TRUST_CERT", false); - - [Option("db-redshift-compat", HelpText = "Enable compatibility for AWS Redshift and DigitalOcean Managed Database (default: false) (env: DB_REDSHIFT_COMPAT)")] - public bool DbRedshiftCompatibility { get; set; } = ParamFallback("DB_REDSHIFT_COMPAT", false); - - // Logging - [Option("db-logging", HelpText = "Enable database logging (default: false) (env: DB_LOGGING)")] - public bool DbLogging { get; set; } = ParamFallback("DB_LOGGING", false); - - /************************************ - * WebApi * - ************************************/ - - [Option('a', "disable-api", HelpText = "Disables the WebApi (default: false) (env: API_DISABLE)")] - public bool DisableApi { get; set; } = ParamFallback("API_DISABLE", false); - - [Option("api-host", HelpText = "Host on which the WebApi listens (default: localhost) (env: API_HOST)")] - public string ApiHost { get; set; } = ParamFallback("API_HOST", "localhost"); - - [Option("api-port", HelpText = "Port on which the WebApi listens (default: 12995) (env: API_PORT)")] - public string ApiPort { get; set; } = ParamFallback("API_PORT", "12995"); - - /************************************ - * Intergrations * - ************************************/ - - [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"); - - /************************************ - * Helper Functions * - ************************************/ - - private static string ParamFallback(string key, string defaultValue = null) - { - var envVar = GetEnvironmentVariable(key); - return !string.IsNullOrEmpty(envVar) ? envVar : defaultValue; - } - - private static bool ParamFallback(string key, bool defaultValue) - { - var envVar = GetEnvironmentVariable(key); - if (!string.IsNullOrEmpty(envVar)) - { - return envVar.ToLower() switch - { - "true" => true, - "1" => true, - "false" => false, - "0" => false, - _ => defaultValue - }; - } - - return defaultValue; - } - - private static string GetEnvironmentVariable(string name) - { - return Environment.GetEnvironmentVariable($"GEEKBOT_{name}"); - } - } -} \ No newline at end of file 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/IUserRepository.cs b/src/Core/UserRepository/IUserRepository.cs deleted file mode 100644 index 32598f6..0000000 --- a/src/Core/UserRepository/IUserRepository.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Threading.Tasks; -using Discord.WebSocket; -using Geekbot.Core.Database.Models; - -namespace Geekbot.Core.UserRepository -{ - public interface IUserRepository - { - Task Update(SocketUser user); - UserModel Get(ulong userId); - } -} \ No newline at end of file diff --git a/src/Core/UserRepository/UserRepository.cs b/src/Core/UserRepository/UserRepository.cs deleted file mode 100644 index 6b436b1..0000000 --- a/src/Core/UserRepository/UserRepository.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using Discord.WebSocket; -using Geekbot.Core.Database; -using Geekbot.Core.Database.Models; -using Geekbot.Core.Extensions; -using Geekbot.Core.Logger; - -namespace Geekbot.Core.UserRepository -{ - public class UserRepository : IUserRepository - { - private readonly DatabaseContext _database; - private readonly IGeekbotLogger _logger; - public UserRepository(DatabaseContext database, IGeekbotLogger logger) - { - _database = database; - _logger = logger; - } - - public async Task Update(SocketUser user) - { - try - { - var savedUser = Get(user.Id); - var isNew = false; - if (savedUser == null) - { - savedUser = new UserModel(); - isNew = true; - } - savedUser.UserId = user.Id.AsLong(); - savedUser.Username = user.Username; - savedUser.Discriminator = user.Discriminator; - savedUser.AvatarUrl = user.GetAvatarUrl() ?? ""; - savedUser.IsBot = user.IsBot; - savedUser.Joined = user.CreatedAt.ToUniversalTime(); - - if (isNew) - { - await _database.Users.AddAsync(savedUser); - } - else - { - _database.Users.Update(savedUser); - } - - await _database.SaveChangesAsync(); - - _logger.Debug(LogSource.UserRepository, "Updated User", savedUser); - await Task.Delay(500); - return true; - } - catch (Exception e) - { - _logger.Warning(LogSource.UserRepository, $"Failed to update user: {user.Username}#{user.Discriminator} ({user.Id})", e); - return false; - } - } - - public UserModel Get(ulong userId) - { - try - { - return _database.Users.FirstOrDefault(u => u.UserId.Equals(userId.AsLong())); - } - catch (Exception e) - { - _logger.Warning(LogSource.UserRepository, $"Failed to get {userId} from repository", e); - return null; - } - } - } -} \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageApiUrls.cs b/src/Core/WikipediaClient/Page/PageApiUrls.cs deleted file mode 100644 index 59d3258..0000000 --- a/src/Core/WikipediaClient/Page/PageApiUrls.cs +++ /dev/null @@ -1,26 +0,0 @@ -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 deleted file mode 100644 index 39bbc0c..0000000 --- a/src/Core/WikipediaClient/Page/PageContentUrlCollection.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 8da17c4..0000000 --- a/src/Core/WikipediaClient/Page/PageContentUrls.cs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 8537325..0000000 --- a/src/Core/WikipediaClient/Page/PageCoordinates.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; - -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 deleted file mode 100644 index 0d0429a..0000000 --- a/src/Core/WikipediaClient/Page/PageImage.cs +++ /dev/null @@ -1,18 +0,0 @@ -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; } - - } -} \ No newline at end of file diff --git a/src/Core/WikipediaClient/Page/PageNamespace.cs b/src/Core/WikipediaClient/Page/PageNamespace.cs deleted file mode 100644 index 29eaba8..0000000 --- a/src/Core/WikipediaClient/Page/PageNamespace.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json.Serialization; - -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/PageTitles.cs b/src/Core/WikipediaClient/Page/PageTitles.cs deleted file mode 100644 index f550c38..0000000 --- a/src/Core/WikipediaClient/Page/PageTitles.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Text.Json.Serialization; - -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/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