mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 09:48:26 -04:00
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
59cea6ee38 | ||
|
cbcfa77a34 | ||
|
cfb202cc95 | ||
|
b7d1fd1b47 | ||
|
4cf3bdb53a | ||
|
aab5bc9744 | ||
|
1f14c9066e | ||
|
9ade3c9537 | ||
|
1dc393d2b1 | ||
|
798b66db9b | ||
|
57e65e5515 | ||
|
86e728b753 | ||
|
fd032d3e91 | ||
|
eab16865cd | ||
|
a34a86bbfa | ||
|
a016b3546f | ||
|
e09435da37 | ||
|
416f3d604c | ||
|
d9f371f994 | ||
|
c1c22d0477 | ||
|
339f13d31a | ||
|
4190f07d9c | ||
|
a9bdf36c53 | ||
|
1913cd4309 | ||
|
624439f684 | ||
|
3e14dc22cb | ||
|
f4178aeacd | ||
|
aaf3c9cfe9 | ||
|
f6ee012b15 | ||
|
363ef42923 | ||
|
cc522ef872 | ||
|
0e192ee7f0 | ||
|
ddd0592b30 | ||
|
c4efe2965b | ||
|
a90b5a62f3 | ||
|
50a4497532 | ||
|
c3d6183d73 | ||
|
864a8fd7b6 | ||
|
e7db631151 | ||
|
c7b312196e | ||
|
8cd7a50720 | ||
|
f82c4c7019 | ||
|
03367c5ec4 | ||
|
01cc6e52d5 | ||
|
c903bc9003 | ||
|
323699d103 | ||
|
63ced029ab |
@@ -97,29 +97,29 @@ upload-windows-updater-release:
|
|||||||
- aws --endpoint-url $AWS_SERVICE_URL s3api put-object --bucket "$AWS_BUCKET_NAME" --key "dl/bot/$INSTALLER_FILE_NAME" --acl public-read --body "$INSTALLER_OUTPUT_DIR/$INSTALLER_FILE_NAME"
|
- aws --endpoint-url $AWS_SERVICE_URL s3api put-object --bucket "$AWS_BUCKET_NAME" --key "dl/bot/$INSTALLER_FILE_NAME" --acl public-read --body "$INSTALLER_OUTPUT_DIR/$INSTALLER_FILE_NAME"
|
||||||
- aws --endpoint-url $AWS_SERVICE_URL s3api put-object --bucket "$AWS_BUCKET_NAME" --key "dl/bot/releases-v3.json" --acl public-read --body "releases-v3.json"
|
- aws --endpoint-url $AWS_SERVICE_URL s3api put-object --bucket "$AWS_BUCKET_NAME" --key "dl/bot/releases-v3.json" --acl public-read --body "releases-v3.json"
|
||||||
|
|
||||||
# docker-build:
|
docker-build:
|
||||||
# # Use the official docker image.
|
# Use the official docker image.
|
||||||
# image: docker:latest
|
image: docker:latest
|
||||||
# stage: build
|
stage: build
|
||||||
# services:
|
services:
|
||||||
# - docker:dind
|
- docker:dind
|
||||||
# before_script:
|
before_script:
|
||||||
# - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||||
# # Default branch leaves tag empty (= latest tag)
|
# Default branch leaves tag empty (= latest tag)
|
||||||
# # All other branches are tagged with the escaped branch name (commit ref slug)
|
# All other branches are tagged with the escaped branch name (commit ref slug)
|
||||||
# script:
|
script:
|
||||||
# - |
|
- |
|
||||||
# if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
|
if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
|
||||||
# tag=""
|
tag=""
|
||||||
# echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
|
echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
|
||||||
# else
|
else
|
||||||
# tag=":$CI_COMMIT_REF_SLUG"
|
tag=":$CI_COMMIT_REF_SLUG"
|
||||||
# echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
|
echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
|
||||||
# fi
|
fi
|
||||||
# - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
|
- docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
|
||||||
# - docker push "$CI_REGISTRY_IMAGE${tag}"
|
- docker push "$CI_REGISTRY_IMAGE${tag}"
|
||||||
# # Run this job in a branch where a Dockerfile exists
|
# Run this job in a branch where a Dockerfile exists
|
||||||
# rules:
|
rules:
|
||||||
# - if: $CI_COMMIT_BRANCH
|
- if: $CI_COMMIT_BRANCH
|
||||||
# exists:
|
exists:
|
||||||
# - Dockerfile
|
- Dockerfile
|
||||||
|
41
CHANGELOG.md
41
CHANGELOG.md
@@ -5,6 +5,44 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
- More cool stuff coming soon
|
||||||
|
|
||||||
|
## [4.0.5] - 21.03.2022
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Fixed several bugs in the currency code
|
||||||
|
- Fixed some potential memory leaks
|
||||||
|
- Fixed some response strings
|
||||||
|
|
||||||
|
## [4.0.4] - 04.03.2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed the `id` which shows up when you add a new Expression
|
||||||
|
- Fixed some strings which were still referring to "CustomReaction(s)" instead of "Expression(s)"
|
||||||
|
|
||||||
|
## [4.0.3] - 04.03.2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Console should no longer spam numbers when `.antispam` is enabled
|
||||||
|
|
||||||
|
## [4.0.2] - 03.03.2022
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed `.rero` not working due to a bug introduced in 4.0
|
||||||
|
|
||||||
|
## [4.0.1] - 03.03.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `usePrivilegedIntents` to creds.yml if you don't have or don't want (?) to use them
|
||||||
|
- Added a human-readable, detailed error message if logging in fails due to missing privileged intents
|
||||||
|
|
||||||
|
## [4.0.0] - 02.03.2022
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Added `.deleteemptyservers` command
|
- Added `.deleteemptyservers` command
|
||||||
- Added `.curtr <id>` which lets you see full information about one of your own transactions with the specified id
|
- Added `.curtr <id>` which lets you see full information about one of your own transactions with the specified id
|
||||||
@@ -43,6 +81,7 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
|
|||||||
- [dev] Moved FilterWordsChannelId to a separate table
|
- [dev] Moved FilterWordsChannelId to a separate table
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Fixed twitch stream notifications (rewrote it to use the new api)
|
||||||
- Fixed an extra whitespace in usage part of command help if the command has no arguments
|
- Fixed an extra whitespace in usage part of command help if the command has no arguments
|
||||||
- Possible small fix for `.prune` ratelimiting
|
- Possible small fix for `.prune` ratelimiting
|
||||||
- `.gvc` should now properly trigger when a user is already in a gvc and changes his activity
|
- `.gvc` should now properly trigger when a user is already in a gvc and changes his activity
|
||||||
@@ -462,4 +501,4 @@ Experimental changelog. Mostly based on [keepachangelog](https://keepachangelog.
|
|||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Removed admin requirement on `.scrm` as it didn't make sense
|
- Removed admin requirement on `.scrm` as it didn't make sense
|
||||||
- Some Music commands are removed because of the complexity they bring in with little value (if you *really* want them back, you can open an issue and specify your *good* reason)
|
- Some Music commands are removed because of the complexity they bring in with little value (if you *really* want them back, you can open an issue and specify your *good* reason)
|
||||||
|
@@ -25,7 +25,7 @@ RUN set -xe; \
|
|||||||
useradd -m nadeko; \
|
useradd -m nadeko; \
|
||||||
apt-get update; \
|
apt-get update; \
|
||||||
apt-get install -y libopus0 libsodium23 libsqlite3-0 curl ffmpeg python3 python3-pip sudo; \
|
apt-get install -y libopus0 libsodium23 libsqlite3-0 curl ffmpeg python3 python3-pip sudo; \
|
||||||
update-alternatives --install /usr/bin/python python /usr/bin/python3.7 1; \
|
update-alternatives --install /usr/bin/python python /usr/bin/python3.9 1; \
|
||||||
echo 'Defaults>nadeko env_keep+="ASPNETCORE_* DOTNET_* NadekoBot_* shard_id total_shards TZ"' > /etc/sudoers.d/nadeko; \
|
echo 'Defaults>nadeko env_keep+="ASPNETCORE_* DOTNET_* NadekoBot_* shard_id total_shards TZ"' > /etc/sudoers.d/nadeko; \
|
||||||
pip3 install --upgrade youtube-dl; \
|
pip3 install --upgrade youtube-dl; \
|
||||||
apt-get remove -y python3-pip; \
|
apt-get remove -y python3-pip; \
|
||||||
@@ -39,4 +39,4 @@ ENV total_shards=1
|
|||||||
|
|
||||||
VOLUME [ "app/data" ]
|
VOLUME [ "app/data" ]
|
||||||
ENTRYPOINT [ "/usr/local/sbin/docker-entrypoint.sh" ]
|
ENTRYPOINT [ "/usr/local/sbin/docker-entrypoint.sh" ]
|
||||||
CMD dotnet NadekoBot.dll "$shard_id" "$total_shards"
|
CMD dotnet NadekoBot.dll "$shard_id" "$total_shards"
|
||||||
|
@@ -1,18 +1,25 @@
|
|||||||
# Setting up NadekoBot with Docker
|
# Setting up NadekoBot with Docker
|
||||||
|
|
||||||
# DO NOT USE YET - WORK IN PROGRESS
|
# WORK IN PROGRESS
|
||||||
|
|
||||||
### Docker Compose
|
### Installation
|
||||||
|
|
||||||
|
1. Create a `/srv/nadeko` folder
|
||||||
|
- `mkdir -p /srv/nadeko`
|
||||||
|
2. Create a `docker-compose.yml`
|
||||||
|
- nano `docker-compose.yml`
|
||||||
|
- copy the following contents into it:
|
||||||
|
##### docker-compose.yml
|
||||||
```yml
|
```yml
|
||||||
version: "3.7"
|
version: "3.7"
|
||||||
services:
|
services:
|
||||||
nadeko:
|
nadeko:
|
||||||
image: registry.gitlab.com/veovis/nadekobot:v3-docker
|
image: registry.gitlab.com/kwoth/nadekobot:latest
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
environment:
|
environment:
|
||||||
TZ: Europe/Paris
|
TZ: Europe/Paris
|
||||||
#NadekoBot_RedisOptions: redis,name=nadeko
|
NadekoBot_RedisOptions: redis,name=nadeko
|
||||||
#NadekoBot_ShardRunCommand: dotnet
|
#NadekoBot_ShardRunCommand: dotnet
|
||||||
#NadekoBot_ShardRunArguments: /app/NadekoBot.dll {0} {1}
|
#NadekoBot_ShardRunArguments: /app/NadekoBot.dll {0} {1}
|
||||||
volumes:
|
volumes:
|
||||||
@@ -27,6 +34,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /srv/nadeko/redis-data:/data
|
- /srv/nadeko/redis-data:/data
|
||||||
```
|
```
|
||||||
|
3. Save your file and run docker compose
|
||||||
|
- `docker-compose up`
|
||||||
|
4. Edit creds in `/srv/nadeko/conf/creds.yml`
|
||||||
|
5. Run it again with
|
||||||
|
- `docker-compose up`
|
||||||
|
|
||||||
### Updating
|
### Updating
|
||||||
- `cd /srv/nadeko`
|
- `cd /srv/nadeko`
|
||||||
- `docker-compose pull`
|
- `docker-compose pull`
|
||||||
|
@@ -26,14 +26,24 @@ It is recommended that you use **Ubuntu 20.04**, as there have been nearly no pr
|
|||||||
|
|
||||||
## Linux From Source
|
## Linux From Source
|
||||||
|
|
||||||
Open Terminal (if you're on an installation with a window manager) and navigate to the location where you want to install the bot (for example `cd ~`)
|
##### Migration from v3 -> v4
|
||||||
|
|
||||||
|
Follow the following few steps only if you're migrating from v3. If not, skip to installation instructions.
|
||||||
|
|
||||||
|
Use the new installer script: `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
|
> - Install prerequisites (type `1` and press `enter`)
|
||||||
|
> - Download (type `2` and press `enter`)
|
||||||
|
> - Run (type `3` and press `enter`)
|
||||||
|
> - Done
|
||||||
|
|
||||||
##### Installation Instructions
|
##### Installation Instructions
|
||||||
|
|
||||||
1. Download and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/master/linuxAIO.sh && bash linuxAIO.sh`
|
Open Terminal (if you're on an installation with a window manager) and navigate to the location where you want to install the bot (for example `cd ~`)
|
||||||
|
|
||||||
|
1. Download and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
2. Install prerequisites (type `1` and press enter)
|
2. Install prerequisites (type `1` and press enter)
|
||||||
3. Download the bot (type `2` and press enter)
|
3. Download the bot (type `2` and press enter)
|
||||||
4. Exit the installer (type `5` and press enter)
|
4. Exit the installer (type `6` and press enter)
|
||||||
5. Copy the creds.yml template `cp nadekobot/output/creds_example.yml nadekobot/output/creds.yml`
|
5. Copy the creds.yml template `cp nadekobot/output/creds_example.yml nadekobot/output/creds.yml`
|
||||||
6. Open `nadekobot/output/creds.yml` with your favorite text editor. We will use nano here
|
6. Open `nadekobot/output/creds.yml` with your favorite text editor. We will use nano here
|
||||||
- `nano nadekobot/output/creds.yml`
|
- `nano nadekobot/output/creds.yml`
|
||||||
@@ -42,12 +52,13 @@ Open Terminal (if you're on an installation with a window manager) and navigate
|
|||||||
- `CTRL` + `X`
|
- `CTRL` + `X`
|
||||||
- `Y`
|
- `Y`
|
||||||
- `Enter`
|
- `Enter`
|
||||||
8. Run the bot (type `3` and press enter)
|
8. Run the installer script again `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
|
9. Run the bot (type `3` and press enter)
|
||||||
|
|
||||||
##### Source Update Instructions
|
##### Source Update Instructions
|
||||||
|
|
||||||
1. ⚠ Stop the bot ⚠
|
1. ⚠ Stop the bot ⚠
|
||||||
2. Update and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/master/linuxAIO.sh && bash linuxAIO.sh`
|
2. Update and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
3. Update the bot (type `2` and press enter)
|
3. Update the bot (type `2` and press enter)
|
||||||
4. Run the bot (type `3` and press enter)
|
4. Run the bot (type `3` and press enter)
|
||||||
5. 🎉
|
5. 🎉
|
||||||
|
@@ -31,7 +31,7 @@ sudo ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/
|
|||||||
|
|
||||||
##### Installation Instructions
|
##### Installation Instructions
|
||||||
|
|
||||||
1. Download and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/master/linuxAIO.sh && bash linuxAIO.sh`
|
1. Download and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
2. Install prerequisites (type `1` and press enter)
|
2. Install prerequisites (type `1` and press enter)
|
||||||
3. Download the bot (type `2` and press enter)
|
3. Download the bot (type `2` and press enter)
|
||||||
4. Exit the installer in order to set up your `creds.yml`
|
4. Exit the installer in order to set up your `creds.yml`
|
||||||
@@ -49,7 +49,7 @@ sudo ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/
|
|||||||
##### Update Instructions
|
##### Update Instructions
|
||||||
|
|
||||||
1. ⚠ Stop the bot
|
1. ⚠ Stop the bot
|
||||||
2. Update and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/master/linuxAIO.sh && bash linuxAIO.sh`
|
2. Update and run the **new** installer script `cd ~ && wget -N https://gitlab.com/Kwoth/nadeko-bash-installer/-/raw/v4/linuxAIO.sh && bash linuxAIO.sh`
|
||||||
3. Update the bot (type `2` and press enter)
|
3. Update the bot (type `2` and press enter)
|
||||||
4. Run the bot (type `3` and press enter)
|
4. Run the bot (type `3` and press enter)
|
||||||
5. 🎉
|
5. 🎉
|
||||||
|
@@ -15,6 +15,9 @@ namespace NadekoBot.Services
|
|||||||
.MinimumLevel.Override("System", LogEventLevel.Information)
|
.MinimumLevel.Override("System", LogEventLevel.Information)
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.File("coord.log", LogEventLevel.Information,
|
||||||
|
rollOnFileSizeLimit: true,
|
||||||
|
fileSizeLimitBytes: 10_000_000)
|
||||||
.WriteTo.Console(LogEventLevel.Information,
|
.WriteTo.Console(LogEventLevel.Information,
|
||||||
theme: GetTheme(),
|
theme: GetTheme(),
|
||||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}")
|
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}")
|
||||||
|
@@ -9,9 +9,10 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.42.0" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.44.0" />
|
||||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.File" Version="4.0.0" />
|
||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@@ -114,14 +114,6 @@ namespace NadekoBot.Coordinator
|
|||||||
StartShard(shardId);
|
StartShard(shardId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status.Process is null or {HasExited: true})
|
|
||||||
{
|
|
||||||
Log.Warning("Shard {ShardId} is starting (process)...", shardId);
|
|
||||||
hadAction = true;
|
|
||||||
StartShard(shardId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DateTime.UtcNow - status.LastUpdate >
|
if (DateTime.UtcNow - status.LastUpdate >
|
||||||
TimeSpan.FromSeconds(_config.UnresponsiveSec))
|
TimeSpan.FromSeconds(_config.UnresponsiveSec))
|
||||||
@@ -139,6 +131,24 @@ namespace NadekoBot.Coordinator
|
|||||||
StartShard(shardId);
|
StartShard(shardId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (status.Process is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
Log.Warning("Shard {ShardId} is starting (process)...", shardId);
|
||||||
|
hadAction = true;
|
||||||
|
StartShard(shardId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
Log.Warning("Process for shard {ShardId} is bugged... ", shardId);
|
||||||
|
hadAction = true;
|
||||||
|
StartShard(shardId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,17 +171,13 @@ namespace NadekoBot.Coordinator
|
|||||||
var status = _shardStatuses[shardId];
|
var status = _shardStatuses[shardId];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (status.Process is { HasExited: false } p)
|
status.Process?.Kill(true);
|
||||||
{
|
}
|
||||||
try
|
catch
|
||||||
{
|
{
|
||||||
p.Kill(true);
|
}
|
||||||
}
|
try
|
||||||
catch
|
{
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
status.Process?.Dispose();
|
status.Process?.Dispose();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -280,10 +286,10 @@ namespace NadekoBot.Coordinator
|
|||||||
for (var shardId = 0; shardId < _shardStatuses.Length; shardId++)
|
for (var shardId = 0; shardId < _shardStatuses.Length; shardId++)
|
||||||
{
|
{
|
||||||
var status = _shardStatuses[shardId];
|
var status = _shardStatuses[shardId];
|
||||||
if (status.Process is { } p)
|
if (status.Process is Process p)
|
||||||
{
|
{
|
||||||
p.Kill();
|
try{p.Kill();} catch {}
|
||||||
p.Dispose();
|
try{p.Dispose();} catch {}
|
||||||
_shardStatuses[shardId] = status with
|
_shardStatuses[shardId] = status with
|
||||||
{
|
{
|
||||||
Process = null,
|
Process = null,
|
||||||
|
@@ -52,6 +52,9 @@ public sealed class Bot
|
|||||||
#else
|
#else
|
||||||
50;
|
50;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(!_creds.UsePrivilegedIntents)
|
||||||
|
Log.Warning("You are not using privileged intents. Some features will not work properly");
|
||||||
|
|
||||||
Client = new(new()
|
Client = new(new()
|
||||||
{
|
{
|
||||||
@@ -63,8 +66,10 @@ public sealed class Bot
|
|||||||
AlwaysDownloadUsers = false,
|
AlwaysDownloadUsers = false,
|
||||||
AlwaysResolveStickers = false,
|
AlwaysResolveStickers = false,
|
||||||
AlwaysDownloadDefaultStickers = false,
|
AlwaysDownloadDefaultStickers = false,
|
||||||
GatewayIntents = GatewayIntents.All,
|
GatewayIntents = _creds.UsePrivilegedIntents
|
||||||
LogGatewayIntentWarnings = false
|
? GatewayIntents.All
|
||||||
|
: GatewayIntents.AllUnprivileged,
|
||||||
|
LogGatewayIntentWarnings = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
_commandService = new(new()
|
_commandService = new(new()
|
||||||
@@ -75,9 +80,7 @@ public sealed class Bot
|
|||||||
|
|
||||||
// _interactionService = new(Client.Rest);
|
// _interactionService = new(Client.Rest);
|
||||||
|
|
||||||
#if GLOBAL_NADEKO || DEBUG
|
|
||||||
Client.Log += Client_Log;
|
Client.Log += Client_Log;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -216,30 +219,28 @@ public sealed class Bot
|
|||||||
|
|
||||||
private async Task LoginAsync(string token)
|
private async Task LoginAsync(string token)
|
||||||
{
|
{
|
||||||
var clientReady = new TaskCompletionSource<bool>();
|
var clientReady = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
Task SetClientReady()
|
async Task SetClientReady()
|
||||||
{
|
{
|
||||||
_ = Task.Run(async () =>
|
clientReady.TrySetResult(true);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
clientReady.TrySetResult(true);
|
foreach (var chan in await Client.GetDMChannelsAsync())
|
||||||
try
|
await chan.CloseAsync();
|
||||||
{
|
}
|
||||||
foreach (var chan in await Client.GetDMChannelsAsync())
|
catch
|
||||||
await chan.CloseAsync();
|
{
|
||||||
}
|
// ignored
|
||||||
catch
|
}
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//connect
|
//connect
|
||||||
Log.Information("Shard {ShardId} logging in ...", Client.ShardId);
|
Log.Information("Shard {ShardId} logging in ...", Client.ShardId);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Client.Ready += SetClientReady;
|
||||||
|
|
||||||
await Client.LoginAsync(TokenType.Bot, token);
|
await Client.LoginAsync(TokenType.Bot, token);
|
||||||
await Client.StartAsync();
|
await Client.StartAsync();
|
||||||
}
|
}
|
||||||
@@ -253,11 +254,10 @@ public sealed class Bot
|
|||||||
LoginErrorHandler.Handle(ex);
|
LoginErrorHandler.Handle(ex);
|
||||||
Helpers.ReadErrorAndExit(4);
|
Helpers.ReadErrorAndExit(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.Ready += SetClientReady;
|
await clientReady.Task.ConfigureAwait(false);
|
||||||
await clientReady.Task;
|
|
||||||
Client.Ready -= SetClientReady;
|
Client.Ready -= SetClientReady;
|
||||||
|
|
||||||
Client.JoinedGuild += Client_JoinedGuild;
|
Client.JoinedGuild += Client_JoinedGuild;
|
||||||
Client.LeftGuild += Client_LeftGuild;
|
Client.LeftGuild += Client_LeftGuild;
|
||||||
|
|
||||||
@@ -341,7 +341,33 @@ public sealed class Bot
|
|||||||
|
|
||||||
private Task Client_Log(LogMessage arg)
|
private Task Client_Log(LogMessage arg)
|
||||||
{
|
{
|
||||||
if (arg.Exception is not null)
|
if (arg.Message?.Contains("unknown dispatch", StringComparison.InvariantCultureIgnoreCase) ?? false)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
if (arg.Exception is { InnerException: WebSocketClosedException { CloseCode: 4014 } })
|
||||||
|
{
|
||||||
|
Log.Error(@"
|
||||||
|
Login failed.
|
||||||
|
|
||||||
|
*** Please enable privileged intents ***
|
||||||
|
|
||||||
|
Certain Nadeko features require Discord's privileged gateway intents.
|
||||||
|
These include greeting and goodbye messages, as well as creating the Owner message channels for DM forwarding.
|
||||||
|
|
||||||
|
How to enable privileged intents:
|
||||||
|
1. Head over to the Discord Developer Portal https://discord.com/developers/applications/
|
||||||
|
2. Select your Application.
|
||||||
|
3. Click on `Bot` in the left side navigation panel, and scroll down to the intents section.
|
||||||
|
4. Enable all intents.
|
||||||
|
5. Restart your bot.
|
||||||
|
|
||||||
|
Read this only if your bot is in 100 or more servers:
|
||||||
|
|
||||||
|
You'll need to apply to use the intents with Discord, but for small selfhosts, all that is required is enabling the intents in the developer portal.
|
||||||
|
Yes, this is a new thing from Discord, as of October 2020. No, there's nothing we can do about it. Yes, we're aware it worked before.
|
||||||
|
While waiting for your bot to be accepted, you can change the 'usePrivilegedIntents' inside your creds.yml to 'false', although this will break many of the nadeko's features");
|
||||||
|
}
|
||||||
|
else if (arg.Exception is not null)
|
||||||
Log.Warning(arg.Exception, "{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message);
|
Log.Warning(arg.Exception, "{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message);
|
||||||
else
|
else
|
||||||
Log.Warning("{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message);
|
Log.Warning("{ErrorSource} | {ErrorMessage}", arg.Source, arg.Message);
|
||||||
|
@@ -14,12 +14,15 @@ public sealed class Creds : IBotCredentials
|
|||||||
[Comment(@"List of Ids of the users who have bot owner permissions
|
[Comment(@"List of Ids of the users who have bot owner permissions
|
||||||
**DO NOT ADD PEOPLE YOU DON'T TRUST**")]
|
**DO NOT ADD PEOPLE YOU DON'T TRUST**")]
|
||||||
public ICollection<ulong> OwnerIds { get; set; }
|
public ICollection<ulong> OwnerIds { get; set; }
|
||||||
|
|
||||||
|
[Comment("Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted")]
|
||||||
|
public bool UsePrivilegedIntents { get; set; }
|
||||||
|
|
||||||
[Comment(@"The number of shards that the bot will running on.
|
[Comment(@"The number of shards that the bot will running on.
|
||||||
Leave at 1 if you don't know what you're doing.")]
|
Leave at 1 if you don't know what you're doing.")]
|
||||||
public int TotalShards { get; set; }
|
public int TotalShards { get; set; }
|
||||||
|
|
||||||
[Comment(
|
[Comment(
|
||||||
@"Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it.
|
@"Login to https://console.cloud.google.com, create a new project, go to APIs & Services -> Library -> YouTube Data API and enable it.
|
||||||
Then, go to APIs and Services -> Credentials and click Create credentials -> API key.
|
Then, go to APIs and Services -> Credentials and click Create credentials -> API key.
|
||||||
Used only for Youtube Data Api (at the moment).")]
|
Used only for Youtube Data Api (at the moment).")]
|
||||||
@@ -96,8 +99,9 @@ Windows default
|
|||||||
|
|
||||||
public Creds()
|
public Creds()
|
||||||
{
|
{
|
||||||
Version = 3;
|
Version = 4;
|
||||||
Token = string.Empty;
|
Token = string.Empty;
|
||||||
|
UsePrivilegedIntents = true;
|
||||||
OwnerIds = new List<ulong>();
|
OwnerIds = new List<ulong>();
|
||||||
TotalShards = 1;
|
TotalShards = 1;
|
||||||
GoogleApiKey = string.Empty;
|
GoogleApiKey = string.Empty;
|
||||||
|
@@ -6,6 +6,7 @@ public interface IBotCredentials
|
|||||||
string Token { get; }
|
string Token { get; }
|
||||||
string GoogleApiKey { get; }
|
string GoogleApiKey { get; }
|
||||||
ICollection<ulong> OwnerIds { get; }
|
ICollection<ulong> OwnerIds { get; }
|
||||||
|
bool UsePrivilegedIntents { get; }
|
||||||
string RapidApiKey { get; }
|
string RapidApiKey { get; }
|
||||||
|
|
||||||
Creds.DbOptions Db { get; }
|
Creds.DbOptions Db { get; }
|
||||||
|
@@ -84,77 +84,6 @@ public static class DiscordUserExtensions
|
|||||||
item.CurrencyAmount = 0;
|
item.CurrencyAmount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryUpdateCurrencyState(
|
|
||||||
this NadekoContext ctx,
|
|
||||||
ulong userId,
|
|
||||||
string name,
|
|
||||||
string discrim,
|
|
||||||
string avatarId,
|
|
||||||
long amount,
|
|
||||||
bool allowNegative = false)
|
|
||||||
{
|
|
||||||
if (amount == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// if remove - try to remove if he has more or equal than the amount
|
|
||||||
// and return number of rows > 0 (was there a change)
|
|
||||||
if (amount < 0 && !allowNegative)
|
|
||||||
{
|
|
||||||
var rows = ctx.Database.ExecuteSqlInterpolated($@"
|
|
||||||
UPDATE DiscordUser
|
|
||||||
SET CurrencyAmount=CurrencyAmount+{amount}
|
|
||||||
WHERE UserId={userId} AND CurrencyAmount>={-amount};");
|
|
||||||
return rows > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if remove and negative is allowed, just remove without any condition
|
|
||||||
if (amount < 0 && allowNegative)
|
|
||||||
{
|
|
||||||
var rows = ctx.Database.ExecuteSqlInterpolated($@"
|
|
||||||
UPDATE DiscordUser
|
|
||||||
SET CurrencyAmount=CurrencyAmount+{amount}
|
|
||||||
WHERE UserId={userId};");
|
|
||||||
return rows > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if add - create a new user with default values if it doesn't exist
|
|
||||||
// if it exists, sum current amount with the new one, if it doesn't
|
|
||||||
// he just has the new amount
|
|
||||||
var updatedUserData = !string.IsNullOrWhiteSpace(name);
|
|
||||||
name ??= "Unknown";
|
|
||||||
discrim ??= "????";
|
|
||||||
avatarId ??= "";
|
|
||||||
|
|
||||||
// just update the amount, there is no new user data
|
|
||||||
if (!updatedUserData)
|
|
||||||
{
|
|
||||||
ctx.Database.ExecuteSqlInterpolated($@"
|
|
||||||
UPDATE OR IGNORE DiscordUser
|
|
||||||
SET CurrencyAmount=CurrencyAmount+{amount}
|
|
||||||
WHERE UserId={userId};
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount, TotalXp)
|
|
||||||
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount}, 0);
|
|
||||||
");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ctx.Database.ExecuteSqlInterpolated($@"
|
|
||||||
UPDATE OR IGNORE DiscordUser
|
|
||||||
SET CurrencyAmount=CurrencyAmount+{amount},
|
|
||||||
Username={name},
|
|
||||||
Discriminator={discrim},
|
|
||||||
AvatarId={avatarId}
|
|
||||||
WHERE UserId={userId};
|
|
||||||
|
|
||||||
INSERT OR IGNORE INTO DiscordUser (UserId, Username, Discriminator, AvatarId, CurrencyAmount, TotalXp)
|
|
||||||
VALUES ({userId}, {name}, {discrim}, {avatarId}, {amount}, 0);
|
|
||||||
");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static decimal GetTotalCurrency(this DbSet<DiscordUser> users)
|
public static decimal GetTotalCurrency(this DbSet<DiscordUser> users)
|
||||||
=> users.Sum((Func<DiscordUser, decimal>)(x => x.CurrencyAmount));
|
=> users.Sum((Func<DiscordUser, decimal>)(x => x.CurrencyAmount));
|
||||||
|
|
||||||
|
@@ -73,6 +73,7 @@ public static class GuildConfigExtensions
|
|||||||
{
|
{
|
||||||
GuildConfig config;
|
GuildConfig config;
|
||||||
|
|
||||||
|
// todo linq2db
|
||||||
if (includes is null)
|
if (includes is null)
|
||||||
config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId);
|
config = ctx.GuildConfigs.IncludeEverything().FirstOrDefault(c => c.GuildId == guildId);
|
||||||
else
|
else
|
||||||
@@ -100,6 +101,26 @@ public static class GuildConfigExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|
||||||
|
// ctx.GuildConfigs
|
||||||
|
// .ToLinqToDBTable()
|
||||||
|
// .InsertOrUpdate(() => new()
|
||||||
|
// {
|
||||||
|
// GuildId = guildId,
|
||||||
|
// Permissions = Permissionv2.GetDefaultPermlist,
|
||||||
|
// WarningsInitialized = true,
|
||||||
|
// WarnPunishments = DefaultWarnPunishments
|
||||||
|
// },
|
||||||
|
// _ => new(),
|
||||||
|
// () => new()
|
||||||
|
// {
|
||||||
|
// GuildId = guildId
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// if(includes is null)
|
||||||
|
// return ctx.GuildConfigs
|
||||||
|
// .ToLinqToDBTable()
|
||||||
|
// .First(x => x.GuildId == guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LogSetting LogSettingsFor(this NadekoContext ctx, ulong guildId)
|
public static LogSetting LogSettingsFor(this NadekoContext ctx, ulong guildId)
|
||||||
|
@@ -1,4 +1,6 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using LinqToDB;
|
||||||
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Db.Models;
|
using NadekoBot.Db.Models;
|
||||||
using NadekoBot.Services.Database;
|
using NadekoBot.Services.Database;
|
||||||
@@ -75,11 +77,22 @@ public static class WaifuExtensions
|
|||||||
.Select(x => x.Waifu.UserId)
|
.Select(x => x.Waifu.UserId)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
public static WaifuInfoStats GetWaifuInfo(this NadekoContext ctx, ulong userId)
|
public static async Task<WaifuInfoStats> GetWaifuInfoAsync(this NadekoContext ctx, ulong userId)
|
||||||
{
|
{
|
||||||
ctx.Database.ExecuteSqlInterpolated($@"
|
await ctx.WaifuInfo
|
||||||
INSERT OR IGNORE INTO WaifuInfo (AffinityId, ClaimerId, Price, WaifuId)
|
.ToLinqToDBTable()
|
||||||
VALUES ({null}, {null}, {1}, (SELECT Id FROM DiscordUser WHERE UserId={userId}));");
|
.InsertOrUpdateAsync(() => new()
|
||||||
|
{
|
||||||
|
AffinityId = null,
|
||||||
|
ClaimerId = null,
|
||||||
|
Price = 1,
|
||||||
|
WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First()
|
||||||
|
},
|
||||||
|
_ => new(),
|
||||||
|
() => new()
|
||||||
|
{
|
||||||
|
WaifuId = ctx.DiscordUser.Where(x => x.UserId == userId).Select(x => x.Id).First()
|
||||||
|
});
|
||||||
|
|
||||||
var toReturn = ctx.WaifuInfo.AsQueryable()
|
var toReturn = ctx.WaifuInfo.AsQueryable()
|
||||||
.Where(w => w.WaifuId
|
.Where(w => w.WaifuId
|
||||||
|
@@ -3,6 +3,7 @@ namespace NadekoBot.Services.Database.Models;
|
|||||||
|
|
||||||
public class WaifuItem : DbEntity
|
public class WaifuItem : DbEntity
|
||||||
{
|
{
|
||||||
|
public WaifuInfo WaifuInfo { get; set; }
|
||||||
public int? WaifuInfoId { get; set; }
|
public int? WaifuInfoId { get; set; }
|
||||||
public string ItemEmoji { get; set; }
|
public string ItemEmoji { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
@@ -37,9 +37,13 @@ public class NadekoContext : DbContext
|
|||||||
public DbSet<NadekoExpression> Expressions { get; set; }
|
public DbSet<NadekoExpression> Expressions { get; set; }
|
||||||
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
public DbSet<CurrencyTransaction> CurrencyTransactions { get; set; }
|
||||||
public DbSet<WaifuUpdate> WaifuUpdates { get; set; }
|
public DbSet<WaifuUpdate> WaifuUpdates { get; set; }
|
||||||
|
public DbSet<WaifuItem> WaifuItem { get; set; }
|
||||||
public DbSet<Warning> Warnings { get; set; }
|
public DbSet<Warning> Warnings { get; set; }
|
||||||
public DbSet<UserXpStats> UserXpStats { get; set; }
|
public DbSet<UserXpStats> UserXpStats { get; set; }
|
||||||
public DbSet<ClubInfo> Clubs { get; set; }
|
public DbSet<ClubInfo> Clubs { get; set; }
|
||||||
|
public DbSet<ClubBans> ClubBans { get; set; }
|
||||||
|
public DbSet<ClubApplicants> ClubApplicants { get; set; }
|
||||||
|
|
||||||
|
|
||||||
//logging
|
//logging
|
||||||
public DbSet<LogSetting> LogSettings { get; set; }
|
public DbSet<LogSetting> LogSettings { get; set; }
|
||||||
|
@@ -29,7 +29,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("ClubApplicants");
|
b.ToTable("ClubApplicants", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubBans", b =>
|
||||||
@@ -44,7 +44,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("ClubBans");
|
b.ToTable("ClubBans", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubInfo", b =>
|
||||||
@@ -86,7 +86,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("OwnerId")
|
b.HasIndex("OwnerId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Clubs");
|
b.ToTable("Clubs", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.DiscordUser", b =>
|
||||||
@@ -155,7 +155,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("DiscordUser");
|
b.ToTable("DiscordUser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.FollowedStream", b =>
|
||||||
@@ -189,7 +189,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("FollowedStream");
|
b.ToTable("FollowedStream", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiAltSetting", b =>
|
||||||
@@ -218,7 +218,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId")
|
b.HasIndex("GuildConfigId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("AntiAltSetting");
|
b.ToTable("AntiAltSetting", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||||
@@ -250,7 +250,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId")
|
b.HasIndex("GuildConfigId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("AntiRaidSetting");
|
b.ToTable("AntiRaidSetting", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b =>
|
||||||
@@ -272,7 +272,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("AntiSpamSettingId");
|
b.HasIndex("AntiSpamSettingId");
|
||||||
|
|
||||||
b.ToTable("AntiSpamIgnore");
|
b.ToTable("AntiSpamIgnore", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b =>
|
||||||
@@ -304,7 +304,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId")
|
b.HasIndex("GuildConfigId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("AntiSpamSetting");
|
b.ToTable("AntiSpamSetting", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoCommand", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoCommand", b =>
|
||||||
@@ -342,7 +342,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("AutoCommands");
|
b.ToTable("AutoCommands", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateChannel", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateChannel", b =>
|
||||||
@@ -370,7 +370,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildId");
|
b.HasIndex("GuildId");
|
||||||
|
|
||||||
b.ToTable("AutoTranslateChannels");
|
b.ToTable("AutoTranslateChannels", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateUser", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AutoTranslateUser", b =>
|
||||||
@@ -398,7 +398,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasAlternateKey("ChannelId", "UserId");
|
b.HasAlternateKey("ChannelId", "UserId");
|
||||||
|
|
||||||
b.ToTable("AutoTranslateUsers");
|
b.ToTable("AutoTranslateUsers", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BanTemplate", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.BanTemplate", b =>
|
||||||
@@ -421,7 +421,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("BanTemplates");
|
b.ToTable("BanTemplates", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistEntry", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistEntry", b =>
|
||||||
@@ -441,7 +441,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Blacklist");
|
b.ToTable("Blacklist", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
|
||||||
@@ -466,7 +466,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("CommandAlias");
|
b.ToTable("CommandAlias", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||||
@@ -491,7 +491,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("CommandCooldown");
|
b.ToTable("CommandCooldown", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b =>
|
||||||
@@ -529,7 +529,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("CurrencyTransactions");
|
b.ToTable("CurrencyTransactions", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.DelMsgOnCmdChannel", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.DelMsgOnCmdChannel", b =>
|
||||||
@@ -554,7 +554,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("DelMsgOnCmdChannel");
|
b.ToTable("DelMsgOnCmdChannel", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordPermOverride", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordPermOverride", b =>
|
||||||
@@ -580,7 +580,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId", "Command")
|
b.HasIndex("GuildId", "Command")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("DiscordPermOverrides");
|
b.ToTable("DiscordPermOverrides", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ExcludedItem", b =>
|
||||||
@@ -605,7 +605,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("XpSettingsId");
|
b.HasIndex("XpSettingsId");
|
||||||
|
|
||||||
b.ToTable("ExcludedItem");
|
b.ToTable("ExcludedItem", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.FeedSub", b =>
|
||||||
@@ -631,7 +631,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasAlternateKey("GuildConfigId", "Url");
|
b.HasAlternateKey("GuildConfigId", "Url");
|
||||||
|
|
||||||
b.ToTable("FeedSub");
|
b.ToTable("FeedSub", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b =>
|
||||||
@@ -653,7 +653,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("FilterChannelId");
|
b.ToTable("FilterChannelId", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b =>
|
||||||
@@ -675,7 +675,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("FilteredWord");
|
b.ToTable("FilteredWord", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterLinksChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterLinksChannelId", b =>
|
||||||
@@ -697,7 +697,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("FilterLinksChannelId");
|
b.ToTable("FilterLinksChannelId", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterWordsChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterWordsChannelId", b =>
|
||||||
@@ -719,7 +719,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("FilterWordsChannelId");
|
b.ToTable("FilterWordsChannelId", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b =>
|
||||||
@@ -741,7 +741,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("GCChannelId");
|
b.ToTable("GCChannelId", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GroupName", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GroupName", b =>
|
||||||
@@ -767,7 +767,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId", "Number")
|
b.HasIndex("GuildConfigId", "Number")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("GroupName");
|
b.ToTable("GroupName", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b =>
|
||||||
@@ -891,7 +891,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("WarnExpireHours");
|
b.HasIndex("WarnExpireHours");
|
||||||
|
|
||||||
b.ToTable("GuildConfigs");
|
b.ToTable("GuildConfigs", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogItem", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogItem", b =>
|
||||||
@@ -917,7 +917,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("LogSettingId", "LogItemId", "ItemType")
|
b.HasIndex("LogSettingId", "LogItemId", "ItemType")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("IgnoredLogChannels");
|
b.ToTable("IgnoredLogChannels", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b =>
|
||||||
@@ -939,7 +939,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("LogSettingId");
|
b.HasIndex("LogSettingId");
|
||||||
|
|
||||||
b.ToTable("IgnoredVoicePresenceCHannels");
|
b.ToTable("IgnoredVoicePresenceCHannels", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ImageOnlyChannel", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ImageOnlyChannel", b =>
|
||||||
@@ -962,7 +962,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("ChannelId")
|
b.HasIndex("ChannelId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("ImageOnlyChannels");
|
b.ToTable("ImageOnlyChannels", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b =>
|
||||||
@@ -1027,7 +1027,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("LogSettings");
|
b.ToTable("LogSettings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlayerSettings", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlayerSettings", b =>
|
||||||
@@ -1064,7 +1064,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("MusicPlayerSettings");
|
b.ToTable("MusicPlayerSettings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b =>
|
||||||
@@ -1087,7 +1087,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("MusicPlaylists");
|
b.ToTable("MusicPlaylists", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b =>
|
||||||
@@ -1109,7 +1109,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("MutedUserId");
|
b.ToTable("MutedUserId", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.NadekoExpression", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.NadekoExpression", b =>
|
||||||
@@ -1147,7 +1147,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Expressions");
|
b.ToTable("Expressions", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklistedTag", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.NsfwBlacklistedTag", b =>
|
||||||
@@ -1169,7 +1169,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildId");
|
b.HasIndex("GuildId");
|
||||||
|
|
||||||
b.ToTable("NsfwBlacklistedTags");
|
b.ToTable("NsfwBlacklistedTags", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b =>
|
||||||
@@ -1209,7 +1209,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("Permissions");
|
b.ToTable("Permissions", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlantedCurrency", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlantedCurrency", b =>
|
||||||
@@ -1246,7 +1246,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("MessageId")
|
b.HasIndex("MessageId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("PlantedCurrency");
|
b.ToTable("PlantedCurrency", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b =>
|
||||||
@@ -1280,7 +1280,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("MusicPlaylistId");
|
b.HasIndex("MusicPlaylistId");
|
||||||
|
|
||||||
b.ToTable("PlaylistSong");
|
b.ToTable("PlaylistSong", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Poll", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Poll", b =>
|
||||||
@@ -1306,7 +1306,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("Poll");
|
b.ToTable("Poll", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollAnswer", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollAnswer", b =>
|
||||||
@@ -1331,7 +1331,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("PollId");
|
b.HasIndex("PollId");
|
||||||
|
|
||||||
b.ToTable("PollAnswer");
|
b.ToTable("PollAnswer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollVote", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PollVote", b =>
|
||||||
@@ -1356,7 +1356,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("PollId");
|
b.HasIndex("PollId");
|
||||||
|
|
||||||
b.ToTable("PollVote");
|
b.ToTable("PollVote", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b =>
|
||||||
@@ -1392,7 +1392,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("Keyword");
|
b.HasIndex("Keyword");
|
||||||
|
|
||||||
b.ToTable("Quotes");
|
b.ToTable("Quotes", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRole", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRole", b =>
|
||||||
@@ -1417,7 +1417,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ReactionRoleMessageId");
|
b.HasIndex("ReactionRoleMessageId");
|
||||||
|
|
||||||
b.ToTable("ReactionRole");
|
b.ToTable("ReactionRole", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRoleMessage", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ReactionRoleMessage", b =>
|
||||||
@@ -1448,7 +1448,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("ReactionRoleMessage");
|
b.ToTable("ReactionRoleMessage", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b =>
|
||||||
@@ -1482,7 +1482,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("When");
|
b.HasIndex("When");
|
||||||
|
|
||||||
b.ToTable("Reminders");
|
b.ToTable("Reminders", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Repeater", b =>
|
||||||
@@ -1517,7 +1517,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("Repeaters");
|
b.ToTable("Repeaters", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b =>
|
||||||
@@ -1546,7 +1546,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("PatreonUserId")
|
b.HasIndex("PatreonUserId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("RewardedUsers");
|
b.ToTable("RewardedUsers", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.RotatingPlayingStatus", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.RotatingPlayingStatus", b =>
|
||||||
@@ -1566,7 +1566,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.ToTable("RotatingStatus");
|
b.ToTable("RotatingStatus", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||||
@@ -1597,7 +1597,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildId", "RoleId")
|
b.HasIndex("GuildId", "RoleId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("SelfAssignableRoles");
|
b.ToTable("SelfAssignableRoles", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b =>
|
||||||
@@ -1637,7 +1637,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("ShopEntry");
|
b.ToTable("ShopEntry", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b =>
|
||||||
@@ -1659,7 +1659,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ShopEntryId");
|
b.HasIndex("ShopEntryId");
|
||||||
|
|
||||||
b.ToTable("ShopEntryItem");
|
b.ToTable("ShopEntryItem", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b =>
|
||||||
@@ -1681,7 +1681,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("SlowmodeIgnoredRole");
|
b.ToTable("SlowmodeIgnoredRole", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b =>
|
||||||
@@ -1703,7 +1703,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("SlowmodeIgnoredUser");
|
b.ToTable("SlowmodeIgnoredUser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleBlacklistedUser", b =>
|
||||||
@@ -1728,7 +1728,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("StreamRoleSettingsId");
|
b.HasIndex("StreamRoleSettingsId");
|
||||||
|
|
||||||
b.ToTable("StreamRoleBlacklistedUser");
|
b.ToTable("StreamRoleBlacklistedUser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleSettings", b =>
|
||||||
@@ -1760,7 +1760,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId")
|
b.HasIndex("GuildConfigId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("StreamRoleSettings");
|
b.ToTable("StreamRoleSettings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.StreamRoleWhitelistedUser", b =>
|
||||||
@@ -1785,7 +1785,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("StreamRoleSettingsId");
|
b.HasIndex("StreamRoleSettingsId");
|
||||||
|
|
||||||
b.ToTable("StreamRoleWhitelistedUser");
|
b.ToTable("StreamRoleWhitelistedUser", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnbanTimer", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnbanTimer", b =>
|
||||||
@@ -1810,7 +1810,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("UnbanTimer");
|
b.ToTable("UnbanTimer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
|
||||||
@@ -1835,7 +1835,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("UnmuteTimer");
|
b.ToTable("UnmuteTimer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnroleTimer", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnroleTimer", b =>
|
||||||
@@ -1863,7 +1863,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("UnroleTimer");
|
b.ToTable("UnroleTimer", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserXpStats", b =>
|
||||||
@@ -1908,7 +1908,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("UserId", "GuildId")
|
b.HasIndex("UserId", "GuildId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("UserXpStats");
|
b.ToTable("UserXpStats", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
|
||||||
@@ -1933,7 +1933,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("VcRoleInfo");
|
b.ToTable("VcRoleInfo", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
||||||
@@ -1968,7 +1968,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("WaifuId")
|
b.HasIndex("WaifuId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("WaifuInfo");
|
b.ToTable("WaifuInfo", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuItem", b =>
|
||||||
@@ -1993,7 +1993,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("WaifuInfoId");
|
b.HasIndex("WaifuInfoId");
|
||||||
|
|
||||||
b.ToTable("WaifuItem");
|
b.ToTable("WaifuItem", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b =>
|
||||||
@@ -2025,7 +2025,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("WaifuUpdates");
|
b.ToTable("WaifuUpdates", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b =>
|
||||||
@@ -2068,7 +2068,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("Warnings");
|
b.ToTable("Warnings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b =>
|
||||||
@@ -2099,7 +2099,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("GuildConfigId");
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
b.ToTable("WarningPunishment");
|
b.ToTable("WarningPunishment", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpCurrencyReward", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpCurrencyReward", b =>
|
||||||
@@ -2124,7 +2124,7 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.HasIndex("XpSettingsId");
|
b.HasIndex("XpSettingsId");
|
||||||
|
|
||||||
b.ToTable("XpCurrencyReward");
|
b.ToTable("XpCurrencyReward", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpRoleReward", b =>
|
||||||
@@ -2153,7 +2153,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("XpSettingsId", "Level")
|
b.HasIndex("XpSettingsId", "Level")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("XpRoleReward");
|
b.ToTable("XpRoleReward", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.XpSettings", b =>
|
||||||
@@ -2176,7 +2176,7 @@ namespace NadekoBot.Migrations
|
|||||||
b.HasIndex("GuildConfigId")
|
b.HasIndex("GuildConfigId")
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("XpSettings");
|
b.ToTable("XpSettings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
modelBuilder.Entity("NadekoBot.Db.Models.ClubApplicants", b =>
|
||||||
|
@@ -10,27 +10,26 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial class DangerousCommands : NadekoModule<DangerousCommandsService>
|
public partial class DangerousCommands : NadekoModule<DangerousCommandsService>
|
||||||
{
|
{
|
||||||
private async Task InternalExecSql(string sql, params object[] reps)
|
private async Task ConfirmActionInternalAsync(string name, Func<Task> action)
|
||||||
{
|
{
|
||||||
sql = string.Format(sql, reps);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithTitle(GetText(strs.sql_confirm_exec))
|
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||||
.WithDescription(Format.Code(sql));
|
.WithDescription(name);
|
||||||
|
|
||||||
if (!await PromptUserConfirmAsync(embed))
|
if (!await PromptUserConfirmAsync(embed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var res = await _service.ExecuteSql(sql);
|
await action();
|
||||||
await SendConfirmAsync(res.ToString());
|
await ctx.OkAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await SendErrorAsync(ex.ToString());
|
await SendErrorAsync(ex.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task SqlSelect([Leftover] string sql)
|
public partial Task SqlSelect([Leftover] string sql)
|
||||||
@@ -57,38 +56,55 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task SqlExec([Leftover] string sql)
|
public async partial Task SqlExec([Leftover] string sql)
|
||||||
=> InternalExecSql(sql);
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var embed = _eb.Create()
|
||||||
|
.WithTitle(GetText(strs.sql_confirm_exec))
|
||||||
|
.WithDescription(Format.Code(sql));
|
||||||
|
|
||||||
|
if (!await PromptUserConfirmAsync(embed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var res = await _service.ExecuteSql(sql);
|
||||||
|
await SendConfirmAsync(res.ToString());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await SendErrorAsync(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifus()
|
public partial Task DeleteWaifus()
|
||||||
=> SqlExec(DangerousCommandsService.WAIFUS_DELETE_SQL);
|
=> ConfirmActionInternalAsync("Delete Waifus", () => _service.DeleteWaifus());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifu(IUser user)
|
public async partial Task DeleteWaifu(IUser user)
|
||||||
=> DeleteWaifu(user.Id);
|
=> await DeleteWaifu(user.Id);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifu(ulong userId)
|
public partial Task DeleteWaifu(ulong userId)
|
||||||
=> InternalExecSql(DangerousCommandsService.WAIFU_DELETE_SQL, userId);
|
=> ConfirmActionInternalAsync($"Delete Waifu {userId}", () => _service.DeleteWaifu(userId));
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteCurrency()
|
public partial Task DeleteCurrency()
|
||||||
=> SqlExec(DangerousCommandsService.CURRENCY_DELETE_SQL);
|
=> ConfirmActionInternalAsync("Delete Currency", () => _service.DeleteCurrency());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeletePlaylists()
|
public partial Task DeletePlaylists()
|
||||||
=> SqlExec(DangerousCommandsService.MUSIC_PLAYLIST_DELETE_SQL);
|
=> ConfirmActionInternalAsync("Delete Playlists", () => _service.DeletePlaylists());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteXp()
|
public partial Task DeleteXp()
|
||||||
=> SqlExec(DangerousCommandsService.XP_DELETE_SQL);
|
=> ConfirmActionInternalAsync("Delete Xp", () => _service.DeleteXp());
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
@@ -108,10 +124,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task PurgeUser([Leftover] IUser user)
|
public partial Task PurgeUser([Leftover] IUser user)
|
||||||
=> PurgeUser(user.Id);
|
=> PurgeUser(user.Id);
|
||||||
//[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
//[OwnerOnly]
|
|
||||||
//public partial Task DeleteUnusedCrnQ() =>
|
|
||||||
// SqlExec(DangerousCommandsService.DeleteUnusedExpressionsAndQuotes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,46 +2,83 @@
|
|||||||
using LinqToDB;
|
using LinqToDB;
|
||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Db.Models;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration.Services;
|
namespace NadekoBot.Modules.Administration.Services;
|
||||||
|
|
||||||
public class DangerousCommandsService : INService
|
public class DangerousCommandsService : INService
|
||||||
{
|
{
|
||||||
public const string WAIFUS_DELETE_SQL = @"DELETE FROM WaifuUpdates;
|
|
||||||
DELETE FROM WaifuItem;
|
|
||||||
DELETE FROM WaifuInfo;";
|
|
||||||
|
|
||||||
public const string WAIFU_DELETE_SQL =
|
|
||||||
@"DELETE FROM WaifuUpdates WHERE UserId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
|
||||||
DELETE FROM WaifuItem WHERE WaifuInfoId=(SELECT Id FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0}));
|
|
||||||
UPDATE WaifuInfo SET ClaimerId=NULL WHERE ClaimerId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
|
||||||
DELETE FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0});";
|
|
||||||
|
|
||||||
public const string CURRENCY_DELETE_SQL =
|
|
||||||
"UPDATE DiscordUser SET CurrencyAmount=0; DELETE FROM CurrencyTransactions; DELETE FROM PlantedCurrency;";
|
|
||||||
|
|
||||||
public const string MUSIC_PLAYLIST_DELETE_SQL = "DELETE FROM MusicPlaylists;";
|
|
||||||
|
|
||||||
public const string XP_DELETE_SQL = @"DELETE FROM UserXpStats;
|
|
||||||
UPDATE DiscordUser
|
|
||||||
SET ClubId=NULL,
|
|
||||||
IsClubAdmin=0,
|
|
||||||
TotalXp=0;
|
|
||||||
DELETE FROM ClubApplicants;
|
|
||||||
DELETE FROM ClubBans;
|
|
||||||
DELETE FROM Clubs;";
|
|
||||||
// public const string DeleteUnusedExpressionsAndQuotes = @"DELETE FROM Expressions
|
|
||||||
//WHERE UseCount=0 AND (DateAdded < date('now', '-7 day') OR DateAdded is null);
|
|
||||||
|
|
||||||
//DELETE FROM Quotes
|
|
||||||
//WHERE UseCount=0 AND (DateAdded < date('now', '-7 day') OR DateAdded is null);";
|
|
||||||
|
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
|
||||||
public DangerousCommandsService(DbService db)
|
public DangerousCommandsService(DbService db)
|
||||||
=> _db = db;
|
=> _db = db;
|
||||||
|
|
||||||
|
public async Task DeleteXp()
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.DiscordUser.UpdateAsync(_ => new DiscordUser()
|
||||||
|
{
|
||||||
|
Club = null,
|
||||||
|
IsClubAdmin = false,
|
||||||
|
TotalXp = 0
|
||||||
|
});
|
||||||
|
await ctx.ClubApplicants.DeleteAsync();
|
||||||
|
await ctx.ClubBans.DeleteAsync();
|
||||||
|
await ctx.Clubs.DeleteAsync();
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteWaifus()
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.WaifuUpdates.DeleteAsync();
|
||||||
|
await ctx.WaifuItem.DeleteAsync();
|
||||||
|
await ctx.WaifuInfo.DeleteAsync();
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteWaifu(ulong userId)
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.WaifuUpdates
|
||||||
|
.Where(x => x.User.UserId == userId)
|
||||||
|
.DeleteAsync();
|
||||||
|
await ctx.WaifuItem
|
||||||
|
.Where(x => x.WaifuInfo.Waifu.UserId == userId)
|
||||||
|
.DeleteAsync();
|
||||||
|
await ctx.WaifuInfo
|
||||||
|
.Where(x => x.Claimer.UserId == userId)
|
||||||
|
.UpdateAsync(old => new WaifuInfo()
|
||||||
|
{
|
||||||
|
ClaimerId = null,
|
||||||
|
});
|
||||||
|
await ctx.WaifuInfo
|
||||||
|
.Where(x => x.Waifu.UserId == userId)
|
||||||
|
.DeleteAsync();
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeletePlaylists()
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.MusicPlaylists.DeleteAsync();
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteCurrency()
|
||||||
|
{
|
||||||
|
await using var ctx = _db.GetDbContext();
|
||||||
|
await ctx.DiscordUser.UpdateAsync(_ => new DiscordUser()
|
||||||
|
{
|
||||||
|
CurrencyAmount = 0
|
||||||
|
});
|
||||||
|
|
||||||
|
await ctx.CurrencyTransactions.DeleteAsync();
|
||||||
|
await ctx.PlantedCurrency.DeleteAsync();
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteSql(string sql)
|
public async Task<int> ExecuteSql(string sql)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@@ -30,7 +30,7 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
|||||||
_client = client;
|
_client = client;
|
||||||
_db = db;
|
_db = db;
|
||||||
|
|
||||||
var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
_enabledOn = uow.ImageOnlyChannels.ToList()
|
_enabledOn = uow.ImageOnlyChannels.ToList()
|
||||||
.GroupBy(x => x.GuildId)
|
.GroupBy(x => x.GuildId)
|
||||||
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
||||||
|
@@ -11,6 +11,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
|||||||
private readonly SelfService _selfService;
|
private readonly SelfService _selfService;
|
||||||
private readonly Replacer _rep;
|
private readonly Replacer _rep;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
|
private readonly DiscordSocketClient _client;
|
||||||
|
|
||||||
public PlayingRotateService(
|
public PlayingRotateService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
@@ -22,6 +23,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
|||||||
_db = db;
|
_db = db;
|
||||||
_bss = bss;
|
_bss = bss;
|
||||||
_selfService = selfService;
|
_selfService = selfService;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
if (client.ShardId == 0)
|
if (client.ShardId == 0)
|
||||||
_rep = new ReplacementBuilder().WithClient(client).WithProviders(phProviders).Build();
|
_rep = new ReplacementBuilder().WithClient(client).WithProviders(phProviders).Build();
|
||||||
@@ -29,6 +31,9 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
|
|||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
|
if (_client.ShardId != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(1));
|
||||||
var index = 0;
|
var index = 0;
|
||||||
while (await timer.WaitForNextTickAsync())
|
while (await timer.WaitForNextTickAsync())
|
||||||
|
@@ -10,7 +10,6 @@ public sealed class UserSpamStats
|
|||||||
lock (_applyLock)
|
lock (_applyLock)
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
Log.Information("{Count}", _messageTracker.Count.ToString());
|
|
||||||
return _messageTracker.Count;
|
return _messageTracker.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ public partial class Administration
|
|||||||
if (input.Length % 2 != 0 || target is null)
|
if (input.Length % 2 != 0 || target is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var all = await input.Chunk(input.Length / 2)
|
var all = await input.Chunk(2)
|
||||||
.Select(async x =>
|
.Select(async x =>
|
||||||
{
|
{
|
||||||
var inputRoleStr = x.First();
|
var inputRoleStr = x.First();
|
||||||
|
@@ -478,7 +478,7 @@ public partial class Administration
|
|||||||
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
var defaultMessage = GetText(strs.bandm(Format.Bold(ctx.Guild.Name), msg));
|
||||||
var embed = _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
|
var embed = _service.GetBanUserDmEmbed(Context, user, defaultMessage, msg, null);
|
||||||
if (embed is not null)
|
if (embed is not null)
|
||||||
await ctx.User.SendAsync(embed);
|
await user.SendAsync(embed);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
using LinqToDB;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
using NadekoBot.Common.TypeReaders.Models;
|
using NadekoBot.Common.TypeReaders.Models;
|
||||||
@@ -224,16 +225,34 @@ public class UserPunishService : INService, IReadyExecutor
|
|||||||
public async Task CheckAllWarnExpiresAsync()
|
public async Task CheckAllWarnExpiresAsync()
|
||||||
{
|
{
|
||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var cleared = await uow.Database.ExecuteSqlRawAsync(@"UPDATE Warnings
|
var cleared = await uow.Warnings
|
||||||
SET Forgiven = 1,
|
.Where(x => uow.GuildConfigs
|
||||||
ForgivenBy = 'Expiry'
|
.Any(y => y.GuildId == x.GuildId
|
||||||
WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND WarnExpireAction = 0)
|
&& y.WarnExpireHours > 0
|
||||||
AND Forgiven = 0
|
&& y.WarnExpireAction == WarnExpireAction.Clear)
|
||||||
AND DateAdded < datetime('now', (SELECT '-' || WarnExpireHours || ' hours' FROM GuildConfigs as gc WHERE gc.GuildId = Warnings.GuildId));");
|
&& x.Forgiven == false
|
||||||
|
&& x.DateAdded
|
||||||
|
< DateTime.UtcNow.AddHours(-uow.GuildConfigs
|
||||||
|
.Where(y => x.GuildId == y.GuildId)
|
||||||
|
.Select(y => y.WarnExpireHours)
|
||||||
|
.First()))
|
||||||
|
.UpdateAsync(_ => new()
|
||||||
|
{
|
||||||
|
Forgiven = true,
|
||||||
|
ForgivenBy = "expiry"
|
||||||
|
});
|
||||||
|
|
||||||
var deleted = await uow.Database.ExecuteSqlRawAsync(@"DELETE FROM Warnings
|
var deleted = await uow.Warnings
|
||||||
WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND WarnExpireAction = 1)
|
.Where(x => uow.GuildConfigs
|
||||||
AND DateAdded < datetime('now', (SELECT '-' || WarnExpireHours || ' hours' FROM GuildConfigs as gc WHERE gc.GuildId = Warnings.GuildId));");
|
.Any(y => y.GuildId == x.GuildId
|
||||||
|
&& y.WarnExpireHours > 0
|
||||||
|
&& y.WarnExpireAction == WarnExpireAction.Delete)
|
||||||
|
&& x.DateAdded
|
||||||
|
< DateTime.UtcNow.AddHours(-uow.GuildConfigs
|
||||||
|
.Where(y => x.GuildId == y.GuildId)
|
||||||
|
.Select(y => y.WarnExpireHours)
|
||||||
|
.First()))
|
||||||
|
.DeleteAsync();
|
||||||
|
|
||||||
if (cleared > 0 || deleted > 0)
|
if (cleared > 0 || deleted > 0)
|
||||||
{
|
{
|
||||||
@@ -241,6 +260,8 @@ WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND
|
|||||||
cleared,
|
cleared,
|
||||||
deleted);
|
deleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await uow.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CheckWarnExpiresAsync(ulong guildId)
|
public async Task CheckWarnExpiresAsync(ulong guildId)
|
||||||
@@ -251,21 +272,24 @@ WHERE GuildId in (SELECT GuildId FROM GuildConfigs WHERE WarnExpireHours > 0 AND
|
|||||||
if (config.WarnExpireHours == 0)
|
if (config.WarnExpireHours == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var hours = $"{-config.WarnExpireHours} hours";
|
|
||||||
if (config.WarnExpireAction == WarnExpireAction.Clear)
|
if (config.WarnExpireAction == WarnExpireAction.Clear)
|
||||||
{
|
{
|
||||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"UPDATE warnings
|
await uow.Warnings
|
||||||
SET Forgiven = 1,
|
.Where(x => x.GuildId == guildId
|
||||||
ForgivenBy = 'Expiry'
|
&& x.Forgiven == false
|
||||||
WHERE GuildId={guildId}
|
&& x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours))
|
||||||
AND Forgiven = 0
|
.UpdateAsync(_ => new()
|
||||||
AND DateAdded < datetime('now', {hours})");
|
{
|
||||||
|
Forgiven = true,
|
||||||
|
ForgivenBy = "expiry"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (config.WarnExpireAction == WarnExpireAction.Delete)
|
else if (config.WarnExpireAction == WarnExpireAction.Delete)
|
||||||
{
|
{
|
||||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"DELETE FROM warnings
|
await uow.Warnings
|
||||||
WHERE GuildId={guildId}
|
.Where(x => x.GuildId == guildId
|
||||||
AND DateAdded < datetime('now', {hours})");
|
&& x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours))
|
||||||
|
.DeleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
|
@@ -31,7 +31,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
|
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,8 +39,8 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
|
|
||||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText(strs.new_cust_react))
|
.WithTitle(GetText(strs.expr_new))
|
||||||
.WithDescription($"#{ex.Id}")
|
.WithDescription($"#{new kwum(ex.Id)}")
|
||||||
.AddField(GetText(strs.trigger), key)
|
.AddField(GetText(strs.trigger), key)
|
||||||
.AddField(GetText(strs.response),
|
.AddField(GetText(strs.response),
|
||||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
||||||
@@ -56,7 +56,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
if ((channel is null && !_creds.IsOwner(ctx.User))
|
if ((channel is null && !_creds.IsOwner(ctx.User))
|
||||||
|| (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
|| (channel is not null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,14 +65,14 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText(strs.edited_cust_react))
|
.WithTitle(GetText(strs.expr_edited))
|
||||||
.WithDescription($"#{id}")
|
.WithDescription($"#{id}")
|
||||||
.AddField(GetText(strs.trigger), ex.Trigger)
|
.AddField(GetText(strs.trigger), ex.Trigger)
|
||||||
.AddField(GetText(strs.response),
|
.AddField(GetText(strs.response),
|
||||||
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
message.Length > 1024 ? GetText(strs.redacted_too_long) : message));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await ReplyErrorLocalizedAsync(strs.edit_fail);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -86,7 +86,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
|
|
||||||
if (expressions is null || !expressions.Any())
|
if (expressions is null || !expressions.Any())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.no_found);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
: " // " + string.Join(" ", ex.GetReactions())))
|
: " // " + string.Join(" ", ex.GetReactions())))
|
||||||
.Join('\n');
|
.Join('\n');
|
||||||
|
|
||||||
return _eb.Create().WithOkColor().WithTitle(GetText(strs.custom_reactions)).WithDescription(desc);
|
return _eb.Create().WithOkColor().WithTitle(GetText(strs.expressions)).WithDescription(desc);
|
||||||
},
|
},
|
||||||
expressions.Length,
|
expressions.Length,
|
||||||
20);
|
20);
|
||||||
@@ -118,7 +118,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
|
|
||||||
if (found is null)
|
if (found is null)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.no_found_id);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,13 +145,13 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
await ctx.Channel.EmbedAsync(_eb.Create()
|
await ctx.Channel.EmbedAsync(_eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(GetText(strs.deleted))
|
.WithTitle(GetText(strs.expr_deleted))
|
||||||
.WithDescription($"#{id}")
|
.WithDescription($"#{id}")
|
||||||
.AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024))
|
.AddField(GetText(strs.trigger), ex.Trigger.TrimTo(1024))
|
||||||
.AddField(GetText(strs.response), ex.Response.TrimTo(1024)));
|
.AddField(GetText(strs.response), ex.Response.TrimTo(1024)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await ReplyErrorLocalizedAsync(strs.no_found_id);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -159,21 +159,21 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ex = _service.GetExpression(ctx.Guild?.Id, id);
|
var ex = _service.GetExpression(ctx.Guild?.Id, id);
|
||||||
if (ex is null)
|
if (ex is null)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.no_found);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emojiStrs.Length == 0)
|
if (emojiStrs.Length == 0)
|
||||||
{
|
{
|
||||||
await _service.ResetExprReactions(ctx.Guild?.Id, id);
|
await _service.ResetExprReactions(ctx.Guild?.Id, id);
|
||||||
await ReplyConfirmLocalizedAsync(strs.crr_reset(Format.Bold(id.ToString())));
|
await ReplyConfirmLocalizedAsync(strs.expr_reset(Format.Bold(id.ToString())));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +204,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
await _service.SetExprReactions(ctx.Guild?.Id, id, succ);
|
await _service.SetExprReactions(ctx.Guild?.Id, id, succ);
|
||||||
|
|
||||||
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.crr_set(Format.Bold(id.ToString()),
|
await ReplyConfirmLocalizedAsync(strs.expr_set(Format.Bold(id.ToString()),
|
||||||
succ.Select(static x => x.ToString()).Join(", ")));
|
succ.Select(static x => x.ToString()).Join(", ")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,14 +237,14 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (success, newVal) = await _service.ToggleExprOptionAsync(id, option);
|
var (success, newVal) = await _service.ToggleExprOptionAsync(id, option);
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.no_found_id);
|
await ReplyErrorLocalizedAsync(strs.expr_no_found_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
.WithDescription("This will delete all custom reactions on this server.")))
|
.WithDescription("This will delete all custom reactions on this server.")))
|
||||||
{
|
{
|
||||||
var count = _service.DeleteAllExpressions(ctx.Guild.Id);
|
var count = _service.DeleteAllExpressions(ctx.Guild.Id);
|
||||||
await ReplyConfirmLocalizedAsync(strs.cleared(count));
|
await ReplyConfirmLocalizedAsync(strs.exprs_cleared(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ public partial class NadekoExpressions : NadekoModule<NadekoExpressionsService>
|
|||||||
{
|
{
|
||||||
if (!AdminInGuildOrOwnerInDm())
|
if (!AdminInGuildOrOwnerInDm())
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.insuff_perms);
|
await ReplyErrorLocalizedAsync(strs.expr_insuff_perms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -76,6 +76,7 @@ public partial class Gambling
|
|||||||
(race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign)));
|
(race.FinishedUsers[0].Bet * (race.Users.Count - 1)) + CurrencySign)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ar.Dispose();
|
||||||
return SendConfirmAsync(GetText(strs.animal_race),
|
return SendConfirmAsync(GetText(strs.animal_race),
|
||||||
GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon)));
|
GetText(strs.animal_race_won(Format.Bold(winner.Username), winner.Animal.Icon)));
|
||||||
}
|
}
|
||||||
@@ -127,6 +128,7 @@ public partial class Gambling
|
|||||||
private Task Ar_OnStartingFailed(AnimalRace race)
|
private Task Ar_OnStartingFailed(AnimalRace race)
|
||||||
{
|
{
|
||||||
_service.AnimalRaces.TryRemove(ctx.Guild.Id, out _);
|
_service.AnimalRaces.TryRemove(ctx.Guild.Id, out _);
|
||||||
|
race.Dispose();
|
||||||
return ReplyErrorLocalizedAsync(strs.animal_race_failed);
|
return ReplyErrorLocalizedAsync(strs.animal_race_failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -65,8 +65,7 @@ public partial class Gambling : GamblingModule<GamblingService>
|
|||||||
|
|
||||||
public async Task<string> GetBalanceStringAsync(ulong userId)
|
public async Task<string> GetBalanceStringAsync(ulong userId)
|
||||||
{
|
{
|
||||||
var wallet = await _cs.GetWalletAsync(userId);
|
var bal = await _cs.GetBalanceAsync(userId);
|
||||||
var bal = await wallet.GetBalance();
|
|
||||||
return N(bal);
|
return N(bal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,7 +60,6 @@ public class GamblingService : INService, IReadyExecutor
|
|||||||
await using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
await uow.CurrencyTransactions
|
await uow.CurrencyTransactions
|
||||||
.DeleteAsync(ct => ct.DateAdded == null || now - ct.DateAdded < days);
|
.DeleteAsync(ct => ct.DateAdded == null || now - ct.DateAdded < days);
|
||||||
await uow.SaveChangesAsync();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -102,17 +101,16 @@ public class GamblingService : INService, IReadyExecutor
|
|||||||
if (maxDecay == 0)
|
if (maxDecay == 0)
|
||||||
maxDecay = int.MaxValue;
|
maxDecay = int.MaxValue;
|
||||||
|
|
||||||
await uow.Database.ExecuteSqlInterpolatedAsync($@"
|
var decay = (double)config.Decay.Percent;
|
||||||
UPDATE DiscordUser
|
await uow.DiscordUser
|
||||||
SET CurrencyAmount=
|
.Where(x => x.CurrencyAmount > config.Decay.MinThreshold && x.UserId != _client.CurrentUser.Id)
|
||||||
CASE WHEN
|
.UpdateAsync(old => new()
|
||||||
{maxDecay} > ROUND(CurrencyAmount * {config.Decay.Percent} - 0.5)
|
{
|
||||||
THEN
|
CurrencyAmount =
|
||||||
CurrencyAmount - ROUND(CurrencyAmount * {config.Decay.Percent} - 0.5)
|
maxDecay > Sql.Round((old.CurrencyAmount * decay) - 0.5)
|
||||||
ELSE
|
? (long)(old.CurrencyAmount - Sql.Round((old.CurrencyAmount * decay) - 0.5))
|
||||||
CurrencyAmount - {maxDecay}
|
: old.CurrencyAmount - maxDecay
|
||||||
END
|
});
|
||||||
WHERE CurrencyAmount > {config.Decay.MinThreshold} AND UserId!={_client.CurrentUser.Id};");
|
|
||||||
|
|
||||||
_cache.SetLastCurrencyDecay();
|
_cache.SetLastCurrencyDecay();
|
||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
|
@@ -35,7 +35,7 @@ public class VoteRewardService : INService, IReadyExecutor
|
|||||||
if (_client.ShardId != 0)
|
if (_client.ShardId != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var http = new HttpClient(new HttpClientHandler
|
using var http = new HttpClient(new HttpClientHandler
|
||||||
{
|
{
|
||||||
AllowAutoRedirect = false,
|
AllowAutoRedirect = false,
|
||||||
ServerCertificateCustomValidationCallback = delegate { return true; }
|
ServerCertificateCustomValidationCallback = delegate { return true; }
|
||||||
|
@@ -236,9 +236,9 @@ public partial class Gambling
|
|||||||
public partial Task WaifuInfo(ulong targetId)
|
public partial Task WaifuInfo(ulong targetId)
|
||||||
=> InternalWaifuInfo(targetId);
|
=> InternalWaifuInfo(targetId);
|
||||||
|
|
||||||
private Task InternalWaifuInfo(ulong targetId, string name = null)
|
private async Task InternalWaifuInfo(ulong targetId, string name = null)
|
||||||
{
|
{
|
||||||
var wi = _service.GetFullWaifuInfoAsync(targetId);
|
var wi = await _service.GetFullWaifuInfoAsync(targetId);
|
||||||
var affInfo = _service.GetAffinityTitle(wi.AffinityCount);
|
var affInfo = _service.GetAffinityTitle(wi.AffinityCount);
|
||||||
|
|
||||||
var waifuItems = _service.GetWaifuItems().ToDictionary(x => x.ItemEmoji, x => x);
|
var waifuItems = _service.GetWaifuItems().ToDictionary(x => x.ItemEmoji, x => x);
|
||||||
@@ -280,7 +280,7 @@ public partial class Gambling
|
|||||||
true)
|
true)
|
||||||
.AddField(GetText(strs.gifts), itemsStr, true);
|
.AddField(GetText(strs.gifts), itemsStr, true);
|
||||||
|
|
||||||
return ctx.Channel.EmbedAsync(embed);
|
await ctx.Channel.EmbedAsync(embed);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
|
@@ -385,10 +385,10 @@ public class WaifuService : INService, IReadyExecutor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WaifuInfoStats GetFullWaifuInfoAsync(ulong targetId)
|
public async Task<WaifuInfoStats> GetFullWaifuInfoAsync(ulong targetId)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
var wi = uow.GetWaifuInfo(targetId);
|
var wi = await uow.GetWaifuInfoAsync(targetId);
|
||||||
if (wi is null)
|
if (wi is null)
|
||||||
{
|
{
|
||||||
wi = new()
|
wi = new()
|
||||||
@@ -409,12 +409,12 @@ public class WaifuService : INService, IReadyExecutor
|
|||||||
return wi;
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WaifuInfoStats GetFullWaifuInfoAsync(IGuildUser target)
|
public async Task<WaifuInfoStats> GetFullWaifuInfoAsync(IGuildUser target)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
await using var uow = _db.GetDbContext();
|
||||||
_ = uow.GetOrCreateUser(target);
|
_ = uow.GetOrCreateUser(target);
|
||||||
|
|
||||||
return GetFullWaifuInfoAsync(target.Id);
|
return await GetFullWaifuInfoAsync(target.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetClaimTitle(int count)
|
public string GetClaimTitle(int count)
|
||||||
|
@@ -359,7 +359,7 @@ public partial class Help : NadekoModule<HelpService>
|
|||||||
};
|
};
|
||||||
|
|
||||||
using var dlClient = new AmazonS3Client(accessKey, secretAcccessKey, config);
|
using var dlClient = new AmazonS3Client(accessKey, secretAcccessKey, config);
|
||||||
var oldVersionObject = await dlClient.GetObjectAsync(new()
|
using var oldVersionObject = await dlClient.GetObjectAsync(new()
|
||||||
{
|
{
|
||||||
BucketName = "nadeko-pictures",
|
BucketName = "nadeko-pictures",
|
||||||
Key = "cmds/versions.json"
|
Key = "cmds/versions.json"
|
||||||
|
@@ -76,7 +76,7 @@ public sealed partial class YtLoader
|
|||||||
var mem = GetScriptResponseSpan(response);
|
var mem = GetScriptResponseSpan(response);
|
||||||
var root = JsonDocument.Parse(mem).RootElement;
|
var root = JsonDocument.Parse(mem).RootElement;
|
||||||
|
|
||||||
var tracksJsonItems = root
|
using var tracksJsonItems = root
|
||||||
.GetProperty("contents")
|
.GetProperty("contents")
|
||||||
.GetProperty("twoColumnSearchResultsRenderer")
|
.GetProperty("twoColumnSearchResultsRenderer")
|
||||||
.GetProperty("primaryContents")
|
.GetProperty("primaryContents")
|
||||||
|
@@ -7,12 +7,6 @@ using Newtonsoft.Json.Linq;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules.Nsfw;
|
namespace NadekoBot.Modules.Nsfw;
|
||||||
|
|
||||||
public record TagRequest(
|
|
||||||
ulong GuildId,
|
|
||||||
bool ForceExplicit,
|
|
||||||
Booru SearchType,
|
|
||||||
params string[] Tags);
|
|
||||||
|
|
||||||
public record UrlReply
|
public record UrlReply
|
||||||
{
|
{
|
||||||
public string Error { get; init; }
|
public string Error { get; init; }
|
||||||
@@ -30,7 +24,6 @@ public class SearchImagesService : ISearchImagesService, INService
|
|||||||
public ConcurrentDictionary<ulong, Timer> AutoBoobTimers { get; } = new();
|
public ConcurrentDictionary<ulong, Timer> AutoBoobTimers { get; } = new();
|
||||||
public ConcurrentDictionary<ulong, Timer> AutoButtTimers { get; } = new();
|
public ConcurrentDictionary<ulong, Timer> AutoButtTimers { get; } = new();
|
||||||
private readonly Random _rng;
|
private readonly Random _rng;
|
||||||
private readonly HttpClient _http;
|
|
||||||
private readonly SearchImageCacher _cache;
|
private readonly SearchImageCacher _cache;
|
||||||
private readonly IHttpClientFactory _httpFactory;
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
@@ -39,14 +32,11 @@ public class SearchImagesService : ISearchImagesService, INService
|
|||||||
|
|
||||||
public SearchImagesService(
|
public SearchImagesService(
|
||||||
DbService db,
|
DbService db,
|
||||||
IHttpClientFactory http,
|
|
||||||
SearchImageCacher cacher,
|
SearchImageCacher cacher,
|
||||||
IHttpClientFactory httpFactory)
|
IHttpClientFactory httpFactory)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_rng = new NadekoRandom();
|
_rng = new NadekoRandom();
|
||||||
_http = http.CreateClient();
|
|
||||||
_http.AddFakeHeaders();
|
|
||||||
_cache = cacher;
|
_cache = cacher;
|
||||||
_httpFactory = httpFactory;
|
_httpFactory = httpFactory;
|
||||||
|
|
||||||
@@ -205,8 +195,10 @@ public class SearchImagesService : ISearchImagesService, INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var http = _httpFactory.CreateClient();
|
||||||
|
http.AddFakeHeaders();
|
||||||
JToken obj;
|
JToken obj;
|
||||||
obj = JArray.Parse(await _http.GetStringAsync($"http://api.oboobs.ru/boobs/{_rng.Next(0, 12000)}"))[0];
|
obj = JArray.Parse(await http.GetStringAsync($"http://api.oboobs.ru/boobs/{_rng.Next(0, 12000)}"))[0];
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Error = "",
|
Error = "",
|
||||||
@@ -269,8 +261,10 @@ public class SearchImagesService : ISearchImagesService, INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
using var http = _httpFactory.CreateClient();
|
||||||
|
http.AddFakeHeaders();
|
||||||
JToken obj;
|
JToken obj;
|
||||||
obj = JArray.Parse(await _http.GetStringAsync($"http://api.obutts.ru/butts/{_rng.Next(0, 6100)}"))[0];
|
obj = JArray.Parse(await http.GetStringAsync($"http://api.obutts.ru/butts/{_rng.Next(0, 6100)}"))[0];
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
Error = "",
|
Error = "",
|
||||||
|
@@ -98,15 +98,16 @@ public partial class Searches
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var fileName = $"{query}-sparkline.{imageData.Extension}";
|
var fileName = $"{query}-sparkline.{imageData.Extension}";
|
||||||
|
using var attachment = new FileAttachment(
|
||||||
|
imageData.FileData,
|
||||||
|
fileName
|
||||||
|
);
|
||||||
await message.ModifyAsync(mp =>
|
await message.ModifyAsync(mp =>
|
||||||
{
|
{
|
||||||
mp.Attachments =
|
mp.Attachments =
|
||||||
new(new[]
|
new(new[]
|
||||||
{
|
{
|
||||||
new FileAttachment(
|
attachment
|
||||||
imageData.FileData,
|
|
||||||
fileName
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mp.Embed = eb.WithImageUrl($"attachment://{fileName}").Build();
|
mp.Embed = eb.WithImageUrl($"attachment://{fileName}").Build();
|
||||||
|
@@ -1,55 +1,55 @@
|
|||||||
using System.Net.Http.Json;
|
// using System.Net.Http.Json;
|
||||||
|
//
|
||||||
namespace NadekoBot.Modules.Searches;
|
// namespace NadekoBot.Modules.Searches;
|
||||||
|
//
|
||||||
public sealed class PolygonApiClient : IDisposable
|
// public sealed class PolygonApiClient : IDisposable
|
||||||
{
|
// {
|
||||||
private const string BASE_URL = "https://api.polygon.io/v3";
|
// private const string BASE_URL = "https://api.polygon.io/v3";
|
||||||
|
//
|
||||||
private readonly HttpClient _httpClient;
|
// private readonly HttpClient _httpClient;
|
||||||
private readonly string _apiKey;
|
// private readonly string _apiKey;
|
||||||
|
//
|
||||||
public PolygonApiClient(HttpClient httpClient, string apiKey)
|
// public PolygonApiClient(HttpClient httpClient, string apiKey)
|
||||||
{
|
// {
|
||||||
_httpClient = httpClient;
|
// _httpClient = httpClient;
|
||||||
_apiKey = apiKey;
|
// _apiKey = apiKey;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
public async Task<IReadOnlyCollection<PolygonTickerData>> TickersAsync(string? ticker = null, string? query = null)
|
// public async Task<IReadOnlyCollection<PolygonTickerData>> TickersAsync(string? ticker = null, string? query = null)
|
||||||
{
|
// {
|
||||||
if (string.IsNullOrWhiteSpace(query))
|
// if (string.IsNullOrWhiteSpace(query))
|
||||||
query = null;
|
// query = null;
|
||||||
|
//
|
||||||
if(query is not null)
|
// if(query is not null)
|
||||||
query = Uri.EscapeDataString(query);
|
// query = Uri.EscapeDataString(query);
|
||||||
|
//
|
||||||
var requestString = $"{BASE_URL}/reference/tickers"
|
// var requestString = $"{BASE_URL}/reference/tickers"
|
||||||
+ "?type=CS"
|
// + "?type=CS"
|
||||||
+ "&active=true"
|
// + "&active=true"
|
||||||
+ "&order=asc"
|
// + "&order=asc"
|
||||||
+ "&limit=1000"
|
// + "&limit=1000"
|
||||||
+ $"&apiKey={_apiKey}";
|
// + $"&apiKey={_apiKey}";
|
||||||
|
//
|
||||||
if (!string.IsNullOrWhiteSpace(ticker))
|
// if (!string.IsNullOrWhiteSpace(ticker))
|
||||||
requestString += $"&ticker={ticker}";
|
// requestString += $"&ticker={ticker}";
|
||||||
|
//
|
||||||
if (!string.IsNullOrWhiteSpace(query))
|
// if (!string.IsNullOrWhiteSpace(query))
|
||||||
requestString += $"&search={query}";
|
// requestString += $"&search={query}";
|
||||||
|
//
|
||||||
|
//
|
||||||
var response = await _httpClient.GetFromJsonAsync<PolygonTickerResponse>(requestString);
|
// var response = await _httpClient.GetFromJsonAsync<PolygonTickerResponse>(requestString);
|
||||||
|
//
|
||||||
if (response is null)
|
// if (response is null)
|
||||||
return Array.Empty<PolygonTickerData>();
|
// return Array.Empty<PolygonTickerData>();
|
||||||
|
//
|
||||||
return response.Results;
|
// return response.Results;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// public async Task<PolygonTickerDetailsV3> TickerDetailsV3Async(string ticker)
|
// // public async Task<PolygonTickerDetailsV3> TickerDetailsV3Async(string ticker)
|
||||||
// {
|
// // {
|
||||||
// return new();
|
// // return new();
|
||||||
// }
|
// // }
|
||||||
|
//
|
||||||
public void Dispose()
|
// public void Dispose()
|
||||||
=> _httpClient.Dispose();
|
// => _httpClient.Dispose();
|
||||||
}
|
// }
|
@@ -34,7 +34,7 @@ public partial class Searches
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
using var http = _httpFactory.CreateClient("memelist");
|
using var http = _httpFactory.CreateClient("memelist");
|
||||||
var res = await http.GetAsync("https://api.memegen.link/templates/");
|
using var res = await http.GetAsync("https://api.memegen.link/templates/");
|
||||||
|
|
||||||
var rawJson = await res.Content.ReadAsStringAsync();
|
var rawJson = await res.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
@@ -109,7 +109,8 @@ public class SearchesService : INService
|
|||||||
using (var avatarImg = Image.Load<Rgba32>(data))
|
using (var avatarImg = Image.Load<Rgba32>(data))
|
||||||
{
|
{
|
||||||
avatarImg.Mutate(x => x.Resize(85, 85).ApplyRoundedCorners(42));
|
avatarImg.Mutate(x => x.Resize(85, 85).ApplyRoundedCorners(42));
|
||||||
data = avatarImg.ToStream().ToArray();
|
await using var avStream = avatarImg.ToStream();
|
||||||
|
data = avStream.ToArray();
|
||||||
DrawAvatar(bg, avatarImg);
|
DrawAvatar(bg, avatarImg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +142,8 @@ public class SearchesService : INService
|
|||||||
bg.Mutate(x => x.DrawImage(flowers, new(0, 0), new GraphicsOptions()));
|
bg.Mutate(x => x.DrawImage(flowers, new(0, 0), new GraphicsOptions()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bg.ToStream().ToArray();
|
await using var stream = bg.ToStream();
|
||||||
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<WeatherData> GetWeatherDataAsync(string query)
|
public Task<WeatherData> GetWeatherDataAsync(string query)
|
||||||
@@ -532,7 +534,7 @@ public class SearchesService : INService
|
|||||||
http.DefaultRequestHeaders.Clear();
|
http.DefaultRequestHeaders.Clear();
|
||||||
|
|
||||||
using var response = await http.SendAsync(msg);
|
using var response = await http.SendAsync(msg);
|
||||||
var content = await response.Content.ReadAsStreamAsync();
|
await using var content = await response.Content.ReadAsStreamAsync();
|
||||||
|
|
||||||
using var document = await _googleParser.ParseDocumentAsync(content);
|
using var document = await _googleParser.ParseDocumentAsync(content);
|
||||||
var elems = document.QuerySelectorAll("div.g > div > div");
|
var elems = document.QuerySelectorAll("div.g > div > div");
|
||||||
|
@@ -3,6 +3,7 @@ using LinqToDB;
|
|||||||
using LinqToDB.EntityFrameworkCore;
|
using LinqToDB.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Common.ModuleBehaviors;
|
using NadekoBot.Common.ModuleBehaviors;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Searches;
|
namespace NadekoBot.Modules.Searches;
|
||||||
@@ -31,12 +32,14 @@ public sealed class TranslateService : ITranslateService, ILateExecutor, IReadyE
|
|||||||
|
|
||||||
public async Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
{
|
{
|
||||||
var ctx = _db.GetDbContext();
|
List<AutoTranslateChannel> cs;
|
||||||
|
await using (var ctx = _db.GetDbContext())
|
||||||
var guilds = _bot.AllGuildConfigs.Select(x => x.GuildId).ToList();
|
{
|
||||||
var cs = await ctx.AutoTranslateChannels.Include(x => x.Users)
|
var guilds = _bot.AllGuildConfigs.Select(x => x.GuildId).ToList();
|
||||||
|
cs = await ctx.AutoTranslateChannels.Include(x => x.Users)
|
||||||
.Where(x => guilds.Contains(x.GuildId))
|
.Where(x => guilds.Contains(x.GuildId))
|
||||||
.ToListAsyncEF();
|
.ToListAsyncEF();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var c in cs)
|
foreach (var c in cs)
|
||||||
{
|
{
|
||||||
@@ -103,7 +106,7 @@ public sealed class TranslateService : ITranslateService, ILateExecutor, IReadyE
|
|||||||
|
|
||||||
public async Task<bool> ToggleAtl(ulong guildId, ulong channelId, bool autoDelete)
|
public async Task<bool> ToggleAtl(ulong guildId, ulong channelId, bool autoDelete)
|
||||||
{
|
{
|
||||||
var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
var old = await ctx.AutoTranslateChannels.ToLinqToDBTable()
|
var old = await ctx.AutoTranslateChannels.ToLinqToDBTable()
|
||||||
.FirstOrDefaultAsyncLinqToDB(x => x.ChannelId == channelId);
|
.FirstOrDefaultAsyncLinqToDB(x => x.ChannelId == channelId);
|
||||||
@@ -164,7 +167,7 @@ public sealed class TranslateService : ITranslateService, ILateExecutor, IReadyE
|
|||||||
if (!_google.Languages.ContainsKey(from) || !_google.Languages.ContainsKey(to))
|
if (!_google.Languages.ContainsKey(from) || !_google.Languages.ContainsKey(to))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
var ch = await ctx.AutoTranslateChannels.GetByChannelId(channelId);
|
var ch = await ctx.AutoTranslateChannels.GetByChannelId(channelId);
|
||||||
|
|
||||||
if (ch is null)
|
if (ch is null)
|
||||||
@@ -206,14 +209,13 @@ public sealed class TranslateService : ITranslateService, ILateExecutor, IReadyE
|
|||||||
|
|
||||||
public async Task<bool> UnregisterUser(ulong channelId, ulong userId)
|
public async Task<bool> UnregisterUser(ulong channelId, ulong userId)
|
||||||
{
|
{
|
||||||
var ctx = _db.GetDbContext();
|
await using var ctx = _db.GetDbContext();
|
||||||
var rows = await ctx.AutoTranslateUsers.ToLinqToDBTable()
|
var rows = await ctx.AutoTranslateUsers.ToLinqToDBTable()
|
||||||
.DeleteAsync(x => x.UserId == userId && x.Channel.ChannelId == channelId);
|
.DeleteAsync(x => x.UserId == userId && x.Channel.ChannelId == channelId);
|
||||||
|
|
||||||
if (_users.TryGetValue(channelId, out var inner))
|
if (_users.TryGetValue(channelId, out var inner))
|
||||||
inner.TryRemove(userId, out _);
|
inner.TryRemove(userId, out _);
|
||||||
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
return rows > 0;
|
return rows > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,7 +62,7 @@ public class PicartoProvider : Provider
|
|||||||
{
|
{
|
||||||
http.DefaultRequestHeaders.Accept.Add(new("application/json"));
|
http.DefaultRequestHeaders.Accept.Add(new("application/json"));
|
||||||
// get id based on the username
|
// get id based on the username
|
||||||
var res = await http.GetAsync($"https://api.picarto.tv/v1/channel/name/{login}");
|
using var res = await http.GetAsync($"https://api.picarto.tv/v1/channel/name/{login}");
|
||||||
|
|
||||||
if (!res.IsSuccessStatusCode)
|
if (!res.IsSuccessStatusCode)
|
||||||
continue;
|
continue;
|
||||||
|
@@ -59,7 +59,7 @@ If you are experiencing ratelimits, you should create your own application at: h
|
|||||||
// so there is no need for ratelimit checks atm
|
// so there is no need for ratelimit checks atm
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var res = await http.PostAsJsonAsync(
|
using var res = await http.PostAsJsonAsync(
|
||||||
$"https://open-api.trovo.live/openplatform/channels/id",
|
$"https://open-api.trovo.live/openplatform/channels/id",
|
||||||
new TrovoRequestData()
|
new TrovoRequestData()
|
||||||
{
|
{
|
||||||
|
@@ -84,12 +84,13 @@ public class PatreonRewardsService : INService, IReadyExecutor
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var res = await http.PostAsync("https://www.patreon.com/api/oauth2/token"
|
using var content = new StringContent(string.Empty);
|
||||||
|
using var res = await http.PostAsync("https://www.patreon.com/api/oauth2/token"
|
||||||
+ "?grant_type=refresh_token"
|
+ "?grant_type=refresh_token"
|
||||||
+ $"&refresh_token={creds.Patreon.RefreshToken}"
|
+ $"&refresh_token={creds.Patreon.RefreshToken}"
|
||||||
+ $"&client_id={creds.Patreon.ClientId}"
|
+ $"&client_id={creds.Patreon.ClientId}"
|
||||||
+ $"&client_secret={creds.Patreon.ClientSecret}",
|
+ $"&client_secret={creds.Patreon.ClientSecret}",
|
||||||
new StringContent(string.Empty));
|
content);
|
||||||
|
|
||||||
res.EnsureSuccessStatusCode();
|
res.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
@@ -78,8 +78,6 @@ public class RemindService : INService
|
|||||||
.ToLinqToDBTable()
|
.ToLinqToDBTable()
|
||||||
.Where(x => x.ServerId / 4194304 % (ulong)_creds.TotalShards == (ulong)_client.ShardId
|
.Where(x => x.ServerId / 4194304 % (ulong)_creds.TotalShards == (ulong)_client.ShardId
|
||||||
&& x.When < now)
|
&& x.When < now)
|
||||||
// .FromSqlInterpolated(
|
|
||||||
// $"select * from reminders where ((serverid >> 22) % {_creds.TotalShards}) == {_client.ShardId} and \"when\" < {now};")
|
|
||||||
.ToListAsyncLinqToDB();
|
.ToListAsyncLinqToDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@ public sealed class RepeaterService : IReadyExecutor, INService
|
|||||||
_creds = creds;
|
_creds = creds;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
|
||||||
var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var shardRepeaters = uow.Set<Repeater>()
|
var shardRepeaters = uow.Set<Repeater>()
|
||||||
.Where(x => (int)(x.GuildId / Math.Pow(2, 22)) % _creds.TotalShards
|
.Where(x => (int)(x.GuildId / Math.Pow(2, 22)) % _creds.TotalShards
|
||||||
== _client.ShardId)
|
== _client.ShardId)
|
||||||
|
@@ -336,7 +336,7 @@ public partial class Utility : NadekoModule
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var res = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
using var res = await http.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
|
||||||
if (!res.IsImage() || res.GetImageSize() is null or > 262_144)
|
if (!res.IsImage() || res.GetImageSize() is null or > 262_144)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalizedAsync(strs.invalid_emoji_link);
|
await ReplyErrorLocalizedAsync(strs.invalid_emoji_link);
|
||||||
|
@@ -121,153 +121,155 @@ public class XpService : INService, IReadyExecutor
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task OnReadyAsync()
|
public async Task OnReadyAsync()
|
||||||
=> UpdateLoop();
|
|
||||||
|
|
||||||
private async Task UpdateLoop()
|
|
||||||
{
|
{
|
||||||
using var timer = new PeriodicTimer(5.Seconds());
|
using var timer = new PeriodicTimer(5.Seconds());
|
||||||
while (await timer.WaitForNextTickAsync())
|
while (await timer.WaitForNextTickAsync())
|
||||||
{
|
{
|
||||||
try
|
await UpdateLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateLoop()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var toNotify =
|
||||||
|
new List<(IGuild Guild, IMessageChannel MessageChannel, IUser User, int Level,
|
||||||
|
XpNotificationLocation NotifyType, NotifOf NotifOf)>();
|
||||||
|
var roleRewards = new Dictionary<ulong, List<XpRoleReward>>();
|
||||||
|
var curRewards = new Dictionary<ulong, List<XpCurrencyReward>>();
|
||||||
|
|
||||||
|
var toAddTo = new List<UserCacheItem>();
|
||||||
|
while (_addMessageXp.TryDequeue(out var usr))
|
||||||
|
toAddTo.Add(usr);
|
||||||
|
|
||||||
|
var group = toAddTo.GroupBy(x => (GuildId: x.Guild.Id, x.User));
|
||||||
|
if (toAddTo.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var toNotify =
|
foreach (var item in group)
|
||||||
new List<(IGuild Guild, IMessageChannel MessageChannel, IUser User, int Level,
|
|
||||||
XpNotificationLocation NotifyType, NotifOf NotifOf)>();
|
|
||||||
var roleRewards = new Dictionary<ulong, List<XpRoleReward>>();
|
|
||||||
var curRewards = new Dictionary<ulong, List<XpCurrencyReward>>();
|
|
||||||
|
|
||||||
var toAddTo = new List<UserCacheItem>();
|
|
||||||
while (_addMessageXp.TryDequeue(out var usr))
|
|
||||||
toAddTo.Add(usr);
|
|
||||||
|
|
||||||
var group = toAddTo.GroupBy(x => (GuildId: x.Guild.Id, x.User));
|
|
||||||
if (toAddTo.Count == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
await using (var uow = _db.GetDbContext())
|
|
||||||
{
|
{
|
||||||
foreach (var item in group)
|
var xp = item.Sum(x => x.XpAmount);
|
||||||
|
|
||||||
|
var usr = uow.GetOrCreateUserXpStats(item.Key.GuildId, item.Key.User.Id);
|
||||||
|
var du = uow.GetOrCreateUser(item.Key.User);
|
||||||
|
|
||||||
|
var globalXp = du.TotalXp;
|
||||||
|
var oldGlobalLevelData = new LevelStats(globalXp);
|
||||||
|
var newGlobalLevelData = new LevelStats(globalXp + xp);
|
||||||
|
|
||||||
|
var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||||
|
usr.Xp += xp;
|
||||||
|
du.TotalXp += xp;
|
||||||
|
if (du.Club is not null)
|
||||||
|
du.Club.Xp += xp;
|
||||||
|
var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
||||||
|
|
||||||
|
if (oldGlobalLevelData.Level < newGlobalLevelData.Level)
|
||||||
{
|
{
|
||||||
var xp = item.Sum(x => x.XpAmount);
|
du.LastLevelUp = DateTime.UtcNow;
|
||||||
|
var first = item.First();
|
||||||
var usr = uow.GetOrCreateUserXpStats(item.Key.GuildId, item.Key.User.Id);
|
if (du.NotifyOnLevelUp != XpNotificationLocation.None)
|
||||||
var du = uow.GetOrCreateUser(item.Key.User);
|
|
||||||
|
|
||||||
var globalXp = du.TotalXp;
|
|
||||||
var oldGlobalLevelData = new LevelStats(globalXp);
|
|
||||||
var newGlobalLevelData = new LevelStats(globalXp + xp);
|
|
||||||
|
|
||||||
var oldGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
|
||||||
usr.Xp += xp;
|
|
||||||
du.TotalXp += xp;
|
|
||||||
if (du.Club is not null)
|
|
||||||
du.Club.Xp += xp;
|
|
||||||
var newGuildLevelData = new LevelStats(usr.Xp + usr.AwardedXp);
|
|
||||||
|
|
||||||
if (oldGlobalLevelData.Level < newGlobalLevelData.Level)
|
|
||||||
{
|
{
|
||||||
du.LastLevelUp = DateTime.UtcNow;
|
toNotify.Add((first.Guild, first.Channel, first.User, newGlobalLevelData.Level,
|
||||||
var first = item.First();
|
du.NotifyOnLevelUp, NotifOf.Global));
|
||||||
if (du.NotifyOnLevelUp != XpNotificationLocation.None)
|
|
||||||
{
|
|
||||||
toNotify.Add((first.Guild, first.Channel, first.User, newGlobalLevelData.Level,
|
|
||||||
du.NotifyOnLevelUp, NotifOf.Global));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldGuildLevelData.Level < newGuildLevelData.Level)
|
|
||||||
{
|
|
||||||
usr.LastLevelUp = DateTime.UtcNow;
|
|
||||||
//send level up notification
|
|
||||||
var first = item.First();
|
|
||||||
if (usr.NotifyOnLevelUp != XpNotificationLocation.None)
|
|
||||||
{
|
|
||||||
toNotify.Add((first.Guild, first.Channel, first.User, newGuildLevelData.Level,
|
|
||||||
usr.NotifyOnLevelUp, NotifOf.Server));
|
|
||||||
}
|
|
||||||
|
|
||||||
//give role
|
|
||||||
if (!roleRewards.TryGetValue(usr.GuildId, out var rrews))
|
|
||||||
{
|
|
||||||
rrews = uow.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
|
|
||||||
roleRewards.Add(usr.GuildId, rrews);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!curRewards.TryGetValue(usr.GuildId, out var crews))
|
|
||||||
{
|
|
||||||
crews = uow.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList();
|
|
||||||
curRewards.Add(usr.GuildId, crews);
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop through levels since last level up, so if a high amount of xp is gained, reward are still applied.
|
|
||||||
for (var i = oldGuildLevelData.Level + 1; i <= newGuildLevelData.Level; i++)
|
|
||||||
{
|
|
||||||
var rrew = rrews.FirstOrDefault(x => x.Level == i);
|
|
||||||
if (rrew is not null)
|
|
||||||
{
|
|
||||||
var role = first.User.Guild.GetRole(rrew.RoleId);
|
|
||||||
if (role is not null)
|
|
||||||
{
|
|
||||||
if (rrew.Remove)
|
|
||||||
_ = first.User.RemoveRoleAsync(role);
|
|
||||||
else
|
|
||||||
_ = first.User.AddRoleAsync(role);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get currency reward for this level
|
|
||||||
var crew = crews.FirstOrDefault(x => x.Level == i);
|
|
||||||
if (crew is not null)
|
|
||||||
//give the user the reward if it exists
|
|
||||||
await _cs.AddAsync(item.Key.User.Id, crew.Amount, new("xp", "level-up"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uow.SaveChanges();
|
if (oldGuildLevelData.Level < newGuildLevelData.Level)
|
||||||
|
{
|
||||||
|
usr.LastLevelUp = DateTime.UtcNow;
|
||||||
|
//send level up notification
|
||||||
|
var first = item.First();
|
||||||
|
if (usr.NotifyOnLevelUp != XpNotificationLocation.None)
|
||||||
|
{
|
||||||
|
toNotify.Add((first.Guild, first.Channel, first.User, newGuildLevelData.Level,
|
||||||
|
usr.NotifyOnLevelUp, NotifOf.Server));
|
||||||
|
}
|
||||||
|
|
||||||
|
//give role
|
||||||
|
if (!roleRewards.TryGetValue(usr.GuildId, out var rrews))
|
||||||
|
{
|
||||||
|
rrews = uow.XpSettingsFor(usr.GuildId).RoleRewards.ToList();
|
||||||
|
roleRewards.Add(usr.GuildId, rrews);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curRewards.TryGetValue(usr.GuildId, out var crews))
|
||||||
|
{
|
||||||
|
crews = uow.XpSettingsFor(usr.GuildId).CurrencyRewards.ToList();
|
||||||
|
curRewards.Add(usr.GuildId, crews);
|
||||||
|
}
|
||||||
|
|
||||||
|
//loop through levels since last level up, so if a high amount of xp is gained, reward are still applied.
|
||||||
|
for (var i = oldGuildLevelData.Level + 1; i <= newGuildLevelData.Level; i++)
|
||||||
|
{
|
||||||
|
var rrew = rrews.FirstOrDefault(x => x.Level == i);
|
||||||
|
if (rrew is not null)
|
||||||
|
{
|
||||||
|
var role = first.User.Guild.GetRole(rrew.RoleId);
|
||||||
|
if (role is not null)
|
||||||
|
{
|
||||||
|
if (rrew.Remove)
|
||||||
|
_ = first.User.RemoveRoleAsync(role);
|
||||||
|
else
|
||||||
|
_ = first.User.AddRoleAsync(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//get currency reward for this level
|
||||||
|
var crew = crews.FirstOrDefault(x => x.Level == i);
|
||||||
|
if (crew is not null)
|
||||||
|
//give the user the reward if it exists
|
||||||
|
await _cs.AddAsync(item.Key.User.Id, crew.Amount, new("xp", "level-up"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await toNotify.Select(async x =>
|
uow.SaveChanges();
|
||||||
{
|
}
|
||||||
if (x.NotifOf == NotifOf.Server)
|
|
||||||
{
|
|
||||||
if (x.NotifyType == XpNotificationLocation.Dm)
|
|
||||||
{
|
|
||||||
await x.User.SendConfirmAsync(_eb,
|
|
||||||
_strings.GetText(strs.level_up_dm(x.User.Mention,
|
|
||||||
Format.Bold(x.Level.ToString()),
|
|
||||||
Format.Bold(x.Guild.ToString() ?? "-")),
|
|
||||||
x.Guild.Id));
|
|
||||||
}
|
|
||||||
else if (x.MessageChannel is not null) // channel
|
|
||||||
{
|
|
||||||
await x.MessageChannel.SendConfirmAsync(_eb,
|
|
||||||
_strings.GetText(strs.level_up_channel(x.User.Mention,
|
|
||||||
Format.Bold(x.Level.ToString())),
|
|
||||||
x.Guild.Id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
IMessageChannel chan;
|
|
||||||
if (x.NotifyType == XpNotificationLocation.Dm)
|
|
||||||
chan = await x.User.CreateDMChannelAsync();
|
|
||||||
else // channel
|
|
||||||
chan = x.MessageChannel;
|
|
||||||
|
|
||||||
await chan.SendConfirmAsync(_eb,
|
await toNotify.Select(async x =>
|
||||||
_strings.GetText(strs.level_up_global(x.User.Mention,
|
{
|
||||||
|
if (x.NotifOf == NotifOf.Server)
|
||||||
|
{
|
||||||
|
if (x.NotifyType == XpNotificationLocation.Dm)
|
||||||
|
{
|
||||||
|
await x.User.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_dm(x.User.Mention,
|
||||||
|
Format.Bold(x.Level.ToString()),
|
||||||
|
Format.Bold(x.Guild.ToString() ?? "-")),
|
||||||
|
x.Guild.Id));
|
||||||
|
}
|
||||||
|
else if (x.MessageChannel is not null) // channel
|
||||||
|
{
|
||||||
|
await x.MessageChannel.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_channel(x.User.Mention,
|
||||||
Format.Bold(x.Level.ToString())),
|
Format.Bold(x.Level.ToString())),
|
||||||
x.Guild.Id));
|
x.Guild.Id));
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.WhenAll();
|
else
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
IMessageChannel chan;
|
||||||
{
|
if (x.NotifyType == XpNotificationLocation.Dm)
|
||||||
Log.Error(ex, "Error In the XP update loop");
|
chan = await x.User.CreateDMChannelAsync();
|
||||||
}
|
else // channel
|
||||||
|
chan = x.MessageChannel;
|
||||||
|
|
||||||
|
await chan.SendConfirmAsync(_eb,
|
||||||
|
_strings.GetText(strs.level_up_global(x.User.Mention,
|
||||||
|
Format.Bold(x.Level.ToString())),
|
||||||
|
x.Guild.Id));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.WhenAll();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "Error In the XP update loop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,24 +23,19 @@
|
|||||||
<PackageReference Include="AWSSDK.S3" Version="3.7.7.21" />
|
<PackageReference Include="AWSSDK.S3" Version="3.7.7.21" />
|
||||||
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.4" />
|
<PackageReference Include="CodeHollow.FeedReader" Version="1.2.4" />
|
||||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||||
<PackageReference Include="Discord.Net" Version="3.3.0" />
|
<PackageReference Include="Discord.Net" Version="3.4.1" />
|
||||||
<PackageReference Include="CoreCLR-NCalc" Version="2.2.92" />
|
<PackageReference Include="CoreCLR-NCalc" Version="2.2.92" />
|
||||||
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.41.1.138" />
|
<PackageReference Include="Google.Apis.Urlshortener.v1" Version="1.41.1.138" />
|
||||||
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.55.0.2449" />
|
<PackageReference Include="Google.Apis.YouTube.v3" Version="1.55.0.2449" />
|
||||||
<PackageReference Include="Google.Apis.Customsearch.v1" Version="1.49.0.2084" />
|
<PackageReference Include="Google.Apis.Customsearch.v1" Version="1.49.0.2084" />
|
||||||
<PackageReference Include="Google.Protobuf" Version="3.19.4" />
|
<PackageReference Include="Google.Protobuf" Version="3.19.4" />
|
||||||
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.42.0" />
|
<PackageReference Include="Grpc.Net.ClientFactory" Version="2.41.0" />
|
||||||
<PackageReference Include="Grpc.Tools" Version="2.43.0">
|
<PackageReference Include="Grpc.Tools" Version="2.41.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Html2Markdown" Version="5.0.2.561" />
|
<PackageReference Include="Html2Markdown" Version="5.0.2.561" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||||
@@ -59,10 +54,22 @@
|
|||||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />
|
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta0010" />
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.2.88" />
|
<PackageReference Include="StackExchange.Redis" Version="2.2.88" />
|
||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
||||||
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.6.1" />
|
|
||||||
<PackageReference Include="Humanizer" Version="2.14.1" />
|
<PackageReference Include="Humanizer" Version="2.14.1" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0" />
|
||||||
|
|
||||||
|
<!-- Db-related packages -->
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
|
||||||
|
<PackageReference Include="linq2db.EntityFrameworkCore" Version="6.6.1" />
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.2" />
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="6.0.3" />
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1" />
|
||||||
|
|
||||||
<!-- Remove this when static abstract interface members support is released -->
|
<!-- Remove this when static abstract interface members support is released -->
|
||||||
<PackageReference Include="System.Runtime.Experimental" Version="6.0.0" />
|
<PackageReference Include="System.Runtime.Experimental" Version="6.0.0" />
|
||||||
|
|
||||||
@@ -71,6 +78,12 @@
|
|||||||
|
|
||||||
<!-- Used by stream notifications -->
|
<!-- Used by stream notifications -->
|
||||||
<PackageReference Include="TwitchLib.Api" Version="3.4.1" />
|
<PackageReference Include="TwitchLib.Api" Version="3.4.1" />
|
||||||
|
|
||||||
|
<!-- Uncomment to check for disposable issues -->
|
||||||
|
<!-- <PackageReference Include="IDisposableAnalyzers" Version="4.0.2">-->
|
||||||
|
<!-- <PrivateAssets>all</PrivateAssets>-->
|
||||||
|
<!-- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
|
||||||
|
<!-- </PackageReference>-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -101,10 +114,15 @@
|
|||||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
|
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionPrefix).$(VersionSuffix)</Version>
|
||||||
<Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version>
|
<Version Condition=" '$(Version)' == '' ">$(VersionPrefix)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'GlobalNadeko' ">
|
||||||
<DefineConstants>$(DefineConstants);GLOBAL_NADEKO</DefineConstants>
|
<!-- Define trace doesn't seem to affect the build at all so I had to remove $(DefineConstants)-->
|
||||||
|
<DefineTrace>false</DefineTrace>
|
||||||
|
<DefineConstants>GLOBAL_NADEKO</DefineConstants>
|
||||||
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
<NoWarn>$(NoWarn);CS1573;CS1591</NoWarn>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>portable</DebugType>
|
||||||
|
<DebugSymbols>false</DebugSymbols>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- TODO: Remove this when the conflict issue in System.Runtime.Experimental is fixed -->
|
<!-- TODO: Remove this when the conflict issue in System.Runtime.Experimental is fixed -->
|
||||||
|
@@ -14,7 +14,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
public Task<IWallet> GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default)
|
public Task<IWallet> GetWalletAsync(ulong userId, CurrencyType type = CurrencyType.Default)
|
||||||
{
|
{
|
||||||
if (type == CurrencyType.Default)
|
if (type == CurrencyType.Default)
|
||||||
return Task.FromResult<IWallet>(new DefaultWallet(userId, _db.GetDbContext()));
|
return Task.FromResult<IWallet>(new DefaultWallet(userId, _db));
|
||||||
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(type));
|
throw new ArgumentOutOfRangeException(nameof(type));
|
||||||
}
|
}
|
||||||
@@ -27,14 +27,12 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
{
|
{
|
||||||
if (type == CurrencyType.Default)
|
if (type == CurrencyType.Default)
|
||||||
{
|
{
|
||||||
await using var ctx = _db.GetDbContext();
|
|
||||||
foreach (var userId in userIds)
|
foreach (var userId in userIds)
|
||||||
{
|
{
|
||||||
var wallet = new DefaultWallet(userId, ctx);
|
var wallet = await GetWalletAsync(userId);
|
||||||
await wallet.Add(amount, txData);
|
await wallet.Add(amount, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
await ctx.SaveChangesAsync();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +56,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
? du.CurrencyAmount - amount
|
? du.CurrencyAmount - amount
|
||||||
: 0
|
: 0
|
||||||
});
|
});
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
long amount,
|
long amount,
|
||||||
TxData txData)
|
TxData txData)
|
||||||
{
|
{
|
||||||
await using var wallet = await GetWalletAsync(userId);
|
var wallet = await GetWalletAsync(userId);
|
||||||
await wallet.Add(amount, txData);
|
await wallet.Add(amount, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +77,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
long amount,
|
long amount,
|
||||||
TxData txData)
|
TxData txData)
|
||||||
{
|
{
|
||||||
await using var wallet = await GetWalletAsync(user.Id);
|
var wallet = await GetWalletAsync(user.Id);
|
||||||
await wallet.Add(amount, txData);
|
await wallet.Add(amount, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +86,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
long amount,
|
long amount,
|
||||||
TxData txData)
|
TxData txData)
|
||||||
{
|
{
|
||||||
await using var wallet = await GetWalletAsync(userId);
|
var wallet = await GetWalletAsync(userId);
|
||||||
return await wallet.Take(amount, txData);
|
return await wallet.Take(amount, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,22 +95,7 @@ public class CurrencyService : ICurrencyService, INService
|
|||||||
long amount,
|
long amount,
|
||||||
TxData txData)
|
TxData txData)
|
||||||
{
|
{
|
||||||
await using var wallet = await GetWalletAsync(user.Id);
|
var wallet = await GetWalletAsync(user.Id);
|
||||||
return await wallet.Take(amount, txData);
|
return await wallet.Take(amount, txData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> TransferAsync(
|
|
||||||
ulong fromId,
|
|
||||||
ulong toId,
|
|
||||||
long amount,
|
|
||||||
string fromName,
|
|
||||||
string note)
|
|
||||||
{
|
|
||||||
await using var fromWallet = await GetWalletAsync(fromId);
|
|
||||||
await using var toWallet = await GetWalletAsync(toId);
|
|
||||||
|
|
||||||
var extra = new TxData("gift", fromName, note, fromId);
|
|
||||||
|
|
||||||
return await fromWallet.Transfer(amount, toWallet, extra);
|
|
||||||
}
|
|
||||||
}
|
}
|
29
src/NadekoBot/Services/Currency/CurrencyServiceExtensions.cs
Normal file
29
src/NadekoBot/Services/Currency/CurrencyServiceExtensions.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using NadekoBot.Services.Currency;
|
||||||
|
|
||||||
|
namespace NadekoBot.Services;
|
||||||
|
|
||||||
|
public static class CurrencyServiceExtensions
|
||||||
|
{
|
||||||
|
public static async Task<long> GetBalanceAsync(this ICurrencyService cs, ulong userId)
|
||||||
|
{
|
||||||
|
var wallet = await cs.GetWalletAsync(userId);
|
||||||
|
return await wallet.GetBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo transfer should be a transaction
|
||||||
|
public static async Task<bool> TransferAsync(
|
||||||
|
this ICurrencyService cs,
|
||||||
|
ulong fromId,
|
||||||
|
ulong toId,
|
||||||
|
long amount,
|
||||||
|
string fromName,
|
||||||
|
string note)
|
||||||
|
{
|
||||||
|
var fromWallet = await cs.GetWalletAsync(fromId);
|
||||||
|
var toWallet = await cs.GetWalletAsync(toId);
|
||||||
|
|
||||||
|
var extra = new TxData("gift", fromName, note, fromId);
|
||||||
|
|
||||||
|
return await fromWallet.Transfer(amount, toWallet, extra);
|
||||||
|
}
|
||||||
|
}
|
@@ -7,48 +7,54 @@ namespace NadekoBot.Services.Currency;
|
|||||||
|
|
||||||
public class DefaultWallet : IWallet
|
public class DefaultWallet : IWallet
|
||||||
{
|
{
|
||||||
|
private readonly DbService _db;
|
||||||
public ulong UserId { get; }
|
public ulong UserId { get; }
|
||||||
|
|
||||||
private readonly NadekoContext _ctx;
|
public DefaultWallet(ulong userId, DbService db)
|
||||||
|
|
||||||
public DefaultWallet(ulong userId, NadekoContext ctx)
|
|
||||||
{
|
{
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
_ctx = ctx;
|
_db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<long> GetBalance()
|
public async Task<long> GetBalance()
|
||||||
=> _ctx.DiscordUser
|
{
|
||||||
.ToLinqToDBTable()
|
await using var ctx = _db.GetDbContext();
|
||||||
.Where(x => x.UserId == UserId)
|
return await ctx.DiscordUser
|
||||||
.Select(x => x.CurrencyAmount)
|
.ToLinqToDBTable()
|
||||||
.FirstOrDefaultAsync();
|
.Where(x => x.UserId == UserId)
|
||||||
|
.Select(x => x.CurrencyAmount)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> Take(long amount, TxData txData)
|
public async Task<bool> Take(long amount, TxData txData)
|
||||||
{
|
{
|
||||||
if (amount < 0)
|
if (amount < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(amount), "Amount to take must be non negative.");
|
throw new ArgumentOutOfRangeException(nameof(amount), "Amount to take must be non negative.");
|
||||||
|
|
||||||
var changed = await _ctx.DiscordUser
|
await using var ctx = _db.GetDbContext();
|
||||||
.Where(x => x.UserId == UserId && x.CurrencyAmount >= amount)
|
|
||||||
.UpdateAsync(x => new()
|
var changed = await ctx.DiscordUser
|
||||||
{
|
.Where(x => x.UserId == UserId && x.CurrencyAmount >= amount)
|
||||||
CurrencyAmount = x.CurrencyAmount - amount
|
.UpdateAsync(x => new()
|
||||||
});
|
{
|
||||||
|
CurrencyAmount = x.CurrencyAmount - amount
|
||||||
|
});
|
||||||
|
|
||||||
if (changed == 0)
|
if (changed == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
await _ctx.CreateLinqToDbContext()
|
await ctx
|
||||||
.InsertAsync(new CurrencyTransaction()
|
.GetTable<CurrencyTransaction>()
|
||||||
{
|
.InsertAsync(() => new()
|
||||||
Amount = -amount,
|
{
|
||||||
Note = txData.Note,
|
Amount = -amount,
|
||||||
UserId = UserId,
|
Note = txData.Note,
|
||||||
Type = txData.Type,
|
UserId = UserId,
|
||||||
Extra = txData.Extra,
|
Type = txData.Type,
|
||||||
OtherId = txData.OtherId
|
Extra = txData.Extra,
|
||||||
});
|
OtherId = txData.OtherId,
|
||||||
|
DateAdded = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -58,9 +64,11 @@ public class DefaultWallet : IWallet
|
|||||||
if (amount <= 0)
|
if (amount <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0.");
|
throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be greater than 0.");
|
||||||
|
|
||||||
await using (var tran = await _ctx.Database.BeginTransactionAsync())
|
await using var ctx = _db.GetDbContext();
|
||||||
|
|
||||||
|
await using (var tran = await ctx.Database.BeginTransactionAsync())
|
||||||
{
|
{
|
||||||
var changed = await _ctx.DiscordUser
|
var changed = await ctx.DiscordUser
|
||||||
.Where(x => x.UserId == UserId)
|
.Where(x => x.UserId == UserId)
|
||||||
.UpdateAsync(x => new()
|
.UpdateAsync(x => new()
|
||||||
{
|
{
|
||||||
@@ -69,7 +77,7 @@ public class DefaultWallet : IWallet
|
|||||||
|
|
||||||
if (changed == 0)
|
if (changed == 0)
|
||||||
{
|
{
|
||||||
await _ctx.DiscordUser
|
await ctx.DiscordUser
|
||||||
.ToLinqToDBTable()
|
.ToLinqToDBTable()
|
||||||
.Value(x => x.UserId, UserId)
|
.Value(x => x.UserId, UserId)
|
||||||
.Value(x => x.Username, "Unknown")
|
.Value(x => x.Username, "Unknown")
|
||||||
@@ -81,29 +89,16 @@ public class DefaultWallet : IWallet
|
|||||||
await tran.CommitAsync();
|
await tran.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var ct = new CurrencyTransaction()
|
await ctx.GetTable<CurrencyTransaction>()
|
||||||
{
|
.InsertAsync(() => new()
|
||||||
Amount = amount,
|
{
|
||||||
UserId = UserId,
|
Amount = amount,
|
||||||
Note = txData.Note,
|
UserId = UserId,
|
||||||
Type = txData.Type,
|
Note = txData.Note,
|
||||||
Extra = txData.Extra,
|
Type = txData.Type,
|
||||||
OtherId = txData.OtherId
|
Extra = txData.Extra,
|
||||||
};
|
OtherId = txData.OtherId,
|
||||||
|
DateAdded = DateTime.UtcNow
|
||||||
await _ctx.CreateLinqToDbContext()
|
});
|
||||||
.InsertAsync(ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_ctx.SaveChanges();
|
|
||||||
_ctx.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask DisposeAsync()
|
|
||||||
{
|
|
||||||
await _ctx.SaveChangesAsync();
|
|
||||||
await _ctx.DisposeAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -38,11 +38,4 @@ public interface ICurrencyService
|
|||||||
IUser user,
|
IUser user,
|
||||||
long amount,
|
long amount,
|
||||||
TxData txData);
|
TxData txData);
|
||||||
|
|
||||||
Task<bool> TransferAsync(
|
|
||||||
ulong from,
|
|
||||||
ulong to,
|
|
||||||
long amount,
|
|
||||||
string fromName,
|
|
||||||
string note);
|
|
||||||
}
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
namespace NadekoBot.Services.Currency;
|
namespace NadekoBot.Services.Currency;
|
||||||
|
|
||||||
public interface IWallet : IDisposable, IAsyncDisposable
|
public interface IWallet
|
||||||
{
|
{
|
||||||
public ulong UserId { get; }
|
public ulong UserId { get; }
|
||||||
|
|
||||||
|
@@ -32,10 +32,9 @@ public class DbService
|
|||||||
using var context = new NadekoContext(_options);
|
using var context = new NadekoContext(_options);
|
||||||
if (context.Database.GetPendingMigrations().Any())
|
if (context.Database.GetPendingMigrations().Any())
|
||||||
{
|
{
|
||||||
var mContext = new NadekoContext(_migrateOptions);
|
using var mContext = new NadekoContext(_migrateOptions);
|
||||||
mContext.Database.Migrate();
|
mContext.Database.Migrate();
|
||||||
mContext.SaveChanges();
|
mContext.SaveChanges();
|
||||||
mContext.Dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Database.ExecuteSqlRaw("PRAGMA journal_mode=WAL");
|
context.Database.ExecuteSqlRaw("PRAGMA journal_mode=WAL");
|
||||||
|
@@ -32,6 +32,7 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
|||||||
|
|
||||||
|
|
||||||
private readonly object _reloadLock = new();
|
private readonly object _reloadLock = new();
|
||||||
|
private readonly IDisposable _changeToken;
|
||||||
|
|
||||||
public BotCredsProvider(int? totalShards = null)
|
public BotCredsProvider(int? totalShards = null)
|
||||||
{
|
{
|
||||||
@@ -52,9 +53,9 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
|||||||
_config = new ConfigurationBuilder().AddYamlFile(CredsPath, false, true)
|
_config = new ConfigurationBuilder().AddYamlFile(CredsPath, false, true)
|
||||||
.AddEnvironmentVariables("NadekoBot_")
|
.AddEnvironmentVariables("NadekoBot_")
|
||||||
.Build();
|
.Build();
|
||||||
|
#if !GLOBAL_NADEKO
|
||||||
ChangeToken.OnChange(() => _config.GetReloadToken(), Reload);
|
_changeToken = ChangeToken.OnChange(() => _config.GetReloadToken(), Reload);
|
||||||
|
#endif
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,9 +166,9 @@ public sealed class BotCredsProvider : IBotCredsProvider
|
|||||||
if (File.Exists(CREDS_FILE_NAME))
|
if (File.Exists(CREDS_FILE_NAME))
|
||||||
{
|
{
|
||||||
var creds = Yaml.Deserializer.Deserialize<Creds>(File.ReadAllText(CREDS_FILE_NAME));
|
var creds = Yaml.Deserializer.Deserialize<Creds>(File.ReadAllText(CREDS_FILE_NAME));
|
||||||
if (creds.Version <= 2)
|
if (creds.Version <= 3)
|
||||||
{
|
{
|
||||||
creds.Version = 3;
|
creds.Version = 4;
|
||||||
File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds));
|
File.WriteAllText(CREDS_FILE_NAME, Yaml.Serializer.Serialize(creds));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,8 @@ public class RemoteGrpcCoordinator : ICoordinator, IReadyExecutor
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(22500);
|
Log.Information("Coordinator is restarting gracefully. Waiting...");
|
||||||
|
await Task.Delay(30_000);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -5,9 +5,9 @@ using System.Diagnostics;
|
|||||||
|
|
||||||
namespace NadekoBot.Services;
|
namespace NadekoBot.Services;
|
||||||
|
|
||||||
public class StatsService : IStatsService, IReadyExecutor, INService, IDisposable
|
public sealed class StatsService : IStatsService, IReadyExecutor, INService, IDisposable
|
||||||
{
|
{
|
||||||
public const string BOT_VERSION = "4.0.0";
|
public const string BOT_VERSION = "4.0.5";
|
||||||
|
|
||||||
public string Author
|
public string Author
|
||||||
=> "Kwoth#2452";
|
=> "Kwoth#2452";
|
||||||
@@ -133,11 +133,16 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnReadyAsync()
|
private void InitializeChannelCount()
|
||||||
{
|
{
|
||||||
var guilds = _client.Guilds;
|
var guilds = _client.Guilds;
|
||||||
textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
|
textChannels = guilds.Sum(static g => g.Channels.Count(static cx => cx is ITextChannel));
|
||||||
voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel));
|
voiceChannels = guilds.Sum(static g => g.Channels.Count(static cx => cx is IVoiceChannel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnReadyAsync()
|
||||||
|
{
|
||||||
|
InitializeChannelCount();
|
||||||
|
|
||||||
using var timer = new PeriodicTimer(TimeSpan.FromHours(1));
|
using var timer = new PeriodicTimer(TimeSpan.FromHours(1));
|
||||||
do
|
do
|
||||||
@@ -189,4 +194,4 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
_currentProcess.Dispose();
|
_currentProcess.Dispose();
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,87 +1,87 @@
|
|||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// // Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
// https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.Process.Sources/ProcessHelper.cs
|
// // https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.Process.Sources/ProcessHelper.cs
|
||||||
|
//
|
||||||
using System.Diagnostics;
|
// using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
// using System.Runtime.InteropServices;
|
||||||
|
//
|
||||||
namespace NadekoBot.Extensions;
|
// namespace NadekoBot.Extensions;
|
||||||
|
//
|
||||||
public static class ProcessExtensions
|
// public static class ProcessExtensions
|
||||||
{
|
// {
|
||||||
private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
// private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(10);
|
// private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(10);
|
||||||
|
//
|
||||||
public static void KillTree(this Process process)
|
// public static void KillTree(this Process process)
|
||||||
=> process.KillTree(_defaultTimeout);
|
// => process.KillTree(_defaultTimeout);
|
||||||
|
//
|
||||||
public static void KillTree(this Process process, TimeSpan timeout)
|
// public static void KillTree(this Process process, TimeSpan timeout)
|
||||||
{
|
// {
|
||||||
if (_isWindows)
|
// if (_isWindows)
|
||||||
RunProcessAndWaitForExit("taskkill", $"/T /F /PID {process.Id}", timeout, out _);
|
// RunProcessAndWaitForExit("taskkill", $"/T /F /PID {process.Id}", timeout, out _);
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
var children = new HashSet<int>();
|
// var children = new HashSet<int>();
|
||||||
GetAllChildIdsUnix(process.Id, children, timeout);
|
// GetAllChildIdsUnix(process.Id, children, timeout);
|
||||||
foreach (var childId in children)
|
// foreach (var childId in children)
|
||||||
KillProcessUnix(childId, timeout);
|
// KillProcessUnix(childId, timeout);
|
||||||
|
//
|
||||||
KillProcessUnix(process.Id, timeout);
|
// KillProcessUnix(process.Id, timeout);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
|
// private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
|
||||||
{
|
// {
|
||||||
var exitCode = RunProcessAndWaitForExit("pgrep", $"-P {parentId}", timeout, out var stdout);
|
// var exitCode = RunProcessAndWaitForExit("pgrep", $"-P {parentId}", timeout, out var stdout);
|
||||||
|
//
|
||||||
if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
|
// if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
|
||||||
{
|
// {
|
||||||
using var reader = new StringReader(stdout);
|
// using var reader = new StringReader(stdout);
|
||||||
while (true)
|
// while (true)
|
||||||
{
|
// {
|
||||||
var text = reader.ReadLine();
|
// var text = reader.ReadLine();
|
||||||
if (text is null)
|
// if (text is null)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
if (int.TryParse(text, out var id))
|
// if (int.TryParse(text, out var id))
|
||||||
{
|
// {
|
||||||
children.Add(id);
|
// children.Add(id);
|
||||||
// Recursively get the children
|
// // Recursively get the children
|
||||||
GetAllChildIdsUnix(id, children, timeout);
|
// GetAllChildIdsUnix(id, children, timeout);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private static void KillProcessUnix(int processId, TimeSpan timeout)
|
// private static void KillProcessUnix(int processId, TimeSpan timeout)
|
||||||
=> RunProcessAndWaitForExit("kill", $"-TERM {processId}", timeout, out _);
|
// => RunProcessAndWaitForExit("kill", $"-TERM {processId}", timeout, out _);
|
||||||
|
//
|
||||||
private static int RunProcessAndWaitForExit(
|
// private static int RunProcessAndWaitForExit(
|
||||||
string fileName,
|
// string fileName,
|
||||||
string arguments,
|
// string arguments,
|
||||||
TimeSpan timeout,
|
// TimeSpan timeout,
|
||||||
out string? stdout)
|
// out string? stdout)
|
||||||
{
|
// {
|
||||||
stdout = null;
|
// stdout = null;
|
||||||
|
//
|
||||||
var startInfo = new ProcessStartInfo
|
// var startInfo = new ProcessStartInfo
|
||||||
{
|
// {
|
||||||
FileName = fileName,
|
// FileName = fileName,
|
||||||
Arguments = arguments,
|
// Arguments = arguments,
|
||||||
RedirectStandardOutput = true,
|
// RedirectStandardOutput = true,
|
||||||
UseShellExecute = false
|
// UseShellExecute = false
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
var process = Process.Start(startInfo);
|
// using var process = Process.Start(startInfo);
|
||||||
|
//
|
||||||
if (process is null)
|
// if (process is null)
|
||||||
return -1;
|
// return -1;
|
||||||
|
//
|
||||||
if (process.WaitForExit((int)timeout.TotalMilliseconds))
|
// if (process.WaitForExit((int)timeout.TotalMilliseconds))
|
||||||
stdout = process.StandardOutput.ReadToEnd();
|
// stdout = process.StandardOutput.ReadToEnd();
|
||||||
else
|
// else
|
||||||
process.Kill();
|
// process.Kill();
|
||||||
|
//
|
||||||
return process.ExitCode;
|
// return process.ExitCode;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
@@ -21,7 +21,7 @@ public static class Rgba32Extensions
|
|||||||
var xOffset = 0;
|
var xOffset = 0;
|
||||||
for (var i = 0; i < imgArray.Count; i++)
|
for (var i = 0; i < imgArray.Count; i++)
|
||||||
{
|
{
|
||||||
var frame = imgArray[i].Frames.CloneFrame(frameNumber % imgArray[i].Frames.Count);
|
using var frame = imgArray[i].Frames.CloneFrame(frameNumber % imgArray[i].Frames.Count);
|
||||||
var offset = xOffset;
|
var offset = xOffset;
|
||||||
imgFrame.Mutate(x => x.DrawImage(frame, new(offset, 0), new GraphicsOptions()));
|
imgFrame.Mutate(x => x.DrawImage(frame, new(offset, 0), new GraphicsOptions()));
|
||||||
xOffset += imgArray[i].Bounds().Width;
|
xOffset += imgArray[i].Bounds().Width;
|
||||||
|
@@ -89,7 +89,7 @@ public static class StringExtensions
|
|||||||
public static async Task<Stream> ToStream(this string str)
|
public static async Task<Stream> ToStream(this string str)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
var sw = new StreamWriter(ms);
|
await using var sw = new StreamWriter(ms);
|
||||||
await sw.WriteAsync(str);
|
await sw.WriteAsync(str);
|
||||||
await sw.FlushAsync();
|
await sw.FlushAsync();
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
# DO NOT CHANGE
|
# DO NOT CHANGE
|
||||||
version: 3
|
version: 4
|
||||||
# Bot token. Do not share with anyone ever -> https://discordapp.com/developers/applications/
|
# Bot token. Do not share with anyone ever -> https://discordapp.com/developers/applications/
|
||||||
token: ''
|
token: ''
|
||||||
# List of Ids of the users who have bot owner permissions
|
# List of Ids of the users who have bot owner permissions
|
||||||
# **DO NOT ADD PEOPLE YOU DON'T TRUST**
|
# **DO NOT ADD PEOPLE YOU DON'T TRUST**
|
||||||
ownerIds: []
|
ownerIds: []
|
||||||
|
# Keep this on 'true' unless you're sure your bot shouldn't use privileged intents or you're waiting to be accepted
|
||||||
|
usePrivilegedIntents: true
|
||||||
# The number of shards that the bot will running on.
|
# The number of shards that the bot will running on.
|
||||||
# Leave at 1 if you don't know what you're doing.
|
# Leave at 1 if you don't know what you're doing.
|
||||||
totalShards: 1
|
totalShards: 1
|
||||||
|
@@ -202,9 +202,9 @@ exprlist:
|
|||||||
Running the command in DM will list global custom reactions, while running it in a server will list server custom reactions.
|
Running the command in DM will list global custom reactions, while running it in a server will list server custom reactions.
|
||||||
Shows enabled settings, followed by id, followed by the trigger.
|
Shows enabled settings, followed by id, followed by the trigger.
|
||||||
**Settings:**
|
**Settings:**
|
||||||
• 🗯️ Triggered if trigger matches any word (`{0}h {0}crca`)
|
• 🗯️ Triggered if trigger matches any word (`{0}h {0}exca`)
|
||||||
• ✉️ Response will be DMed (`{0}h {0}crdm`)
|
• ✉️ Response will be DMed (`{0}h {0}exdm`)
|
||||||
• ❌ Trigger will be deleted (`{0}h {0}crad`)
|
• ❌ Trigger will be deleted (`{0}h {0}exad`)
|
||||||
args:
|
args:
|
||||||
- "1"
|
- "1"
|
||||||
- "all"
|
- "all"
|
||||||
@@ -889,7 +889,7 @@ deleteplaylist:
|
|||||||
args:
|
args:
|
||||||
- "5"
|
- "5"
|
||||||
queueautoplay:
|
queueautoplay:
|
||||||
desc: "Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs and when queue is empty)"
|
desc: "Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs)"
|
||||||
args:
|
args:
|
||||||
- ""
|
- ""
|
||||||
streamadd:
|
streamadd:
|
||||||
@@ -2154,4 +2154,4 @@ showembed:
|
|||||||
deleteemptyservers:
|
deleteemptyservers:
|
||||||
desc: "Deletes all servers in which the bot is the only member."
|
desc: "Deletes all servers in which the bot is the only member."
|
||||||
args:
|
args:
|
||||||
- ""
|
- ""
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"deleted": "Custom Reaction deleted",
|
"expr_deleted": "Expression deleted",
|
||||||
"insuff_perms": "Insufficient permissions. Requires Bot ownership for global custom reactions, and Administrator for server custom reactions.",
|
"expr_insuff_perms": "Insufficient permissions. Requires Bot ownership for global expressions, and Administrator for server expressions.",
|
||||||
"custom_reactions": "Custom Reactions",
|
"expressions": "Expressions",
|
||||||
"new_cust_react": "New Custom Reaction",
|
"expr_new": "New Expression",
|
||||||
"no_found": "No custom reaction found.",
|
"expr_no_found": "No expression found.",
|
||||||
"no_found_id": "No custom reaction found with that id.",
|
"expr_no_found_id": "No expression found with that id.",
|
||||||
"cleared": "All {0} custom reactions on this server have been removed.",
|
"exprs_cleared": "All {0} expressions on this server have been removed.",
|
||||||
"crr_reset": "Custom reaction with id {0} will no longer add reactions.",
|
"expr_reset": "Expression with id {0} will no longer add reactions.",
|
||||||
"crr_set": "Custom reaction with id {0} will add following reactions to the response message: {1}",
|
"expr_set": "Expression with id {0} will add following reactions to the response message: {1}",
|
||||||
"invalid_emojis": "All emojis you've specified are invalid.",
|
"invalid_emojis": "All emojis you've specified are invalid.",
|
||||||
"invalid_emoji_link": "Specified link is either not an image or exceeds 256KB.",
|
"invalid_emoji_link": "Specified link is either not an image or exceeds 256KB.",
|
||||||
"emoji_add_error": "Error adding emoji. You either ran out of emoji slots, or image size is inadequate.",
|
"emoji_add_error": "Error adding emoji. You either ran out of emoji slots, or image size is inadequate.",
|
||||||
@@ -636,8 +636,8 @@
|
|||||||
"vcrole_added": "Users who join {0} voice channel will get {1} role.",
|
"vcrole_added": "Users who join {0} voice channel will get {1} role.",
|
||||||
"vcrole_removed": "Users who join {0} voice channel will no longer get a role.",
|
"vcrole_removed": "Users who join {0} voice channel will no longer get a role.",
|
||||||
"vc_role_list": "Voice channel roles",
|
"vc_role_list": "Voice channel roles",
|
||||||
"option_disabled": "{0} option is now disabled for custom reaction with id {1}.",
|
"option_disabled": "{0} option is now disabled for the expression with id {1}.",
|
||||||
"option_enabled": "{0} option is now enabled for custom reaction with id {1}.",
|
"option_enabled": "{0} option is now enabled for the expression with id {1}.",
|
||||||
"aliases_none": "No alias found",
|
"aliases_none": "No alias found",
|
||||||
"alias_added": "Typing {0} will now be an alias of {1}.",
|
"alias_added": "Typing {0} will now be an alias of {1}.",
|
||||||
"alias_list": "List of aliases",
|
"alias_list": "List of aliases",
|
||||||
@@ -847,7 +847,7 @@
|
|||||||
"club_apps_for": "Applicants for {0} club",
|
"club_apps_for": "Applicants for {0} club",
|
||||||
"club_leaderboard": "Club leaderboard - page {0}",
|
"club_leaderboard": "Club leaderboard - page {0}",
|
||||||
"template_reloaded": "Xp template has been reloaded.",
|
"template_reloaded": "Xp template has been reloaded.",
|
||||||
"edited_cust_react": "Custom Reaction Edited",
|
"expr_edited": "Expression Edited",
|
||||||
"self_assign_are_exclusive": "You can only choose 1 role from each group.",
|
"self_assign_are_exclusive": "You can only choose 1 role from each group.",
|
||||||
"self_assign_are_not_exclusive": "You can choose any number of roles from any group.",
|
"self_assign_are_not_exclusive": "You can choose any number of roles from any group.",
|
||||||
"self_assign_group": "Group {0}",
|
"self_assign_group": "Group {0}",
|
||||||
@@ -870,7 +870,6 @@
|
|||||||
"feed_no_feed": "You haven't subscribed to any feeds on this server.",
|
"feed_no_feed": "You haven't subscribed to any feeds on this server.",
|
||||||
"restart_fail": "You must setup RestartCommand in your creds.yml",
|
"restart_fail": "You must setup RestartCommand in your creds.yml",
|
||||||
"restarting": "Restarting.",
|
"restarting": "Restarting.",
|
||||||
"edit_fail": "Custom reaction with that ID does not exist.",
|
|
||||||
"streaming": "Streaming",
|
"streaming": "Streaming",
|
||||||
"rafflecur": "{0} Currency Raffle",
|
"rafflecur": "{0} Currency Raffle",
|
||||||
"rafflecur_joined": "User {0} joined the raffle",
|
"rafflecur_joined": "User {0} joined the raffle",
|
||||||
|
Reference in New Issue
Block a user