Compare commits
149 commits
datadog-lo
...
master
Author | SHA1 | Date | |
---|---|---|---|
4b62dd99aa | |||
d9e29f8b95 | |||
dc800d144d | |||
a3e10b15c1 | |||
2946ed523e | |||
b0d603e518 | |||
be06870892 | |||
94bdc1081b | |||
29f44c34bc | |||
245e88726a | |||
15e1d10839 | |||
c1b5a4d449 | |||
fdd23ad00f | |||
7cc9fc92d9 | |||
5b40b7b2e7 | |||
eefd8452cd | |||
a3623ccddd | |||
b30c048bac | |||
193a651495 | |||
3fa8fac867 | |||
2fe8e2fa4f | |||
bdaf16f53f | |||
0e5785e3a1 | |||
d03525d363 | |||
17cb5951ee | |||
699a93200b | |||
1b396a529c | |||
0f7f936492 | |||
bcc2742e81 | |||
5d6e5cf2ad | |||
df6672305d | |||
c2c30846fb | |||
e13cf9d830 | |||
09af445436 | |||
4d97201319 | |||
9cfac1ad38 | |||
9beef55979 | |||
4f4e16d674 | |||
ae1b28ff77 | |||
ee31e66e75 | |||
c9af82015b | |||
7d4a81dcde | |||
1a1d1406ec | |||
65d84c0ba6 | |||
a460041c52 | |||
54cbb00880 | |||
d0bc5810a9 | |||
47299dd1de | |||
e01a066920 | |||
6b3a3a9ec2 | |||
4395d9e9dd | |||
6d39c2d33f | |||
31f12a4110 | |||
eb648b94d9 | |||
fe1063167f | |||
866c28b76b | |||
10b29cce8a | |||
34f15402b4 | |||
ea17ce2866 | |||
c15a66255f | |||
e74aeb1403 | |||
5a520ff567 | |||
01df35b12b | |||
44ae2eeaf6 | |||
8c2eabfd21 | |||
cf0cd743b8 | |||
7b06965f14 | |||
6f94de5a14 | |||
616ac5e430 | |||
913ea23732 | |||
e20faa43e1 | |||
772557978b | |||
177c773451 | |||
29a2e5c4a2 | |||
78c139293f | |||
89ea6df6e2 | |||
29e22acbc0 | |||
dd941f5f94 | |||
588c93b87d | |||
a1893c7414 | |||
24749d9009 | |||
9a2bf84a05 | |||
d2b9daac57 | |||
d17ca4c556 | |||
aaea8d0540 | |||
d975594d21 | |||
2de6381f9d | |||
65bb7f6cac | |||
60547140ea | |||
209887e237 | |||
d81fb2a3d9 | |||
85d06b76e0 | |||
447c6d8042 | |||
1b9d8732d5 | |||
954c6c2be3 | |||
3d117aebe1 | |||
0a9099a6d2 | |||
d16828077d | |||
a1f8d033c2 | |||
f02c30e660 | |||
833a8a0dd8 | |||
d708525a2f | |||
aa826f962d | |||
3299ac4eab | |||
1f518e980c | |||
5c507b026c | |||
989057a0b0 | |||
f19ddb30b2 | |||
e712403dd9 | |||
18ece35ffe | |||
f22956368b | |||
9a55d8447f | |||
90668b6aac | |||
8d037c786e | |||
86068ecc44 | |||
8fcc629106 | |||
611b179d62 | |||
5a50ba5820 | |||
8bd8efa66a | |||
153ce3dca4 | |||
5b99ee951b | |||
9ad39058ac | |||
41e0a9f8d7 | |||
49870b6b91 | |||
52fe5bdec1 | |||
f25c9250ec | |||
1c64328587 | |||
d1d57ba714 | |||
c77b501b6c | |||
6c142f41d3 | |||
c1b8394e1b | |||
eddd005d34 | |||
644d877e29 | |||
bbb9b89422 | |||
4fd62e9184 | |||
0434335239 | |||
21303bfca8 | |||
e495e2df17 | |||
d477a4b056 | |||
8bdf2e9681 | |||
17f62d7607 | |||
01f0d2f43b | |||
29bb8035fe | |||
29c0def713 | |||
7e792bd782 | |||
714b0008bc | |||
97d479adc4 | |||
baf09e2f38 | |||
09dbeb9766 |
244 changed files with 5918 additions and 2019 deletions
|
@ -7,13 +7,13 @@
|
|||
ansible_python_interpreter: /usr/bin/python3
|
||||
tasks:
|
||||
- name: Login to Gitlab Docker Registry
|
||||
docker_login:
|
||||
'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
|
||||
docker_container:
|
||||
'community.docker.docker_container':
|
||||
name: GeekbotProd
|
||||
image: "{{ lookup('env', 'IMAGE_TAG') }}"
|
||||
recreate: yes
|
||||
|
@ -34,5 +34,5 @@
|
|||
GEEKBOT_SENTRY: "{{ lookup('env', 'GEEKBOT_SENTRY') }}"
|
||||
GEEKBOT_DB_REDSHIFT_COMPAT: "true"
|
||||
- name: Cleanup Old Container
|
||||
docker_prune:
|
||||
'community.docker.docker_prune':
|
||||
images: yes
|
||||
|
|
|
@ -5,12 +5,12 @@ stages:
|
|||
- ops
|
||||
|
||||
variables:
|
||||
VERSION: 4.3.0-$CI_COMMIT_SHORT_SHA
|
||||
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:5.0
|
||||
image: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
artifacts:
|
||||
expire_in: 1h
|
||||
paths:
|
||||
|
@ -18,7 +18,7 @@ Build:
|
|||
script:
|
||||
- dotnet restore
|
||||
- dotnet test tests
|
||||
- dotnet publish --version-suffix $VERSION -r linux-x64 -c Release -o ./app ./src/Bot/
|
||||
- dotnet publish --version-suffix "$VERSION" -r linux-x64 -c Release -p:DebugType=embedded --no-self-contained -o ./app ./src/Startup/
|
||||
|
||||
Package:
|
||||
stage: docker
|
||||
|
@ -34,7 +34,7 @@ Package:
|
|||
|
||||
Deploy:
|
||||
stage: deploy
|
||||
image: ansible/ansible-runner
|
||||
image: quay.io/ansible/ansible-runner:stable-2.12-latest
|
||||
only:
|
||||
- master
|
||||
variables:
|
||||
|
@ -46,6 +46,7 @@ Deploy:
|
|||
- chmod -R 600 /root/.ssh
|
||||
- ssh-keyscan -p 65432 $PROD_IP > /root/.ssh/known_hosts
|
||||
script:
|
||||
- ansible-galaxy collection install -r ansible-requirements.yml
|
||||
- ansible-playbook -i $PROD_IP, .deploy.yml
|
||||
|
||||
Sentry:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:5.0
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0
|
||||
|
||||
COPY ./app /app/
|
||||
|
||||
|
|
|
@ -11,6 +11,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj",
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot", "src\Bot\Bot.csproj", "{DBF79896-9F7F-443D-B336-155E276DFF16}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands", "src\Commands\Commands.csproj", "{7C771DFE-912A-4276-B0A6-047E09603F1E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interactions", "src\Interactions\Interactions.csproj", "{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startup", "src\Startup\Startup.csproj", "{A691B018-4B19-4A7A-A0F6-DBB17641254F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -33,6 +39,18 @@ Global
|
|||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
3
ansible-requirements.yml
Normal file
3
ansible-requirements.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
collections:
|
||||
- name: community.docker
|
||||
version: 2.7.0
|
|
@ -1,34 +1,25 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<ApplicationIcon>derp.ico</ApplicationIcon>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<RootNamespace>Geekbot.Bot</RootNamespace>
|
||||
<AssemblyName>Geekbot</AssemblyName>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<AssemblyName>Geekbot.Bot</AssemblyName>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.0-DEV</Version>
|
||||
<Company>Pizza and Coffee Studios</Company>
|
||||
<Authors>Pizza and Coffee Studios</Authors>
|
||||
<Description>A Discord bot</Description>
|
||||
<RepositoryUrl>https://github.com/pizzaandcoffee/Geekbot.net</RepositoryUrl>
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageProjectUrl>https://geekbot.pizzaandcoffee.rocks</PackageProjectUrl>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<Optimize>true</Optimize>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.45.0.1929" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.24" />
|
||||
<PackageReference Include="JikanDotNet" Version="1.5.1" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.36" />
|
||||
<PackageReference Include="JikanDotNet" Version="1.6.0" />
|
||||
<PackageReference Include="MtgApiManager.Lib" Version="1.2.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="PokeApi.NET" Version="1.1.2" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
<PackageReference Include="Sentry" Version="3.11.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Storage\*">
|
||||
|
@ -36,113 +27,7 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Commands\Commands.csproj" />
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\Web\Web.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localization\Ship.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Ship.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Rank.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Rank.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Karma.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Karma.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Internal.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Internal.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Cookies.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Cookies.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Roll.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Roll.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Choose.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Choose.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Admin.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Admin.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Quote.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Quote.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Role.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Role.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Stats.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Stats.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Localization\Ship.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>ship.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Rank.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Rank.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Ship.Designer.cs">
|
||||
<DependentUpon>Ship.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Karma.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Karma.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Internal.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Internal.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Cookies.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Cookies.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Roll.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Roll.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Choose.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Choose.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Admin.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Admin.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Quote.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Quote.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Role.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Role.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="Localization\Stats.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Stats.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
127
src/Bot/BotStartup.cs
Normal file
127
src/Bot/BotStartup.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
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<string> 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<DiscordSocketClient>(_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<IGuildSettingsManager>());
|
||||
var userHandler = new UserHandler(serviceProvider.GetService<IUserRepository>(), _logger, serviceProvider.GetService<DatabaseContext>(), _client);
|
||||
var reactionHandler = new ReactionHandler(serviceProvider.GetService<IReactionListener>());
|
||||
var statsHandler = new StatsHandler(_logger, serviceProvider.GetService<DatabaseContext>());
|
||||
var messageDeletedHandler = new MessageDeletedHandler(serviceProvider.GetService<DatabaseContext>(), _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;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System;
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace Geekbot.Core.CommandPreconditions
|
||||
namespace Geekbot.Bot.CommandPreconditions
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class DisableInDirectMessageAttribute : PreconditionAttribute
|
|
@ -9,11 +9,12 @@ using System.Threading.Tasks;
|
|||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Localization = Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
[Group("mod")]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[DisableInDirectMessage]
|
||||
public class Mod : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Mod(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("namehistory", RunMode = RunMode.Async)]
|
||||
[Summary("See past usernames of an user")]
|
||||
public async Task UsernameHistory([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Context.Channel.SendMessageAsync("This command has been removed due to low usage and excessively high database usage");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,14 +6,15 @@ using System.Threading.Tasks;
|
|||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Net;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.ReactionListener;
|
||||
using Localization = Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Admin
|
||||
{
|
||||
|
|
|
@ -3,13 +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 PokeAPI;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games
|
||||
{
|
||||
public class Pokedex : ModuleBase
|
||||
public class Pokedex : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Bot.Utils;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.KvInMemoryStore;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
using Sentry;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games.Roll
|
||||
{
|
||||
|
@ -34,63 +31,20 @@ namespace Geekbot.Bot.Commands.Games.Roll
|
|||
{
|
||||
try
|
||||
{
|
||||
var number = _randomNumberGenerator.Next(1, 100);
|
||||
int.TryParse(stuff, out var guess);
|
||||
if (guess <= 100 && guess > 0)
|
||||
{
|
||||
var kvKey = $"{Context?.Guild?.Id ?? 0}:{Context.User.Id}:RollsPrevious";
|
||||
|
||||
var prevRoll = _kvInMemoryStore.Get<RollTimeout>(kvKey);
|
||||
|
||||
if (prevRoll?.LastGuess == guess && prevRoll?.GuessedOn.AddDays(1) > DateTime.Now)
|
||||
{
|
||||
await ReplyAsync(string.Format(
|
||||
Localization.Roll.NoPrevGuess,
|
||||
Context.Message.Author.Mention,
|
||||
DateLocalization.FormatDateTimeAsRemaining(prevRoll.GuessedOn.AddDays(1))));
|
||||
return;
|
||||
}
|
||||
|
||||
_kvInMemoryStore.Set(kvKey, new RollTimeout {LastGuess = guess, GuessedOn = DateTime.Now});
|
||||
|
||||
await ReplyAsync(string.Format(Localization.Roll.Rolled, Context.Message.Author.Mention, number, guess));
|
||||
if (guess == number)
|
||||
{
|
||||
await ReplyAsync(string.Format(Localization.Roll.Gratz, Context.Message.Author));
|
||||
var user = await GetUser(Context.User.Id);
|
||||
user.Rolls += 1;
|
||||
_database.Rolls.Update(user);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(string.Format(Localization.Roll.RolledNoGuess, Context.Message.Author.Mention, number));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<RollsModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Rolls.FirstOrDefault(u => u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId);
|
||||
return user;
|
||||
}
|
||||
|
||||
private async Task<RollsModel> CreateNewRow(ulong userId)
|
||||
{
|
||||
var user = new RollsModel()
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Rolls = 0
|
||||
};
|
||||
var newUser = _database.Rolls.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
||||
{
|
||||
public class LolMmr : ModuleBase
|
||||
public class LolMmr : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
@ -46,9 +46,9 @@ namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
|||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"**MMR for {summonerName}**");
|
||||
sb.AppendLine($"Normal: {data.Normal.Avg}");
|
||||
sb.AppendLine($"Ranked: {data.Ranked.Avg}");
|
||||
sb.AppendLine($"ARAM: {data.ARAM.Avg}");
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
using Newtonsoft.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.LolMmr
|
||||
{
|
||||
public class LolMrrInfoDto
|
||||
{
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
public decimal Avg { get; set; } = 0;
|
||||
[JsonPropertyName("avg")]
|
||||
public decimal? Avg { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ 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;
|
||||
|
@ -11,7 +12,7 @@ using MtgApiManager.Lib.Service;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class MagicTheGathering : ModuleBase
|
||||
public class MagicTheGathering : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IMtgManaConverter _manaConverter;
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanListItemDto
|
||||
{
|
||||
public string Definition { get; set; }
|
||||
public string Permalink { get; set; }
|
||||
public string ThumbsUp { get; set; }
|
||||
public string Word { get; set; }
|
||||
public string Example { get; set; }
|
||||
public string ThumbsDown { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanResponseDto
|
||||
{
|
||||
public string[] Tags { get; set; }
|
||||
public List<UrbanListItemDto> List { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
public class UrbanDictionary : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public UrbanDictionary(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("urban", RunMode = RunMode.Async)]
|
||||
[Summary("Lookup something on urban dictionary")]
|
||||
public async Task UrbanDefine([Remainder] [Summary("word")] string word)
|
||||
{
|
||||
try
|
||||
{
|
||||
var definitions = await HttpAbstractions.Get<UrbanResponseDto>(new Uri($"https://api.urbandictionary.com/v0/define?term={word}"));
|
||||
if (definitions.List.Count == 0)
|
||||
{
|
||||
await ReplyAsync("That word hasn't been defined...");
|
||||
return;
|
||||
}
|
||||
|
||||
var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder
|
||||
{
|
||||
Name = definition.Word,
|
||||
Url = definition.Permalink
|
||||
});
|
||||
eb.WithColor(new Color(239, 255, 0));
|
||||
|
||||
static string ShortenIfToLong(string str, int maxLength) => str.Length > maxLength ? $"{str.Substring(0, maxLength - 5)}[...]" : str;
|
||||
|
||||
if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = ShortenIfToLong(definition.Definition, 1800);
|
||||
if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", ShortenIfToLong(definition.Example, 1024));
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp);
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown);
|
||||
if (definitions.Tags?.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags));
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
39
src/Bot/Commands/Integrations/UrbanDictionary.cs
Normal file
39
src/Bot/Commands/Integrations/UrbanDictionary.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ 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;
|
||||
|
@ -14,7 +15,7 @@ using HtmlAgilityPack;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Integrations
|
||||
{
|
||||
public class Wikipedia : ModuleBase
|
||||
public class Wikipedia : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IWikipediaClient _wikipediaClient;
|
||||
|
|
|
@ -1,58 +1,59 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
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 : ModuleBase
|
||||
public class Youtube : TransactionModuleBase
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
// private readonly IGlobalSettings _globalSettings;
|
||||
// private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
// public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
|
||||
// {
|
||||
// _globalSettings = globalSettings;
|
||||
// _errorHandler = errorHandler;
|
||||
// }
|
||||
|
||||
[Command("yt", RunMode = RunMode.Async)]
|
||||
[Summary("Search for something on youtube.")]
|
||||
public async Task Yt([Remainder] [Summary("title")] string searchQuery)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,12 +2,13 @@ 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 : ModuleBase
|
||||
public class BenedictCumberbatchNameGenerator : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
|
|
@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
||||
{
|
||||
public class Cat : ModuleBase
|
||||
public class Cat : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Cat
|
||||
{
|
||||
internal class CatResponseDto
|
||||
{
|
||||
[JsonPropertyName("file")]
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
||||
{
|
||||
internal class ChuckNorrisJokeResponseDto
|
||||
{
|
||||
[JsonPropertyName("value")]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Chuck
|
||||
{
|
||||
public class ChuckNorrisJokes : ModuleBase
|
||||
public class ChuckNorrisJokes : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Dad
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dad
|
||||
{
|
||||
internal class DadJokeResponseDto
|
||||
{
|
||||
[JsonPropertyName("joke")]
|
||||
public string Joke { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dad
|
||||
{
|
||||
public class DadJokes : ModuleBase
|
||||
public class DadJokes : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dog
|
||||
{
|
||||
public class Dog : ModuleBase
|
||||
public class Dog : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Dog
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Dog
|
||||
{
|
||||
internal class DogResponseDto
|
||||
{
|
||||
[JsonPropertyName("url")]
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
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 : ModuleBase
|
||||
public class EightBall : GeekbotCommandBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public EightBall(IErrorHandler errorHandler)
|
||||
public EightBall(IErrorHandler errorHandler, IGuildSettingsManager guildSettingsManager) : base(errorHandler, guildSettingsManager)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("8ball", RunMode = RunMode.Async)]
|
||||
|
@ -21,36 +22,19 @@ namespace Geekbot.Bot.Commands.Randomness
|
|||
{
|
||||
try
|
||||
{
|
||||
var replies = new List<string>
|
||||
var enumerator = Localization.EightBall.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true).GetEnumerator();
|
||||
var replies = new List<string>();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
"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"
|
||||
};
|
||||
|
||||
replies.Add(enumerator.Value?.ToString());
|
||||
}
|
||||
|
||||
var answer = new Random().Next(replies.Count);
|
||||
await ReplyAsync(replies[answer]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
await ErrorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Media;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Fortune : ModuleBase
|
||||
public class Fortune : TransactionModuleBase
|
||||
{
|
||||
private readonly IFortunesProvider _fortunes;
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Gdq : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Gdq(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("gdq", RunMode = RunMode.Async)]
|
||||
[Summary("Get a quote from the GDQ donation generator.")]
|
||||
public async Task GetQuote()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new WebClient();
|
||||
var url = new Uri("http://taskinoz.com/gdq/api/");
|
||||
var response = client.DownloadString(url);
|
||||
|
||||
await ReplyAsync(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class GreetingBaseDto
|
||||
{
|
||||
public string Language { get; set; }
|
||||
public string LanguageNative { get; set; }
|
||||
public string LanguageCode { get; set; }
|
||||
public string Script { get; set; }
|
||||
public GreetingDto Primary { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class GreetingDto
|
||||
{
|
||||
public string Text { get; set; }
|
||||
public string Dialect { get; set; }
|
||||
public string Romanization { get; set; }
|
||||
public string[] Use { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Greetings
|
||||
{
|
||||
public class Greetings : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Greetings(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("hello", RunMode = RunMode.Async)]
|
||||
[Alias("greeting", "hi", "hallo")]
|
||||
[Summary("Say hello to the bot and get a reply in a random language")]
|
||||
public async Task GetGreeting()
|
||||
{
|
||||
try
|
||||
{
|
||||
var greeting = await HttpAbstractions.Get<GreetingBaseDto>(new Uri("https://api.greetings.dev/v1/greeting"));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.Title = greeting.Primary.Text;
|
||||
eb.AddInlineField("Language", greeting.Language);
|
||||
|
||||
if (greeting.Primary.Dialect != null)
|
||||
{
|
||||
eb.AddInlineField("Dialect", greeting.Primary.Dialect);
|
||||
}
|
||||
|
||||
if (greeting.Primary.Romanization != null)
|
||||
{
|
||||
eb.AddInlineField("Roman", greeting.Primary.Romanization);
|
||||
}
|
||||
|
||||
await ReplyAsync(string.Empty, false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Kanye
|
||||
{
|
||||
public class Kanye : ModuleBase
|
||||
public class Kanye : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness.Kanye
|
||||
{
|
||||
public class KanyeResponseDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
[JsonPropertyName("quote")]
|
||||
public string Quote { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Media;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class RandomAnimals : ModuleBase
|
||||
public class RandomAnimals : TransactionModuleBase
|
||||
{
|
||||
private readonly IMediaProvider _mediaProvider;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ 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
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ 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;
|
||||
|
@ -11,7 +12,7 @@ using Geekbot.Core.Extensions;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Randomness
|
||||
{
|
||||
public class Slap : ModuleBase
|
||||
public class Slap : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
|
@ -76,10 +77,14 @@ namespace Geekbot.Bot.Commands.Randomness
|
|||
"teapot",
|
||||
"candle",
|
||||
"dictionary",
|
||||
"powerless banhammer"
|
||||
"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(things.Count - 1)]}");
|
||||
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);
|
||||
|
@ -127,4 +132,4 @@ namespace Geekbot.Bot.Commands.Randomness
|
|||
e.UserId.Equals(userId.AsLong()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Bot.Utils;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
using Localization = Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Rpg
|
||||
{
|
||||
|
@ -37,14 +37,16 @@ namespace Geekbot.Bot.Commands.Rpg
|
|||
try
|
||||
{
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (actor.LastPayout.Value.AddDays(1).Date > DateTime.Now.Date)
|
||||
var timeoutDays = 1;
|
||||
if (actor.LastPayout?.AddDays(timeoutDays) > DateTime.Now.ToUniversalTime())
|
||||
{
|
||||
var formattedWaitTime = DateLocalization.FormatDateTimeAsRemaining(DateTimeOffset.Now.AddDays(1).Date);
|
||||
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;
|
||||
actor.LastPayout = DateTimeOffset.Now.ToUniversalTime();
|
||||
await SetUser(actor);
|
||||
await ReplyAsync(string.Format(Localization.Cookies.GetCookies, 10, actor.Cookies));
|
||||
|
||||
|
@ -78,6 +80,12 @@ namespace Geekbot.Bot.Commands.Rpg
|
|||
{
|
||||
var giver = await GetUser(Context.User.Id);
|
||||
|
||||
if (amount < 1)
|
||||
{
|
||||
await ReplyAsync(Localization.Cookies.CantTakeCookies);
|
||||
return;
|
||||
}
|
||||
|
||||
if (giver.Cookies < amount)
|
||||
{
|
||||
await ReplyAsync(Localization.Cookies.NotEnoughToGive);
|
||||
|
@ -146,7 +154,7 @@ namespace Geekbot.Bot.Commands.Rpg
|
|||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Cookies = 0,
|
||||
LastPayout = DateTimeOffset.MinValue
|
||||
LastPayout = DateTimeOffset.MinValue.ToUniversalTime()
|
||||
};
|
||||
var newUser = _database.Cookies.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
|
|
|
@ -3,7 +3,8 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
@ -11,7 +12,7 @@ using Geekbot.Core.Levels;
|
|||
|
||||
namespace Geekbot.Bot.Commands.User
|
||||
{
|
||||
public class GuildInfo : ModuleBase
|
||||
public class GuildInfo : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Bot.Utils;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Commands.Karma;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
|
@ -28,122 +26,51 @@ namespace Geekbot.Bot.Commands.User
|
|||
[Summary("Increase Someones Karma")]
|
||||
public async Task Good([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync(string.Format(Localization.Karma.CannotChangeOwnUp, Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
{
|
||||
var formatedWaitTime = DateLocalization.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(string.Format(Localization.Karma.WaitUntill, Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma += 1;
|
||||
SetUser(target);
|
||||
|
||||
actor.TimeOut = DateTimeOffset.Now;
|
||||
SetUser(actor);
|
||||
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(user.GetAvatarUrl())
|
||||
.WithName(user.Username));
|
||||
|
||||
eb.WithColor(new Color(138, 219, 146));
|
||||
eb.Title = Localization.Karma.Increased;
|
||||
eb.AddInlineField(Localization.Karma.By, Context.User.Username);
|
||||
eb.AddInlineField(Localization.Karma.Amount, "+1");
|
||||
eb.AddInlineField(Localization.Karma.Current, target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
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 actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
var author = new Interactions.Resolved.User()
|
||||
{
|
||||
await ReplyAsync(string.Format(Localization.Karma.CannotChangeOwnDown, Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
Id = Context.User.Id.ToString(),
|
||||
Username = Context.User.Username,
|
||||
Discriminator = Context.User.Discriminator,
|
||||
Avatar = Context.User.AvatarId,
|
||||
};
|
||||
var targetUser = new Interactions.Resolved.User()
|
||||
{
|
||||
var formatedWaitTime = DateLocalization.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(string.Format(Localization.Karma.WaitUntill, Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma -= 1;
|
||||
SetUser(target);
|
||||
|
||||
actor.TimeOut = DateTimeOffset.Now;
|
||||
SetUser(actor);
|
||||
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 _database.SaveChangesAsync();
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(user.GetAvatarUrl())
|
||||
.WithName(user.Username));
|
||||
|
||||
eb.WithColor(new Color(138, 219, 146));
|
||||
eb.Title = Localization.Karma.Decreased;
|
||||
eb.AddInlineField(Localization.Karma.By, Context.User.Username);
|
||||
eb.AddInlineField(Localization.Karma.Amount, "-1");
|
||||
eb.AddInlineField(Localization.Karma.Current, target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
await ReplyAsync(string.Empty, false, res.ToDiscordNetEmbed().Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TimeoutFinished(DateTimeOffset lastKarma)
|
||||
{
|
||||
return lastKarma.AddMinutes(3) > DateTimeOffset.Now;
|
||||
}
|
||||
|
||||
private async Task<KarmaModel> GetUser(ulong userId)
|
||||
{
|
||||
var user = _database.Karma.FirstOrDefault(u =>u.GuildId.Equals(Context.Guild.Id.AsLong()) && u.UserId.Equals(userId.AsLong())) ?? await CreateNewRow(userId);
|
||||
return user;
|
||||
}
|
||||
|
||||
private void SetUser(KarmaModel user)
|
||||
{
|
||||
_database.Karma.Update(user);
|
||||
}
|
||||
|
||||
private async Task<KarmaModel> CreateNewRow(ulong userId)
|
||||
{
|
||||
var user = new KarmaModel()
|
||||
{
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = userId.AsLong(),
|
||||
Karma = 0,
|
||||
TimeOut = DateTimeOffset.MinValue
|
||||
};
|
||||
var newUser = _database.Karma.Add(user).Entity;
|
||||
await _database.SaveChangesAsync();
|
||||
return newUser;
|
||||
}
|
||||
}
|
||||
}
|
43
src/Bot/Commands/User/Rank.cs
Normal file
43
src/Bot/Commands/User/Rank.cs
Normal file
|
@ -0,0 +1,43 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.Highscores;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User.Ranking
|
||||
{
|
||||
public class Rank : GeekbotCommandBase
|
||||
{
|
||||
private readonly IEmojiConverter _emojiConverter;
|
||||
private readonly IHighscoreManager _highscoreManager;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public Rank(DatabaseContext database, IErrorHandler errorHandler, IEmojiConverter emojiConverter, IHighscoreManager highscoreManager, IGuildSettingsManager guildSettingsManager)
|
||||
: base(errorHandler, guildSettingsManager)
|
||||
{
|
||||
_database = database;
|
||||
_emojiConverter = emojiConverter;
|
||||
_highscoreManager = highscoreManager;
|
||||
}
|
||||
|
||||
[Command("rank", RunMode = RunMode.Async)]
|
||||
[Summary("get user top 10 in messages or karma")]
|
||||
[DisableInDirectMessage]
|
||||
public async Task RankCmd([Summary("type")] string typeUnformated = "messages", [Summary("amount")] int amount = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
HighscoreTypes type;
|
||||
try
|
||||
{
|
||||
type = Enum.Parse<HighscoreTypes>(typeUnformated, true);
|
||||
if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync(Localization.Rank.InvalidType);
|
||||
return;
|
||||
}
|
||||
|
||||
var replyBuilder = new StringBuilder();
|
||||
if (amount > 20)
|
||||
{
|
||||
await ReplyAsync(Localization.Rank.LimitingTo20Warning);
|
||||
amount = 20;
|
||||
}
|
||||
|
||||
var guildId = Context.Guild.Id;
|
||||
Dictionary<HighscoreUserDto, int> highscoreUsers;
|
||||
try
|
||||
{
|
||||
highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount);
|
||||
}
|
||||
catch (HighscoreListEmptyException)
|
||||
{
|
||||
await ReplyAsync(string.Format(Localization.Rank.NoTypeFoundForServer, type));
|
||||
return;
|
||||
}
|
||||
|
||||
var guildMessages = 0;
|
||||
if (type == HighscoreTypes.messages)
|
||||
{
|
||||
guildMessages = _database.Messages
|
||||
.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong()))
|
||||
.Select(e => e.MessageCount)
|
||||
.Sum();
|
||||
}
|
||||
|
||||
var failedToRetrieveUser = highscoreUsers.Any(e => string.IsNullOrEmpty(e.Key.Username));
|
||||
|
||||
if (failedToRetrieveUser) replyBuilder.AppendLine(Localization.Rank.FailedToResolveAllUsernames).AppendLine();
|
||||
|
||||
replyBuilder.AppendLine(string.Format(Localization.Rank.HighscoresFor, type.ToString().CapitalizeFirst(), Context.Guild.Name));
|
||||
|
||||
var highscorePlace = 1;
|
||||
foreach (var (user, value) in highscoreUsers)
|
||||
{
|
||||
replyBuilder.Append(highscorePlace < 11
|
||||
? $"{_emojiConverter.NumberToEmoji(highscorePlace)} "
|
||||
: $"`{highscorePlace}.` ");
|
||||
|
||||
replyBuilder.Append(user.Username != null
|
||||
? $"**{user.Username}#{user.Discriminator}**"
|
||||
: $"**{user.Id}**");
|
||||
|
||||
replyBuilder.Append(type == HighscoreTypes.messages
|
||||
? $" - {value} {type} - {Math.Round((double) (100 * value) / guildMessages, 2)}%\n"
|
||||
: $" - {value} {type}\n");
|
||||
|
||||
highscorePlace++;
|
||||
}
|
||||
|
||||
await ReplyAsync(replyBuilder.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,13 +3,14 @@ using System.Linq;
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.Levels;
|
||||
using Localization = Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.User
|
||||
{
|
||||
|
@ -54,6 +55,8 @@ namespace Geekbot.Bot.Commands.User
|
|||
?.FirstOrDefault(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong()))
|
||||
?.Cookies ?? 0;
|
||||
|
||||
var quotes = _database.Quotes.Count(e => e.GuildId.Equals(Context.Guild.Id.AsLong()) && e.UserId.Equals(userInfo.Id.AsLong()));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder()
|
||||
.WithIconUrl(userInfo.GetAvatarUrl())
|
||||
|
@ -68,9 +71,9 @@ namespace Geekbot.Bot.Commands.User
|
|||
e.UserId.Equals(userInfo.Id.AsLong()));
|
||||
|
||||
eb.AddInlineField(Localization.Stats.OnDiscordSince,
|
||||
$"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} days)")
|
||||
$"{createdAt.Day}.{createdAt.Month}.{createdAt.Year} ({age} {Localization.Stats.Days})")
|
||||
.AddInlineField(Localization.Stats.JoinedServer,
|
||||
$"{joinedAt.Day}.{joinedAt.Month}.{joinedAt.Year} ({joinedDayAgo} days)")
|
||||
$"{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)
|
||||
|
@ -78,6 +81,7 @@ namespace Geekbot.Bot.Commands.User
|
|||
|
||||
if (correctRolls != null) eb.AddInlineField(Localization.Stats.GuessedRolls, correctRolls.Rolls);
|
||||
if (cookies > 0) eb.AddInlineField(Localization.Stats.Cookies, cookies);
|
||||
if (quotes > 0) eb.AddInlineField(Localization.Stats.Quotes, quotes);
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class AvatarGetter : ModuleBase
|
||||
public class AvatarGetter : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
@ -21,8 +22,8 @@ namespace Geekbot.Bot.Commands.Utils
|
|||
{
|
||||
try
|
||||
{
|
||||
if (user == null) user = Context.User;
|
||||
var url = user.GetAvatarUrl().Replace("128", "1024");
|
||||
user ??= Context.User;
|
||||
var url = user.GetAvatarUrl(ImageFormat.Auto, 1024);
|
||||
await ReplyAsync(url);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -11,7 +11,7 @@ using Geekbot.Core.ErrorHandling;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class Changelog : ModuleBase
|
||||
public class Changelog : TransactionModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitDto
|
||||
{
|
||||
[JsonPropertyName("commit")]
|
||||
public CommitInfoDto Commit { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +1,13 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Changelog
|
||||
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; }
|
||||
}
|
||||
}
|
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Localization = Geekbot.Core.Localization;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
|
@ -14,7 +13,7 @@ namespace Geekbot.Bot.Commands.Utils
|
|||
}
|
||||
|
||||
[Command("choose", RunMode = RunMode.Async)]
|
||||
[Summary("Let the bot choose for you, seperate options with a semicolon.")]
|
||||
[Summary("Let the bot choose for you, separate options with a semicolon.")]
|
||||
public async Task Command([Remainder] [Summary("option1;option2")]
|
||||
string choices)
|
||||
{
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.Extensions;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils.Corona
|
||||
{
|
||||
public class CoronaStats : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public CoronaStats(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("corona", RunMode = RunMode.Async)]
|
||||
[Summary("Get the latest worldwide corona statistics")]
|
||||
public async Task Summary()
|
||||
{
|
||||
try
|
||||
{
|
||||
var summary = await HttpAbstractions.Get<CoronaSummaryDto>(new Uri("https://api.covid19api.com/world/total"));
|
||||
var activeCases = summary.TotalConfirmed - (summary.TotalRecovered + summary.TotalDeaths);
|
||||
|
||||
string CalculatePercentage(decimal i) => (i / summary.TotalConfirmed).ToString("#0.##%");
|
||||
var activePercent = CalculatePercentage(activeCases);
|
||||
var recoveredPercentage = CalculatePercentage(summary.TotalRecovered);
|
||||
var deathsPercentage = CalculatePercentage(summary.TotalDeaths);
|
||||
|
||||
var numberFormat = "#,#";
|
||||
var totalFormatted = summary.TotalConfirmed.ToString(numberFormat);
|
||||
var activeFormatted = activeCases.ToString(numberFormat);
|
||||
var recoveredFormatted = summary.TotalRecovered.ToString(numberFormat);
|
||||
var deathsFormatted = summary.TotalDeaths.ToString(numberFormat);
|
||||
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
Author = new EmbedAuthorBuilder
|
||||
{
|
||||
Name = "Confirmed Corona Cases",
|
||||
IconUrl = "https://www.redcross.org/content/dam/icons/disasters/virus/Virus-1000x1000-R-Pl.png"
|
||||
},
|
||||
Footer = new EmbedFooterBuilder
|
||||
{
|
||||
Text = "Source: covid19api.com",
|
||||
},
|
||||
Color = Color.Red
|
||||
};
|
||||
eb.AddField("Total", totalFormatted);
|
||||
eb.AddInlineField("Active", $"{activeFormatted} ({activePercent})");
|
||||
eb.AddInlineField("Recovered", $"{recoveredFormatted} ({recoveredPercentage})");
|
||||
eb.AddInlineField("Deaths", $"{deathsFormatted} ({deathsPercentage})");
|
||||
|
||||
await Context.Channel.SendMessageAsync(String.Empty, false, eb.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Geekbot.Bot.Commands.Utils.Corona
|
||||
{
|
||||
public class CoronaSummaryDto
|
||||
{
|
||||
public decimal TotalConfirmed { get; set; }
|
||||
public decimal TotalDeaths { get; set; }
|
||||
public decimal TotalRecovered { get; set; }
|
||||
}
|
||||
}
|
|
@ -3,12 +3,13 @@ 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 : ModuleBase
|
||||
public class Dice : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IDiceParser _diceParser;
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Emojify : ModuleBase
|
||||
public class Emojify : TransactionModuleBase
|
||||
{
|
||||
private readonly IEmojiConverter _emojiConverter;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Emojify(IErrorHandler errorHandler, IEmojiConverter emojiConverter)
|
||||
public Emojify(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_emojiConverter = emojiConverter;
|
||||
}
|
||||
|
||||
[Command("emojify", RunMode = RunMode.Async)]
|
||||
|
@ -23,7 +20,7 @@ namespace Geekbot.Bot.Commands.Utils
|
|||
{
|
||||
try
|
||||
{
|
||||
var emojis = _emojiConverter.TextToEmoji(text);
|
||||
var emojis = EmojiConverter.TextToEmoji(text);
|
||||
if (emojis.Length > 1999)
|
||||
{
|
||||
await ReplyAsync("I can't take that much at once!");
|
||||
|
|
|
@ -3,11 +3,12 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Help : ModuleBase
|
||||
public class Help : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
@ -26,7 +27,7 @@ namespace Geekbot.Bot.Commands.Utils
|
|||
|
||||
sb.AppendLine("For a list of all commands, please visit the following page");
|
||||
sb.AppendLine("https://geekbot.pizzaandcoffee.rocks/commands");
|
||||
var dm = await Context.User.GetOrCreateDMChannelAsync();
|
||||
var dm = await Context.User.CreateDMChannelAsync(RequestOptions.Default);
|
||||
await dm.SendMessageAsync(sb.ToString());
|
||||
await Context.Message.AddReactionAsync(new Emoji("✅"));
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ using Geekbot.Core.Extensions;
|
|||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Info : ModuleBase
|
||||
public class Info : TransactionModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly CommandService _commands;
|
||||
|
|
|
@ -2,11 +2,12 @@ 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 : ModuleBase
|
||||
public class Lmgtfy : TransactionModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Utils
|
||||
{
|
||||
public class Ping : ModuleBase
|
||||
public class Ping : TransactionModuleBase
|
||||
{
|
||||
[Command("👀", RunMode = RunMode.Async)]
|
||||
[Summary("Look at the bot.")]
|
||||
|
|
|
@ -4,8 +4,8 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Bot.CommandPreconditions;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.CommandPreconditions;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.Database.Models;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
|
@ -13,6 +13,11 @@ 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
|
||||
{
|
||||
|
@ -22,13 +27,15 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly bool _isDev;
|
||||
|
||||
public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, IGuildSettingsManager guildSettingsManager)
|
||||
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";
|
||||
}
|
||||
|
@ -39,23 +46,26 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
{
|
||||
try
|
||||
{
|
||||
var totalQuotes = await _database.Quotes.CountAsync(e => e.GuildId.Equals(Context.Guild.Id.AsLong()));
|
||||
|
||||
if (totalQuotes == 0)
|
||||
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 random = _randomNumberGenerator.Next(0, totalQuotes - 1);
|
||||
var quote = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).Skip(random).Take(1);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,22 +84,6 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
{
|
||||
await QuoteFromMention(user, false);
|
||||
}
|
||||
|
||||
[Command("add")]
|
||||
[Alias("save")]
|
||||
[Summary("Add a quote from a message id")]
|
||||
public async Task AddQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
await QuoteFromMessageId(messageId, true);
|
||||
}
|
||||
|
||||
[Command("make")]
|
||||
[Alias("preview")]
|
||||
[Summary("Preview a quote from a message id")]
|
||||
public async Task ReturnSpecifiedQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
await QuoteFromMessageId(messageId, false);
|
||||
}
|
||||
|
||||
[Command("add")]
|
||||
[Alias("save")]
|
||||
|
@ -160,8 +154,8 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
.Where(row => row.GuildId == Context.Guild.Id.AsLong())
|
||||
.GroupBy(row => row.UserId)
|
||||
.Select(row => new { userId = row.Key, amount = row.Count()})
|
||||
.OrderBy(row => row.amount)
|
||||
.Last();
|
||||
.OrderByDescending(row => row.amount)
|
||||
.First();
|
||||
var mostQuotedPersonUser = Context.Client.GetUserAsync(mostQuotedPerson.userId.AsUlong()).Result ?? new UserPolyfillDto {Username = "Unknown User"};
|
||||
|
||||
var quotesByYear = _database.Quotes
|
||||
|
@ -208,21 +202,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
|
||||
}
|
||||
|
||||
private async Task QuoteFromMessageId(ulong messageId, bool saveToDb)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||
|
||||
await ProcessQuote(message, saveToDb, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ErrorHandler.HandleCommandException(e, Context, "I couldn't find a message with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task QuoteFromMessageLink(string messageLink, bool saveToDb)
|
||||
private async Task QuoteFromMessageLink(string messageLink, bool saveToDb)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -253,7 +233,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
}
|
||||
}
|
||||
|
||||
private async Task ProcessQuote(IMessage message, bool saveToDb, bool showMessageIdWarning = false)
|
||||
private async Task ProcessQuote(IMessage message, bool saveToDb)
|
||||
{
|
||||
if (message.Author.Id == Context.Message.Author.Id && saveToDb && !_isDev)
|
||||
{
|
||||
|
@ -278,27 +258,38 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
|
||||
var sb = new StringBuilder();
|
||||
if (saveToDb) sb.AppendLine(Localization.Quote.QuoteAdded);
|
||||
if (showMessageIdWarning) sb.AppendLine(Localization.Quote.MessageIdDeprecation);
|
||||
|
||||
await ReplyAsync(sb.ToString(), false, embed.Build());
|
||||
}
|
||||
|
||||
private EmbedBuilder QuoteBuilder(QuoteModel quote)
|
||||
{
|
||||
var user = Context.Client.GetUserAsync(quote.UserId.AsUlong()).Result ?? new UserPolyfillDto { Username = "Unknown User" };
|
||||
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));
|
||||
if (quote.InternalId == 0)
|
||||
{
|
||||
eb.Title = $"{user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}";
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.Title = $"#{quote.InternalId} | {user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}";
|
||||
}
|
||||
eb.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;
|
||||
}
|
||||
|
||||
|
@ -322,7 +313,7 @@ namespace Geekbot.Bot.Commands.Utils.Quote
|
|||
InternalId = internalId,
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
Time = message.Timestamp.DateTime,
|
||||
Time = message.Timestamp.DateTime.ToUniversalTime(),
|
||||
Quote = message.Content,
|
||||
Image = image
|
||||
};
|
||||
|
|
|
@ -21,12 +21,10 @@ namespace Geekbot.Bot.Handlers
|
|||
private readonly RestApplication _applicationInfo;
|
||||
private readonly IGuildSettingsManager _guildSettingsManager;
|
||||
private readonly List<ulong> _ignoredServers;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public CommandHandler(DatabaseContext database, IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo,
|
||||
public CommandHandler(IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo,
|
||||
IGuildSettingsManager guildSettingsManager)
|
||||
{
|
||||
_database = database;
|
||||
_client = client;
|
||||
_logger = logger;
|
||||
_servicesProvider = servicesProvider;
|
||||
|
@ -39,7 +37,7 @@ namespace Geekbot.Bot.Handlers
|
|||
_ignoredServers = new List<ulong>
|
||||
{
|
||||
228623803201224704, // SwitzerLAN
|
||||
169844523181015040, // EEvent
|
||||
// 169844523181015040, // EEvent
|
||||
248531441548263425, // MYI
|
||||
110373943822540800 // Discord Bots
|
||||
};
|
||||
|
|
|
@ -23,11 +23,11 @@ namespace Geekbot.Bot.Handlers
|
|||
_client = client;
|
||||
}
|
||||
|
||||
public async Task HandleMessageDeleted(Cacheable<IMessage, ulong> message, ISocketMessageChannel channel)
|
||||
public async Task HandleMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheableMessageChannel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guildSocketData = ((IGuildChannel) channel).Guild;
|
||||
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)
|
||||
{
|
||||
|
@ -35,7 +35,7 @@ namespace Geekbot.Bot.Handlers
|
|||
var sb = new StringBuilder();
|
||||
if (message.Value != null)
|
||||
{
|
||||
sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>");
|
||||
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
|
||||
|
|
|
@ -14,19 +14,19 @@ namespace Geekbot.Bot.Handlers
|
|||
_reactionListener = reactionListener;
|
||||
}
|
||||
|
||||
public Task Added(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
public Task Added(Cacheable<IUserMessage, ulong> cacheableUserMessage, Cacheable<IMessageChannel, ulong> cacheableMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.GiveRole(socketMessageChannel, reaction);
|
||||
_reactionListener.GiveRole(cacheableMessageChannel.Value, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Removed(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
public Task Removed(Cacheable<IUserMessage, ulong> cacheableUserMessage, Cacheable<IMessageChannel, ulong> cacheableMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.RemoveRole(socketMessageChannel, reaction);
|
||||
_reactionListener.RemoveRole(cacheableMessageChannel.Value, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ 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;
|
||||
|
||||
|
@ -13,11 +14,26 @@ namespace Geekbot.Bot.Handlers
|
|||
{
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly DatabaseContext _database;
|
||||
private string _season;
|
||||
|
||||
public StatsHandler(IGeekbotLogger logger, DatabaseContext database)
|
||||
{
|
||||
_logger = logger;
|
||||
_database = database;
|
||||
_season = SeasonsUtils.GetCurrentSeason();
|
||||
|
||||
var timer = new System.Timers.Timer()
|
||||
{
|
||||
Enabled = true,
|
||||
AutoReset = true,
|
||||
Interval = TimeSpan.FromMinutes(5).TotalMilliseconds
|
||||
};
|
||||
timer.Elapsed += (sender, args) =>
|
||||
{
|
||||
var current = SeasonsUtils.GetCurrentSeason();
|
||||
if (current == _season) return;
|
||||
_season = SeasonsUtils.GetCurrentSeason();
|
||||
};
|
||||
}
|
||||
|
||||
public async Task UpdateStats(SocketMessage message)
|
||||
|
@ -33,22 +49,16 @@ namespace Geekbot.Bot.Handlers
|
|||
|
||||
var channel = (SocketGuildChannel) message.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)
|
||||
// ignore the discord bots server
|
||||
// ToDo: create a clean solution for this...
|
||||
if (channel.Guild.Id == 110373943822540800)
|
||||
{
|
||||
await _database.Messages.AddAsync(new MessagesModel
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
MessageCount = 1
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await UpdateTotalTable(message, channel);
|
||||
await UpdateSeasonsTable(message, channel);
|
||||
|
||||
|
||||
if (message.Author.IsBot) return;
|
||||
_logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||
|
@ -58,5 +68,47 @@ namespace Geekbot.Bot.Handlers
|
|||
_logger.Error(LogSource.Message, "Could not process message stats", e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateTotalTable(SocketMessage message, SocketGuildChannel channel)
|
||||
{
|
||||
var rowId = await _database.Database.ExecuteSqlRawAsync(
|
||||
"UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}",
|
||||
channel.Guild.Id.AsLong(),
|
||||
message.Author.Id.AsLong()
|
||||
);
|
||||
|
||||
if (rowId == 0)
|
||||
{
|
||||
await _database.Messages.AddAsync(new MessagesModel
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
MessageCount = 1
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateSeasonsTable(SocketMessage message, SocketGuildChannel channel)
|
||||
{
|
||||
var rowId = await _database.Database.ExecuteSqlRawAsync(
|
||||
"UPDATE \"MessagesSeasons\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1} AND \"Season\" = {2}",
|
||||
channel.Guild.Id.AsLong(),
|
||||
message.Author.Id.AsLong(),
|
||||
_season
|
||||
);
|
||||
|
||||
if (rowId == 0)
|
||||
{
|
||||
await _database.MessagesSeasons.AddAsync(new MessageSeasonsModel()
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
Season = _season,
|
||||
MessageCount = 1
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,15 +74,15 @@ namespace Geekbot.Bot.Handlers
|
|||
await _userRepository.Update(newUser);
|
||||
}
|
||||
|
||||
public async Task Left(SocketGuildUser user)
|
||||
public async Task Left(SocketGuild socketGuild, SocketUser socketUser)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(user.Guild.Id.AsLong()));
|
||||
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($"{user.Username}#{user.Discriminator} left the server");
|
||||
await modChannelSocket.SendMessageAsync($"{socketUser.Username}#{socketUser.Discriminator} left the server");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -90,7 +90,7 @@ namespace Geekbot.Bot.Handlers
|
|||
_logger.Error(LogSource.Geekbot, "Failed to send leave message", e);
|
||||
}
|
||||
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
_logger.Information(LogSource.Geekbot, $"{socketUser.Username} ({socketUser.Id}) joined {socketGuild.Name} ({socketGuild.Id})");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,228 +0,0 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CommandLine;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.Bot.Handlers;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Core.Converters;
|
||||
using Geekbot.Core.Database;
|
||||
using Geekbot.Core.DiceParser;
|
||||
using Geekbot.Core.ErrorHandling;
|
||||
using Geekbot.Core.GlobalSettings;
|
||||
using Geekbot.Core.GuildSettingsManager;
|
||||
using Geekbot.Core.Highscores;
|
||||
using Geekbot.Core.KvInMemoryStore;
|
||||
using Geekbot.Core.Levels;
|
||||
using Geekbot.Core.Logger;
|
||||
using Geekbot.Core.Media;
|
||||
using Geekbot.Core.RandomNumberGenerator;
|
||||
using Geekbot.Core.ReactionListener;
|
||||
using Geekbot.Core.UserRepository;
|
||||
using Geekbot.Core.WikipediaClient;
|
||||
using Geekbot.Web;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Geekbot.Bot
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private DiscordSocketClient _client;
|
||||
private CommandService _commands;
|
||||
private DatabaseInitializer _databaseInitializer;
|
||||
private IGlobalSettings _globalSettings;
|
||||
private IServiceProvider _servicesProvider;
|
||||
private GeekbotLogger _logger;
|
||||
private IUserRepository _userRepository;
|
||||
private RunParameters _runParameters;
|
||||
private IReactionListener _reactionListener;
|
||||
private IGuildSettingsManager _guildSettingsManager;
|
||||
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
RunParameters runParameters = null;
|
||||
Parser.Default.ParseArguments<RunParameters>(args)
|
||||
.WithParsed(e => runParameters = e)
|
||||
.WithNotParsed(_ => Environment.Exit(GeekbotExitCode.InvalidArguments.GetHashCode()));
|
||||
|
||||
var logo = new StringBuilder();
|
||||
logo.AppendLine(@" ____ _____ _____ _ ______ ___ _____");
|
||||
logo.AppendLine(@" / ___| ____| ____| |/ / __ ) / _ \\_ _|");
|
||||
logo.AppendLine(@"| | _| _| | _| | ' /| _ \| | | || |");
|
||||
logo.AppendLine(@"| |_| | |___| |___| . \| |_) | |_| || |");
|
||||
logo.AppendLine(@" \____|_____|_____|_|\_\____/ \___/ |_|");
|
||||
logo.AppendLine($"Version {Constants.BotVersion()} ".PadRight(41, '='));
|
||||
Console.WriteLine(logo.ToString());
|
||||
var logger = new GeekbotLogger(runParameters);
|
||||
logger.Information(LogSource.Geekbot, "Starting...");
|
||||
try
|
||||
{
|
||||
await new Program().Start(runParameters, logger);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(LogSource.Geekbot, "RIP", e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Start(RunParameters runParameters, GeekbotLogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_runParameters = runParameters;
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Connecting to Database");
|
||||
var database = ConnectToDatabase();
|
||||
_globalSettings = new GlobalSettings(database);
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Connecting to Discord");
|
||||
SetupDiscordClient();
|
||||
await Login();
|
||||
_logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers");
|
||||
await _client.SetGameAsync(_globalSettings.GetKey("Game"));
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Loading Dependencies and Handlers");
|
||||
RegisterDependencies();
|
||||
await RegisterHandlers();
|
||||
|
||||
_logger.Information(LogSource.Api, "Starting Web API");
|
||||
StartWebApi();
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Done and ready for use");
|
||||
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
||||
private async Task Login()
|
||||
{
|
||||
try
|
||||
{
|
||||
var token = await GetToken();
|
||||
await _client.LoginAsync(TokenType.Bot, token);
|
||||
await _client.StartAsync();
|
||||
while (!_client.ConnectionState.Equals(ConnectionState.Connected)) await Task.Delay(25);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Could not connect to Discord", e);
|
||||
Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private DatabaseContext ConnectToDatabase()
|
||||
{
|
||||
_databaseInitializer = new DatabaseInitializer(_runParameters, _logger);
|
||||
var database = _databaseInitializer.Initialize();
|
||||
database.Database.EnsureCreated();
|
||||
if(!_runParameters.InMemory) database.Database.Migrate();
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
private async Task<string> GetToken()
|
||||
{
|
||||
var token = _runParameters.Token ?? _globalSettings.GetKey("DiscordToken");
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
Console.Write("Your bot Token: ");
|
||||
var newToken = Console.ReadLine();
|
||||
await _globalSettings.SetKey("DiscordToken", newToken);
|
||||
await _globalSettings.SetKey("Game", "Ping Pong");
|
||||
token = newToken;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private void SetupDiscordClient()
|
||||
{
|
||||
_client = new DiscordSocketClient(new DiscordSocketConfig
|
||||
{
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
MessageCacheSize = 1000,
|
||||
ExclusiveBulkDelete = true
|
||||
});
|
||||
|
||||
var discordLogger = new DiscordLogger(_logger);
|
||||
_client.Log += discordLogger.Log;
|
||||
}
|
||||
|
||||
private void RegisterDependencies()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
_userRepository = new UserRepository(_databaseInitializer.Initialize(), _logger);
|
||||
_reactionListener = new ReactionListener(_databaseInitializer.Initialize());
|
||||
_guildSettingsManager = new GuildSettingsManager(_databaseInitializer.Initialize());
|
||||
var fortunes = new FortunesProvider(_logger);
|
||||
var levelCalc = new LevelCalc();
|
||||
var emojiConverter = new EmojiConverter();
|
||||
var mtgManaConverter = new MtgManaConverter();
|
||||
var wikipediaClient = new WikipediaClient();
|
||||
var randomNumberGenerator = new RandomNumberGenerator(_globalSettings);
|
||||
var mediaProvider = new MediaProvider(_logger, randomNumberGenerator);
|
||||
var kvMemoryStore = new KvInInMemoryStore();
|
||||
var errorHandler = new ErrorHandler(_logger, _runParameters, () => Localization.Internal.SomethingWentWrong);
|
||||
var diceParser = new DiceParser(randomNumberGenerator);
|
||||
|
||||
services.AddSingleton(_userRepository);
|
||||
services.AddSingleton<IGeekbotLogger>(_logger);
|
||||
services.AddSingleton<ILevelCalc>(levelCalc);
|
||||
services.AddSingleton<IEmojiConverter>(emojiConverter);
|
||||
services.AddSingleton<IFortunesProvider>(fortunes);
|
||||
services.AddSingleton<IMediaProvider>(mediaProvider);
|
||||
services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
|
||||
services.AddSingleton<IWikipediaClient>(wikipediaClient);
|
||||
services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator);
|
||||
services.AddSingleton<IKvInMemoryStore>(kvMemoryStore);
|
||||
services.AddSingleton<IGlobalSettings>(_globalSettings);
|
||||
services.AddSingleton<IErrorHandler>(errorHandler);
|
||||
services.AddSingleton<IDiceParser>(diceParser);
|
||||
services.AddSingleton<IReactionListener>(_reactionListener);
|
||||
services.AddSingleton<IGuildSettingsManager>(_guildSettingsManager);
|
||||
services.AddSingleton(_client);
|
||||
services.AddTransient<IHighscoreManager>(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository));
|
||||
services.AddTransient(e => _databaseInitializer.Initialize());
|
||||
|
||||
_servicesProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
private async Task RegisterHandlers()
|
||||
{
|
||||
var applicationInfo = await _client.GetApplicationInfoAsync();
|
||||
|
||||
_commands = new CommandService();
|
||||
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _servicesProvider);
|
||||
|
||||
var commandHandler = new CommandHandler(_databaseInitializer.Initialize(), _client, _logger, _servicesProvider, _commands, applicationInfo, _guildSettingsManager);
|
||||
var userHandler = new UserHandler(_userRepository, _logger, _databaseInitializer.Initialize(), _client);
|
||||
var reactionHandler = new ReactionHandler(_reactionListener);
|
||||
var statsHandler = new StatsHandler(_logger, _databaseInitializer.Initialize());
|
||||
var messageDeletedHandler = new MessageDeletedHandler(_databaseInitializer.Initialize(), _logger, _client);
|
||||
|
||||
_client.MessageReceived += commandHandler.RunCommand;
|
||||
_client.MessageDeleted += messageDeletedHandler.HandleMessageDeleted;
|
||||
_client.UserJoined += userHandler.Joined;
|
||||
_client.UserUpdated += userHandler.Updated;
|
||||
_client.UserLeft += userHandler.Left;
|
||||
_client.ReactionAdded += reactionHandler.Added;
|
||||
_client.ReactionRemoved += reactionHandler.Removed;
|
||||
if (!_runParameters.InMemory) _client.MessageReceived += statsHandler.UpdateStats;
|
||||
}
|
||||
|
||||
private void StartWebApi()
|
||||
{
|
||||
if (_runParameters.DisableApi)
|
||||
{
|
||||
_logger.Warning(LogSource.Api, "Web API is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
var highscoreManager = new HighscoreManager(_databaseInitializer.Initialize(), _userRepository);
|
||||
WebApiStartup.StartWebApi(_logger, _runParameters, _commands, _databaseInitializer.Initialize(), _client, _globalSettings, highscoreManager);
|
||||
}
|
||||
}
|
||||
}
|
23
src/Commands/Commands.csproj
Normal file
23
src/Commands/Commands.csproj
Normal file
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.0-DEV</Version>
|
||||
<RootNamespace>Geekbot.Commands</RootNamespace>
|
||||
<AssemblyName>Geekbot.Commands</AssemblyName>
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
<NoWarn>CS8618</NoWarn>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\Interactions\Interactions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
103
src/Commands/Karma/Karma.cs
Normal file
103
src/Commands/Karma/Karma.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
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<Embed> 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<KarmaModel> 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<KarmaModel> 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;
|
||||
}
|
||||
}
|
8
src/Commands/Karma/KarmaChange.cs
Normal file
8
src/Commands/Karma/KarmaChange.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Geekbot.Commands.Karma;
|
||||
|
||||
public enum KarmaChange
|
||||
{
|
||||
Up,
|
||||
Same,
|
||||
Down
|
||||
}
|
102
src/Commands/Rank.cs
Normal file
102
src/Commands/Rank.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
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<HighscoreTypes>(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<HighscoreUserDto, int> 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();
|
||||
}
|
||||
}
|
||||
}
|
91
src/Commands/Roll/Roll.cs
Normal file
91
src/Commands/Roll/Roll.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
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<string> 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<string> RunFromInteraction(string guildId, string userId, string userName, int guess)
|
||||
{
|
||||
return await this.Run(long.Parse(guildId), long.Parse(userId), userName, guess);
|
||||
}
|
||||
|
||||
private async Task<string> 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<RollTimeout>(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<RollsModel> 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<RollsModel> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.Bot.Commands.Games.Roll
|
||||
{
|
||||
public class RollTimeout
|
||||
{
|
||||
public int LastGuess { get; set; }
|
||||
public DateTime GuessedOn { get; set; }
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace Geekbot.Commands.Roll
|
||||
{
|
||||
public record RollTimeout
|
||||
{
|
||||
public int LastGuess { get; set; }
|
||||
public DateTime GuessedOn { get; set; }
|
||||
}
|
||||
}
|
37
src/Commands/UrbanDictionary/UrbanDictionary.cs
Normal file
37
src/Commands/UrbanDictionary/UrbanDictionary.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
using System.Drawing;
|
||||
using Geekbot.Core;
|
||||
using Geekbot.Interactions.Embed;
|
||||
|
||||
namespace Geekbot.Commands.UrbanDictionary;
|
||||
|
||||
public class UrbanDictionary
|
||||
{
|
||||
public static async Task<Embed?> Run(string term)
|
||||
{
|
||||
var definitions = await HttpAbstractions.Get<UrbanDictionaryResponse>(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;
|
||||
}
|
||||
}
|
24
src/Commands/UrbanDictionary/UrbanDictionaryListItem.cs
Normal file
24
src/Commands/UrbanDictionary/UrbanDictionaryListItem.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
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; }
|
||||
}
|
12
src/Commands/UrbanDictionary/UrbanDictionaryResponse.cs
Normal file
12
src/Commands/UrbanDictionary/UrbanDictionaryResponse.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Geekbot.Commands.UrbanDictionary;
|
||||
|
||||
public struct UrbanDictionaryResponse
|
||||
{
|
||||
[JsonPropertyName("tags")]
|
||||
public string[] Tags { get; set; }
|
||||
|
||||
[JsonPropertyName("list")]
|
||||
public List<UrbanDictionaryListItem?> List { get; set; }
|
||||
}
|
11
src/Core/BotCommandLookup/CommandInfo.cs
Normal file
11
src/Core/BotCommandLookup/CommandInfo.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.Core.BotCommandLookup;
|
||||
|
||||
public struct CommandInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Dictionary<string, ParameterInfo> Parameters { get; set; }
|
||||
public List<string> Aliases { get; set; }
|
||||
public string Summary { get; set; }
|
||||
}
|
87
src/Core/BotCommandLookup/CommandLookup.cs
Normal file
87
src/Core/BotCommandLookup/CommandLookup.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
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<CommandInfo> GetCommands()
|
||||
{
|
||||
var commands = SearchCommands(_assembly);
|
||||
var result = new List<CommandInfo>();
|
||||
commands.ForEach(x => GetCommandDefinition(ref result, x));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<TypeInfo> SearchCommands(Assembly assembly)
|
||||
{
|
||||
bool IsLoadableModule(TypeInfo info) => info.DeclaredMethods.Any(x => x.GetCustomAttribute<CommandAttribute>() != null || x.GetCustomAttribute<GroupAttribute>() != null);
|
||||
return assembly
|
||||
.DefinedTypes
|
||||
.Where(typeInfo => typeInfo.IsPublic || typeInfo.IsNestedPublic)
|
||||
.Where(IsLoadableModule)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void GetCommandDefinition(ref List<CommandInfo> commandInfos, TypeInfo commandType)
|
||||
{
|
||||
var methods = commandType
|
||||
.GetMethods()
|
||||
.Where(x => x.GetCustomAttribute<CommandAttribute>() != 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<string, ParameterInfo>(),
|
||||
};
|
||||
|
||||
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<string>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var param in command.GetParameters())
|
||||
{
|
||||
var paramName = param.Name ?? string.Empty;
|
||||
var paramInfo = new ParameterInfo()
|
||||
{
|
||||
Summary = param.GetCustomAttribute<SummaryAttribute>()?.Text ?? string.Empty,
|
||||
Type = param.ParameterType.Name,
|
||||
DefaultValue = param.DefaultValue?.ToString()
|
||||
};
|
||||
commandInfo.Parameters.Add(paramName, paramInfo);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(commandInfo.Name))
|
||||
{
|
||||
commandInfos.Add(commandInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
src/Core/BotCommandLookup/ParameterInfo.cs
Normal file
8
src/Core/BotCommandLookup/ParameterInfo.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Geekbot.Core.BotCommandLookup;
|
||||
|
||||
public struct ParameterInfo
|
||||
{
|
||||
public string Summary { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string DefaultValue { get; set; }
|
||||
}
|
|
@ -3,88 +3,133 @@ using System.Text;
|
|||
|
||||
namespace Geekbot.Core.Converters
|
||||
{
|
||||
public class EmojiConverter : IEmojiConverter
|
||||
public static class EmojiConverter
|
||||
{
|
||||
public string NumberToEmoji(int number)
|
||||
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 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())]);
|
||||
returnString.Append(NumberEmojiMap[int.Parse(n.ToString())]);
|
||||
}
|
||||
return returnString.ToString();
|
||||
}
|
||||
|
||||
public string TextToEmoji(string text)
|
||||
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 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;
|
||||
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();
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.Core.Converters
|
||||
{
|
||||
public interface IEmojiConverter
|
||||
{
|
||||
string NumberToEmoji(int number);
|
||||
string TextToEmoji(string text);
|
||||
}
|
||||
}
|
|
@ -1,33 +1,94 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.0-DEV</Version>
|
||||
<RootNamespace>Geekbot.Core</RootNamespace>
|
||||
<AssemblyName>Geekbot.Core</AssemblyName>
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Anemonis.RandomOrg" Version="1.14.0" />
|
||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||
<PackageReference Include="Discord.Net" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0-rc.1.*" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Discord.Net" Version="3.7.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.12">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.12">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.12" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.12" />
|
||||
<PackageReference Include="NLog" Version="4.7.2" />
|
||||
<PackageReference Include="NLog.Config" Version="4.7.2" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.0-rc1" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
<PackageReference Include="SumoLogic.Logging.NLog" Version="1.0.1.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.10" />
|
||||
<PackageReference Include="Sentry" Version="3.11.0" />
|
||||
<PackageReference Include="SumoLogic.Logging.NLog" Version="1.0.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Localization\Admin.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Admin.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Choose.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Choose.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Cookies.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Cookies.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Corona.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Corona.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\EightBall.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>EightBall.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Internal.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Internal.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Karma.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Karma.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Quote.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Quote.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Rank.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Rank.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Role.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Role.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Roll.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Roll.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Ship.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Ship.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="Localization\Stats.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Stats.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -11,6 +11,7 @@ namespace Geekbot.Core.Database
|
|||
public DbSet<KarmaModel> Karma { get; set; }
|
||||
public DbSet<ShipsModel> Ships { get; set; }
|
||||
public DbSet<RollsModel> Rolls { get; set; }
|
||||
public DbSet<MessageSeasonsModel> MessagesSeasons { get; set; }
|
||||
public DbSet<MessagesModel> Messages { get; set; }
|
||||
public DbSet<SlapsModel> Slaps { get; set; }
|
||||
public DbSet<GlobalsModel> Globals { get; set; }
|
||||
|
|
21
src/Core/Database/Models/MessageSeasonsModel.cs
Normal file
21
src/Core/Database/Models/MessageSeasonsModel.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
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; }
|
||||
}
|
||||
}
|
|
@ -1,13 +1,17 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Geekbot.Bot.Utils
|
||||
namespace Geekbot.Core
|
||||
{
|
||||
public class DateLocalization
|
||||
{
|
||||
public static string FormatDateTimeAsRemaining(DateTimeOffset dateTime)
|
||||
{
|
||||
var remaining = dateTime - DateTimeOffset.Now;
|
||||
return FormatDateTimeAsRemaining(dateTime - DateTimeOffset.Now);
|
||||
}
|
||||
|
||||
public static string FormatDateTimeAsRemaining(TimeSpan remaining)
|
||||
{
|
||||
const string formattable = "{0} {1}";
|
||||
var sb = new StringBuilder();
|
||||
|
|
@ -63,9 +63,9 @@ namespace Geekbot.Core.DiceParser
|
|||
throw new DiceException("Die must have at least 2 sides") { DiceName = DiceName };
|
||||
}
|
||||
|
||||
if (Sides > 144)
|
||||
if (Sides > 145)
|
||||
{
|
||||
throw new DiceException("Die can not have more than 144 sides") { DiceName = DiceName };
|
||||
throw new DiceException("Die can not have more than 145 sides") { DiceName = DiceName };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.Core.Logger;
|
||||
using SharpRaven;
|
||||
using SharpRaven.Data;
|
||||
using Sentry;
|
||||
using Exception = System.Exception;
|
||||
|
||||
namespace Geekbot.Core.ErrorHandling
|
||||
|
@ -12,7 +11,6 @@ namespace Geekbot.Core.ErrorHandling
|
|||
{
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly Func<string> _getDefaultErrorText;
|
||||
private readonly IRavenClient _raven;
|
||||
private readonly bool _errorsInChat;
|
||||
|
||||
public ErrorHandler(IGeekbotLogger logger, RunParameters runParameters, Func<string> getDefaultErrorText)
|
||||
|
@ -20,17 +18,6 @@ namespace Geekbot.Core.ErrorHandling
|
|||
_logger = logger;
|
||||
_getDefaultErrorText = getDefaultErrorText;
|
||||
_errorsInChat = runParameters.ExposeErrors;
|
||||
|
||||
var sentryDsn = runParameters.SentryEndpoint;
|
||||
if (!string.IsNullOrEmpty(sentryDsn))
|
||||
{
|
||||
_raven = new RavenClient(sentryDsn) { Release = Constants.BotVersion(), Environment = "Production" };
|
||||
_logger.Information(LogSource.Geekbot, $"Command Errors will be logged to Sentry: {sentryDsn}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_raven = null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task HandleCommandException(Exception e, ICommandContext context, string errorMessage = "def")
|
||||
|
@ -83,18 +70,19 @@ namespace Geekbot.Core.ErrorHandling
|
|||
|
||||
private void ReportExternal(Exception e, MessageDto errorObj)
|
||||
{
|
||||
if (_raven == null) return;
|
||||
if (!SentrySdk.IsEnabled) 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ using Geekbot.Core.GuildSettingsManager;
|
|||
|
||||
namespace Geekbot.Core
|
||||
{
|
||||
public class GeekbotCommandBase : ModuleBase<ICommandContext>
|
||||
public class GeekbotCommandBase : TransactionModuleBase
|
||||
{
|
||||
protected readonly IGuildSettingsManager GuildSettingsManager;
|
||||
protected GuildSettingsModel GuildSettings;
|
||||
|
@ -22,9 +22,14 @@ namespace Geekbot.Core
|
|||
protected override void BeforeExecute(CommandInfo command)
|
||||
{
|
||||
base.BeforeExecute(command);
|
||||
|
||||
var setupSpan = Transaction.StartChild("Setup");
|
||||
|
||||
GuildSettings = GuildSettingsManager.GetSettings(Context?.Guild?.Id ?? 0);
|
||||
var language = GuildSettings.Language;
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language == "CHDE" ? "de-ch" : language);
|
||||
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
|
||||
|
||||
setupSpan.Finish();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Geekbot.Core.Highscores
|
|||
|
||||
}
|
||||
|
||||
public Dictionary<HighscoreUserDto, int> GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount)
|
||||
public Dictionary<HighscoreUserDto, int> GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null)
|
||||
{
|
||||
var list = type switch
|
||||
{
|
||||
|
@ -26,6 +26,8 @@ namespace Geekbot.Core.Highscores
|
|||
HighscoreTypes.karma => GetKarmaList(guildId, amount),
|
||||
HighscoreTypes.rolls => GetRollsList(guildId, amount),
|
||||
HighscoreTypes.cookies => GetCookiesList(guildId, amount),
|
||||
HighscoreTypes.seasons => GetMessageSeasonList(guildId, amount, season),
|
||||
HighscoreTypes.quotes => GetQuotesList(guildId, amount),
|
||||
_ => new Dictionary<ulong, int>()
|
||||
};
|
||||
|
||||
|
@ -75,6 +77,19 @@ namespace Geekbot.Core.Highscores
|
|||
.ToDictionary(key => key.UserId.AsUlong(), key => key.MessageCount);
|
||||
}
|
||||
|
||||
public Dictionary<ulong, int> 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<ulong, int> GetKarmaList(ulong guildId, int amount)
|
||||
{
|
||||
return _database.Karma
|
||||
|
@ -101,5 +116,16 @@ namespace Geekbot.Core.Highscores
|
|||
.Take(amount)
|
||||
.ToDictionary(key => key.UserId.AsUlong(), key => key.Cookies);
|
||||
}
|
||||
|
||||
private Dictionary<ulong, int> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
messages,
|
||||
karma,
|
||||
rolls,
|
||||
cookies
|
||||
cookies,
|
||||
seasons,
|
||||
quotes
|
||||
}
|
||||
}
|
|
@ -4,8 +4,9 @@ namespace Geekbot.Core.Highscores
|
|||
{
|
||||
public interface IHighscoreManager
|
||||
{
|
||||
Dictionary<HighscoreUserDto, int> GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount);
|
||||
Dictionary<HighscoreUserDto, int> GetHighscoresWithUserData(HighscoreTypes type, ulong guildId, int amount, string season = null);
|
||||
Dictionary<ulong, int> GetMessageList(ulong guildId, int amount);
|
||||
Dictionary<ulong, int> GetMessageSeasonList(ulong guildId, int amount, string season);
|
||||
Dictionary<ulong, int> GetKarmaList(ulong guildId, int amount);
|
||||
Dictionary<ulong, int> GetRollsList(ulong guildId, int amount);
|
||||
}
|
||||
|
|
16
src/Core/Highscores/SeasonsUtils.cs
Normal file
16
src/Core/Highscores/SeasonsUtils.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
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}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.Core
|
||||
{
|
||||
|
@ -22,21 +26,164 @@ namespace Geekbot.Core
|
|||
return client;
|
||||
}
|
||||
|
||||
public static async Task<T> Get<T>(Uri location, HttpClient httpClient = null, bool disposeClient = true)
|
||||
public static async Task<TResponse> Get<TResponse>(Uri location, HttpClient httpClient = null, bool disposeClient = true, int maxRetries = 3)
|
||||
{
|
||||
httpClient ??= CreateDefaultClient();
|
||||
httpClient.BaseAddress = location;
|
||||
|
||||
var response = await httpClient.GetAsync(location.PathAndQuery);
|
||||
response.EnsureSuccessStatusCode();
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if (disposeClient)
|
||||
HttpResponseMessage response;
|
||||
try
|
||||
{
|
||||
httpClient.Dispose();
|
||||
response = await Execute(() => httpClient.GetAsync(location.PathAndQuery), maxRetries);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (disposeClient)
|
||||
{
|
||||
httpClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(stringResponse);
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
return JsonSerializer.Deserialize<TResponse>(stringResponse);
|
||||
}
|
||||
|
||||
public static async Task<TResponse> Post<TResponse>(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<TResponse>(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<HttpResponseMessage> Execute(Func<Task<HttpResponseMessage>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,7 @@
|
|||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Geekbot.Bot.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
namespace Geekbot.Core.Localization {
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
|
@ -22,24 +19,24 @@ namespace Geekbot.Bot.Localization {
|
|||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Admin {
|
||||
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")]
|
||||
internal Admin() {
|
||||
public Admin() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Admin", typeof(Admin).Assembly);
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Admin", typeof(Admin).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
|
@ -51,7 +48,7 @@ namespace Geekbot.Bot.Localization {
|
|||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
|
@ -63,7 +60,7 @@ namespace Geekbot.Bot.Localization {
|
|||
/// <summary>
|
||||
/// Looks up a localized string similar to I'm talking english.
|
||||
/// </summary>
|
||||
internal static string GetLanguage {
|
||||
public static string GetLanguage {
|
||||
get {
|
||||
return ResourceManager.GetString("GetLanguage", resourceCulture);
|
||||
}
|
||||
|
@ -72,7 +69,7 @@ namespace Geekbot.Bot.Localization {
|
|||
/// <summary>
|
||||
/// Looks up a localized string similar to I will reply in english from now on.
|
||||
/// </summary>
|
||||
internal static string NewLanguageSet {
|
||||
public static string NewLanguageSet {
|
||||
get {
|
||||
return ResourceManager.GetString("NewLanguageSet", resourceCulture);
|
||||
}
|
|
@ -8,10 +8,7 @@
|
|||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Geekbot.Bot.Localization {
|
||||
using System;
|
||||
|
||||
|
||||
namespace Geekbot.Core.Localization {
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
|
@ -22,24 +19,24 @@ namespace Geekbot.Bot.Localization {
|
|||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Choose {
|
||||
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")]
|
||||
internal Choose() {
|
||||
public Choose() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
public static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Bot.Localization.Choose", typeof(Choose).Assembly);
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Geekbot.Core.Localization.Choose", typeof(Choose).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
|
@ -51,7 +48,7 @@ namespace Geekbot.Bot.Localization {
|
|||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
public static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
|
@ -63,7 +60,7 @@ namespace Geekbot.Bot.Localization {
|
|||
/// <summary>
|
||||
/// Looks up a localized string similar to I Choose **{0}**.
|
||||
/// </summary>
|
||||
internal static string Choice {
|
||||
public static string Choice {
|
||||
get {
|
||||
return ResourceManager.GetString("Choice", resourceCulture);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue