Compare commits
265 commits
GeekbotBas
...
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 | |||
4c3b7044ce | |||
2fb815bc97 | |||
ffab56d4a5 | |||
fe51dfe540 | |||
28a5b9322e | |||
41795aa13f | |||
ed7748833a | |||
7ef0b6a319 | |||
216188f61f | |||
58bd4d17d0 | |||
ae9b9caeb9 | |||
b743539c74 | |||
482a74839a | |||
cbe2aa23c9 | |||
d3c284102b | |||
f71349b378 | |||
81373b7614 | |||
ce1153a0e2 | |||
8246c7a862 | |||
546b5450e7 | |||
3c4a5c638b | |||
a78e92d230 | |||
79fb7dece6 | |||
60e36daaec | |||
33829e91bc | |||
078c884df7 | |||
90af781c7b | |||
12388fd7d0 | |||
187fd6a04f | |||
726ee77ed4 | |||
ad086a5e0c | |||
7942308059 | |||
c893e45004 | |||
d68ce459ef | |||
bd117e2595 | |||
97ad54df9e | |||
61ce14a61d | |||
fc0af492ad | |||
7b6dd2d2f9 | |||
c22d0cf941 | |||
3813290f89 | |||
9003d6249e | |||
913b4a5f10 | |||
4659f793f5 | |||
fff2324232 | |||
77e912501d | |||
4cd7ac1d79 | |||
5e9cb8a4c1 | |||
efed2f7120 | |||
ba0d116f3e | |||
0589b8e91b | |||
c94d73736d | |||
580a514ce5 | |||
cc22774729 | |||
859db4ebdd | |||
acd1cee16c | |||
6d44960867 | |||
d7e313c9fa | |||
279a8975c9 | |||
194bfd3d3b | |||
8f41999015 | |||
619f63067c | |||
56f788878a | |||
d9f8e9a80e | |||
a4b914d576 | |||
3213e10b88 | |||
f23b8099f1 | |||
e0f17d00ea | |||
a0b1ec44f6 | |||
4655424fb0 | |||
9cc944fcc1 | |||
e564e80849 | |||
76bb645394 | |||
1ea851be22 | |||
fb676e8918 | |||
83dc2c8e49 | |||
f7908c2a0c | |||
baea4528e1 | |||
12199f4ad4 | |||
0898e9b6bd | |||
8018d5e750 | |||
d91c21e607 | |||
6692b3bc77 | |||
3108a68407 | |||
ff968a490f | |||
520633c590 | |||
46fee88f03 | |||
33b17b373f | |||
2e501008df | |||
656393cc7b | |||
5cf1248bf0 | |||
c031d2bfb4 | |||
fc5ff87c8f | |||
569715f124 | |||
ee548390a5 | |||
2a616f8c5d | |||
77b3d612f2 | |||
f12bdcf4cd | |||
3bd7274d68 | |||
3568b61f38 | |||
21f813d342 | |||
dd9cf3c5d7 | |||
cd04549834 | |||
20c75019f9 | |||
8dd914e012 | |||
b7b4a600cd | |||
19df65fc76 | |||
309f06370b | |||
f1387f824e | |||
143722eccf | |||
1bfd7c7a12 | |||
fe4a78b743 | |||
7a250f6642 | |||
ac43d087b1 | |||
8fadff4092 | |||
288c976674 |
398 changed files with 11739 additions and 5515 deletions
38
.deploy.yml
Normal file
38
.deploy.yml
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
- name: Geekbot Deploy
|
||||
hosts: all
|
||||
remote_user: geekbot
|
||||
vars:
|
||||
ansible_port: 65432
|
||||
ansible_python_interpreter: /usr/bin/python3
|
||||
tasks:
|
||||
- name: Login to Gitlab Docker Registry
|
||||
'community.docker.docker_login':
|
||||
registry_url: "{{ lookup('env', 'CI_REGISTRY') }}"
|
||||
username: "{{ lookup('env', 'CI_REGISTRY_USER') }}"
|
||||
password: "{{ lookup('env', 'CI_REGISTRY_PASSWORD') }}"
|
||||
reauthorize: yes
|
||||
- name: Replace Prod Container
|
||||
'community.docker.docker_container':
|
||||
name: GeekbotProd
|
||||
image: "{{ lookup('env', 'IMAGE_TAG') }}"
|
||||
recreate: yes
|
||||
pull: yes
|
||||
restart_policy: always
|
||||
keep_volumes: no
|
||||
ports:
|
||||
- "12995:12995"
|
||||
env:
|
||||
GEEKBOT_DB_HOST: "{{ lookup('env', 'GEEKBOT_DB_HOST') }}"
|
||||
GEEKBOT_DB_USER: "{{ lookup('env', 'GEEKBOT_DB_USER') }}"
|
||||
GEEKBOT_DB_PASSWORD: "{{ lookup('env', 'GEEKBOT_DB_PASSWORD') }}"
|
||||
GEEKBOT_DB_PORT: "{{ lookup('env', 'GEEKBOT_DB_PORT') }}"
|
||||
GEEKBOT_DB_DATABASE: "{{ lookup('env', 'GEEKBOT_DB_DATABASE') }}"
|
||||
GEEKBOT_DB_REQUIRE_SSL: "true"
|
||||
GEEKBOT_DB_TRUST_CERT: "true"
|
||||
GEEKBOT_SUMOLOGIC: "{{ lookup('env', 'GEEKBOT_SUMOLOCIG') }}"
|
||||
GEEKBOT_SENTRY: "{{ lookup('env', 'GEEKBOT_SENTRY') }}"
|
||||
GEEKBOT_DB_REDSHIFT_COMPAT: "true"
|
||||
- name: Cleanup Old Container
|
||||
'community.docker.docker_prune':
|
||||
images: yes
|
18
.gitignore
vendored
18
.gitignore
vendored
|
@ -1,16 +1,10 @@
|
|||
Geekbot.net/bin
|
||||
Geekbot.net/obj
|
||||
Geekbot.net/tmp/
|
||||
Tests/bin
|
||||
Tests/obj
|
||||
Backup/
|
||||
/*/**/bin
|
||||
/*/**/obj
|
||||
src/Bot/tmp/
|
||||
src/Bot/Logs/*
|
||||
!/src/Bot/Logs/.keep
|
||||
.vs/
|
||||
UpgradeLog.htm
|
||||
.idea
|
||||
.vscode
|
||||
Geekbot.net/Logs/*
|
||||
!/Geekbot.net/Logs/.keep
|
||||
Geekbot.net.sln.DotSettings.user
|
||||
Geekbot.net/temp/
|
||||
WikipediaApi/bin/
|
||||
WikipediaApi/obj/
|
||||
app
|
||||
|
|
|
@ -1,65 +1,69 @@
|
|||
stages:
|
||||
- build
|
||||
- ops
|
||||
- docker
|
||||
- deploy
|
||||
- ops
|
||||
|
||||
before_script:
|
||||
- set -e
|
||||
- set -u
|
||||
- set -o pipefail
|
||||
variables:
|
||||
VERSION: 4.4.0-V$CI_COMMIT_SHORT_SHA
|
||||
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
||||
|
||||
build:
|
||||
Build:
|
||||
stage: build
|
||||
image: mcr.microsoft.com/dotnet/core/sdk:2.2
|
||||
image: mcr.microsoft.com/dotnet/sdk:6.0
|
||||
artifacts:
|
||||
expire_in: 1h
|
||||
paths:
|
||||
- Geekbot.net/Binaries/
|
||||
- app
|
||||
script:
|
||||
- dotnet restore -s https://api.nuget.org/v3/index.json -s https://www.myget.org/F/discord-net/api/v3/index.json
|
||||
- dotnet test Tests
|
||||
- dotnet publish --version-suffix ${CI_COMMIT_SHA:0:8} --configuration Release -o Binaries ./
|
||||
- dotnet restore
|
||||
- dotnet test tests
|
||||
- dotnet publish --version-suffix "$VERSION" -r linux-x64 -c Release -p:DebugType=embedded --no-self-contained -o ./app ./src/Startup/
|
||||
|
||||
sentry:
|
||||
Package:
|
||||
stage: docker
|
||||
image: docker
|
||||
only:
|
||||
- master
|
||||
services:
|
||||
- docker:stable-dind
|
||||
script:
|
||||
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
|
||||
- docker build -t $IMAGE_TAG .
|
||||
- docker push $IMAGE_TAG
|
||||
|
||||
Deploy:
|
||||
stage: deploy
|
||||
image: quay.io/ansible/ansible-runner:stable-2.12-latest
|
||||
only:
|
||||
- master
|
||||
variables:
|
||||
ANSIBLE_NOCOWS: 1
|
||||
before_script:
|
||||
- mkdir /root/.ssh
|
||||
- cp $SSH_PRIVATE_KEY /root/.ssh/id_ed25519
|
||||
- cp $SSH_PUBLIC_KEY /root/.ssh/id_ed25519.pub
|
||||
- chmod -R 600 /root/.ssh
|
||||
- ssh-keyscan -p 65432 $PROD_IP > /root/.ssh/known_hosts
|
||||
script:
|
||||
- ansible-galaxy collection install -r ansible-requirements.yml
|
||||
- ansible-playbook -i $PROD_IP, .deploy.yml
|
||||
|
||||
Sentry:
|
||||
stage: ops
|
||||
image: getsentry/sentry-cli
|
||||
allow_failure: true
|
||||
only:
|
||||
- master
|
||||
dependencies:
|
||||
- build
|
||||
script:
|
||||
- sentry-cli releases new -p geekbot 4.1.0-${CI_COMMIT_SHA:0:8}
|
||||
- sentry-cli releases set-commits --auto 4.1.0-${CI_COMMIT_SHA:0:8}
|
||||
- sentry-cli releases deploys 4.1.0-${CI_COMMIT_SHA:0:8} new -e Production
|
||||
- sentry-cli releases new -p geekbot $VERSION
|
||||
- sentry-cli releases set-commits --auto $VERSION
|
||||
- sentry-cli releases deploys $VERSION new -e Production
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
Github Mirror:
|
||||
stage: ops
|
||||
image: runebaas/rsync-ssh-git
|
||||
only:
|
||||
- master
|
||||
dependencies:
|
||||
- build
|
||||
- sentry
|
||||
environment:
|
||||
name: Production
|
||||
url: https://discordapp.com/oauth2/authorize?client_id=171249478546882561&scope=bot&permissions=1416834054
|
||||
before_script:
|
||||
- eval $(ssh-agent -s)
|
||||
- mkdir -p ~/.ssh
|
||||
- '[[ -f /.dockerenv ]] && echo -e "Host *\n StrictHostKeyChecking no" > ~/.ssh/config'
|
||||
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null
|
||||
- chmod 700 ~/.ssh
|
||||
script:
|
||||
- rsync -rav -e "ssh -p 65432" ./Geekbot.net/Binaries/* geekbot@$DEPIP:$DEPPATH
|
||||
- ssh -p 65432 geekbot@$DEPIP "sudo systemctl restart geekbot.service"
|
||||
|
||||
mirror:
|
||||
stage: deploy
|
||||
image: runebaas/rsync-ssh-git
|
||||
only:
|
||||
- master
|
||||
dependencies:
|
||||
- build
|
||||
- sentry
|
||||
script:
|
||||
- git push https://runebaas:$TOKEN@github.com/pizzaandcoffee/Geekbot.net.git origin/master:master -f
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
FROM microsoft/dotnet:2.1-aspnetcore-runtime
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:6.0
|
||||
|
||||
COPY Geekbot.net/Binaries /app/
|
||||
COPY ./app /app/
|
||||
|
||||
EXPOSE 12995/tcp
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ./run.sh
|
||||
ENTRYPOINT ./Geekbot
|
||||
|
|
|
@ -3,11 +3,19 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||
# Visual Studio 2013
|
||||
VisualStudioVersion = 12.0.0.0
|
||||
MinimumVisualStudioVersion = 10.0.0.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Geekbot.net", "Geekbot.net/Geekbot.net.csproj", "{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "src\Core\Core.csproj", "{47671723-52A9-4668-BBC5-2BA76AE3B288}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WikipediaApi", "WikipediaApi\WikipediaApi.csproj", "{1084D499-EF94-4834-9E6A-B2AD81B60078}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{0A63D5DC-6325-4F53-8ED2-9843239B76CC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bot", "src\Bot\Bot.csproj", "{DBF79896-9F7F-443D-B336-155E276DFF16}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands", "src\Commands\Commands.csproj", "{7C771DFE-912A-4276-B0A6-047E09603F1E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interactions", "src\Interactions\Interactions.csproj", "{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Startup", "src\Startup\Startup.csproj", "{A691B018-4B19-4A7A-A0F6-DBB17641254F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -15,18 +23,34 @@ Global
|
|||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FDCB3D92-E7B5-47BB-A9B5-CFAEFA57CDB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4CAF5F02-EFFE-4FDA-BD44-EEADDBA9600E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1084D499-EF94-4834-9E6A-B2AD81B60078}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47671723-52A9-4668-BBC5-2BA76AE3B288}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0A63D5DC-6325-4F53-8ED2-9843239B76CC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DBF79896-9F7F-443D-B336-155E276DFF16}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C771DFE-912A-4276-B0A6-047E09603F1E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FF6859D9-C539-4910-BE1E-9ECFED2F46FA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A691B018-4B19-4A7A-A0F6-DBB17641254F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,267 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.CommandPreconditions;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
|
||||
namespace Geekbot.net.Commands.Admin
|
||||
{
|
||||
[Group("admin")]
|
||||
[RequireUserPermission(GuildPermission.Administrator)]
|
||||
[DisableInDirectMessage]
|
||||
public class Admin : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Admin(DatabaseContext database, DiscordSocketClient client, IErrorHandler errorHandler,
|
||||
ITranslationHandler translationHandler)
|
||||
{
|
||||
_database = database;
|
||||
_client = client;
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translationHandler;
|
||||
}
|
||||
|
||||
[Command("welcome", RunMode = RunMode.Async)]
|
||||
[Summary("Set a Welcome Message (use '$user' to mention the new joined user).")]
|
||||
public async Task SetWelcomeMessage([Remainder, Summary("message")] string welcomeMessage)
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.WelcomeMessage = welcomeMessage;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var formatedMessage = welcomeMessage.Replace("$user", Context.User.Mention);
|
||||
await ReplyAsync($"Welcome message has been changed\r\nHere is an example of how it would look:\r\n{formatedMessage}");
|
||||
}
|
||||
|
||||
[Command("welcomechannel", RunMode = RunMode.Async)]
|
||||
[Summary("Set a channel for the welcome messages (by default it uses the top most channel)")]
|
||||
public async Task SelectWelcomeChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = await channel.SendMessageAsync("...");
|
||||
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.WelcomeChannel = channel.Id.AsLong();
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
await m.DeleteAsync();
|
||||
|
||||
await ReplyAsync("Successfully saved the welcome channel");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("modchannel", RunMode = RunMode.Async)]
|
||||
[Summary("Set a channel for moderation purposes")]
|
||||
public async Task SelectModChannel([Summary("#Channel")] ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var m = await channel.SendMessageAsync("verifying...");
|
||||
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.ModChannel = channel.Id.AsLong();
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("Successfully saved mod channel, you can now do the following");
|
||||
sb.AppendLine("- `!admin showleave` - send message to mod channel when someone leaves");
|
||||
sb.AppendLine("- `!admin showdel` - send message to mod channel when someone deletes a message");
|
||||
await m.ModifyAsync(e => e.Content = sb.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "That channel doesn't seem to exist or i don't have write permissions");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("showleave", RunMode = RunMode.Async)]
|
||||
[Summary("Toggle - notify modchannel when someone leaves")]
|
||||
public async Task ShowLeave()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
var modChannel = await GetModChannel(guild.ModChannel.AsUlong());
|
||||
if (modChannel == null) return;
|
||||
|
||||
guild.ShowLeave = !guild.ShowLeave;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
await modChannel.SendMessageAsync(guild.ShowLeave
|
||||
? "Saved - now sending messages here when someone leaves"
|
||||
: "Saved - stopping sending messages here when someone leaves"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("showdel", RunMode = RunMode.Async)]
|
||||
[Summary("Toggle - notify modchannel when someone deletes a message")]
|
||||
public async Task ShowDelete()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
var modChannel = await GetModChannel(guild.ModChannel.AsUlong());
|
||||
if (modChannel == null) return;
|
||||
|
||||
guild.ShowDelete = !guild.ShowDelete;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
await modChannel.SendMessageAsync(guild.ShowDelete
|
||||
? "Saved - now sending messages here when someone deletes a message"
|
||||
: "Saved - stopping sending messages here when someone deletes a message"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("setlang", RunMode = RunMode.Async)]
|
||||
[Summary("Change the bots language")]
|
||||
public async Task SetLanguage([Summary("language")] string languageRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
var language = languageRaw.ToUpper();
|
||||
var success = await _translation.SetLanguage(Context.Guild.Id, language);
|
||||
if (success)
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.Language = language;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
await ReplyAsync(transContext.GetString("NewLanguageSet"));
|
||||
return;
|
||||
}
|
||||
|
||||
await ReplyAsync(
|
||||
$"That doesn't seem to be a supported language\r\nSupported Languages are {string.Join(", ", _translation.SupportedLanguages)}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("wiki", RunMode = RunMode.Async)]
|
||||
[Summary("Change the wikipedia instance (use lang code in xx.wikipedia.org)")]
|
||||
public async Task SetWikiLanguage([Summary("language")] string languageRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
var language = languageRaw.ToLower();
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.WikiLang = language;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
await ReplyAsync($"Now using the {language} wikipedia");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("ping", RunMode = RunMode.Async)]
|
||||
[Summary("Enable the ping reply.")]
|
||||
public async Task TogglePing()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.Ping = !guild.Ping;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
await ReplyAsync(guild.Ping ? "i will reply to ping now" : "No more pongs...");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("hui", RunMode = RunMode.Async)]
|
||||
[Summary("Enable the ping reply.")]
|
||||
public async Task ToggleHui()
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = await GetGuildSettings(Context.Guild.Id);
|
||||
guild.Hui = !guild.Hui;
|
||||
_database.GuildSettings.Update(guild);
|
||||
await _database.SaveChangesAsync();
|
||||
await ReplyAsync(guild.Hui ? "i will reply to hui now" : "No more hui's...");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<GuildSettingsModel> GetGuildSettings(ulong guildId)
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildId.AsLong()));
|
||||
if (guild != null) return guild;
|
||||
Console.WriteLine("Adding non-exist Guild Settings to database");
|
||||
_database.GuildSettings.Add(new GuildSettingsModel()
|
||||
{
|
||||
GuildId = guildId.AsLong(),
|
||||
Hui = false,
|
||||
Ping = false,
|
||||
Language = "EN",
|
||||
ShowDelete = false,
|
||||
ShowLeave = false,
|
||||
WikiLang = "en"
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
return _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildId.AsLong()));
|
||||
}
|
||||
|
||||
private async Task<ISocketMessageChannel> GetModChannel(ulong channelId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(channelId == ulong.MinValue) throw new Exception();
|
||||
var modChannel = (ISocketMessageChannel) _client.GetChannel(channelId);
|
||||
if(modChannel == null) throw new Exception();
|
||||
return modChannel;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync(
|
||||
"Modchannel doesn't seem to exist, please set one with `!admin modchannel [channelId]`");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Lib.CommandPreconditions;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
|
||||
namespace Geekbot.net.Commands.Admin
|
||||
{
|
||||
[Group("mod")]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[DisableInDirectMessage]
|
||||
public class Mod : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public Mod(IUserRepository userRepositry, IErrorHandler errorHandler, DiscordSocketClient client)
|
||||
{
|
||||
_userRepository = userRepositry;
|
||||
_errorHandler = errorHandler;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
[Command("namehistory", RunMode = RunMode.Async)]
|
||||
[Summary("See past usernames of an user")]
|
||||
public async Task UsernameHistory([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userRepo = _userRepository.Get(user.Id);
|
||||
if (userRepo != null && userRepo.UsedNames != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($":bust_in_silhouette: {user.Username} has been known as:");
|
||||
foreach (var name in userRepo.UsedNames) sb.AppendLine($"- `{name.Name}`");
|
||||
await ReplyAsync(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync($"No name changes found for {user.Username}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
$"I don't have enough permissions do that");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.AlmostRedis;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
using Geekbot.net.Lib.RandomNumberGenerator;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Geekbot.net.Commands.Games
|
||||
{
|
||||
public class Roll : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IAlmostRedis _redis;
|
||||
private readonly ITranslationHandler _translation;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
||||
public Roll(IAlmostRedis redis, IErrorHandler errorHandler, ITranslationHandler translation, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
_redis = redis;
|
||||
_translation = translation;
|
||||
_database = database;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("roll", RunMode = RunMode.Async)]
|
||||
[Summary("Guess which number the bot will roll (1-100")]
|
||||
public async Task RollCommand([Remainder] [Summary("guess")] string stuff = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var number = _randomNumberGenerator.Next(1, 100);
|
||||
var guess = 1000;
|
||||
int.TryParse(stuff, out guess);
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
if (guess <= 100 && guess > 0)
|
||||
{
|
||||
var prevRoll = _redis.Db.HashGet($"{Context.Guild.Id}:RollsPrevious2", Context.Message.Author.Id).ToString()?.Split('|');
|
||||
if (prevRoll?.Length == 2)
|
||||
{
|
||||
if (prevRoll[0] == guess.ToString() && DateTime.Parse(prevRoll[1]) > DateTime.Now.AddDays(-1))
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NoPrevGuess", Context.Message.Author.Mention));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_redis.Db.HashSet($"{Context.Guild.Id}:RollsPrevious2", new[] {new HashEntry(Context.Message.Author.Id, $"{guess}|{DateTime.Now}")});
|
||||
|
||||
await ReplyAsync(transContext.GetString("Rolled", Context.Message.Author.Mention, number, guess));
|
||||
if (guess == number)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("Gratz", Context.Message.Author));
|
||||
_redis.Db.HashIncrement($"{Context.Guild.Id}:Rolls", Context.User.Id.ToString());
|
||||
var user = await GetUser(Context.User.Id);
|
||||
user.Rolls += 1;
|
||||
_database.Rolls.Update(user);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("RolledNoGuess", Context.Message.Author.Mention, number));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class Google : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public Google(IErrorHandler errorHandler, IGlobalSettings globalSettings)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
[Command("google", RunMode = RunMode.Async)]
|
||||
[Summary("Google Something.")]
|
||||
public async Task AskGoogle([Remainder, Summary("search-text")] string searchText)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
var apiKey = _globalSettings.GetKey("GoogleGraphKey");
|
||||
if (string.IsNullOrEmpty(apiKey))
|
||||
{
|
||||
await ReplyAsync("No Google API key has been set, please contact my owner");
|
||||
return;
|
||||
}
|
||||
|
||||
var url = new Uri($"https://kgsearch.googleapis.com/v1/entities:search?languages=en&limit=1&query={searchText}&key={apiKey}");
|
||||
var responseString = client.DownloadString(url);
|
||||
var response = JsonConvert.DeserializeObject<GoogleKgApiResponseDto>(responseString);
|
||||
|
||||
if (!response.ItemListElement.Any())
|
||||
{
|
||||
await ReplyAsync("No results were found...");
|
||||
return;
|
||||
}
|
||||
|
||||
var data = response.ItemListElement.First().Result;
|
||||
var eb = new EmbedBuilder
|
||||
{
|
||||
Title = data.Name
|
||||
};
|
||||
if(!string.IsNullOrEmpty(data.Description)) eb.WithDescription(data.Description);
|
||||
if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.Url)) eb.WithUrl(data.DetailedDtoDescription.Url);
|
||||
if(!string.IsNullOrEmpty(data.DetailedDtoDescription?.ArticleBody)) eb.AddField("Details", data.DetailedDtoDescription.ArticleBody);
|
||||
if(!string.IsNullOrEmpty(data.Image?.ContentUrl)) eb.WithThumbnailUrl(data.Image.ContentUrl);
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class GoogleKgApiDetailedDto
|
||||
{
|
||||
public string ArticleBody { get; set; }
|
||||
public string Url { get; set; }
|
||||
public string License { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class GoogleKgApiElementDto
|
||||
{
|
||||
public GoogleKgApiResultDto Result { get; set; }
|
||||
public double ResultScore { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class GoogleKgApiImageDto
|
||||
{
|
||||
public string ContentUrl { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class GoogleKgApiResponseDto
|
||||
{
|
||||
public List<GoogleKgApiElementDto> ItemListElement { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Integrations.Google
|
||||
{
|
||||
public class GoogleKgApiResultDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
public GoogleKgApiImageDto Image { get; set; }
|
||||
public GoogleKgApiDetailedDto DetailedDtoDescription { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.Clients;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations
|
||||
{
|
||||
public class Mal : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly IMalClient _malClient;
|
||||
|
||||
public Mal(IMalClient malClient, IErrorHandler errorHandler)
|
||||
{
|
||||
_malClient = malClient;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("anime", RunMode = RunMode.Async)]
|
||||
[Summary("Show Info about an Anime.")]
|
||||
public async Task SearchAnime([Remainder] [Summary("anime-name")] string animeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_malClient.IsLoggedIn())
|
||||
{
|
||||
var anime = await _malClient.GetAnime(animeName);
|
||||
if (anime != null)
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
|
||||
var description = HttpUtility.HtmlDecode(anime.Synopsis)
|
||||
.Replace("<br />", "")
|
||||
.Replace("[i]", "*")
|
||||
.Replace("[/i]", "*");
|
||||
|
||||
eb.Title = anime.Title;
|
||||
eb.Description = description;
|
||||
eb.ImageUrl = anime.Image;
|
||||
eb.AddInlineField("Premiered", $"{anime.StartDate}");
|
||||
eb.AddInlineField("Ended", anime.EndDate == "0000-00-00" ? "???" : anime.EndDate);
|
||||
eb.AddInlineField("Status", anime.Status);
|
||||
eb.AddInlineField("Episodes", anime.Episodes);
|
||||
eb.AddInlineField("MAL Score", anime.Score);
|
||||
eb.AddInlineField("Type", anime.Type);
|
||||
eb.AddField("MAL Link", $"https://myanimelist.net/anime/{anime.Id}");
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync("No anime found with that name...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(
|
||||
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
|
||||
}
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("manga", RunMode = RunMode.Async)]
|
||||
[Summary("Show Info about a Manga.")]
|
||||
public async Task SearchManga([Remainder] [Summary("manga-name")] string mangaName)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_malClient.IsLoggedIn())
|
||||
{
|
||||
var manga = await _malClient.GetManga(mangaName);
|
||||
if (manga != null)
|
||||
{
|
||||
var eb = new EmbedBuilder();
|
||||
|
||||
var description = HttpUtility.HtmlDecode(manga.Synopsis)
|
||||
.Replace("<br />", "")
|
||||
.Replace("[i]", "*")
|
||||
.Replace("[/i]", "*");
|
||||
|
||||
eb.Title = manga.Title;
|
||||
eb.Description = description;
|
||||
eb.ImageUrl = manga.Image;
|
||||
eb.AddInlineField("Premiered", $"{manga.StartDate}");
|
||||
eb.AddInlineField("Ended", manga.EndDate == "0000-00-00" ? "???" : manga.EndDate);
|
||||
eb.AddInlineField("Status", manga.Status);
|
||||
eb.AddInlineField("Volumes", manga.Volumes);
|
||||
eb.AddInlineField("Chapters", manga.Chapters);
|
||||
eb.AddInlineField("MAL Score", manga.Score);
|
||||
eb.AddField("MAL Link", $"https://myanimelist.net/manga/{manga.Id}");
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync("No manga found with that name...");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(
|
||||
"Unfortunally i'm not connected to MyAnimeList.net, please tell my senpai to connect me");
|
||||
}
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "The MyAnimeList.net API refused to answer");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanListItemDto
|
||||
{
|
||||
public string Definition { get; set; }
|
||||
public string Permalink { get; set; }
|
||||
public string ThumbsUp { get; set; }
|
||||
public string Word { get; set; }
|
||||
public string Example { get; set; }
|
||||
public string ThumbsDown { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
internal class UrbanResponseDto
|
||||
{
|
||||
public string[] Tags { get; set; }
|
||||
public List<UrbanListItemDto> List { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations.UbranDictionary
|
||||
{
|
||||
public class UrbanDictionary : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public UrbanDictionary(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("urban", RunMode = RunMode.Async)]
|
||||
[Summary("Lookup something on urban dictionary")]
|
||||
public async Task UrbanDefine([Remainder] [Summary("word")] string word)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://api.urbandictionary.com");
|
||||
var response = await client.GetAsync($"/v0/define?term={word}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var definitions = JsonConvert.DeserializeObject<UrbanResponseDto>(stringResponse);
|
||||
if (definitions.List.Count == 0)
|
||||
{
|
||||
await ReplyAsync("That word hasn't been defined...");
|
||||
return;
|
||||
}
|
||||
|
||||
var definition = definitions.List.First(e => !string.IsNullOrWhiteSpace(e.Example));
|
||||
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithAuthor(new EmbedAuthorBuilder
|
||||
{
|
||||
Name = definition.Word,
|
||||
Url = definition.Permalink
|
||||
});
|
||||
eb.WithColor(new Color(239, 255, 0));
|
||||
if (!string.IsNullOrEmpty(definition.Definition)) eb.Description = definition.Definition;
|
||||
if (!string.IsNullOrEmpty(definition.Example)) eb.AddField("Example", definition.Example ?? "(no example given...)");
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsUp)) eb.AddInlineField("Upvotes", definition.ThumbsUp);
|
||||
if (!string.IsNullOrEmpty(definition.ThumbsDown)) eb.AddInlineField("Downvotes", definition.ThumbsDown);
|
||||
if (definitions.Tags?.Length > 0) eb.AddField("Tags", string.Join(", ", definitions.Tags));
|
||||
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Google.Apis.Services;
|
||||
using Google.Apis.YouTube.v3;
|
||||
|
||||
namespace Geekbot.net.Commands.Integrations
|
||||
{
|
||||
public class Youtube : ModuleBase
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Youtube(IGlobalSettings globalSettings, IErrorHandler errorHandler)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("yt", RunMode = RunMode.Async)]
|
||||
[Summary("Search for something on youtube.")]
|
||||
public async Task Yt([Remainder] [Summary("title")] string searchQuery)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness.Cat
|
||||
{
|
||||
public class Cat : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Cat(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("cat", RunMode = RunMode.Async)]
|
||||
[Summary("Return a random image of a cat.")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.BaseAddress = new Uri("https://aws.random.cat");
|
||||
var response = await client.GetAsync("/meow");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var catFile = JsonConvert.DeserializeObject<CatResponseDto>(stringResponse);
|
||||
var eb = new EmbedBuilder();
|
||||
eb.ImageUrl = catFile.File;
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync("Seems like the dog cought the cat (error occured)");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Randomness.Cat
|
||||
{
|
||||
internal class CatResponseDto
|
||||
{
|
||||
public string File { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Media;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness
|
||||
{
|
||||
public class CheckEm : ModuleBase
|
||||
{
|
||||
private readonly IMediaProvider _checkEmImages;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public CheckEm(IMediaProvider mediaProvider, IErrorHandler errorHandler)
|
||||
{
|
||||
_checkEmImages = mediaProvider;
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("checkem", RunMode = RunMode.Async)]
|
||||
[Summary("Check for dubs")]
|
||||
public async Task MuhDubs()
|
||||
{
|
||||
try
|
||||
{
|
||||
var number = new Random().Next(10000000, 99999999);
|
||||
var dubtriqua = "";
|
||||
|
||||
var ns = GetIntArray(number);
|
||||
if (ns[7] == ns[6])
|
||||
{
|
||||
dubtriqua = "DUBS";
|
||||
if (ns[6] == ns[5])
|
||||
{
|
||||
dubtriqua = "TRIPS";
|
||||
if (ns[5] == ns[4])
|
||||
dubtriqua = "QUADS";
|
||||
}
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine($"Check em {Context.User.Mention}");
|
||||
sb.AppendLine($"**{number}**");
|
||||
if (!string.IsNullOrEmpty(dubtriqua))
|
||||
sb.AppendLine($":tada: {dubtriqua} :tada:");
|
||||
sb.AppendLine(_checkEmImages.GetCheckem());
|
||||
|
||||
await ReplyAsync(sb.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private int[] GetIntArray(int num)
|
||||
{
|
||||
var listOfInts = new List<int>();
|
||||
while (num > 0)
|
||||
{
|
||||
listOfInts.Add(num % 10);
|
||||
num = num / 10;
|
||||
}
|
||||
|
||||
listOfInts.Reverse();
|
||||
return listOfInts.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Randomness.Chuck
|
||||
{
|
||||
internal class ChuckNorrisJokeResponseDto
|
||||
{
|
||||
public string Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness.Chuck
|
||||
{
|
||||
public class ChuckNorrisJokes : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public ChuckNorrisJokes(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("chuck", RunMode = RunMode.Async)]
|
||||
[Summary("A random chuck norris joke")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
var response = await client.GetAsync("https://api.chucknorris.io/jokes/random");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var data = JsonConvert.DeserializeObject<ChuckNorrisJokeResponseDto>(stringResponse);
|
||||
await ReplyAsync(data.Value);
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
await ReplyAsync("Api down...");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Randomness.Dad
|
||||
{
|
||||
internal class DadJokeResponseDto
|
||||
{
|
||||
public string Joke { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness.Dad
|
||||
{
|
||||
public class DadJokes : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public DadJokes(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("dad", RunMode = RunMode.Async)]
|
||||
[Summary("A random dad joke")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
var response = await client.GetAsync("https://icanhazdadjoke.com/");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var data = JsonConvert.DeserializeObject<DadJokeResponseDto>(stringResponse);
|
||||
await ReplyAsync(data.Joke);
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
await ReplyAsync("Api down...");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness.Dog
|
||||
{
|
||||
public class Dog : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Dog(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("dog", RunMode = RunMode.Async)]
|
||||
[Summary("Return a random image of a dog.")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.BaseAddress = new Uri("http://random.dog");
|
||||
var response = await client.GetAsync("/woof.json");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var dogFile = JsonConvert.DeserializeObject<DogResponseDto>(stringResponse);
|
||||
var eb = new EmbedBuilder();
|
||||
eb.ImageUrl = dogFile.Url;
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
catch (HttpRequestException e)
|
||||
{
|
||||
await ReplyAsync($"Seems like the dog got lost (error occured)\r\n{e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Randomness.Dog
|
||||
{
|
||||
internal class DogResponseDto
|
||||
{
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness
|
||||
{
|
||||
public class EightBall : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public EightBall(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("8ball", RunMode = RunMode.Async)]
|
||||
[Summary("Ask 8Ball a Question.")]
|
||||
public async Task Ball([Remainder] [Summary("question")] string echo)
|
||||
{
|
||||
try
|
||||
{
|
||||
var replies = new List<string>
|
||||
{
|
||||
"It is certain",
|
||||
"It is decidedly so",
|
||||
"Without a doubt",
|
||||
"Yes, definitely",
|
||||
"You may rely on it",
|
||||
"As I see it, yes",
|
||||
"Most likely",
|
||||
"Outlook good",
|
||||
"Yes",
|
||||
"Signs point to yes",
|
||||
"Reply hazy try again",
|
||||
"Ask again later",
|
||||
"Better not tell you now",
|
||||
"Cannot predict now",
|
||||
"Concentrate and ask again",
|
||||
"Don't count on it",
|
||||
"My reply is no",
|
||||
"My sources say no",
|
||||
"Outlook not so good",
|
||||
"Very doubtful"
|
||||
};
|
||||
|
||||
var answer = new Random().Next(replies.Count);
|
||||
await ReplyAsync(replies[answer]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness
|
||||
{
|
||||
public class Gdq : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Gdq(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("gdq", RunMode = RunMode.Async)]
|
||||
[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,53 +0,0 @@
|
|||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Commands.Randomness.Dad;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Randomness.Kanye
|
||||
{
|
||||
public class Kanye : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Kanye(IErrorHandler errorHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
[Command("kanye", RunMode = RunMode.Async)]
|
||||
[Summary("A random kayne west quote")]
|
||||
public async Task Say()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.Accept.Clear();
|
||||
client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
||||
var response = await client.GetAsync("https://api.kanye.rest/");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var data = JsonConvert.DeserializeObject<KanyeResponseDto>(stringResponse);
|
||||
await ReplyAsync(data.Quote);
|
||||
}
|
||||
catch (HttpRequestException)
|
||||
{
|
||||
await ReplyAsync("Api down...");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Randomness.Kanye
|
||||
{
|
||||
public class KanyeResponseDto
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Quote { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.CommandPreconditions;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
|
||||
namespace Geekbot.net.Commands.User
|
||||
{
|
||||
[DisableInDirectMessage]
|
||||
public class Karma : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Karma(DatabaseContext database, IErrorHandler errorHandler, ITranslationHandler translation)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translation;
|
||||
}
|
||||
|
||||
[Command("good", RunMode = RunMode.Async)]
|
||||
[Summary("Increase Someones Karma")]
|
||||
public async Task Good([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotChangeOwn", Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
{
|
||||
var formatedWaitTime = transContext.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(transContext.GetString("WaitUntill", Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma = 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 = transContext.GetString("Increased");
|
||||
eb.AddInlineField(transContext.GetString("By"), Context.User.Username);
|
||||
eb.AddInlineField(transContext.GetString("Amount"), "+1");
|
||||
eb.AddInlineField(transContext.GetString("Current"), target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
[Command("bad", RunMode = RunMode.Async)]
|
||||
[Summary("Decrease Someones Karma")]
|
||||
public async Task Bad([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var actor = await GetUser(Context.User.Id);
|
||||
if (user.Id == Context.User.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotChangeOwn", Context.User.Username));
|
||||
}
|
||||
else if (TimeoutFinished(actor.TimeOut))
|
||||
{
|
||||
var formatedWaitTime = transContext.FormatDateTimeAsRemaining(actor.TimeOut.AddMinutes(3));
|
||||
await ReplyAsync(transContext.GetString("WaitUntill", Context.User.Username, formatedWaitTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
var target = await GetUser(user.Id);
|
||||
target.Karma = 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 = transContext.GetString("Decreased");
|
||||
eb.AddInlineField(transContext.GetString("By"), Context.User.Username);
|
||||
eb.AddInlineField(transContext.GetString("Amount"), "-1");
|
||||
eb.AddInlineField(transContext.GetString("Current"), target.Karma);
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TimeoutFinished(DateTimeOffset lastKarma)
|
||||
{
|
||||
return lastKarma.AddMinutes(3) > DateTimeOffset.Now;
|
||||
}
|
||||
|
||||
private async Task<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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Lib.CommandPreconditions;
|
||||
using Geekbot.net.Lib.Converters;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Highscores;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
|
||||
namespace Geekbot.net.Commands.User.Ranking
|
||||
{
|
||||
public class Rank : ModuleBase
|
||||
{
|
||||
private readonly IEmojiConverter _emojiConverter;
|
||||
private readonly IHighscoreManager _highscoreManager;
|
||||
private readonly ITranslationHandler _translationHandler;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public Rank(DatabaseContext database, IErrorHandler errorHandler, IUserRepository userRepository,
|
||||
IEmojiConverter emojiConverter, IHighscoreManager highscoreManager, ITranslationHandler translationHandler)
|
||||
{
|
||||
_database = database;
|
||||
_errorHandler = errorHandler;
|
||||
_userRepository = userRepository;
|
||||
_emojiConverter = emojiConverter;
|
||||
_highscoreManager = highscoreManager;
|
||||
_translationHandler = translationHandler;
|
||||
}
|
||||
|
||||
[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
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
HighscoreTypes type;
|
||||
try
|
||||
{
|
||||
type = Enum.Parse<HighscoreTypes>(typeUnformated, true);
|
||||
if (!Enum.IsDefined(typeof(HighscoreTypes), type)) throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("InvalidType"));
|
||||
return;
|
||||
}
|
||||
|
||||
var replyBuilder = new StringBuilder();
|
||||
if (amount > 20)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("LimitingTo20Warning"));
|
||||
amount = 20;
|
||||
}
|
||||
|
||||
var guildId = Context.Guild.Id;
|
||||
Dictionary<HighscoreUserDto, int> highscoreUsers;
|
||||
try
|
||||
{
|
||||
highscoreUsers = _highscoreManager.GetHighscoresWithUserData(type, guildId, amount);
|
||||
}
|
||||
catch (HighscoreListEmptyException)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NoTypeFoundForServer", type));
|
||||
return;
|
||||
}
|
||||
|
||||
int 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(transContext.GetString("FailedToResolveAllUsernames"));
|
||||
replyBuilder.AppendLine(transContext.GetString("HighscoresFor", type.ToString().CapitalizeFirst(), Context.Guild.Name));
|
||||
var highscorePlace = 1;
|
||||
foreach (var user in highscoreUsers)
|
||||
{
|
||||
replyBuilder.Append(highscorePlace < 11
|
||||
? $"{_emojiConverter.NumberToEmoji(highscorePlace)} "
|
||||
: $"`{highscorePlace}.` ");
|
||||
|
||||
replyBuilder.Append(user.Key.Username != null
|
||||
? $"**{user.Key.Username}#{user.Key.Discriminator}**"
|
||||
: $"**{user.Key.Id}**");
|
||||
|
||||
replyBuilder.Append(type == HighscoreTypes.messages
|
||||
? $" - {user.Value} {type} - {Math.Round((double) (100 * user.Value) / guildMessages, digits: 2)}%\n"
|
||||
: $" - {user.Value} {type}\n");
|
||||
|
||||
highscorePlace++;
|
||||
}
|
||||
|
||||
await ReplyAsync(replyBuilder.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Commands.Utils.Changelog
|
||||
{
|
||||
public class Changelog : ModuleBase
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
|
||||
public Changelog(IErrorHandler errorHandler, DiscordSocketClient client)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
[Command("changelog", RunMode = RunMode.Async)]
|
||||
[Summary("Show the latest 10 updates")]
|
||||
public async Task GetChangelog()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://api.github.com");
|
||||
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent",
|
||||
"http://developer.github.com/v3/#user-agent-required");
|
||||
var response = await client.GetAsync("/repos/pizzaandcoffee/geekbot.net/commits");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await response.Content.ReadAsStringAsync();
|
||||
var commits = JsonConvert.DeserializeObject<List<CommitDto>>(stringResponse);
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithColor(new Color(143, 165, 102));
|
||||
eb.WithAuthor(new EmbedAuthorBuilder
|
||||
{
|
||||
IconUrl = _client.CurrentUser.GetAvatarUrl(),
|
||||
Name = "Latest Updates",
|
||||
Url = "https://geekbot.pizzaandcoffee.rocks/updates"
|
||||
});
|
||||
var sb = new StringBuilder();
|
||||
foreach (var commit in commits.Take(10))
|
||||
sb.AppendLine($"- {commit.Commit.Message} ({commit.Commit.Author.Date:yyyy-MM-dd})");
|
||||
eb.Description = sb.ToString();
|
||||
eb.WithFooter(new EmbedFooterBuilder
|
||||
{
|
||||
Text = $"List generated from github commits on {DateTime.Now:yyyy-MM-dd}"
|
||||
});
|
||||
await ReplyAsync("", false, eb.Build());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.net.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitAuthorDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Email { get; set; }
|
||||
public DateTimeOffset Date { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitDto
|
||||
{
|
||||
public CommitInfoDto Commit { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Utils.Changelog
|
||||
{
|
||||
public class CommitInfoDto
|
||||
{
|
||||
public CommitAuthorDto Author { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
|
||||
namespace Geekbot.net.Commands.Utils
|
||||
{
|
||||
public class Choose : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly ITranslationHandler _translation;
|
||||
|
||||
public Choose(IErrorHandler errorHandler, ITranslationHandler translation)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_translation = translation;
|
||||
}
|
||||
|
||||
[Command("choose", RunMode = RunMode.Async)]
|
||||
[Summary("Let the bot choose for you, seperate options with a semicolon.")]
|
||||
public async Task Command([Remainder] [Summary("option1;option2")]
|
||||
string choices)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translation.GetGuildContext(Context);
|
||||
var choicesArray = choices.Split(';');
|
||||
var choice = new Random().Next(choicesArray.Length);
|
||||
await ReplyAsync(transContext.GetString("Choice", choicesArray[choice].Trim()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Lib.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.net.Commands.Utils.Dice
|
||||
{
|
||||
public class Dice : ModuleBase
|
||||
{
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
|
||||
public Dice(IRandomNumberGenerator randomNumberGenerator)
|
||||
{
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
}
|
||||
|
||||
[Command("dice", RunMode = RunMode.Async)]
|
||||
[Summary("Roll a dice.")]
|
||||
public async Task RollCommand([Remainder] [Summary("dice-type")] string diceType = "1d20")
|
||||
{
|
||||
var splitedDices = diceType.Split("+");
|
||||
var dices = new List<DiceTypeDto>();
|
||||
var mod = 0;
|
||||
foreach (var i in splitedDices)
|
||||
{
|
||||
var dice = ToDice(i);
|
||||
if (dice.Sides != 0 && dice.Times != 0)
|
||||
{
|
||||
dices.Add(dice);
|
||||
}
|
||||
else if (dice.Mod != 0)
|
||||
{
|
||||
if (mod != 0)
|
||||
{
|
||||
await ReplyAsync("You can only have one mod");
|
||||
return;
|
||||
}
|
||||
|
||||
mod = dice.Mod;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dices.Any())
|
||||
{
|
||||
await ReplyAsync(
|
||||
"That is not a valid dice, examples are: 1d20, 1d6, 2d6, 1d6+2, 1d6+2d8+1d20+6, etc...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (dices.Any(d => d.Times > 20))
|
||||
{
|
||||
await ReplyAsync("You can't throw more than 20 dices");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dices.Any(d => d.Sides > 144))
|
||||
{
|
||||
await ReplyAsync("A dice can't have more than 144 sides");
|
||||
return;
|
||||
}
|
||||
|
||||
var rep = new StringBuilder();
|
||||
rep.AppendLine($":game_die: {Context.User.Mention}");
|
||||
rep.Append("**Result:** ");
|
||||
var resultStrings = new List<string>();
|
||||
var total = 0;
|
||||
var extraText = "";
|
||||
foreach (var dice in dices)
|
||||
{
|
||||
var results = new List<int>();
|
||||
for (var i = 0; i < dice.Times; i++)
|
||||
{
|
||||
var roll = _randomNumberGenerator.Next(1, dice.Sides);
|
||||
total += roll;
|
||||
results.Add(roll);
|
||||
if (roll == dice.Sides) extraText = "**Critical Hit!**";
|
||||
if (roll == 1) extraText = "**Critical Fail!**";
|
||||
}
|
||||
|
||||
resultStrings.Add($"{dice.DiceType} ({string.Join(",", results)})");
|
||||
}
|
||||
|
||||
rep.Append(string.Join(" + ", resultStrings));
|
||||
if (mod != 0)
|
||||
{
|
||||
rep.Append($" + {mod}");
|
||||
total += mod;
|
||||
}
|
||||
|
||||
rep.AppendLine();
|
||||
rep.AppendLine($"**Total:** {total}");
|
||||
if (extraText != "") rep.AppendLine(extraText);
|
||||
await ReplyAsync(rep.ToString());
|
||||
}
|
||||
|
||||
private DiceTypeDto ToDice(string dice)
|
||||
{
|
||||
var diceParts = dice.Split('d');
|
||||
if (diceParts.Length == 2
|
||||
&& int.TryParse(diceParts[0], out var times)
|
||||
&& int.TryParse(diceParts[1], out var max))
|
||||
return new DiceTypeDto
|
||||
{
|
||||
DiceType = dice,
|
||||
Times = times,
|
||||
Sides = max
|
||||
};
|
||||
if (dice.Length == 1
|
||||
&& int.TryParse(diceParts[0], out var mod))
|
||||
return new DiceTypeDto
|
||||
{
|
||||
Mod = mod
|
||||
};
|
||||
return new DiceTypeDto();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Geekbot.net.Commands.Utils.Dice
|
||||
{
|
||||
internal class DiceTypeDto
|
||||
{
|
||||
public string DiceType { get; set; }
|
||||
public int Times { get; set; }
|
||||
public int Sides { get; set; }
|
||||
public int Mod { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,254 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.CommandPreconditions;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
using Geekbot.net.Lib.Polyfills;
|
||||
using Geekbot.net.Lib.RandomNumberGenerator;
|
||||
|
||||
namespace Geekbot.net.Commands.Utils.Quote
|
||||
{
|
||||
[Group("quote")]
|
||||
[DisableInDirectMessage]
|
||||
public class Quote : ModuleBase
|
||||
{
|
||||
private readonly IErrorHandler _errorHandler;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IRandomNumberGenerator _randomNumberGenerator;
|
||||
private readonly ITranslationHandler _translationHandler;
|
||||
|
||||
public Quote(IErrorHandler errorHandler, DatabaseContext database, IRandomNumberGenerator randomNumberGenerator, ITranslationHandler translationHandler)
|
||||
{
|
||||
_errorHandler = errorHandler;
|
||||
_database = database;
|
||||
_randomNumberGenerator = randomNumberGenerator;
|
||||
_translationHandler = translationHandler;
|
||||
}
|
||||
|
||||
[Command]
|
||||
[Summary("Return a random quoute from the database")]
|
||||
public async Task GetRandomQuote()
|
||||
{
|
||||
try
|
||||
{
|
||||
var s = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong())).ToList();
|
||||
|
||||
if (!s.Any())
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
await ReplyAsync(transContext.GetString("NoQuotesFound"));
|
||||
return;
|
||||
}
|
||||
|
||||
var random = _randomNumberGenerator.Next(0, s.Count());
|
||||
var quote = s[random];
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "Whoops, seems like the quote was to edgy to return");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("save")]
|
||||
[Summary("Save a quote from the last sent message by @user")]
|
||||
public async Task SaveQuote([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
if (user.Id == Context.Message.Author.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotSaveOwnQuotes"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.IsBot)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotQuoteBots"));
|
||||
return;
|
||||
}
|
||||
|
||||
var lastMessage = await GetLastMessageByUser(user);
|
||||
if (lastMessage == null) return;
|
||||
|
||||
var quote = CreateQuoteObject(lastMessage);
|
||||
_database.Quotes.Add(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("QuoteAdded"), false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I counldn't find a quote from that user :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("save")]
|
||||
[Summary("Save a quote from a message id")]
|
||||
public async Task SaveQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||
if (message.Author.Id == Context.Message.Author.Id)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotSaveOwnQuotes"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Author.IsBot)
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("CannotQuoteBots"));
|
||||
return;
|
||||
}
|
||||
|
||||
var quote = CreateQuoteObject(message);
|
||||
_database.Quotes.Add(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("QuoteAdded"), false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I couldn't find a message with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("make")]
|
||||
[Summary("Create a quote from the last sent message by @user")]
|
||||
public async Task ReturnSpecifiedQuote([Summary("@someone")] IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lastMessage = await GetLastMessageByUser(user);
|
||||
if (lastMessage == null) return;
|
||||
var quote = CreateQuoteObject(lastMessage);
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I counldn't find a quote from that user :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("make")]
|
||||
[Summary("Create a quote from a message id")]
|
||||
public async Task ReturnSpecifiedQuote([Summary("message-ID")] ulong messageId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var message = await Context.Channel.GetMessageAsync(messageId);
|
||||
var quote = CreateQuoteObject(message);
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync("", false, embed.Build());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context,
|
||||
"I couldn't find a message with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
[Command("remove")]
|
||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||
[Summary("Remove a quote (required mod permissions)")]
|
||||
public async Task RemoveQuote([Summary("quote-ID")] int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var transContext = await _translationHandler.GetGuildContext(Context);
|
||||
var quote = _database.Quotes.Where(e => e.GuildId == Context.Guild.Id.AsLong() && e.InternalId == id)?.FirstOrDefault();
|
||||
if (quote != null)
|
||||
{
|
||||
_database.Quotes.Remove(quote);
|
||||
await _database.SaveChangesAsync();
|
||||
var embed = QuoteBuilder(quote);
|
||||
await ReplyAsync(transContext.GetString("Removed", id), false, embed.Build());
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyAsync(transContext.GetString("NotFoundWithId"));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await _errorHandler.HandleCommandException(e, Context, "I couldn't find a quote with that id :disappointed:");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IMessage> GetLastMessageByUser(IUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = Context.Channel.GetMessagesAsync().Flatten();
|
||||
return await list.FirstOrDefault(msg =>
|
||||
msg.Author.Id == user.Id &&
|
||||
msg.Embeds.Count == 0 &&
|
||||
msg.Id != Context.Message.Id &&
|
||||
!msg.Content.ToLower().StartsWith("!"));
|
||||
}
|
||||
catch
|
||||
{
|
||||
await ReplyAsync($"No quoteable message have been sent by {user.Username} in this channel");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private EmbedBuilder QuoteBuilder(QuoteModel quote)
|
||||
{
|
||||
var user = Context.Client.GetUserAsync(quote.UserId.AsUlong()).Result ?? new UserPolyfillDto { Username = "Unknown User" };
|
||||
var eb = new EmbedBuilder();
|
||||
eb.WithColor(new Color(143, 167, 232));
|
||||
eb.Title = $"#{quote.InternalId} | {user.Username} @ {quote.Time.Day}.{quote.Time.Month}.{quote.Time.Year}";
|
||||
eb.Description = quote.Quote;
|
||||
eb.ThumbnailUrl = user.GetAvatarUrl();
|
||||
if (quote.Image != null) eb.ImageUrl = quote.Image;
|
||||
return eb;
|
||||
}
|
||||
|
||||
private QuoteModel CreateQuoteObject(IMessage message)
|
||||
{
|
||||
string image;
|
||||
try
|
||||
{
|
||||
image = message.Attachments.First().Url;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
image = null;
|
||||
}
|
||||
|
||||
var last = _database.Quotes.Where(e => e.GuildId.Equals(Context.Guild.Id.AsLong()))
|
||||
.OrderByDescending(e => e.InternalId).FirstOrDefault();
|
||||
int internalId = 1;
|
||||
if (last != null) internalId = last.InternalId + 1;
|
||||
return new QuoteModel()
|
||||
{
|
||||
InternalId = internalId,
|
||||
GuildId = Context.Guild.Id.AsLong(),
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
Time = message.Timestamp.DateTime,
|
||||
Quote = message.Content,
|
||||
Image = image
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Geekbot.net.Database.Models
|
||||
{
|
||||
public class GuildsModel
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public long GuildId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Required]
|
||||
public long Owner { get; set; }
|
||||
|
||||
public string IconUrl { get; set; }
|
||||
|
||||
public DateTimeOffset CreatedAt { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Geekbot.net.Database.Models
|
||||
{
|
||||
public class PollModel
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public long GuildId { get; set; }
|
||||
|
||||
[Required]
|
||||
public long ChannelId { get; set; }
|
||||
|
||||
public string Question { get; set; }
|
||||
|
||||
public long Creator { get; set; }
|
||||
|
||||
public long MessageId { get; set; }
|
||||
|
||||
public List<PollQuestionModel> Options { get; set; }
|
||||
|
||||
public bool IsFinshed { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Geekbot.net.Database.Models
|
||||
{
|
||||
public class PollQuestionModel
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public int OptionId { get; set; }
|
||||
|
||||
public string OptionText { get; set; }
|
||||
|
||||
public int Votes { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Geekbot.net.Database.Models
|
||||
{
|
||||
public class UserUsedNamesModel
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public DateTimeOffset FirstSeen { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace Geekbot.net.Database
|
||||
{
|
||||
public class SqlConnectionString
|
||||
{
|
||||
public string Host { get; set; }
|
||||
public string Port { get; set; }
|
||||
public string Database { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Server={Host};Port={Port};Database={Database};Uid={Username};Pwd={Password};";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<ApplicationIcon>derp.ico</ApplicationIcon>
|
||||
<Version>4.1.0</Version>
|
||||
<VersionSuffix>$(VersionSuffix)</VersionSuffix>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(Version)-$(VersionSuffix)</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">$(Version)-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>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.4.3" />
|
||||
<PackageReference Include="Discord.Net">
|
||||
<Version>2.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.38.0.1488" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.9.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.Redis" Version="0.4.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Cors" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="2.2.0" />
|
||||
<PackageReference Include="MtgApiManager.Lib" Version="1.2.1" />
|
||||
<PackageReference Include="MyAnimeListSharp" Version="1.3.4" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
|
||||
<PackageReference Include="NLog" Version="4.5.11" />
|
||||
<PackageReference Include="NLog.Config" Version="4.5.11" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.2.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="2.0.0-preview1" />
|
||||
<PackageReference Include="PokeApi.NET" Version="1.1.1" />
|
||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||
<PackageReference Include="SumoLogic.Logging.NLog" Version="1.0.1.1" />
|
||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Json">
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Runtime.Serialization.Primitives">
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Utf8Json" Version="1.3.7" />
|
||||
<PackageReference Include="YamlDotNet" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Storage\checkEmPics">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\croissant">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\fortunes">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\pandas">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\pumpkin">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\squirrel">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\turtles">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\pinguins">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\foxes">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Lib\Converters\MtgManaEmojis.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Storage\dab">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Lib\Localization\Translations.yml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WikipediaApi\WikipediaApi.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,264 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Rest;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.AlmostRedis;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Geekbot.net.Lib.ReactionListener;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Geekbot.net
|
||||
{
|
||||
public class Handlers
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IDiscordClient _client;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly IAlmostRedis _redis;
|
||||
private readonly IServiceProvider _servicesProvider;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IReactionListener _reactionListener;
|
||||
private readonly DatabaseContext _messageCounterDatabaseContext;
|
||||
|
||||
public Handlers(DatabaseInitializer databaseInitializer, IDiscordClient client, IGeekbotLogger logger, IAlmostRedis redis,
|
||||
IServiceProvider servicesProvider, CommandService commands, IUserRepository userRepository,
|
||||
IReactionListener reactionListener)
|
||||
{
|
||||
_database = databaseInitializer.Initialize();
|
||||
_messageCounterDatabaseContext = databaseInitializer.Initialize();
|
||||
_client = client;
|
||||
_logger = logger;
|
||||
_redis = redis;
|
||||
_servicesProvider = servicesProvider;
|
||||
_commands = commands;
|
||||
_userRepository = userRepository;
|
||||
_reactionListener = reactionListener;
|
||||
}
|
||||
|
||||
//
|
||||
// Incoming Messages
|
||||
//
|
||||
|
||||
public Task RunCommand(SocketMessage messageParam)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask;
|
||||
if (message.Author.IsBot) return Task.CompletedTask;
|
||||
var argPos = 0;
|
||||
|
||||
var lowCaseMsg = message.ToString().ToLower();
|
||||
if (lowCaseMsg.StartsWith("hui"))
|
||||
{
|
||||
var hasPing = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(((SocketGuildChannel) message.Channel).Guild.Id.AsLong()))?.Hui ?? false;
|
||||
if (hasPing)
|
||||
{
|
||||
message.Channel.SendMessageAsync("hui!!!");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
if (lowCaseMsg.StartsWith("ping ") || lowCaseMsg.Equals("ping"))
|
||||
{
|
||||
var hasPing = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(((SocketGuildChannel) message.Channel).Guild.Id.AsLong()))?.Ping ?? false;
|
||||
if (hasPing)
|
||||
{
|
||||
message.Channel.SendMessageAsync("pong");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(message.HasCharPrefix('!', ref argPos) ||
|
||||
message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return Task.CompletedTask;
|
||||
var context = new CommandContext(_client, message);
|
||||
var commandExec = _commands.ExecuteAsync(context, argPos, _servicesProvider);
|
||||
_logger.Information(LogSource.Command,
|
||||
context.Message.Content.Split(" ")[0].Replace("!", ""),
|
||||
SimpleConextConverter.ConvertContext(context));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to Process Message", e);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateStats(SocketMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (message == null) return;
|
||||
if (message.Channel.Name.StartsWith('@'))
|
||||
{
|
||||
_logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message, true));
|
||||
return;
|
||||
}
|
||||
|
||||
var channel = (SocketGuildChannel) message.Channel;
|
||||
|
||||
// just testing, redis will remain the source of truth for now
|
||||
var rowId = await _messageCounterDatabaseContext.Database.ExecuteSqlCommandAsync(
|
||||
"UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}",
|
||||
channel.Guild.Id.AsLong(),
|
||||
message.Author.Id.AsLong()
|
||||
);
|
||||
|
||||
if (rowId == 0)
|
||||
{
|
||||
_messageCounterDatabaseContext.Messages.Add(new MessagesModel
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
MessageCount = 1
|
||||
});
|
||||
_messageCounterDatabaseContext.SaveChanges();
|
||||
}
|
||||
|
||||
await _redis.Db.HashIncrementAsync($"{channel.Guild.Id}:Messages", message.Author.Id.ToString());
|
||||
await _redis.Db.HashIncrementAsync($"{channel.Guild.Id}:Messages", 0.ToString());
|
||||
|
||||
if (message.Author.IsBot) return;
|
||||
_logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Message, "Could not process message stats", e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// User Stuff
|
||||
//
|
||||
|
||||
public async Task UserJoined(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userRepoUpdate = _userRepository.Update(user);
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
|
||||
if (!user.IsBot)
|
||||
{
|
||||
var guildSettings = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId == user.Guild.Id.AsLong());
|
||||
var message = guildSettings?.WelcomeMessage;
|
||||
if (string.IsNullOrEmpty(message)) return;
|
||||
message = message.Replace("$user", user.Mention);
|
||||
|
||||
var fallbackSender = new Func<Task<RestUserMessage>>(() => user.Guild.DefaultChannel.SendMessageAsync(message));
|
||||
if (guildSettings.WelcomeChannel != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var target = await _client.GetChannelAsync(guildSettings.WelcomeChannel.AsUlong());
|
||||
var channel = target as ISocketMessageChannel;
|
||||
await channel.SendMessageAsync(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message to user defined welcome channel", e);
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
|
||||
await userRepoUpdate;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message", e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UserUpdated(SocketUser oldUser, SocketUser newUser)
|
||||
{
|
||||
await _userRepository.Update(newUser);
|
||||
}
|
||||
|
||||
public async Task UserLeft(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g =>
|
||||
g.GuildId.Equals(user.Guild.Id.AsLong()));
|
||||
if (guild?.ShowLeave ?? false)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send leave message", e);
|
||||
}
|
||||
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
}
|
||||
|
||||
//
|
||||
// Message Stuff
|
||||
//
|
||||
|
||||
public async Task MessageDeleted(Cacheable<IMessage, ulong> message, ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guildSocketData = ((IGuildChannel) channel).Guild;
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildSocketData.Id.AsLong()));
|
||||
if ((guild?.ShowDelete ?? false) && guild?.ModChannel != 0)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
var sb = new StringBuilder();
|
||||
if (message.Value != null)
|
||||
{
|
||||
sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>");
|
||||
sb.AppendLine(message.Value.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("Someone deleted a message, the message was not cached...");
|
||||
}
|
||||
|
||||
await modChannelSocket.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send delete message...", e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Reactions
|
||||
//
|
||||
|
||||
public Task ReactionAdded(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.GiveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ReactionRemoved(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.RemoveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Geekbot.net.Lib.AlmostRedis
|
||||
{
|
||||
// if anyone ever sees this, please come up with a better fucking name, i'd appriciate it
|
||||
public class AlmostRedis : IAlmostRedis
|
||||
{
|
||||
private readonly GeekbotLogger _logger;
|
||||
private readonly RunParameters _runParameters;
|
||||
|
||||
public AlmostRedis(GeekbotLogger logger, RunParameters runParameters)
|
||||
{
|
||||
_logger = logger;
|
||||
_runParameters = runParameters;
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
Connection = ConnectionMultiplexer.Connect($"{_runParameters.RedisHost}:{_runParameters.RedisPort}");
|
||||
Db = Connection.GetDatabase(int.Parse(_runParameters.RedisDatabase));
|
||||
_logger.Information(LogSource.Redis, $"Connected to Redis on {Connection.Configuration} at {Db.Database}");
|
||||
}
|
||||
|
||||
public IDatabase Db { get; private set; }
|
||||
|
||||
public ConnectionMultiplexer Connection { get; private set; }
|
||||
|
||||
public IEnumerable<RedisKey> GetAllKeys()
|
||||
{
|
||||
return Connection.GetServer($"{_runParameters.RedisHost}:{_runParameters.RedisPort}").Keys(int.Parse(_runParameters.RedisDatabase));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Geekbot.net.Lib.AlmostRedis
|
||||
{
|
||||
public interface IAlmostRedis
|
||||
{
|
||||
void Connect();
|
||||
IDatabase Db { get; }
|
||||
ConnectionMultiplexer Connection { get; }
|
||||
IEnumerable<RedisKey> GetAllKeys();
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using MyAnimeListSharp.Core;
|
||||
|
||||
namespace Geekbot.net.Lib.Clients
|
||||
{
|
||||
public interface IMalClient
|
||||
{
|
||||
bool IsLoggedIn();
|
||||
Task<AnimeEntry> GetAnime(string query);
|
||||
Task<MangaEntry> GetManga(string query);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using MyAnimeListSharp.Auth;
|
||||
using MyAnimeListSharp.Core;
|
||||
using MyAnimeListSharp.Facade.Async;
|
||||
|
||||
namespace Geekbot.net.Lib.Clients
|
||||
{
|
||||
public class MalClient : IMalClient
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private ICredentialContext _credentials;
|
||||
private AnimeSearchMethodsAsync _animeSearch;
|
||||
private MangaSearchMethodsAsync _mangaSearch;
|
||||
|
||||
public MalClient(IGlobalSettings globalSettings, IGeekbotLogger logger)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_logger = logger;
|
||||
ReloadClient();
|
||||
}
|
||||
|
||||
public bool ReloadClient()
|
||||
{
|
||||
var malCredentials = _globalSettings.GetKey("MalCredentials");
|
||||
if (!string.IsNullOrEmpty(malCredentials))
|
||||
{
|
||||
var credSplit = malCredentials.Split('|');
|
||||
_credentials = new CredentialContext()
|
||||
{
|
||||
UserName = credSplit[0],
|
||||
Password = credSplit[1]
|
||||
};
|
||||
_animeSearch = new AnimeSearchMethodsAsync(_credentials);
|
||||
_mangaSearch = new MangaSearchMethodsAsync(_credentials);
|
||||
_logger.Debug(LogSource.Geekbot, "Logged in to MAL");
|
||||
return true;
|
||||
}
|
||||
_logger.Debug(LogSource.Geekbot, "No MAL Credentials Set!");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public bool IsLoggedIn()
|
||||
{
|
||||
return _credentials != null;
|
||||
}
|
||||
|
||||
public async Task<AnimeEntry> GetAnime(string query)
|
||||
{
|
||||
var response = await _animeSearch.SearchDeserializedAsync(query);
|
||||
return response.Entries.Count == 0 ? null : response.Entries[0];
|
||||
}
|
||||
|
||||
public async Task<MangaEntry> GetManga(string query)
|
||||
{
|
||||
var response = await _mangaSearch.SearchDeserializedAsync(query);
|
||||
return response.Entries.Count == 0 ? null : response.Entries[0];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace Geekbot.net.Lib.Converters
|
||||
{
|
||||
public class EmojiConverter : IEmojiConverter
|
||||
{
|
||||
public string NumberToEmoji(int number)
|
||||
{
|
||||
if (number == 10)
|
||||
{
|
||||
return "🔟";
|
||||
}
|
||||
var emojiMap = new[]
|
||||
{
|
||||
":zero:",
|
||||
":one:",
|
||||
":two:",
|
||||
":three:",
|
||||
":four:",
|
||||
":five:",
|
||||
":six:",
|
||||
":seven:",
|
||||
":eight:",
|
||||
":nine:"
|
||||
};
|
||||
var numbers = number.ToString().ToCharArray();
|
||||
var returnString = new StringBuilder();
|
||||
foreach (var n in numbers)
|
||||
{
|
||||
returnString.Append(emojiMap[int.Parse(n.ToString())]);
|
||||
}
|
||||
return returnString.ToString();
|
||||
}
|
||||
|
||||
public string TextToEmoji(string text)
|
||||
{
|
||||
var emojiMap = new Hashtable
|
||||
{
|
||||
['A'] = ":regional_indicator_a: ",
|
||||
['B'] = ":b: ",
|
||||
['C'] = ":regional_indicator_c: ",
|
||||
['D'] = ":regional_indicator_d: ",
|
||||
['E'] = ":regional_indicator_e: ",
|
||||
['F'] = ":regional_indicator_f: ",
|
||||
['G'] = ":regional_indicator_g: ",
|
||||
['H'] = ":regional_indicator_h: ",
|
||||
['I'] = ":regional_indicator_i: ",
|
||||
['J'] = ":regional_indicator_j: ",
|
||||
['K'] = ":regional_indicator_k: ",
|
||||
['L'] = ":regional_indicator_l: ",
|
||||
['M'] = ":regional_indicator_m: ",
|
||||
['N'] = ":regional_indicator_n: ",
|
||||
['O'] = ":regional_indicator_o: ",
|
||||
['P'] = ":regional_indicator_p: ",
|
||||
['Q'] = ":regional_indicator_q: ",
|
||||
['R'] = ":regional_indicator_r: ",
|
||||
['S'] = ":regional_indicator_s: ",
|
||||
['T'] = ":regional_indicator_t: ",
|
||||
['U'] = ":regional_indicator_u: ",
|
||||
['V'] = ":regional_indicator_v: ",
|
||||
['W'] = ":regional_indicator_w: ",
|
||||
['X'] = ":regional_indicator_x: ",
|
||||
['Y'] = ":regional_indicator_y: ",
|
||||
['Z'] = ":regional_indicator_z: ",
|
||||
['!'] = ":exclamation: ",
|
||||
['?'] = ":question: ",
|
||||
['#'] = ":hash: ",
|
||||
['*'] = ":star2: ",
|
||||
['+'] = ":heavy_plus_sign: ",
|
||||
['0'] = ":zero: ",
|
||||
['1'] = ":one: ",
|
||||
['2'] = ":two: ",
|
||||
['3'] = ":three: ",
|
||||
['4'] = ":four: ",
|
||||
['5'] = ":five: ",
|
||||
['6'] = ":six: ",
|
||||
['7'] = ":seven: ",
|
||||
['8'] = ":eight: ",
|
||||
['9'] = ":nine: ",
|
||||
[' '] = " "
|
||||
};
|
||||
var letters = text.ToUpper().ToCharArray();
|
||||
var returnString = new StringBuilder();
|
||||
foreach (var n in letters)
|
||||
{
|
||||
var emoji = emojiMap[n] ?? n;
|
||||
returnString.Append(emoji);
|
||||
}
|
||||
return returnString.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace Geekbot.net.Lib.Converters
|
||||
{
|
||||
public interface IEmojiConverter
|
||||
{
|
||||
string NumberToEmoji(int number);
|
||||
string TextToEmoji(string text);
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Utf8Json;
|
||||
|
||||
namespace Geekbot.net.Lib.Converters
|
||||
{
|
||||
public class MtgManaConverter : IMtgManaConverter
|
||||
{
|
||||
private Dictionary<string, string> _manaDict;
|
||||
|
||||
public MtgManaConverter()
|
||||
{
|
||||
// these emotes can be found at https://discord.gg/bz8HyA7
|
||||
var mtgEmojis = File.ReadAllText(Path.GetFullPath("./Lib/Converters/MtgManaEmojis.json"));
|
||||
_manaDict = JsonSerializer.Deserialize<Dictionary<string, string>>(mtgEmojis);
|
||||
}
|
||||
|
||||
public string ConvertMana(string mana)
|
||||
{
|
||||
var rgx = Regex.Matches(mana, @"(\{(.*?)\})");
|
||||
foreach (Match manaTypes in rgx)
|
||||
{
|
||||
var m = _manaDict.GetValueOrDefault(manaTypes.Value);
|
||||
if (!string.IsNullOrEmpty(m))
|
||||
{
|
||||
mana = mana.Replace(manaTypes.Value, m);
|
||||
}
|
||||
}
|
||||
return mana;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
{
|
||||
"{0}": "<:mtg_0:415216130043412482>",
|
||||
"{1}": "<:mtg_1:415216130253389835>",
|
||||
"{2}": "<:mtg_2:415216130031091713>",
|
||||
"{3}": "<:mtg_3:415216130467037194>",
|
||||
"{4}": "<:mtg_4:415216130026635295>",
|
||||
"{5}": "<:mtg_5:415216130492203008>",
|
||||
"{6}": "<:mtg_6:415216130458779658>",
|
||||
"{7}": "<:mtg_7:415216130190475265>",
|
||||
"{8}": "<:mtg_8:415216130517630986>",
|
||||
"{9}": "<:mtg_9:415216130500722689>",
|
||||
"{10": "<:mtg_10:415216130450391051>",
|
||||
"{11}": "<:mtg_11:415216130811101185>",
|
||||
"{12}": "<:mtg_12:415216130525888532>",
|
||||
"{13}": "<:mtg_13:415216130517631000>",
|
||||
"{14}": "<:mtg_14:415216130165178370>",
|
||||
"{15}": "<:mtg_15:415216130576089108>",
|
||||
"{16}": "<:mtg_16:415216130358247425>",
|
||||
"{17}": "<:mtg_17:415216130601517056>",
|
||||
"{18}": "<:mtg_18:415216130462842891>",
|
||||
"{19}": "<:mtg_19:415216130614099988>",
|
||||
"{20}": "<:mtg_20:415216130656043038>",
|
||||
"{W}": "<:mtg_white:415216131515744256>",
|
||||
"{U}": "<:mtg_blue:415216130521694209>",
|
||||
"{B}": "<:mtg_black:415216130873884683>",
|
||||
"{R}": "<:mtg_red:415216131322806272>",
|
||||
"{G}": "<:mtg_green:415216131180331009>",
|
||||
"{S}": "<:mtg_s:415216131293446144>",
|
||||
"{T}": "<:mtg_tap:415258392727257088>",
|
||||
"{C}": "<:mtg_colorless:415216130706374666>",
|
||||
"{2/W}": "<:mtg_2w:415216130446065664>",
|
||||
"{2/U}": "<:mtg_2u:415216130429550592>",
|
||||
"{2/B}": "<:mtg_2b:415216130160984065>",
|
||||
"{2/R}": "<:mtg_2r:415216130454716436>",
|
||||
"{2/G}": "<:mtg_2g:415216130420899840>",
|
||||
"{W/U}": "<:mtg_wu:415216130970484736>",
|
||||
"{W/B}": "<:mtg_wb:415216131222011914>",
|
||||
"{U/R}": "<:mtg_ur:415216130962096128>",
|
||||
"{U/B}": "<:mtg_ub:415216130865758218>",
|
||||
"{R/W}": "<:mtg_rw:415216130878210057>",
|
||||
"{G/W}": "<:mtg_gw:415216130567962646>",
|
||||
"{G/U}": "<:mtg_gu:415216130739666945>",
|
||||
"{B/R}": "<:mtg_br:415216130580283394>",
|
||||
"{B/G}": "<:mtg_bg:415216130781609994>",
|
||||
"{U/P}": "<:mtg_up:415216130861432842>",
|
||||
"{R/P}": "<:mtg_rp:415216130597322783>",
|
||||
"{G/P}": "<:mtg_gp:415216130760769546>",
|
||||
"{W/P}": "<:mtg_wp:415216131541041172>",
|
||||
"{B/P}": "<:mtg_bp:415216130664169482>"
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
namespace Geekbot.net.Lib.Extensions
|
||||
{
|
||||
public static class DbSetExtensions
|
||||
{
|
||||
public static EntityEntry<T> AddIfNotExists<T>(this DbSet<T> dbSet, T entity, Expression<Func<T, bool>> predicate = null) where T : class, new()
|
||||
{
|
||||
var exists = predicate != null ? dbSet.Any(predicate) : dbSet.Any();
|
||||
return !exists ? dbSet.Add(entity) : null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
namespace Geekbot.net.Lib.Highscores
|
||||
{
|
||||
public enum HighscoreTypes
|
||||
{
|
||||
messages,
|
||||
karma,
|
||||
rolls,
|
||||
cookies
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
|
||||
namespace Geekbot.net.Lib.Localization
|
||||
{
|
||||
public interface ITranslationHandler
|
||||
{
|
||||
Task<string> GetString(ulong guildId, string command, string stringName);
|
||||
string GetString(string language, string command, string stringName);
|
||||
Task<Dictionary<string, string>> GetDict(ICommandContext context, string command);
|
||||
Task<TranslationGuildContext> GetGuildContext(ICommandContext context);
|
||||
Task<bool> SetLanguage(ulong guildId, string language);
|
||||
List<string> SupportedLanguages { get; }
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Geekbot.net.Lib.Localization
|
||||
{
|
||||
public class TranslationGuildContext
|
||||
{
|
||||
public ITranslationHandler TranslationHandler { get; }
|
||||
public string Language { get; }
|
||||
public Dictionary<string, string> Dict { get; }
|
||||
|
||||
public TranslationGuildContext(ITranslationHandler translationHandler, string language, Dictionary<string, string> dict)
|
||||
{
|
||||
TranslationHandler = translationHandler;
|
||||
Language = language;
|
||||
Dict = dict;
|
||||
}
|
||||
|
||||
public string GetString(string stringToFormat, params object[] args)
|
||||
{
|
||||
return string.Format(Dict[stringToFormat] ?? "", args);
|
||||
}
|
||||
|
||||
public string FormatDateTimeAsRemaining(DateTimeOffset dateTime)
|
||||
{
|
||||
var remaining = dateTime - DateTimeOffset.Now;
|
||||
const string formattable = "{0} {1}";
|
||||
var sb = new StringBuilder();
|
||||
|
||||
if (remaining.Days > 0)
|
||||
{
|
||||
var s = GetTimeString(TimeTypes.Days);
|
||||
sb.AppendFormat(formattable, remaining.Days, GetSingOrPlur(remaining.Days, s));
|
||||
}
|
||||
|
||||
if (remaining.Hours > 0)
|
||||
{
|
||||
if (sb.Length > 0) sb.Append(", ");
|
||||
var s = GetTimeString(TimeTypes.Hours);
|
||||
sb.AppendFormat(formattable, remaining.Hours, GetSingOrPlur(remaining.Hours, s));
|
||||
}
|
||||
|
||||
if (remaining.Minutes > 0)
|
||||
{
|
||||
if (sb.Length > 0) sb.Append(", ");
|
||||
var s = GetTimeString(TimeTypes.Minutes);
|
||||
sb.AppendFormat(formattable, remaining.Minutes, GetSingOrPlur(remaining.Minutes, s));
|
||||
}
|
||||
|
||||
if (remaining.Seconds > 0)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
var and = TranslationHandler.GetString(Language, "dateTime", "And");
|
||||
sb.AppendFormat(" {0} ", and);
|
||||
}
|
||||
var s = GetTimeString(TimeTypes.Seconds);
|
||||
sb.AppendFormat(formattable, remaining.Seconds, GetSingOrPlur(remaining.Seconds, s));
|
||||
}
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
public Task<bool> SetLanguage(ulong guildId, string language)
|
||||
{
|
||||
return TranslationHandler.SetLanguage(guildId, language);
|
||||
}
|
||||
|
||||
private string GetTimeString(TimeTypes type)
|
||||
{
|
||||
return TranslationHandler.GetString(Language, "dateTime", type.ToString());
|
||||
}
|
||||
|
||||
private string GetSingOrPlur(int number, string rawString)
|
||||
{
|
||||
var versions = rawString.Split('|');
|
||||
return number == 1 ? versions[0] : versions[1];
|
||||
}
|
||||
|
||||
private enum TimeTypes
|
||||
{
|
||||
Days,
|
||||
Hours,
|
||||
Minutes,
|
||||
Seconds
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,208 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.Commands;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Utf8Json;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Geekbot.net.Lib.Localization
|
||||
{
|
||||
public class TranslationHandler : ITranslationHandler
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly Dictionary<ulong, string> _serverLanguages;
|
||||
private Dictionary<string, Dictionary<string, Dictionary<string, string>>> _translations;
|
||||
|
||||
public TranslationHandler(DatabaseContext database, IGeekbotLogger logger)
|
||||
{
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
_logger.Information(LogSource.Geekbot, "Loading Translations");
|
||||
LoadTranslations();
|
||||
_serverLanguages = new Dictionary<ulong, string>();
|
||||
}
|
||||
|
||||
private void LoadTranslations()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Read the file
|
||||
var translationFile = File.ReadAllText(Path.GetFullPath("./Lib/Localization/Translations.yml"));
|
||||
|
||||
// Deserialize
|
||||
var input = new StringReader(translationFile);
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var rawTranslations = deserializer.Deserialize<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(input);
|
||||
|
||||
// Sort
|
||||
var sortedPerLanguage = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
|
||||
foreach (var command in rawTranslations)
|
||||
{
|
||||
foreach (var str in command.Value)
|
||||
{
|
||||
foreach (var lang in str.Value)
|
||||
{
|
||||
if (!sortedPerLanguage.ContainsKey(lang.Key))
|
||||
{
|
||||
var commandDict = new Dictionary<string, Dictionary<string, string>>();
|
||||
var strDict = new Dictionary<string, string>
|
||||
{
|
||||
{str.Key, lang.Value}
|
||||
};
|
||||
commandDict.Add(command.Key, strDict);
|
||||
sortedPerLanguage.Add(lang.Key, commandDict);
|
||||
}
|
||||
if (!sortedPerLanguage[lang.Key].ContainsKey(command.Key))
|
||||
{
|
||||
var strDict = new Dictionary<string, string>
|
||||
{
|
||||
{str.Key, lang.Value}
|
||||
};
|
||||
sortedPerLanguage[lang.Key].Add(command.Key, strDict);
|
||||
}
|
||||
if (!sortedPerLanguage[lang.Key][command.Key].ContainsKey(str.Key))
|
||||
{
|
||||
sortedPerLanguage[lang.Key][command.Key].Add(str.Key, lang.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_translations = sortedPerLanguage;
|
||||
|
||||
// Find Languages
|
||||
SupportedLanguages = new List<string>();
|
||||
foreach (var lang in sortedPerLanguage)
|
||||
{
|
||||
SupportedLanguages.Add(lang.Key);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to load Translations", e);
|
||||
Environment.Exit(GeekbotExitCode.TranslationsFailed.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GetServerLanguage(ulong guildId)
|
||||
{
|
||||
try
|
||||
{
|
||||
string lang;
|
||||
try
|
||||
{
|
||||
lang = _serverLanguages[guildId];
|
||||
if (!string.IsNullOrEmpty(lang))
|
||||
{
|
||||
return lang;
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
catch
|
||||
{
|
||||
lang = (await GetGuild(guildId)).Language ?? "EN";
|
||||
_serverLanguages[guildId] = lang;
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Could not get guild language", e);
|
||||
return "EN";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetString(ulong guildId, string command, string stringName)
|
||||
{
|
||||
var serverLang = await GetServerLanguage(guildId);
|
||||
return GetString(serverLang, command, stringName);
|
||||
}
|
||||
|
||||
public string GetString(string language, string command, string stringName)
|
||||
{
|
||||
var translation = _translations[language][command][stringName];
|
||||
if (!string.IsNullOrWhiteSpace(translation)) return translation;
|
||||
translation = _translations[command][stringName]["EN"];
|
||||
if (string.IsNullOrWhiteSpace(translation))
|
||||
{
|
||||
_logger.Warning(LogSource.Geekbot, $"No translation found for {command} - {stringName}");
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
private async Task<Dictionary<string, string>> GetDict(ICommandContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
var command = context.Message.Content.Split(' ').First().TrimStart('!').ToLower();
|
||||
var serverLanguage = await GetServerLanguage(context.Guild?.Id ?? 0);
|
||||
return _translations[serverLanguage][command];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "No translations for command found", e);
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<TranslationGuildContext> GetGuildContext(ICommandContext context)
|
||||
{
|
||||
var dict = await GetDict(context);
|
||||
var language = await GetServerLanguage(context.Guild?.Id ?? 0);
|
||||
return new TranslationGuildContext(this, language, dict);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, string>> GetDict(ICommandContext context, string command)
|
||||
{
|
||||
try
|
||||
{
|
||||
var serverLanguage = await GetServerLanguage(context.Guild?.Id ?? 0);
|
||||
return _translations[serverLanguage][command];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "No translations for command found", e);
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> SetLanguage(ulong guildId, string language)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!SupportedLanguages.Contains(language)) return false;
|
||||
var guild = await GetGuild(guildId);
|
||||
guild.Language = language;
|
||||
_database.GuildSettings.Update(guild);
|
||||
_serverLanguages[guildId] = language;
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Error while changing language", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> SupportedLanguages { get; private set; }
|
||||
|
||||
private async Task<GuildSettingsModel> GetGuild(ulong guildId)
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildId.AsLong()));
|
||||
if (guild != null) return guild;
|
||||
_database.GuildSettings.Add(new GuildSettingsModel
|
||||
{
|
||||
GuildId = guildId.AsLong()
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
return _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildId.AsLong()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
---
|
||||
dateTime:
|
||||
Days:
|
||||
EN: "day|days"
|
||||
CHDE: "tag|täg"
|
||||
Hours:
|
||||
EN: "hour|hours"
|
||||
CHDE: "stund|stunde"
|
||||
Minutes:
|
||||
EN: "minute|minutes"
|
||||
CHDE: "minute|minute"
|
||||
Seconds:
|
||||
EN: "second|seconds"
|
||||
CHDE: "sekunde|sekunde"
|
||||
And:
|
||||
EN: "and"
|
||||
CHDE: "und"
|
||||
admin:
|
||||
NewLanguageSet:
|
||||
EN: "I will reply in english from now on"
|
||||
CHDE: "I werd ab jetzt uf schwiizerdüütsch antworte, äuuä"
|
||||
GetLanguage:
|
||||
EN: "I'm talking english"
|
||||
CHDE: "I red schwiizerdüütsch"
|
||||
errorHandler:
|
||||
SomethingWentWrong:
|
||||
EN: "Something went wrong :confused:"
|
||||
CHDE: "Öppis isch schief gange :confused:"
|
||||
httpErrors:
|
||||
403:
|
||||
EN: "Seems like i don't have enough permission to that :confused:"
|
||||
CHDE: "Gseht danach us das ich nid gnueg recht han zum das mache :confused:"
|
||||
choose:
|
||||
Choice:
|
||||
EN: "I Choose **{0}**"
|
||||
CHDE: "I nimme **{0}**"
|
||||
good:
|
||||
CannotChangeOwn:
|
||||
EN: "Sorry {0}, but you can't give yourself karma"
|
||||
CHDE: "Sorry {0}, aber du chasch dr selber kei karma geh"
|
||||
WaitUntill:
|
||||
EN: "Sorry {0}, but you have to wait {1} before you can give karma again..."
|
||||
CHDE: "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch geh..."
|
||||
Increased:
|
||||
EN: "Karma gained"
|
||||
CHDE: "Karma becho"
|
||||
By:
|
||||
EN: "By"
|
||||
CHDE: "Vo"
|
||||
Amount:
|
||||
EN: "Amount"
|
||||
CHDE: "Mengi"
|
||||
Current:
|
||||
EN: "Current"
|
||||
CHDE: "Jetzt"
|
||||
bad:
|
||||
CannotChangeOwn:
|
||||
EN: "Sorry {0}, but you can't lower your own karma"
|
||||
CHDE: "Sorry {0}, aber du chasch dr din eigete karma nid weg neh"
|
||||
WaitUntill:
|
||||
EN: "Sorry {0}, but you have to wait {1} before you can lower karma again..."
|
||||
CHDE: "Sorry {0}, aber du musch no {1} warte bisch d wieder karma chasch senke..."
|
||||
Decreased:
|
||||
EN: "Karma lowered"
|
||||
CHDE: "Karma gsenkt"
|
||||
By:
|
||||
EN: "By"
|
||||
CHDE: "Vo"
|
||||
Amount:
|
||||
EN: "Amount"
|
||||
CHDE: "Mengi"
|
||||
Current:
|
||||
EN: "Current"
|
||||
CHDE: "Jetzt"
|
||||
roll:
|
||||
Rolled:
|
||||
EN: "{0}, you rolled {1}, your guess was {2}"
|
||||
CHDE: "{0}, du hesch {1} grollt und hesch {2} grate"
|
||||
Gratz:
|
||||
EN: "Congratulations {0}, your guess was correct!"
|
||||
CHDE: "Gratuliere {0}, du hesch richtig grate!"
|
||||
RolledNoGuess:
|
||||
EN: "{0}, you rolled {1}"
|
||||
CHDE: "{0}, du hesch {1} grollt"
|
||||
NoPrevGuess:
|
||||
EN: ":red_circle: {0}, you can't guess the same number again"
|
||||
CHDE: ":red_circle: {0}, du chasch nid nomol es gliche rate"
|
||||
cookies:
|
||||
GetCookies:
|
||||
EN: "You got {0} cookies, there are now {1} cookies in you cookie jar"
|
||||
CHDE: "Du häsch {0} guetzli becho, du häsch jetzt {1} guetzli ih dr büchse"
|
||||
WaitForMoreCookies:
|
||||
EN: "You already got cookies in the last 24 hours, you can have more cookies in {0}"
|
||||
CHDE: "Du hesch scho guetzli becho ih de letzti 24 stund, du chasch meh ha in {0}"
|
||||
InYourJar:
|
||||
EN: "There are {0} cookies in you cookie jar"
|
||||
CHDE: "Es hät {0} guetzli ih dineri büchs"
|
||||
Given:
|
||||
EN: "You gave {0} cookies to {1}"
|
||||
CHDE: "Du hesch {1} {0} guetzli geh"
|
||||
NotEnoughToGive:
|
||||
EN: "You don't have enough cookies"
|
||||
CHDE: "Du hesch nid gnueg guetzli"
|
||||
NotEnoughCookiesToEat:
|
||||
EN: "Your cookie jar looks almost empty, you should probably not eat a cookie"
|
||||
CHDE: "Du hesch chuum no guetzli ih dineri büchs, du sötsch warschinli keini esse"
|
||||
AteCookies:
|
||||
EN: "You ate {0} cookies, you've only got {1} cookies left"
|
||||
CHDE: "Du hesch {0} guetzli gesse und hesch jezt no {1} übrig"
|
||||
role:
|
||||
NoRolesConfigured:
|
||||
EN: "There are no roles configured for this server"
|
||||
CHDE: "Es sind kei rolle für dä server konfiguriert"
|
||||
ListHeader:
|
||||
EN: "**Self Service Roles on {0}**"
|
||||
CHDE: "**Self Service Rollene uf {0}**"
|
||||
ListInstruction:
|
||||
EN: "To get a role, use `!role [name]`"
|
||||
CHDE: "Zum ä rolle becho, schriib `!role [name]`"
|
||||
RoleNotFound:
|
||||
EN: "That role doesn't exist or is not on the whitelist"
|
||||
CHDE: "Die rolle gids nid or isch nid uf dr whitelist"
|
||||
RemovedUserFromRole:
|
||||
EN: "Removed you from {0}"
|
||||
CHDE: "Han di entfernt vo {0}"
|
||||
AddedUserFromRole:
|
||||
EN: "Added you to {0}"
|
||||
CHDE: "Han di hinzue gfüegt zu {0}"
|
||||
CannotAddManagedRole:
|
||||
EN: "You can't add a role that is managed by discord"
|
||||
CHDE: "Du chasch kei rolle hinzuefüge wo verwalted wird vo discord"
|
||||
CannotAddDangerousRole:
|
||||
EN: "You cannot add that role to self service because it contains one or more dangerous permissions"
|
||||
CHDE: "Du chasch die rolle nid hinzuefüge will er ein oder mehreri gföhrlichi berechtigunge het"
|
||||
AddedRoleToWhitelist:
|
||||
EN: "Added {0} to the whitelist"
|
||||
CHDE: "{0} isch zur whitelist hinzuegfüegt"
|
||||
RemovedRoleFromWhitelist:
|
||||
EN: "Removed {0} from the whitelist"
|
||||
CHDE: "{0} isch vo dr whitelist glöscht"
|
||||
quote:
|
||||
NoQuotesFound:
|
||||
EN: "This server doesn't seem to have any quotes yet. You can add a quote with `!quote save @user` or `!quote save <messageId>`"
|
||||
CHDE: "Dä server het no kei quotes. Du chasch quotes hinzuefüege mit `!quote save @user` oder `!quote save <messageId>`"
|
||||
CannotSaveOwnQuotes:
|
||||
EN: "You can't save your own quotes..."
|
||||
CHDE: "Du chasch kei quotes vo dir selber speichere..."
|
||||
CannotQuoteBots:
|
||||
EN: "You can't save quotes by a bot..."
|
||||
CHDE: "Du chasch kei quotes vomne bot speichere..."
|
||||
QuoteAdded:
|
||||
EN: "**Quote Added**"
|
||||
CHDE: "**Quote hinzugfüegt**"
|
||||
Removed:
|
||||
EN: "**Removed #{0}**"
|
||||
CHDE: "**#{0} glöscht**"
|
||||
NotFoundWithId:
|
||||
EN: "I couldn't find a quote with that ID :disappointed:"
|
||||
CHDE: "Ich chan kei quote finde mit därri ID :disappointed:"
|
||||
rank:
|
||||
InvalidType:
|
||||
EN: "Valid types are '`messages`' '`karma`', '`rolls`' and '`cookies`'"
|
||||
CHDE: "Gültigi paramenter sind '`messages`' '`karma`', '`rolls`' und '`cookies`'"
|
||||
LimitingTo20Warning:
|
||||
EN: ":warning: Limiting to 20\n"
|
||||
CHDE: ":warning: Limitiert uf 20\n"
|
||||
NoTypeFoundForServer:
|
||||
EN: "No {0} found on this server"
|
||||
CHDE: "Kei {0} gfunde für dä server"
|
||||
FailedToResolveAllUsernames:
|
||||
EN: ":warning: I couldn't find all usernames. Maybe they left the server?\n"
|
||||
CHDE: ":warning: Ich han nid alli benutzername gfunde. villiicht hend sie de server verlah?\n"
|
||||
HighscoresFor:
|
||||
EN: ":bar_chart: **{0} Highscore for {1}**"
|
||||
CHDE: ":bar_chart: **{0} Highscore für {1}**"
|
|
@ -1,84 +0,0 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.Lib.Logger
|
||||
{
|
||||
public class GeekbotLogger : IGeekbotLogger
|
||||
{
|
||||
private readonly bool _logAsJson;
|
||||
private readonly NLog.Logger _logger;
|
||||
private readonly JsonSerializerSettings _serializerSettings;
|
||||
|
||||
public GeekbotLogger(RunParameters runParameters, bool sumologicActive)
|
||||
{
|
||||
_logAsJson = sumologicActive || runParameters.LogJson;
|
||||
_logger = LoggerFactory.CreateNLog(runParameters, sumologicActive);
|
||||
_serializerSettings = new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
|
||||
NullValueHandling = NullValueHandling.Include
|
||||
};
|
||||
Information(LogSource.Geekbot, "Using GeekbotLogger");
|
||||
}
|
||||
|
||||
public void Trace(LogSource source, string message, object extra = null)
|
||||
{
|
||||
_logger.Trace(CreateLogString("Trace", source, message, null, extra));
|
||||
}
|
||||
|
||||
public void Debug(LogSource source, string message, object extra = null)
|
||||
{
|
||||
if (_logAsJson) _logger.Info(CreateLogString("Debug", source, message, null, extra));
|
||||
else _logger.Debug(CreateLogString("Debug", source, message, null, extra));
|
||||
}
|
||||
|
||||
public void Information(LogSource source, string message, object extra = null)
|
||||
{
|
||||
_logger.Info(CreateLogString("Information", source, message, null, extra));
|
||||
}
|
||||
|
||||
public void Warning(LogSource source, string message, Exception stackTrace = null, object extra = null)
|
||||
{
|
||||
if (_logAsJson) _logger.Info(CreateLogString("Warning", source, message, stackTrace, extra));
|
||||
else _logger.Warn(CreateLogString("Warning", source, message, stackTrace, extra));
|
||||
}
|
||||
|
||||
public void Error(LogSource source, string message, Exception stackTrace, object extra = null)
|
||||
{
|
||||
if (_logAsJson) _logger.Info(CreateLogString("Error", source, message, stackTrace, extra));
|
||||
else _logger.Error(stackTrace, CreateLogString("Error", source, message, stackTrace, extra));
|
||||
}
|
||||
|
||||
public NLog.Logger GetNLogger()
|
||||
{
|
||||
return _logger;
|
||||
}
|
||||
|
||||
public bool LogAsJson()
|
||||
{
|
||||
return _logAsJson;
|
||||
}
|
||||
|
||||
private string CreateLogString(string type, LogSource source, string message, Exception stackTrace = null, object extra = null)
|
||||
{
|
||||
if (_logAsJson)
|
||||
{
|
||||
var logObject = new GeekbotLoggerObject
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Type = type,
|
||||
Source = source,
|
||||
Message = message,
|
||||
StackTrace = stackTrace,
|
||||
Extra = extra
|
||||
};
|
||||
return JsonConvert.SerializeObject(logObject, Formatting.None, _serializerSettings);
|
||||
}
|
||||
|
||||
if (source != LogSource.Message) return $"[{source}] - {message}";
|
||||
|
||||
var m = (MessageDto) extra;
|
||||
return $"[{source}] - [{m?.Guild.Name} - {m?.Channel.Name}] {m?.User.Name}: {m?.Message.Content}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Geekbot.net.Lib.Logger
|
||||
{
|
||||
public class GeekbotLoggerObject
|
||||
{
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string Type { get; set; }
|
||||
public LogSource Source { get; set; }
|
||||
public string Message { get; set; }
|
||||
public Exception StackTrace { get; set; }
|
||||
public object Extra { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
namespace Geekbot.net.Lib.Media
|
||||
{
|
||||
public interface IMediaProvider
|
||||
{
|
||||
string GetCheckem();
|
||||
string GetPanda();
|
||||
string GetCrossant();
|
||||
string GetSquirrel();
|
||||
string GetPumpkin();
|
||||
string GetTurtle();
|
||||
string GetPinguin();
|
||||
string GetFox();
|
||||
string GetDab();
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
|
||||
namespace Geekbot.net.Lib.Media
|
||||
{
|
||||
public class MediaProvider : IMediaProvider
|
||||
{
|
||||
private readonly Random _random;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private string[] _checkemImages;
|
||||
private string[] _pandaImages;
|
||||
private string[] _croissantImages;
|
||||
private string[] _squirrelImages;
|
||||
private string[] _pumpkinImages;
|
||||
private string[] _turtlesImages;
|
||||
private string[] _pinguinImages;
|
||||
private string[] _foxImages;
|
||||
private string[] _dabImages;
|
||||
|
||||
public MediaProvider(IGeekbotLogger logger)
|
||||
{
|
||||
_random = new Random();
|
||||
_logger = logger;
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Loading Media Files");
|
||||
|
||||
LoadCheckem();
|
||||
LoadPandas();
|
||||
BakeCroissants();
|
||||
LoadSquirrels();
|
||||
LoadPumpkins();
|
||||
LoadTurtles();
|
||||
LoadPinguins();
|
||||
LoadFoxes();
|
||||
LoadDab();
|
||||
}
|
||||
|
||||
private void LoadCheckem()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/checkEmPics"));
|
||||
_checkemImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_checkemImages.Length} CheckEm Images");
|
||||
}
|
||||
|
||||
private void LoadPandas()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pandas"));
|
||||
_pandaImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_pandaImages.Length} Panda Images");
|
||||
}
|
||||
|
||||
private void BakeCroissants()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/croissant"));
|
||||
_croissantImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_croissantImages.Length} Croissant Images");
|
||||
}
|
||||
|
||||
private void LoadSquirrels()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/squirrel"));
|
||||
_squirrelImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_squirrelImages.Length} Squirrel Images");
|
||||
}
|
||||
|
||||
private void LoadPumpkins()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pumpkin"));
|
||||
_pumpkinImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_pumpkinImages.Length} Pumpkin Images");
|
||||
}
|
||||
|
||||
private void LoadTurtles()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/turtles"));
|
||||
_turtlesImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_turtlesImages.Length} Turtle Images");
|
||||
}
|
||||
|
||||
private void LoadPinguins()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/pinguins"));
|
||||
_pinguinImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_pinguinImages.Length} Pinguin Images");
|
||||
}
|
||||
|
||||
private void LoadFoxes()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/foxes"));
|
||||
_foxImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_foxImages.Length} Foxes Images");
|
||||
}
|
||||
|
||||
private void LoadDab()
|
||||
{
|
||||
var rawLinks = File.ReadAllText(Path.GetFullPath("./Storage/dab"));
|
||||
_dabImages = rawLinks.Split("\n");
|
||||
_logger.Trace(LogSource.Geekbot, $"Loaded {_dabImages.Length} Dab Images");
|
||||
}
|
||||
|
||||
public string GetCheckem()
|
||||
{
|
||||
return _checkemImages[_random.Next(0, _checkemImages.Length)];
|
||||
}
|
||||
|
||||
public string GetPanda()
|
||||
{
|
||||
return _pandaImages[_random.Next(0, _pandaImages.Length)];
|
||||
}
|
||||
|
||||
public string GetCrossant()
|
||||
{
|
||||
return _croissantImages[_random.Next(0, _croissantImages.Length)];
|
||||
}
|
||||
|
||||
public string GetSquirrel()
|
||||
{
|
||||
return _squirrelImages[_random.Next(0, _squirrelImages.Length)];
|
||||
}
|
||||
|
||||
public string GetPumpkin()
|
||||
{
|
||||
return _pumpkinImages[_random.Next(0, _pumpkinImages.Length)];
|
||||
}
|
||||
|
||||
public string GetTurtle()
|
||||
{
|
||||
return _turtlesImages[_random.Next(0, _turtlesImages.Length)];
|
||||
}
|
||||
|
||||
public string GetPinguin()
|
||||
{
|
||||
return _pinguinImages[_random.Next(0, _pinguinImages.Length)];
|
||||
}
|
||||
|
||||
public string GetFox()
|
||||
{
|
||||
return _foxImages[_random.Next(0, _foxImages.Length)];
|
||||
}
|
||||
|
||||
public string GetDab()
|
||||
{
|
||||
return _dabImages[_random.Next(0, _dabImages.Length)];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Geekbot.net.Lib.RandomNumberGenerator
|
||||
{
|
||||
public class RandomNumberGenerator : IRandomNumberGenerator
|
||||
{
|
||||
readonly RNGCryptoServiceProvider csp;
|
||||
|
||||
public RandomNumberGenerator()
|
||||
{
|
||||
csp = new RNGCryptoServiceProvider();
|
||||
}
|
||||
|
||||
public int Next(int minValue, int maxExclusiveValue)
|
||||
{
|
||||
if (minValue >= maxExclusiveValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("minValue must be lower than maxExclusiveValue");
|
||||
}
|
||||
|
||||
var diff = (long)maxExclusiveValue - minValue;
|
||||
var upperBound = uint.MaxValue / diff * diff;
|
||||
|
||||
uint ui;
|
||||
do
|
||||
{
|
||||
ui = GetRandomUInt();
|
||||
} while (ui >= upperBound);
|
||||
return (int)(minValue + (ui % diff));
|
||||
}
|
||||
|
||||
private uint GetRandomUInt()
|
||||
{
|
||||
var randomBytes = GenerateRandomBytes(sizeof(uint));
|
||||
return BitConverter.ToUInt32(randomBytes, 0);
|
||||
}
|
||||
|
||||
private byte[] GenerateRandomBytes(int bytesNumber)
|
||||
{
|
||||
var buffer = new byte[bytesNumber];
|
||||
csp.GetBytes(buffer);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
|
||||
namespace Geekbot.net.Lib.ReactionListener
|
||||
{
|
||||
public interface IReactionListener
|
||||
{
|
||||
bool IsListener(ulong id);
|
||||
Task AddRoleToListener(string messageId, IEmote emoji, IRole role);
|
||||
void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction);
|
||||
void GiveRole(ISocketMessageChannel message, SocketReaction reaction);
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Geekbot.net.Lib.ReactionListener
|
||||
{
|
||||
public class ReactionListener : IReactionListener
|
||||
{
|
||||
private readonly IDatabase _redis;
|
||||
private Dictionary<string, Dictionary<IEmote, ulong>> _listener;
|
||||
|
||||
public ReactionListener(IDatabase redis)
|
||||
{
|
||||
_redis = redis;
|
||||
LoadListeners();
|
||||
}
|
||||
|
||||
private Task LoadListeners()
|
||||
{
|
||||
var ids = _redis.SetMembers("MessageIds");
|
||||
_listener = new Dictionary<string, Dictionary<IEmote, ulong>>();
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var reactions = _redis.HashGetAll($"Messages:{id}");
|
||||
var messageId = id;
|
||||
var emojiDict = new Dictionary<IEmote, ulong>();
|
||||
foreach (var r in reactions)
|
||||
{
|
||||
IEmote emote;
|
||||
if (!r.Name.ToString().StartsWith('<'))
|
||||
{
|
||||
var emo = new Emoji(r.Name);
|
||||
emote = emo;
|
||||
}
|
||||
else
|
||||
{
|
||||
emote = Emote.Parse(r.Name);
|
||||
}
|
||||
emojiDict.Add(emote, ulong.Parse(r.Value));
|
||||
}
|
||||
_listener.Add(messageId, emojiDict);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public bool IsListener(ulong id)
|
||||
{
|
||||
return _listener.ContainsKey(id.ToString());
|
||||
}
|
||||
|
||||
public Task AddRoleToListener(string messageId, IEmote emoji, IRole role)
|
||||
{
|
||||
if (_redis.SetMembers("MessageIds").All(e => e.ToString() != messageId))
|
||||
{
|
||||
_redis.SetAdd("MessageIds", messageId);
|
||||
}
|
||||
_redis.HashSet($"Messages:{messageId}", new[] {new HashEntry(emoji.ToString(), role.Id.ToString())});
|
||||
_redis.SetAdd("MessageIds", messageId);
|
||||
if (_listener.ContainsKey(messageId))
|
||||
{
|
||||
_listener[messageId].Add(emoji, role.Id);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
var dict = new Dictionary<IEmote, ulong>();
|
||||
dict.Add(emoji, role.Id);
|
||||
_listener.Add(messageId, dict);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async void RemoveRole(ISocketMessageChannel channel, SocketReaction reaction)
|
||||
{
|
||||
var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote];
|
||||
var guild = (SocketGuildChannel) channel;
|
||||
var role = guild.Guild.GetRole(roleId);
|
||||
await ((IGuildUser) reaction.User.Value).RemoveRoleAsync(role);
|
||||
}
|
||||
|
||||
public async void GiveRole(ISocketMessageChannel channel, SocketReaction reaction)
|
||||
{
|
||||
var roleId = _listener[reaction.MessageId.ToString()][reaction.Emote];
|
||||
var guild = (SocketGuildChannel) channel;
|
||||
var role = guild.Guild.GetRole(roleId);
|
||||
await ((IGuildUser) reaction.User.Value).AddRoleAsync(role);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
using CommandLine;
|
||||
|
||||
namespace Geekbot.net.Lib
|
||||
{
|
||||
public class RunParameters
|
||||
{
|
||||
/************************************
|
||||
* General *
|
||||
************************************/
|
||||
|
||||
[Option('V', "verbose", Default = false, HelpText = "Logs everything.")]
|
||||
public bool Verbose { get; set; }
|
||||
|
||||
[Option('j', "log-json", Default = false, HelpText = "Logger outputs json")]
|
||||
public bool LogJson { get; set; }
|
||||
|
||||
[Option('a', "disable-api", Default = false, HelpText = "Disables the web api")]
|
||||
public bool DisableApi { get; set; }
|
||||
|
||||
[Option('e', "expose-errors", Default = false, HelpText = "Shows internal errors in the chat")]
|
||||
public bool ExposeErrors { get; set; }
|
||||
|
||||
[Option("token", Default = null, HelpText = "Set a new bot token")]
|
||||
public string Token { get; set; }
|
||||
|
||||
/************************************
|
||||
* Database *
|
||||
************************************/
|
||||
|
||||
[Option("in-memory", Default = false, HelpText = "Uses the in-memory database instead of postgresql")]
|
||||
public bool InMemory { get; set; }
|
||||
|
||||
// Postresql connection
|
||||
[Option("database", Default = "geekbot", HelpText = "Select a postgresql database")]
|
||||
public string DbDatabase { get; set; }
|
||||
|
||||
[Option("db-host", Default = "localhost", HelpText = "Set a postgresql host (e.g. 127.0.0.1)")]
|
||||
public string DbHost { get; set; }
|
||||
|
||||
[Option("db-port", Default = "5432", HelpText = "Set a postgresql host (e.g. 5432)")]
|
||||
public string DbPort { get; set; }
|
||||
|
||||
[Option("db-user", Default = "geekbot", HelpText = "Set a postgresql user")]
|
||||
public string DbUser { get; set; }
|
||||
|
||||
[Option("db-password", Default = "", HelpText = "Set a posgresql password")]
|
||||
public string DbPassword { get; set; }
|
||||
|
||||
// Logging
|
||||
[Option("db-logging", Default = false, HelpText = "Enable database logging")]
|
||||
public bool DbLogging { get; set; }
|
||||
|
||||
/************************************
|
||||
* Redis *
|
||||
************************************/
|
||||
|
||||
[Option("redis-host", Default = "127.0.0.1", HelpText = "Set a redis host")]
|
||||
public string RedisHost { get; set; }
|
||||
|
||||
[Option("redis-port", Default = "6379", HelpText = "Set a redis port")]
|
||||
public string RedisPort { get; set; }
|
||||
|
||||
[Option("redis-database", Default = "6", HelpText = "Select a redis database (1-15)")]
|
||||
public string RedisDatabase { get; set; }
|
||||
|
||||
/************************************
|
||||
* WebApi *
|
||||
************************************/
|
||||
|
||||
[Option("api-host", Default = "localhost", HelpText = "Host on which the WebApi listens")]
|
||||
public string ApiHost { get; set; }
|
||||
|
||||
[Option("api-port", Default = "12995", HelpText = "Port on which the WebApi listens")]
|
||||
public string ApiPort { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,213 +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.net.Database;
|
||||
using Geekbot.net.Lib;
|
||||
using Geekbot.net.Lib.AlmostRedis;
|
||||
using Geekbot.net.Lib.Clients;
|
||||
using Geekbot.net.Lib.Converters;
|
||||
using Geekbot.net.Lib.ErrorHandling;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Geekbot.net.Lib.Highscores;
|
||||
using Geekbot.net.Lib.Levels;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Geekbot.net.Lib.Media;
|
||||
using Geekbot.net.Lib.RandomNumberGenerator;
|
||||
using Geekbot.net.Lib.ReactionListener;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WikipediaApi;
|
||||
|
||||
namespace Geekbot.net
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private DiscordSocketClient _client;
|
||||
private CommandService _commands;
|
||||
private DatabaseInitializer _databaseInitializer;
|
||||
private IGlobalSettings _globalSettings;
|
||||
private IServiceCollection _services;
|
||||
private IServiceProvider _servicesProvider;
|
||||
private string _token;
|
||||
private GeekbotLogger _logger;
|
||||
private IUserRepository _userRepository;
|
||||
private RunParameters _runParameters;
|
||||
private IAlmostRedis _redis;
|
||||
|
||||
private static void 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 sumologicActive = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GEEKBOT_SUMO"));
|
||||
var logger = new GeekbotLogger(runParameters, sumologicActive);
|
||||
logger.Information(LogSource.Geekbot, "Starting...");
|
||||
try
|
||||
{
|
||||
new Program().MainAsync(runParameters, logger).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(LogSource.Geekbot, "RIP", e);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task MainAsync(RunParameters runParameters, GeekbotLogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_runParameters = runParameters;
|
||||
logger.Information(LogSource.Geekbot, "Initing Stuff");
|
||||
var discordLogger = new DiscordLogger(logger);
|
||||
|
||||
_client = new DiscordSocketClient(new DiscordSocketConfig
|
||||
{
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
MessageCacheSize = 1000,
|
||||
ExclusiveBulkDelete = true
|
||||
});
|
||||
_client.Log += discordLogger.Log;
|
||||
_commands = new CommandService();
|
||||
|
||||
_databaseInitializer = new DatabaseInitializer(runParameters, logger);
|
||||
var database = _databaseInitializer.Initialize();
|
||||
database.Database.EnsureCreated();
|
||||
if(!_runParameters.InMemory) database.Database.Migrate();
|
||||
|
||||
_globalSettings = new GlobalSettings(database);
|
||||
|
||||
try
|
||||
{
|
||||
_redis = new AlmostRedis(logger, runParameters);
|
||||
_redis.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.Error(LogSource.Redis, "Redis Connection Failed", e);
|
||||
Environment.Exit(GeekbotExitCode.RedisConnectionFailed.GetHashCode());
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
_services = new ServiceCollection();
|
||||
|
||||
_userRepository = new UserRepository(_databaseInitializer.Initialize(), logger);
|
||||
var fortunes = new FortunesProvider(logger);
|
||||
var mediaProvider = new MediaProvider(logger);
|
||||
var malClient = new MalClient(_globalSettings, logger);
|
||||
var levelCalc = new LevelCalc();
|
||||
var emojiConverter = new EmojiConverter();
|
||||
var mtgManaConverter = new MtgManaConverter();
|
||||
var wikipediaClient = new WikipediaClient();
|
||||
var randomNumberGenerator = new RandomNumberGenerator();
|
||||
|
||||
_services.AddSingleton<IAlmostRedis>(_redis);
|
||||
_services.AddSingleton<IUserRepository>(_userRepository);
|
||||
_services.AddSingleton<IGeekbotLogger>(logger);
|
||||
_services.AddSingleton<ILevelCalc>(levelCalc);
|
||||
_services.AddSingleton<IEmojiConverter>(emojiConverter);
|
||||
_services.AddSingleton<IFortunesProvider>(fortunes);
|
||||
_services.AddSingleton<IMediaProvider>(mediaProvider);
|
||||
_services.AddSingleton<IMalClient>(malClient);
|
||||
_services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
|
||||
_services.AddSingleton<IWikipediaClient>(wikipediaClient);
|
||||
_services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator);
|
||||
_services.AddSingleton<IGlobalSettings>(_globalSettings);
|
||||
_services.AddTransient<IHighscoreManager>((e) => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository));
|
||||
_services.AddTransient<DatabaseContext>((e) => _databaseInitializer.Initialize());
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Connecting to Discord");
|
||||
|
||||
await Login();
|
||||
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
||||
private async Task Login()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _client.LoginAsync(TokenType.Bot, _token);
|
||||
await _client.StartAsync();
|
||||
var isConneted = await IsConnected();
|
||||
if (isConneted)
|
||||
{
|
||||
await _client.SetGameAsync(_globalSettings.GetKey("Game"));
|
||||
_logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers");
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Registering Stuff");
|
||||
var translationHandler = new TranslationHandler(_databaseInitializer.Initialize(), _logger);
|
||||
var errorHandler = new ErrorHandler(_logger, translationHandler, _globalSettings, _runParameters.ExposeErrors);
|
||||
var reactionListener = new ReactionListener(_redis.Db);
|
||||
_services.AddSingleton<IErrorHandler>(errorHandler);
|
||||
_services.AddSingleton<ITranslationHandler>(translationHandler);
|
||||
_services.AddSingleton(_client);
|
||||
_services.AddSingleton<IReactionListener>(reactionListener);
|
||||
_servicesProvider = _services.BuildServiceProvider();
|
||||
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _servicesProvider);
|
||||
|
||||
var handlers = new Handlers(_databaseInitializer, _client, _logger, _redis, _servicesProvider, _commands, _userRepository, reactionListener);
|
||||
|
||||
_client.MessageReceived += handlers.RunCommand;
|
||||
_client.MessageDeleted += handlers.MessageDeleted;
|
||||
_client.UserJoined += handlers.UserJoined;
|
||||
_client.UserUpdated += handlers.UserUpdated;
|
||||
_client.UserLeft += handlers.UserLeft;
|
||||
_client.ReactionAdded += handlers.ReactionAdded;
|
||||
_client.ReactionRemoved += handlers.ReactionRemoved;
|
||||
if (!_runParameters.InMemory) _client.MessageReceived += handlers.UpdateStats;
|
||||
|
||||
var webserver = _runParameters.DisableApi ? Task.Delay(10) : StartWebApi();
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Done and ready for use");
|
||||
|
||||
await webserver;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Could not connect to Discord", e);
|
||||
Environment.Exit(GeekbotExitCode.CouldNotLogin.GetHashCode());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsConnected()
|
||||
{
|
||||
while (!_client.ConnectionState.Equals(ConnectionState.Connected))
|
||||
await Task.Delay(25);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Task StartWebApi()
|
||||
{
|
||||
_logger.Information(LogSource.Api, "Starting Webserver");
|
||||
var highscoreManager = new HighscoreManager(_databaseInitializer.Initialize(), _userRepository);
|
||||
WebApi.WebApiStartup.StartWebApi(_logger, _runParameters, _commands, _databaseInitializer.Initialize(), _client, _globalSettings, highscoreManager);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
http://s19.postimg.org/pcq2kwzoj/4cb.png
|
||||
http://s19.postimg.org/cvetk0f4z/5_Dim_Dy6p.jpg
|
||||
http://s19.postimg.org/5hzfl1v37/1310151998600.jpg
|
||||
http://s19.postimg.org/53y3lgazn/1324181141954.jpg
|
||||
http://s19.postimg.org/724rjg3hf/1392512742365.png
|
||||
http://s19.postimg.org/3rgejkdk3/1393501296733.png
|
||||
http://s19.postimg.org/a6ffg8k9v/1401667341503.jpg
|
||||
http://s19.postimg.org/qiph5yylf/1419231572452.jpg
|
||||
http://s19.postimg.org/fqwi4m8ir/1427600681401.png
|
||||
http://s19.postimg.org/4c00zzw6b/1447813628974.png
|
||||
http://s19.postimg.org/uuio8puw3/b5_3q_ycaaavxtf.jpg
|
||||
http://s19.postimg.org/bghu913fn/check_em_by_boyboy99100_d57xp3y.png
|
||||
http://s19.postimg.org/s1pgooujn/l_Hkppjs.jpg
|
||||
http://s19.postimg.org/m08itft0j/checkem.jpg
|
||||
https://old.postimg.org/image/6vx33rb1b/
|
||||
https://old.postimg.org/image/wxiaz1mov/
|
||||
https://old.postimg.org/image/azqfizx27/
|
||||
https://old.postimg.org/image/6iy2kbiu7/
|
||||
https://old.postimg.org/image/k8slt45y7/
|
||||
https://old.postimg.org/image/t7ruxmplr/
|
||||
https://old.postimg.org/image/ssbzqvean/
|
||||
https://old.postimg.org/image/kbchfy9lr/
|
||||
https://old.postimg.org/image/dl0lk9btr/
|
||||
https://old.postimg.org/image/e5k80oufz/
|
||||
https://old.postimg.org/image/er005baqn/
|
||||
https://old.postimg.org/image/bfk2uzcin/
|
||||
https://old.postimg.org/image/556fp0jkv/
|
||||
https://old.postimg.org/image/i0efbryu7/
|
||||
https://old.postimg.org/image/943n7u87z/
|
||||
https://old.postimg.org/image/xn5op5cm7/
|
||||
https://old.postimg.org/image/3l5p4d0kf/
|
||||
https://old.postimg.org/image/5boq5ui3j/
|
||||
https://old.postimg.org/image/ru082bqcf/
|
||||
https://old.postimg.org/image/ytea1oqan/
|
||||
https://old.postimg.org/image/vu7dekgtb/
|
||||
https://old.postimg.org/image/hl7qwi2an/
|
||||
https://old.postimg.org/image/5aescfg9r/
|
||||
https://old.postimg.org/image/9gzmrrfvj/
|
||||
https://old.postimg.org/image/50bv6tr1b/
|
||||
https://old.postimg.org/image/afkl7silb/
|
||||
https://old.postimg.org/image/nrdsgzllr/
|
||||
https://old.postimg.org/image/s32e5zsin/
|
||||
https://old.postimg.org/image/5sej60v8f/
|
||||
https://old.postimg.org/image/lgfqctau7/
|
||||
https://old.postimg.org/image/tn7q4e0wv/
|
||||
https://old.postimg.org/image/8612arz1b/
|
||||
https://old.postimg.org/image/w5tf52mn3/
|
||||
https://old.postimg.org/image/zdxwi48wv/
|
||||
https://old.postimg.org/image/lphwghd0f/
|
||||
https://old.postimg.org/image/uzu0k0nq7/
|
||||
https://old.postimg.org/image/3vqzsxjbz/
|
||||
https://old.postimg.org/image/5d7uqqyov/
|
||||
https://old.postimg.org/image/dntnyku8v/
|
||||
https://old.postimg.org/image/dsxf891jz/
|
||||
https://old.postimg.org/image/3nyrioizj/
|
||||
https://old.postimg.org/image/6zx2bzaqn/
|
||||
https://old.postimg.org/image/wu6v1raqn/
|
||||
https://old.postimg.org/image/hb9f4n2fz/
|
||||
https://old.postimg.org/image/p7yhqm3a7/
|
||||
https://old.postimg.org/image/oelvxzx9b/
|
||||
https://old.postimg.org/image/vcq03xvdr/
|
||||
https://old.postimg.org/image/b08t1yqlb/
|
||||
https://old.postimg.org/image/6yrpwayan/
|
||||
https://old.postimg.org/image/btleukwm7/
|
||||
https://old.postimg.org/image/62ztuldzz/
|
||||
https://old.postimg.org/image/w3iq9pxr3/
|
||||
https://old.postimg.org/image/byp6493xb/
|
||||
https://old.postimg.org/image/xp2lf9xcv/
|
||||
https://old.postimg.org/image/j9p9u49pb/
|
||||
https://old.postimg.org/image/hvxmytafz/
|
||||
https://old.postimg.org/image/5eqzbnfa7/
|
||||
https://old.postimg.org/image/do2uq290f/
|
||||
https://old.postimg.org/image/54o261q1r/
|
||||
https://old.postimg.org/image/94qm4jr4v/
|
||||
https://old.postimg.org/image/lee88y0pr/
|
||||
https://old.postimg.org/image/bncb58cv3/
|
||||
https://old.postimg.org/image/5246j7me7/
|
||||
https://old.postimg.org/image/4uby8ym1r/
|
||||
https://old.postimg.org/image/qn996tj4v/
|
||||
https://old.postimg.org/image/c1dn4twyn/
|
||||
https://old.postimg.org/image/6rd9ra23j/
|
||||
https://lehcark14.files.wordpress.com/2008/08/botan16.jpg
|
||||
http://i.imgur.com/p9vALew.jpg
|
||||
http://i.imgur.com/4a9l2Rm.png
|
||||
http://i.imgur.com/RNtixMQ.jpg
|
||||
https://pbs.twimg.com/media/Cro9aIGUEAAkXCP.jpg
|
||||
http://s16.postimg.org/empvloimd/Check_em_Guts.png
|
||||
https://s18.postimg.io/qgbhe7u09/1424491645996.gif
|
||||
http://s19.postimg.org/hhemlt7xf/3eb.jpg
|
||||
http://s19.postimg.org/cwsg6vo83/8aa.png
|
||||
http://s19.postimg.org/rh9j1pj6r/28mohl4.png
|
||||
http://s19.postimg.org/zba4n3qzn/86d.jpg
|
||||
http://s19.postimg.org/cb3hart5v/2016_09_16_08_58_45.png
|
||||
http://s19.postimg.org/m9ofx92lf/bb1.jpg
|
||||
http://s19.postimg.org/maydqo4f7/e8b.jpg
|
||||
http://s19.postimg.org/yqzoy5n4z/fbe.png
|
||||
http://s19.postimg.org/xd822unvn/giphy.gif
|
||||
http://s19.postimg.org/c4udlf9er/l_TU3eup.jpg
|
||||
https://66.media.tumblr.com/cc893a0ee40d73d083da3df4bdaf45cc/tumblr_mx8psiFduG1t1g1k8o1_500.gif
|
||||
http://i.imgur.com/swbXHSy.gif
|
||||
http://img1.reactor.cc/pics/post/full/Anime-Touhou-Project-Yakumo-Yukari-%D0%A0%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D1%8F-1303807.jpeg
|
||||
http://i.imgur.com/ftGLHE0.png
|
||||
http://i.imgur.com/JELDhKQ.png
|
||||
http://imgur.com/yBJound
|
||||
http://i.imgur.com/f7gAVPJ.png
|
||||
http://i.imgur.com/HxWyo2Z.jpg
|
||||
http://i.imgur.com/8Eb9CxQ.png
|
||||
http://i.imgur.com/kOECcjz.png
|
||||
http://i.imgur.com/MJLu7oJ.jpg
|
||||
http://i.imgur.com/itG3rPM.jpg
|
||||
http://i.imgur.com/G83Go9t.jpg
|
||||
http://i.imgur.com/jI2dBnU.jpg
|
||||
http://i.imgur.com/FtALzg0.jpg
|
||||
http://i.imgur.com/GwZpJEv.gif
|
||||
http://i.imgur.com/TYGRD3B.gif
|
||||
http://i.imgur.com/P6TxLS3.png
|
||||
http://i.imgur.com/phTVTdn.jpg
|
||||
http://i.imgur.com/thhR6UE.jpg
|
||||
http://i.imgur.com/KbROufx.jpg
|
||||
http://i.imgur.com/sQqWbcm.jpg
|
||||
http://i.imgur.com/YYpis53.png
|
||||
http://i.imgur.com/kwaRd54.gif
|
|
@ -1,17 +0,0 @@
|
|||
https://i2.wp.com/epicureandculture.com/wp-content/uploads/2014/12/shutterstock_172040546.jpg
|
||||
http://www.bakespace.com/images/large/5d79070cf21b2f33c3a1dd4336cb27d2.jpeg
|
||||
http://food.fnr.sndimg.com/content/dam/images/food/fullset/2015/5/7/1/SD1B43_croissants-recipe_s4x3.jpg.rend.hgtvcom.616.462.suffix/1431052139248.jpeg
|
||||
http://img.taste.com.au/u-Bwjfm_/taste/2016/11/mini-croissants-with-3-fillings-14692-1.jpeg
|
||||
https://media.newyorker.com/photos/590974702179605b11ad8096/16:9/w_1200,h_630,c_limit/Gopnik-TheMurkyMeaningsofStraightenedOutCroissants.jpg
|
||||
http://bt.static-redmouse.ch/sites/bielertagblatt.ch/files/styles/bt_article_showroom_landscape/hash/84/c9/84c9aed08415265911ec05c46d25d3ef.jpg?itok=hP5PnHaT
|
||||
https://www.dermann.at/wp-content/uploads/Schokocroissant_HPBild_1400x900px.jpeg
|
||||
https://www.bettybossi.ch/static/rezepte/x/bb_bkxx060101_0360a_x.jpg
|
||||
http://www.engel-beck.ch/uploads/pics/tete-de-moine-gipfel-.jpg
|
||||
https://storage.cpstatic.ch/storage/og_image/laugengipfel--425319.jpg
|
||||
https://www.backhaus-kutzer.de/fileadmin/templates/Resources/Public/img/produkte/suesses-gebaeck/Milchhoernchen.png
|
||||
https://www.kuechengoetter.de/uploads/media/1000x524/00/36390-vanillekipferl-0.jpg?v=1-0
|
||||
https://c1.staticflickr.com/3/2835/10874180753_2b2916e3ce_b.jpg
|
||||
http://www.mistercool.ch/wp-content/uploads/2017/02/Gipfel-mit-Cerealien-7168.png
|
||||
https://scontent-sea1-1.cdninstagram.com/t51.2885-15/s480x480/e35/c40.0.999.999/15099604_105396696611384_2866237281000226816_n.jpg?ig_cache_key=MTM4MzQxOTU1MDc5NjUxNzcwMA%3D%3D.2.c
|
||||
http://www.lecrobag.de/wp-content/uploads/2014/03/Wurst_2014_l.jpg
|
||||
https://www.thecookierookie.com/wp-content/uploads/2017/02/sheet-pan-chocolate-croissants-collage1.jpeg
|
|
@ -1,29 +0,0 @@
|
|||
https://i.ytimg.com/vi/qF6OOGuT_hI/maxresdefault.jpg
|
||||
https://www.hd-wallpapersdownload.com/script/bulk-upload/desktop-funny-fox-wallpaper.jpg
|
||||
http://moziru.com/images/drawn-fox-funny-18.jpg
|
||||
https://static.tumblr.com/bb34d8f163098ad1daafcffbdbb03975/rk23uap/Nwwp0rmi2/tumblr_static_tumblr_static__640.jpg
|
||||
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQoHUFOnZ3wJ2kT1skNdztFXXSvpU8bEoGS1alNZiuyLXvGJhcY
|
||||
http://childrenstorytales.com/wp-content/uploads/2011/03/how-to-draw-a-red-fox-in-the-snow.jpg
|
||||
https://www.popsci.com/sites/popsci.com/files/styles/1000_1x_/public/import/2013/images/2013/09/redfoxyawn.jpg?itok=yRkSVe8T
|
||||
https://hdqwalls.com/wallpapers/wild-fox-art.jpg
|
||||
https://ae01.alicdn.com/kf/HTB1Q9dpLpXXXXbhXpXXq6xXFXXXl/new-cute-fox-toy-lifelike-soft-long-yellow-fox-doll-gift-about-73cm.jpg_640x640.jpg
|
||||
https://i.imgur.com/ktK9yXX.jpg
|
||||
https://res.cloudinary.com/teepublic/image/private/s--yTx2ncFA--/t_Preview/b_rgb:c8e0ec,c_limit,f_auto,h_313,q_90,w_313/v1506478249/production/designs/1932607_0
|
||||
http://4.bp.blogspot.com/-Hz-o_KYj3Xk/Vlm2mwbztjI/AAAAAAAA8Ss/jbH5ovjmC9A/s1600/ScreenShot5502.jpg
|
||||
https://i.pinimg.com/originals/1e/d5/2f/1ed52f70873a95ac02fa074e48edfb71.jpg
|
||||
https://i.imgur.com/2vCrtap.jpg
|
||||
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSfukWGu_IBaDeJOMBqOhVAwsDfqEPw0BFpCn5_-Iyr_xjd7zi9
|
||||
https://cdn.pixabay.com/photo/2017/01/31/18/36/animal-2026297_960_720.png
|
||||
https://i.pinimg.com/originals/e2/63/67/e26367a0844633b2a697b0a9d69e8cc9.jpg
|
||||
https://i.ebayimg.com/images/g/BvkAAOSwqxdTqrip/s-l300.jpg
|
||||
https://res.cloudinary.com/teepublic/image/private/s--1R53bger--/t_Preview/b_rgb:eae0c7,c_limit,f_jpg,h_630,q_90,w_630/v1481013120/production/designs/914528_1.jpg
|
||||
https://i.pinimg.com/originals/97/fe/69/97fe698462afde7b4209ccefeecbce71.jpg
|
||||
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT6G0ch6g-wG1TuDJ6BbkOFelMNnkgFXC6CxOw7qSNjoFkx-BCe
|
||||
https://wallpaperscraft.com/image/fox_forest_grass_117190_540x960.jpg
|
||||
https://image.freepik.com/free-vector/cartoon-flat-illustration-funny-cute-fox_6317-1174.jpg
|
||||
https://orig00.deviantart.net/2feb/f/2013/137/a/f/fox_and_curious_squirrel_by_tamarar-d65ju8d.jpg
|
||||
https://res.cloudinary.com/teepublic/image/private/s--dICeNmBx--/t_Preview/b_rgb:6e2229,c_limit,f_jpg,h_630,q_90,w_630/v1505243196/production/designs/1890493_1.jpg
|
||||
https://vignette.wikia.nocookie.net/puppyinmypocketfanon/images/4/49/L-Baby-Fox.jpg/revision/latest?cb=20130421001806
|
||||
http://7-themes.com/data_images/out/69/7009194-fox-puppy.jpg
|
||||
http://www.tehcute.com/pics/201401/little-fox-big.jpg
|
||||
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR6QXB1APLdUsyzO39kPvhnC9cOvcwzEtsxown9QjWilWppia2mwg
|
|
@ -1,13 +0,0 @@
|
|||
https://i.ytimg.com/vi/Qr6sULJnu2o/maxresdefault.jpg
|
||||
https://www.apex-expeditions.com/wp-content/uploads/2015/08/newzealandSlider_Macquarie_ElephantSealKingPenguins_GRiehle_1366x601.jpg
|
||||
https://www.birdlife.org/sites/default/files/styles/1600/public/slide.jpg?itok=HRhQfA1S
|
||||
http://experimentexchange.com/wp-content/uploads/2016/07/penguins-fact.jpg
|
||||
http://images.mentalfloss.com/sites/default/files/styles/mf_image_16x9/public/istock-511366776.jpg?itok=cWhdWNZ8&resize=1100x619
|
||||
https://www.thevaporplace.ch/media/catalog/product/cache/1/thumbnail/800x800/9df78eab33525d08d6e5fb8d27136e95/a/t/atopack_penguin-15.jpg
|
||||
https://www.superfastbusiness.com/wp-content/uploads/2015/10/real-time-penguin-algorithm-featured.jpg
|
||||
http://www.antarctica.gov.au/__data/assets/image/0011/147737/varieties/antarctic.jpg
|
||||
https://vignette.wikia.nocookie.net/robloxcreepypasta/images/1/11/AAEAAQAAAAAAAAdkAAAAJDc3YzkyYjJhLTYyZjctNDY2Mi04M2VjLTg4NjY4ZjgwYzRmNg.png/revision/latest?cb=20180207200526
|
||||
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR3xV0lhpZuhT8Nmm6LaITsppZ7VfWcWXuyu2cPHrlv_dt_M92K5g
|
||||
http://goboiano.com/wp-content/uploads/2017/04/Penguin-Kemeno-Friends-Waifu.jpg
|
||||
https://cdn.yoast.com/app/uploads/2015/10/Penguins_1200x628.png
|
||||
https://images.justwatch.com/backdrop/8611153/s1440/pingu
|
|
@ -1,23 +0,0 @@
|
|||
https://i.pinimg.com/736x/0a/a7/8a/0aa78af25e114836e1a42585fb7b09ed--funny-pumpkins-pumkin-carving.jpg
|
||||
http://wdy.h-cdn.co/assets/16/31/980x1470/gallery-1470321728-shot-two-021.jpg
|
||||
https://i.pinimg.com/736x/6c/62/bf/6c62bfa73a19ffd9fc6f2d720d5e9764--cool-pumpkin-carving-carving-pumpkins.jpg
|
||||
http://images6.fanpop.com/image/photos/38900000/Jack-o-Lantern-halloween-38991566-500-415.jpg
|
||||
http://ghk.h-cdn.co/assets/15/37/1441834730-pumpkin-carve-2.jpg
|
||||
http://diy.sndimg.com/content/dam/images/diy/fullset/2011/7/26/1/iStock-10761186_halloween-pumpkin-in-garden_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420851319631.jpeg
|
||||
http://ghk.h-cdn.co/assets/cm/15/11/54ffe537af882-snail-pumpkin-de.jpg
|
||||
https://www.digsdigs.com/photos/2009/10/100-halloween-pumpkin-carving-ideas-12.jpg
|
||||
http://diy.sndimg.com/content/dam/images/diy/fullset/2010/6/4/0/CI-Kyle-Nishioka_big-teeth-Jack-O-Lantern_s4x3.jpg.rend.hgtvcom.966.725.suffix/1420699522718.jpeg
|
||||
https://twistedsifter.files.wordpress.com/2011/10/most-amazing-pumpkin-carving-ray-villafane-10.jpg?w=521&h=739
|
||||
https://i.pinimg.com/736x/09/c4/b1/09c4b187b266c1f65332294f66009944--funny-pumpkins-halloween-pumpkins.jpg
|
||||
http://www.evilmilk.com/pictures/The_Pumpkin_Man.jpg
|
||||
http://cache.lovethispic.com/uploaded_images/blogs/13-Funny-Pumpkin-Carvings-5773-9.JPG
|
||||
http://ihappyhalloweenpictures.com/wp-content/uploads/2016/10/funny-halloween-pumpkin.jpg
|
||||
http://www.smallhomelove.com/wp-content/uploads/2012/08/leg-eating-pumpkin.jpg
|
||||
https://cdn.shopify.com/s/files/1/0773/6789/articles/Halloween_Feature_8ff7a7c4-2cb3-4584-a85f-5d4d1e6ca26e.jpg?v=1476211360
|
||||
http://4vector.com/i/free-vector-pumpkin-boy-color-version-clip-art_107714_Pumpkin_Boy_Color_Version_clip_art_hight.png
|
||||
https://i.pinimg.com/736x/59/8a/0f/598a0fbf789631b76c1ffd4443194d8e--halloween-pumpkins-fall-halloween.jpg
|
||||
https://i.pinimg.com/originals/8f/86/f9/8f86f95457467872b371ba697d341961.jpg
|
||||
http://nerdist.com/wp-content/uploads/2015/08/taleshalloween1.jpg
|
||||
http://www.designbolts.com/wp-content/uploads/2014/09/Scary-Pumpkin_Grin_stencil-Ideas.jpg
|
||||
http://vignette2.wikia.nocookie.net/scoobydoo/images/7/75/Pumpkin_monsters_%28Witch%27s_Ghost%29.png/revision/latest?cb=20140520070213
|
||||
https://taholtorf.files.wordpress.com/2013/10/36307-1920x1280.jpg
|
|
@ -1,45 +0,0 @@
|
|||
http://orig14.deviantart.net/6016/f/2010/035/c/b/first_squirrel_assassin_by_shotokanteddy.jpg
|
||||
https://thumbs-prod.si-cdn.com/eoEYA_2Hau4795uKoecUZZgz-3w=/800x600/filters:no_upscale()/https://public-media.smithsonianmag.com/filer/52/f9/52f93262-c29b-4a4f-b031-0c7ad145ed5f/42-33051942.jpg
|
||||
http://images5.fanpop.com/image/photos/30700000/Squirrel-squirrels-30710732-400-300.jpg
|
||||
https://www.lovethegarden.com/sites/default/files/files/Red%20%26%20Grey%20Squirrel%20picture%20side%20by%20side-LR.jpg
|
||||
http://i.dailymail.co.uk/i/pix/2016/02/24/16/158F7E7C000005DC-3462228-image-a-65_1456331226865.jpg
|
||||
http://2.bp.blogspot.com/-egfnMhUb8tg/T_dAIu1m6cI/AAAAAAAAPPU/v4x9q4WqWl8/s640/cute-squirrel-hey-watcha-thinkin-about.jpg
|
||||
https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Squirrel_posing.jpg/287px-Squirrel_posing.jpg
|
||||
https://i.pinimg.com/736x/51/db/9b/51db9bad4a87d445d321923c7d56b501--red-squirrel-animal-kingdom.jpg
|
||||
https://metrouk2.files.wordpress.com/2016/10/ad_223291521.jpg?w=620&h=949&crop=1
|
||||
http://www.redsquirrelsunited.org.uk/wp-content/uploads/2016/07/layer-slider.jpg
|
||||
http://images.mentalfloss.com/sites/default/files/squirrel-hero.jpg?resize=1100x740
|
||||
https://i.pinimg.com/736x/ce/9c/59/ce9c5990b193046400d98724595cdaf3--red-squirrel-chipmunks.jpg
|
||||
https://www.brooklynpaper.com/assets/photos/40/30/dtg-squirrel-attacks-prospect-park-patrons-2017-07-28-bk01_z.jpg
|
||||
http://www.freakingnews.com/pictures/16000/Squirrel-Shark-16467.jpg
|
||||
http://img09.deviantart.net/5c1c/i/2013/138/0/6/barbarian_squirel_by_coucoucmoa-d64r9m4.jpg
|
||||
https://i.pinimg.com/736x/b4/5c/0d/b45c0d00b1a57e9f84f27f13cb019001--baby-squirrel-red-squirrel.jpg
|
||||
https://i.pinimg.com/736x/0f/75/87/0f7587bb613ab524763afe8c9a532e5c--cute-squirrel-squirrels.jpg
|
||||
http://cdn.images.express.co.uk/img/dynamic/128/590x/Grey-squirrel-828838.jpg
|
||||
http://www.lovethispic.com/uploaded_images/79964-Squirrel-Smelling-A-Flower.jpg
|
||||
https://i.pinimg.com/736x/23/d5/f9/23d5f9868f7d76c79c49bef53ae08f7f--squirrel-funny-red-squirrel.jpg
|
||||
http://stories.barkpost.com/wp-content/uploads/2016/01/squirrel-3-copy.jpg
|
||||
https://i.ytimg.com/vi/pzUs0DdzK3Y/hqdefault.jpg
|
||||
https://www.askideas.com/media/41/I-Swear-It-Wasnt-Me-Funny-Squirrel-Meme-Picture-For-Facebook.jpg
|
||||
https://i.pinimg.com/736x/2d/54/d8/2d54d8d2a9b3ab9d3e78544b75afd88e--funny-animal-pictures-humorous-pictures.jpg
|
||||
http://www.funny-animalpictures.com/media/content/items/images/funnysquirrels0012_O.jpg
|
||||
http://funny-pics.co/wp-content/uploads/funny-squirrel-and-coffee-picture.jpg
|
||||
https://pbs.twimg.com/media/Bi4Ij6CIgAAgEdZ.jpg
|
||||
http://www.funnyjunksite.com/pictures/wp-content/uploads/2015/06/Funny-Superman-Squirrels.jpg
|
||||
https://i.pinimg.com/736x/bf/35/00/bf3500104f8394909d116259d1f0575e--funny-squirrel-squirrel-girl.jpg
|
||||
http://quotespill.com/wp-content/uploads/2017/07/Squirrel-Meme-Draw-me-like-one-of-your-french-squirrrels-min.jpg
|
||||
https://i.pinimg.com/736x/e2/16/bb/e216bba53f80fc8e0111d371e9850159--funny-squirrels-cute-squirrel.jpg
|
||||
https://i.pinimg.com/736x/52/43/c9/5243c93377245be1f686218c266d775c--funny-squirrel-baby-squirrel.jpg
|
||||
https://i.pinimg.com/736x/0c/be/1d/0cbe1da8ad2c0cf3882a806b6fd88965--cute-pictures-funny-animal-pictures.jpg
|
||||
https://i.pinimg.com/736x/e5/08/67/e508670aa00ca3c896eccb81c4f6e2a8--funny-squirrel-baby-squirrel.jpg
|
||||
https://i.pinimg.com/736x/1c/7d/4f/1c7d4f067a10066aad802ce5ac468d71--group-boards-a-squirrel.jpg
|
||||
http://funny-pics.co/wp-content/uploads/funny-squirrel-on-a-branch.jpg
|
||||
http://loldamn.com/wp-content/uploads/2016/06/funny-squirrel-playing-water-bending.jpg
|
||||
https://cdn.trendhunterstatic.com/thumbs/squirrel-photography.jpeg
|
||||
https://i.pinimg.com/736x/d6/42/12/d64212cc6221916db4173962bf6c131a--cute-squirrel-baby-squirrel.jpg
|
||||
https://i.pinimg.com/236x/10/13/58/101358f2afc2c7d6b6a668046e7b8382--funny-animal-pictures-funny-animals.jpg
|
||||
https://i.pinimg.com/736x/da/0d/fe/da0dfe93bb26887795f906e8fa97d68e--secret-squirrel-cute-squirrel.jpg
|
||||
http://2.bp.blogspot.com/-HLieBqEuQoM/UDkRmeyzB5I/AAAAAAAABHs/RtsEynn5t6Y/s1600/hd-squirrel-wallpaper-with-a-brown-squirrel-eating-watermelon-wallpapers-backgrounds-pictures-photos.jpg
|
||||
http://www.city-data.com/forum/members/brenda-starz-328928-albums-brenda-s-funny-squirrel-comment-pic-s-pic5075-punk-squirrels.jpg
|
||||
http://img15.deviantart.net/9c50/i/2011/213/c/9/just_taking_it_easy_by_lou_in_canada-d42do3d.jpg
|
||||
http://3.bp.blogspot.com/-AwsSk76R2Is/USQa3-dszKI/AAAAAAAABUQ/KF_F8HbtP1U/w1200-h630-p-k-no-nu/crazySquirrel.jpg
|
|
@ -1,7 +0,0 @@
|
|||
namespace Geekbot.net.WebApi
|
||||
{
|
||||
public class ApiError
|
||||
{
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Callback
|
||||
{
|
||||
public class CallbackController : Controller
|
||||
{
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public CallbackController(DiscordSocketClient client, IGlobalSettings globalSettings)
|
||||
{
|
||||
_client = client;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
[Route("/callback")]
|
||||
public async Task<IActionResult> DoCallback([FromQuery] string code)
|
||||
{
|
||||
var token = "";
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.BaseAddress = new Uri("https://discordapp.com");
|
||||
var appInfo = await _client.GetApplicationInfoAsync();
|
||||
var accessToken = _globalSettings.GetKey("OAuthToken");
|
||||
var callbackUrl = _globalSettings.GetKey("OAuthCallbackUrl");
|
||||
|
||||
var form = new Dictionary<string, string>();
|
||||
form.Add("client_id", appInfo.Id.ToString());
|
||||
form.Add("client_secret", accessToken);
|
||||
form.Add("grant_type", "authorization_code");
|
||||
form.Add("code", code);
|
||||
form.Add("scope", "identify email guilds");
|
||||
form.Add("redirect_uri", callbackUrl);
|
||||
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
|
||||
var result = await client.PostAsync("/api/oauth2/token", new FormUrlEncodedContent(form));
|
||||
result.EnsureSuccessStatusCode();
|
||||
|
||||
var stringResponse = await result.Content.ReadAsStringAsync();
|
||||
var responseData = JsonConvert.DeserializeObject<CallbackTokenResponseDto>(stringResponse);
|
||||
token = responseData.access_token;
|
||||
}
|
||||
|
||||
return new RedirectResult($"https://geekbot.pizzaandcoffee.rocks/login?token={token}", false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
namespace Geekbot.net.WebApi.Controllers.Callback
|
||||
{
|
||||
public class CallbackTokenResponseDto
|
||||
{
|
||||
public string access_token { get; set; }
|
||||
public string token_type { get; set; }
|
||||
public int expires_in { get; set; }
|
||||
public string refresh_token { get; set; }
|
||||
public string scope { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
using System.Linq;
|
||||
using Discord.Commands;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Commands
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class CommandController : Controller
|
||||
{
|
||||
private readonly CommandService _commands;
|
||||
|
||||
public CommandController(CommandService commands)
|
||||
{
|
||||
_commands = commands;
|
||||
}
|
||||
|
||||
[Route("/v1/commands")]
|
||||
public IActionResult GetCommands()
|
||||
{
|
||||
var commandList = (from cmd in _commands.Commands
|
||||
let cmdParamsObj = cmd.Parameters.Select(cmdParam => new CommandParamDto
|
||||
{
|
||||
Summary = cmdParam.Summary,
|
||||
Default = cmdParam.DefaultValue?.ToString(),
|
||||
Type = cmdParam.Type?.ToString()
|
||||
})
|
||||
.ToList()
|
||||
let param = string.Join(", !", cmd.Aliases)
|
||||
select new CommandDto
|
||||
{
|
||||
Name = cmd.Name,
|
||||
Summary = cmd.Summary,
|
||||
IsAdminCommand = param.Contains("admin") || param.Contains("owner"),
|
||||
Aliases = cmd.Aliases.ToList(),
|
||||
Params = cmdParamsObj
|
||||
}).ToList();
|
||||
return Ok(commandList.FindAll(e => !e.Aliases[0].StartsWith("owner")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Commands
|
||||
{
|
||||
public class CommandDto
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public bool IsAdminCommand { get; set; }
|
||||
public List<string> Aliases { get; set; }
|
||||
public List<CommandParamDto> Params { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Geekbot.net.WebApi.Controllers.Commands
|
||||
{
|
||||
public class CommandParamDto
|
||||
{
|
||||
public string Summary { get; set; }
|
||||
public string Default { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Geekbot.net.Lib.Highscores;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Highscores
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class HighscoreController : Controller
|
||||
{
|
||||
private readonly IHighscoreManager _highscoreManager;
|
||||
|
||||
public HighscoreController(IHighscoreManager highscoreManager)
|
||||
{
|
||||
_highscoreManager = highscoreManager;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Route("/v1/highscore")]
|
||||
public IActionResult GetHighscores([FromBody] HighscoreControllerPostBodyDto body)
|
||||
{
|
||||
if (!ModelState.IsValid || body == null)
|
||||
{
|
||||
var error = new SerializableError(ModelState);
|
||||
return BadRequest(error);
|
||||
}
|
||||
|
||||
Dictionary<HighscoreUserDto, int> list;
|
||||
try
|
||||
{
|
||||
list = _highscoreManager.GetHighscoresWithUserData(body.Type, body.GuildId, body.Amount);
|
||||
}
|
||||
catch (HighscoreListEmptyException)
|
||||
{
|
||||
return NotFound(new ApiError
|
||||
{
|
||||
Message = $"No {body.Type} found on this server"
|
||||
});
|
||||
}
|
||||
|
||||
var response = new List<HighscoreControllerReponseBody>();
|
||||
var counter = 1;
|
||||
foreach (var item in list)
|
||||
{
|
||||
response.Add(new HighscoreControllerReponseBody
|
||||
{
|
||||
count = item.Value,
|
||||
rank = counter,
|
||||
user = item.Key
|
||||
});
|
||||
counter++;
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Geekbot.net.Lib.Highscores;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Highscores
|
||||
{
|
||||
public class HighscoreControllerPostBodyDto
|
||||
{
|
||||
[Required]
|
||||
public ulong GuildId { get; set; }
|
||||
|
||||
public HighscoreTypes Type { get; set; } = HighscoreTypes.messages;
|
||||
|
||||
[Range(1, 150)]
|
||||
public int Amount { get; set; } = 50;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
using Geekbot.net.Lib.Highscores;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Highscores
|
||||
{
|
||||
public class HighscoreControllerReponseBody
|
||||
{
|
||||
public int rank { get; set; }
|
||||
public HighscoreUserDto user { get; set; }
|
||||
public int count { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace Geekbot.net.WebApi.Controllers.Status
|
||||
{
|
||||
public class ApiStatusDto
|
||||
{
|
||||
public string GeekbotVersion { get; set; }
|
||||
public string ApiVersion { get; set; }
|
||||
public string Status { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
using System.Globalization;
|
||||
using Geekbot.net.Lib;
|
||||
using Microsoft.AspNetCore.Cors;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Geekbot.net.WebApi.Controllers.Status
|
||||
{
|
||||
[EnableCors("AllowSpecificOrigin")]
|
||||
public class StatusController : Controller
|
||||
{
|
||||
[Route("/")]
|
||||
public IActionResult GetCommands()
|
||||
{
|
||||
var responseBody = new ApiStatusDto
|
||||
{
|
||||
GeekbotVersion = Constants.BotVersion(),
|
||||
ApiVersion = Constants.ApiVersion.ToString(CultureInfo.InvariantCulture),
|
||||
Status = "Online"
|
||||
};
|
||||
return Ok(responseBody);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
using System.Collections.Concurrent;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.net.WebApi.Logging
|
||||
{
|
||||
public class AspLogProvider : ILoggerProvider
|
||||
{
|
||||
private readonly IGeekbotLogger _geekbotLogger;
|
||||
|
||||
private readonly ConcurrentDictionary<string, AspLogger> _loggers = new ConcurrentDictionary<string, AspLogger>();
|
||||
|
||||
public AspLogProvider(IGeekbotLogger geekbotLogger)
|
||||
{
|
||||
_geekbotLogger = geekbotLogger;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_loggers.Clear();
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return _loggers.GetOrAdd(categoryName, name => new AspLogger(categoryName, _geekbotLogger));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
using System;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.net.WebApi.Logging
|
||||
{
|
||||
public class AspLogger : ILogger
|
||||
{
|
||||
private readonly string _categoryName;
|
||||
private readonly IGeekbotLogger _geekbotLogger;
|
||||
|
||||
public AspLogger(string categoryName, IGeekbotLogger geekbotLogger)
|
||||
{
|
||||
geekbotLogger.Trace(LogSource.Api, $"Adding {categoryName}");
|
||||
_categoryName = categoryName;
|
||||
_geekbotLogger = geekbotLogger;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
_geekbotLogger.Trace(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Debug:
|
||||
_geekbotLogger.Debug(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Information:
|
||||
_geekbotLogger.Information(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}");
|
||||
break;
|
||||
case LogLevel.Warning:
|
||||
_geekbotLogger.Warning(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}", exception);
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
case LogLevel.Critical:
|
||||
_geekbotLogger.Error(LogSource.Api, $"{eventId.Id} - {_categoryName} - {state}", exception);
|
||||
break;
|
||||
case LogLevel.None:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(logLevel));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
return !_geekbotLogger.LogAsJson() && _geekbotLogger.GetNLogger().IsEnabled(ToGeekbotLogLevel(logLevel));
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private static NLog.LogLevel ToGeekbotLogLevel(LogLevel level)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case LogLevel.Trace:
|
||||
return NLog.LogLevel.Trace;
|
||||
case LogLevel.Debug:
|
||||
return NLog.LogLevel.Debug;
|
||||
case LogLevel.Information:
|
||||
return NLog.LogLevel.Info;
|
||||
case LogLevel.Warning:
|
||||
return NLog.LogLevel.Warn;
|
||||
case LogLevel.Error:
|
||||
return NLog.LogLevel.Error;
|
||||
case LogLevel.Critical:
|
||||
return NLog.LogLevel.Fatal;
|
||||
case LogLevel.None:
|
||||
return NLog.LogLevel.Off;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(level));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
using System.Net;
|
||||
using System.Reflection;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Lib;
|
||||
using Geekbot.net.Lib.GlobalSettings;
|
||||
using Geekbot.net.Lib.Highscores;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Geekbot.net.WebApi.Logging;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Geekbot.net.WebApi
|
||||
{
|
||||
public static class WebApiStartup
|
||||
{
|
||||
public static void StartWebApi(IGeekbotLogger logger, RunParameters runParameters, CommandService commandService,
|
||||
DatabaseContext databaseContext, DiscordSocketClient client, IGlobalSettings globalSettings, IHighscoreManager highscoreManager)
|
||||
{
|
||||
WebHost.CreateDefaultBuilder()
|
||||
.UseKestrel(options =>
|
||||
{
|
||||
options.Listen(IPAddress.Any, int.Parse(runParameters.ApiPort));
|
||||
})
|
||||
.ConfigureServices(services =>
|
||||
{
|
||||
services.AddMvc();
|
||||
services.AddSingleton<CommandService>(commandService);
|
||||
services.AddSingleton<DatabaseContext>(databaseContext);
|
||||
services.AddSingleton<DiscordSocketClient>(client);
|
||||
services.AddSingleton<IGlobalSettings>(globalSettings);
|
||||
services.AddSingleton<IHighscoreManager>(highscoreManager);
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOrigin",
|
||||
builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
|
||||
});
|
||||
})
|
||||
.Configure(app =>
|
||||
{
|
||||
app.UseMvc();
|
||||
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().Build());
|
||||
})
|
||||
.ConfigureLogging(logging =>
|
||||
{
|
||||
logging.ClearProviders();
|
||||
logging.SetMinimumLevel(LogLevel.Debug);
|
||||
logging.AddProvider(new AspLogProvider(logger));
|
||||
})
|
||||
.UseSetting(WebHostDefaults.ApplicationKey, typeof(Program).GetTypeInfo().Assembly.FullName)
|
||||
.Build().Run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Geekbot.net.Lib.Localization;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Tests.Lib.Localization
|
||||
{
|
||||
public class TranslationGuildContext_test
|
||||
{
|
||||
public class FormatDateTimeAsRemainingTestDto
|
||||
{
|
||||
public DateTimeOffset DateTime { get; set; }
|
||||
public string Expected { get; set; }
|
||||
}
|
||||
|
||||
public static TestData<FormatDateTimeAsRemainingTestDto> FormatDateTimeAsRemainingData =>
|
||||
new TestData<FormatDateTimeAsRemainingTestDto>
|
||||
{
|
||||
{
|
||||
"Wait for days",
|
||||
new FormatDateTimeAsRemainingTestDto
|
||||
{
|
||||
DateTime = DateTimeOffset.Now.AddDays(5),
|
||||
Expected = "4 days, 23 hours, 59 minutes and 59 seconds"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Wait for minutes",
|
||||
new FormatDateTimeAsRemainingTestDto
|
||||
{
|
||||
DateTime = DateTimeOffset.Now.AddMinutes(5),
|
||||
Expected = "4 minutes and 59 seconds"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Wait for seconds",
|
||||
new FormatDateTimeAsRemainingTestDto
|
||||
{
|
||||
DateTime = DateTimeOffset.Now.AddSeconds(5),
|
||||
Expected = "4 seconds"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[Theory, MemberData(nameof(FormatDateTimeAsRemainingData))]
|
||||
public void FormatDateTimeAsRemaining(string testName, FormatDateTimeAsRemainingTestDto testData)
|
||||
{
|
||||
var translationHandlerMock = new Mock<ITranslationHandler>(MockBehavior.Loose);
|
||||
translationHandlerMock
|
||||
.Setup(thm => thm.GetString("EN", "dateTime", "Days"))
|
||||
.Returns("day|days");
|
||||
translationHandlerMock
|
||||
.Setup(thm => thm.GetString("EN", "dateTime", "Hours"))
|
||||
.Returns("hour|hours");
|
||||
translationHandlerMock
|
||||
.Setup(thm => thm.GetString("EN", "dateTime", "Minutes"))
|
||||
.Returns("minute|minutes");
|
||||
translationHandlerMock
|
||||
.Setup(thm => thm.GetString("EN", "dateTime", "Seconds"))
|
||||
.Returns("second|seconds");
|
||||
translationHandlerMock
|
||||
.Setup(thm => thm.GetString("EN", "dateTime", "And"))
|
||||
.Returns("and");
|
||||
|
||||
var context = new TranslationGuildContext(translationHandlerMock.Object, "EN", new Dictionary<string, string>());
|
||||
var result = context.FormatDateTimeAsRemaining(testData.DateTime);
|
||||
Assert.Equal(result, testData.Expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Tests.Lib.Localization
|
||||
{
|
||||
public class Translations_test
|
||||
{
|
||||
[Fact]
|
||||
public void TranslationsYamlIsValid()
|
||||
{
|
||||
// Read the file
|
||||
var translationFile = File.ReadAllText(Path.GetFullPath("./../../../../Geekbot.net/Lib/Localization/Translations.yml"));
|
||||
|
||||
// Deserialize
|
||||
var input = new StringReader(translationFile);
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var rawTranslations = deserializer.Deserialize<Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(input);
|
||||
|
||||
// These languages must be supported
|
||||
var supportedLanguages = new List<string>
|
||||
{
|
||||
"EN",
|
||||
"CHDE"
|
||||
};
|
||||
|
||||
// Iterate every single key to make sure it's populated
|
||||
foreach (var command in rawTranslations)
|
||||
{
|
||||
foreach (var str in command.Value)
|
||||
{
|
||||
str.Value.Select(e => e.Key).ToList().Should().BeEquivalentTo(supportedLanguages, str.Key);
|
||||
foreach (var lang in str.Value)
|
||||
{
|
||||
lang.Value.Should().NotBeNullOrEmpty($"{command.Key} / {str.Key} / {lang.Key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace WikipediaApi.Page
|
||||
{
|
||||
public class PageApiUrls
|
||||
{
|
||||
public Uri Summary { get; set; }
|
||||
public Uri Metadata { get; set; }
|
||||
public Uri References { get; set; }
|
||||
public Uri Media { get; set; }
|
||||
public Uri EditHtml { get; set; }
|
||||
public Uri TalkPageHtml { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace WikipediaApi.Page
|
||||
{
|
||||
public class PageContentUrlCollection
|
||||
{
|
||||
public PageContentUrls Desktop { get; set; }
|
||||
public PageContentUrls Mobile { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace WikipediaApi.Page
|
||||
{
|
||||
public class PageContentUrls
|
||||
{
|
||||
public Uri Page { get; set; }
|
||||
public Uri Revisions { get; set; }
|
||||
public Uri Edit { get; set; }
|
||||
public Uri Talk { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace WikipediaApi.Page
|
||||
{
|
||||
public class PageCoordinates
|
||||
{
|
||||
public float Lat { get; set; }
|
||||
public float Lon { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace WikipediaApi.Page
|
||||
{
|
||||
public class PageImage
|
||||
{
|
||||
public Uri Source { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue